Compare commits

...

183 Commits

Author SHA1 Message Date
jenkins 451bde1244 chore(release): cut v1.2.10 release 2014-01-24 15:28:28 -08:00
Matias Niemelä 4f827f587b docs(changelog): release notes for 1.2.10 2014-01-24 13:34:45 -05:00
Matias Niemelä 131410b61b docs(search): make sure the forward slash doesn't focus on search while on another input element
Closes #5969
2014-01-24 13:02:50 -05:00
Matias Niemelä ca6b7d0fa2 feat($animate): provide support for a close callback
Closes #5685
Closes #5053
Closes #4993
2014-01-24 12:21:29 -05:00
Brian Ford 40dc806e03 docs(guide/filter): link to an example of a filter unit test 2014-01-23 13:43:31 -08:00
Peter Bacon Darwin 5e9835b4f2 docs(ngdoc): ensure module installation docs are accurate
The ngMock module is built into a package called angular-mocks, which is
not named consistently and the docs were giving invalid info.

Closes #5810
2014-01-23 17:27:30 +00:00
Caitlin Potter e0209169bf fix(a): don't preventDefault on click when SVGAElement has an xlink:href attribute
Before this change, an SVGAElement with an xlink:href attribute and no href or name attribute which
was compiled by the angular HTML compiler would never be clickable, due to the htmlAnchorDirective
calling event.preventDefault() due to the missing href attribute.

This change corrects this behaviour by also testing the xlink:href attribute if the element in
question is determined to be an SVG anchor tag (with the href property having type SVGAnimatedString)

Closes #5896
Closes #5897
2014-01-22 14:51:47 -05:00
Martin Probst b07afa0465 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 #5906
2014-01-22 11:38:14 -08:00
Allon Hadaya c3b5e16d84 docs(ngRoute): grammar correction
grammar: occurs -> occur

Closes #5937
2014-01-22 14:26:33 -05:00
Igor Minar 7f444a205e style($interval): remove ws and replace comma with semicolon 2014-01-22 11:14:59 -08:00
Julie 82213efff2 test(doc:protractor): turn off animation for doc end to end tests to speed things up 2014-01-22 12:41:35 -05:00
gabrielbrasil ec59be67bc docs(ngMock): $log.error property contains messages from $log.error, not $log.log
Closes #5932
2014-01-22 11:34:56 -05:00
Caitlin Potter 79e519feda fix(input): use Chromium's email validation regexp
This change uses the regexp from Chromium/Blink to validate emails, and corrects
an error in the validation engine, which previously considered an invalid email
to be valid. Additionally, the regexp was invalidating emails with capital
letters, however this is not the behaviour recomended in the spec, or implemented
in Chromium.

Closes #5899
Closes #5924
2014-01-21 21:40:55 -05:00
matthewhintzen 7cf5544a9f docs(tutorial): update step_12.ngdoc
This time I feel good about this modification to the document, the code listing
on the tutorial page for the animation.js DID NOT match what was actually IN the
file for that branch.  Updated tutorial to reflect actual contents of file

Closes #5922
2014-01-21 17:23:05 -08:00
Narretz 030a9b8d33 docs(changelog): remove reverted commit from 1.2.9
Closes #5868
2014-01-21 17:17:14 -08:00
Igor Minar 310f129c1d docs(guide/directive): clarify attr object definition
Closes #5884
2014-01-21 17:14:00 -08:00
Igor Minar 0fc64ad8a1 style(guide/directive): remove ws 2014-01-21 17:12:34 -08:00
Jan Hancic 12d1f5700d chore(docs): add spacing to tutorial buttons
Added 5px of right margin to tutorial buttons (Previous, Live demom ...).

Closes #5901
2014-01-21 17:04:49 -08:00
Brian Ford 60e80509a8 docs(select): add callout style for a note 2014-01-21 17:02:50 -08:00
Dan Matthews 3c12d36e73 docs(select): add object comparison warning 2014-01-21 16:58:41 -08:00
Caitlin Potter fd6bac7de5 fix(ngRoute): pipe preceding route param no longer masks ? or * operator
Before this change,

```js
$routeProvider.when('/foo/:bar|?', { ... });
```

would not have the expected effect --- the parameter would not be optional, and
the pipe would not be included in the parameter name.

Following this change, the presence of the pipe operator will typically cause an
exception to be thrown due to the fact that the generated regexp is invalid.

The net result of this change is that ? and * operators will not be masked, and
pipe operators will need to be removed, although it's unexpected that these are
being used anywhere.

Closes #5920
2014-01-21 19:56:57 -05:00
George Cox 6d525f06c0 docs(tutorial): remove 'going forward' nonsense
Closes #5914

time/space dimension error
2014-01-21 16:45:27 -08:00
George Cox d7e6f1b192 docs(tutorial): fix grammar
Closes #5909
2014-01-21 16:43:52 -08:00
Stéphane Reynaud 5b9ff6cf48 docs(guide/controller): fix duplicated "and" typo
Remove the second instance of the word "and" from the docs where it was duplicated.
2014-01-21 16:28:30 -08:00
Lucas Galfasó f09b6aa5b5 fix($parse): do not use locals to resolve object properties
Do not use the locals when performing a field access in an angular expression.

Closes #5838
Closes #5862
2014-01-21 19:27:04 -05:00
Abraham 8b395ff325 docs(ngEventDirs): document priority of event directives
The general assumption is that if @priority is not defined, the priority is 0. BUT it's not
necessarily harmful to be explicit about this.

Closes #5852
2014-01-19 23:29:39 -05:00
Christoph Burgdorf 6c9131ef10 docs($http): remove outdated part about $http outside of $apply phase
This removes some outdated advice which no longer is true against the latest angular version.

The information about unit testing with ngMocks remains, because it's always good to have
information like that easily found. This little snippet is not worded perfectly, and is not
a very good example unit test, so additional work is needed here.

Relates to #5206
Closes #5485
2014-01-18 22:52:58 -05:00
Vlad GURDIGA 99c5027bf2 docs($provide): fix Markdown formatting for provider method
Indentation made Markdown parser think that it’s a block of code.

Closes #5446
2014-01-18 22:09:56 -05:00
letsmakesense 90e60d2d54 docs($q): note that function okToGreet is expected to be defined in example
the function okToGreet wasn't defined, so this example wouldn't work properly.

I've decided that instead of adding unrelated code to the example, it should just be noted that the
function is expected to be defined in the lexical scope.

Closes #5878
2014-01-18 17:36:58 -05:00
Bastian Buchholz 928d000db7 docs(ngInit): ng-init is an attribute/class directive, not an element directive
As discussed in comments on https://github.com/angular/angular.js/commit/42ec95ebae716c81087684b55ed8fa8c13888abc#commitcomment-5109829,
ngInit is not an element directive, so @clkao's example should reflect this.

Closes #5879
2014-01-18 17:10:46 -05:00
Chia-liang Kao 42ec95ebae docs(ngInit): note precedence when used with filters
Clears up expression priority issue

Closes #3869
Closes #5873
2014-01-18 15:35:33 -05:00
Joshua Flanagan 1028cfaa30 docs(services): use $log service in example consistently with $log API
The $log provider returns an object and not a function, so this example, which appears to be using
the $log provider, should call it as it would be called in a real-world application.

Closes #5875
2014-01-18 15:26:18 -05:00
Ben McCann 756c52d6c1 docs(directive): link to directive registration api function
Originally, this issue was regarding documenting `restrict: 'CM'` in the directive guide, but it
was pointed out that the restrict documentation is covered in the $compile documentation. Because of
this, a link was simply added to the $compile documentation.

However, the wording suggests that it's actually linking to the directive registration function, in
$compileProvider, so the docs will link there instead. There is a link only a paragraph below to the
$compile documentation, so this does not hurt.

Closes #5516
2014-01-17 22:36:05 -05:00
Jeff Jewiss c3e1a41d6f docs(api): adds links to top level guides
The main api docs page is probably the main landing page for many devs
looking to learn angular, so linking to the main guide pages would
likely help.

Closes #5869
2014-01-17 19:19:27 -05:00
Abdessamad Idrissi 8dd4f14a04 docs(input): document ngValue directive
Extend the example with ng-value showing how to deal with default checked radio boxes.

Closes #5654
2014-01-17 18:15:25 -05:00
Cameron Spear 7ba30fd2e7 docs($sce): correct documentation for angular 1.2.0
Include mention of `ngSanitize` (and add it to the example), as well as removing (and clarifying if
needed) references to `ng-html-bind-unsafe`.

Closes #5551
2014-01-17 17:12:53 -05:00
Andreas Gruenbacher 5adea0ba64 docs(ngChange): clarify difference between ng-change DOM change event
The ng-change event triggers immediately, which makes a difference for text input fields and text
areas, where the JavaScript onchange event would only be called at the end of the change.

Closes #5640
2014-01-17 16:40:10 -05:00
Bruce Davidson 2262ca6697 docs(contributing): add instructions to install grunt-cli/bower globally on unix systems
Closes #5814
Closes #5811
2014-01-17 15:51:29 -05:00
刘朋飞 cd74f74468 docs(tutorial): add missing semicolon to code snippet
Lets encourage people to use semicolons in javascript :>

Closes #5834
2014-01-17 15:34:33 -05:00
Neil Rubens fced1c0c16 docs(tutorial): fix typo
Correction misspelling: easist -> easiest

Closes #5850
2014-01-16 23:11:52 -05:00
Rob Wormald 1cdcddb5cc docs(animations): renamed animate-show-hide to sample-show-hide
This always throws me off - I think it helps to make it clear that the class name is arbitrary, and
what matters is the .ng-etc classes.

Closes #5848
2014-01-16 21:49:01 -05:00
Leniel Macaferi 0e4d7cacad docs(tutorial): reference node command before scripts\web-server.js
Amended to also clarify this note in the mac/linux tab.

Closes #5845
2014-01-16 19:13:53 -05:00
akerekes 6a9ccacd62 docs(concepts): fix typos in explanation
Code uses module names with '2' as suffix while the explanation used the module names without the
suffix. The diagram is correct but also does not suffix the module names.

Closes #5567
2014-01-15 19:31:06 -05:00
Foxandxss e591ddcb30 docs(ngShowHide): make a note of values considered to be falsy
This issue has been a focus of problems for some users and we discussed it on the IRC that it should
be at least documented.

~Amended the style to use bootstrap notes, I think overall it looks better and catches the eyes more
easily. However there are no anchor links to these, if these are necessary they can be added later.

Closes #3436
Closes #5762
2014-01-15 17:59:01 -05:00
John Lannon cd0af8a771 docs(README): fix typo
Closes #5813
2014-01-15 17:46:12 -05:00
Roy Ling 51a7f9dc4a docs(guide/directive): rephrase for consistency
- referring to `=attr` rather than `=prop` is consistent with note under example with =customerInfo
- change `prop` to `attr` (basically `prop` refers to property in JS object, `attr` is for HTML tag)
- change the function name in description to match the name in code example

Closes #5786
2014-01-15 17:41:17 -05:00
jenkins 61eb426ab4 chore(release): update cdn version 2014-01-15 13:39:34 -08:00
jenkins 8ea8da4f11 chore(release): start v1.2.10 (1.2.10) 2014-01-15 10:15:55 -08:00
jenkins 07ee29c563 chore(release): cut v1.2.9 release 2014-01-15 10:02:10 -08:00
Peter Bacon Darwin 9f5d0cf79f docs(changelog): release notes for 1.2.9 2014-01-15 17:24:18 +00:00
Matias Niemelä 1413328e6a fix(ngMock): ensure ngAnimate isn't a required mock 2014-01-15 03:43:52 -05:00
Matias Niemelä 7d09bd30f9 chore($animate): remove Moz statements from requestAnimationFrame 2014-01-15 03:29:20 -05:00
Matias Niemelä dde1b29497 feat($animate): provide support for DOM callbacks 2014-01-14 13:21:28 -05:00
Matias Niemelä 4ae3184c59 feat($animate): use requestAnimationFrame instead of a timeout to issue a reflow
Closes #4278
Closes #4225
2014-01-14 13:21:19 -05:00
Matias Niemelä ed53100a0d fix($animate): ensure the final closing timeout respects staggering animations 2014-01-14 13:20:50 -05:00
Matias Niemelä 6df598d9f5 chore($animate): remove useless and expired test 2014-01-14 13:20:27 -05:00
Matias Niemelä 4aa9df7a7a fix($animate): prevent race conditions for class-based animations when animating on the same CSS class
Closes #5588
2014-01-14 13:20:10 -05:00
Matias Niemelä 7d5d62dafe fix($animate): correctly detect and handle CSS transition changes during class addition and removal
When a CSS class containing transition code is added to an element then an animation should kick off.
ngAnimate doesn't do this. It only respects transition styles that are already present on the element
or on the setup class (but not the addClass animation).
2014-01-14 13:19:09 -05:00
Matias Niemelä 524650a40e fix($animate): avoid accidentally matching substrings when resolving the presence of className tokens 2014-01-14 13:18:50 -05:00
Sebastian Müller 02a45826f1 docs(docs): preserve path to current doc page when switching versions
Preserve URL path when switching between doc versions.

Closes #4661
Closes #5773
2014-01-14 06:39:44 +00:00
Lukas Ruebbelke e324c14907 docs(provider): replaced coffeescript with comparable javascript example 2014-01-13 23:03:36 -05:00
Hendrixer e1cfb1957f fix($http): ensure default headers PUT and POST are different objects
Send PUT and POST through copy() to make sure they are not the same.

Closes #5742
Closes #5747
Closes #5764
2014-01-13 16:50:15 -08:00
marcwright 2a3586381f docs(tutorial): fix a typo
Closes #5769
2014-01-13 16:40:56 -08:00
Igor Minar 834d316829 docs(forEach): remove obsolte note 2014-01-13 16:31:43 -08:00
Mehul Patel c61be8d0e6 docs(angular.forEach): specifies that .forEach filters using .hasOwnProperty
Closes #5180
Closes #5776
2014-01-13 16:31:42 -08:00
Pop 465212835f docs(guide): fix a typo 2014-01-13 16:24:56 -08:00
Frederik Creemers b3acddea37 docs(CONTRIBUTING.md): add link to coding rules
add a link insie the Submitting a Pull Request section
2014-01-13 16:18:14 -08:00
Igor Minar 308598795a revert: fix($route): update current route upon $route instantiation
This reverts commit 2b344dbd20.

I think I merged this commit prematurely and in addition to that
we found out that it's breaking google apps.

Jen Bourey will provide more info at the original PR #5681
2014-01-13 15:12:17 -08:00
Noam Lewis 2cd09c9f0e fix($rootScope): prevent infinite $digest by checking if asyncQueue is empty when decrementing ttl
An infinite $digest loop can be caused by expressions that invoke a promise.
The problem is that $digest does not decrement ttl unless it finds dirty changes;
it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the
condition for terminating the $digest loop.

Fixes #2622
2014-01-13 09:53:38 -08:00
Leniel Macaferi 34fee06ca7 docs(tutorial): referenced test.bat for Windows users in step 2
Closes #5748
2014-01-11 20:15:50 -08:00
Igor Minar c7a46d4b8a docs(ngView): moar better autoscroll docs
Closes #5734
2014-01-11 14:29:05 -08:00
Gias Kay Lee de065f1961 docs(ngView): add param info
Closes #5734
Closes #5741
2014-01-11 14:18:07 -08:00
Seth Stone c3ab915d2e docs(tutorial): add missing beforeEach(module()) to test
Test snippet was missing this necessary statement that was present in the sample code.

Closes #5743
2014-01-11 14:09:52 -08:00
Roy Ling f4a4f42abb docs(api/index): fix typo
Closes #5738
2014-01-10 23:43:32 -08:00
jesse b2c84ccde3 docs($sce): corrected typo & markup.
the --> that

value --> `value`

Closes #5735
2014-01-10 23:42:36 -08:00
Daniel Zimmermann 2b344dbd20 fix($route): update current route upon $route instantiation
This fixes cases where the first ngView is loaded in a template asynchronously (such as through ngInclude), as the service will miss the first  event otherwise.

Closes #4957
2014-01-10 23:42:36 -08:00
Jeff Cross cde840fdf8 docs(i18n): remove use of gendered pronoun 2014-01-10 20:15:18 -08:00
Naomi Black f9656dab2d docs: update step_04.ngdoc with a clarification
closes #5730
2014-01-10 17:11:39 -08:00
Naomi Black a0d759c613 docs: add clarification in step 2 of the tutorial 2014-01-10 16:54:20 -08:00
jenkins 0d421f093d chore(release): update cdn version 2014-01-10 14:33:27 -08:00
jenkins 5f937e54df chore(release): start v1.2.9 (1.2.9) 2014-01-10 12:51:00 -08:00
jenkins 0f9a1c21e6 chore(release): cut v1.2.8 release 2014-01-10 12:37:49 -08:00
Brian Ford ece7854972 docs(changelog): release notes for 1.2.8 2014-01-10 11:49:06 -08:00
Ajay Roopakalu 8ace8073fd docs(select): update regexp grouping cheat-sheat
Update the regexp grouping comment to reflect the changes needed for
multiline expressions in ng-options for <select>.

Closes #5602
2014-01-10 09:50:28 -08:00
Ajay Roopakalu 43a2f3d0bf feat(select): allow multiline ng-options
This patch allows the ng-options value of a <select> element to span
multiple lines, which would previously throw an error when used with filters.

Closes #5602
2014-01-10 09:50:28 -08:00
Igor Minar a9cccbe14f fix($http): return responseText on IE8 for requests with responseType set
Closes #4464
Closes #4738
Closes #5636
2014-01-10 02:25:36 -08:00
Narretz 36c9e42de2 docs: fix the 'view source' button for snapshots
Closes #5590
Closes #5641
2014-01-10 02:22:27 -08:00
René Wilhelm 9f566db33c docs(\$resource): fixed typo (s/seapph/search)
Closes #5718
2014-01-10 01:10:19 -08:00
Caitlin Potter c77b2bcca3 docs($location): fix link to $locationChangeSuccess event
Closes #5717
2014-01-10 00:58:40 -08:00
Igor Minar 5a4145fe16 revert: fix($location): return '/' for root path in hashbang mode
This reverts commit 63cd873fef.

The change breaks existing tests of Google apps. The problem is that
while we tried to avoid adding #/ to window.location.href unnecessarily
we failed doing so. Likely because by setting $path, at some point
(during a digest) we try to check if $location changed and we mistake the
default '/' with an explicit settign of the path via the `path()` method.
This results in us writing the url with '#/' into $browser.url() which updates
the window.location by adding "#/" to the url - something we tried to avoid
in the first place.

I'll reopen PR #5712.
2014-01-09 23:47:35 -08:00
Jeff Cross 039b990d8d test(docs): add protractor tests for docs app
Closes #5437
2014-01-09 22:41:52 -08:00
Tobias Bosch 5a9cb8be3f chore(build): bugfix for script utils 2014-01-09 17:37:27 -08:00
Caitlin Potter 63cd873fef fix($location): return '/' for root path in hashbang mode
Before this change, on the root of the application, $location.path() would return
the empty string. Following this change, it will always return a root of '/'.

Closes #5650
Closes #5712
2014-01-09 17:35:25 -08:00
Igor Minar 69452fa94f docs(tutorial): improve experiment instructions
Closes #5697
2014-01-09 17:24:10 -08:00
Julie 2ed4ad5502 feat(build): add a grunt test for running protractor tests extracted from the docs 2014-01-09 17:21:46 -08:00
René Wilhelm 1d2a388830 fix(docs): Add missing whitespace 2014-01-09 16:51:47 -08:00
stucash ac05276a51 fix(docs): Update reference to $routeProvider.otherwise 2014-01-09 16:48:15 -08:00
Craig Younkins cb9c0f200a fix(docs): Clarifying versions of IE that need special fixes 2014-01-09 16:34:16 -08:00
Tobias Bosch b1d676b7f7 chore(build): check cdn before executing the release-after-cdn script 2014-01-09 15:29:02 -08:00
Tobias Bosch 9ddef840b6 chore(build): add relase-after-cdn script 2014-01-09 14:59:55 -08:00
Rafał Jagoda 28fc80bba0 fix($httpBackend): Allow status code 0 from any protocol
Android 4.1 stock browser also returns status code 0 when
a template is loaded via `http` and the application is cached using
appcache.

Fixes #1356.
Closes #5547.
2014-01-09 10:10:11 -08:00
Julie b6c42d5e81 feat(docs): adding the <doc:protractor> ngdoc-tag
This is the first step in migrating tests from <doc:scenario> to <doc:protractor>.
In-documentation examples with doc:protractor sections will have their contents
output to a tab on the docs site as well as output to a standalone test file in
build/docs/ptore2e.
2014-01-08 13:07:58 -08:00
Gias Kay Lee 1c045f1b46 docs(script): add more detailed information
Closes #5671
Closes #5676
2014-01-08 00:49:29 -08:00
Artemy Tregubenko 95e1b2d612 fix($httpBackend): cancelled JSONP requests will not print error in the console
When you cancel a JSONP request, angular deletes the callback for it. However the script still executes, and since the callback is now deleted and undefined, the script throws an exception visible in the console. The quick fix for this is not to delete the callback, but replace it with `angular.noop`.

Closes #5615
Closes #5616
2014-01-08 00:35:19 -08:00
Igor Minar 75345e3487 docs($document): moar better description
Closes #5678
2014-01-07 17:07:48 -08:00
Igor Minar f4fe28bd92 docs($document): improve the description
Closes #5678
2014-01-07 17:06:22 -08:00
Tobias Bosch ace13b94e6 chore(build): fix typo in release script 2014-01-07 17:00:53 -08:00
Gias Kay Lee 5df7e73adf refactor(booleanAttrs, ngSwitch): use link function instead of compile function where appropriate
Replace two compile functions that immediately return a post-link function with link function definitions instead.

Closes #5664
2014-01-07 16:54:35 -08:00
Zhong Liang Ong e115342fce docs(directives): Fixed typo from HMTL to HTML in line 283
HTML was mis-spelt as HMTL
2014-01-07 16:51:47 -08:00
Tobias Bosch e89150ca0f chore(build): Add angular-seed and angular-phonecat to the release 2014-01-07 15:49:03 -08:00
Vojta Jina 9693a426e3 chore(travis): use Safari 7 2014-01-07 11:53:50 -08:00
Vojta Jina 162485d303 chore(travis): use FF26
I think it's better to not specify the version as that should give the latest available version.
We should probably revert this commit at some point.
2014-01-07 11:53:17 -08:00
Vojta Jina affcbad501 test(ngMock): fix the tests to not use global msie
My bad when merging 7e916455b3.

These tests are run with compiled Angular and then the msie is not defined.
2014-01-06 19:08:05 -08:00
Andrew C. Greenberg 7e916455b3 fix(ngMock window.inject): Remove Error 'stack' property changes
Recent browsers, particularly PhantomJS 1.9.2 and Safari 7.0
treat the stack property as non-configurable and unwritable.

Because window.inject captures the stack at the time of the inject,
and attempts to insert it into a captured throw from the injected
function by modifying e.stack, a meaningless error message and
stack is thrown instead.

This commit inserts two tests exposing the problem, and implements
a proposed solution that builds a new error-like object that mimicks
the old Error object, but with the additional stack information, and
captures the toString function from the Error object prototype.  This
appears to work for the browsers suppoerted here.
2014-01-06 17:47:06 -08:00
Ben Wiklund cdc4d485a6 refactor(input): wrapped validation logic in helper function
Closes #5643
2014-01-06 17:35:13 -08:00
Gias Kay Lee c894470d41 docs($compile): fix a typo
Closes #5639
2014-01-06 17:35:13 -08:00
Jay Goldman 1b0718bf89 docs(tutorial/step-12): replaced a missing apostrophe and fixed grammar errors
Fixed a missing apostrophe and some grammar in the Animating 'ngClass' with JavaScript section
2014-01-06 20:06:27 -05:00
jesse 53fd24ffcb docs(form): changed capitalization in CSS classes section
In order to improve readability from "Is set" (confused on my screen as 'Ls set') updated the
capitalization describing the setting of 4 CSS classes.

Closes #5642
2014-01-06 16:44:52 -08:00
Ben Wiklund eb90672aae chore(inputSpec): fixed typo 2014-01-06 16:37:47 -08:00
Roy Ling 28cfd96fdc docs(forms): show directive name instead of link path 2014-01-06 16:34:49 -08:00
Tyler McGinnis 99d5defb1a docs(guide/i18n): fix a typo
Closes #5651
2014-01-06 16:11:53 -08:00
Tobias Bosch efbc242875 chore(build): bugfixes to build scripts on Jenkins 2014-01-06 15:48:30 -08:00
Vojta Jina d4d58f287f docs(tutorial): do not recommend global install of Karma
Closes #5498
2014-01-06 14:48:50 -08:00
Tobias Bosch dc89db33df chore(build): bugfixes to build scripts on Jenkins. 2014-01-06 14:11:44 -08:00
Tobias Bosch 5dc27959d5 chore(build): refactor build scripts in prepare/publish phase
Refactored all scripts so that they are divided into a `prepare`
and a `publish` phase. By this we can build, test, tag, commit
everything first. Only if all of this is ok we start pushing
to Github. By this we keep Github consistent even in error cases.

Extracted include script `/scripts/utils.inc`:
- parse and validate named arguments in the style
  `--name=value`
- proxy git command and deactivate `git push` based on
  command option `--git_push_dry_run=true`
  (will be inherited to child scripts)
- enable/disable bash debug mode by command option
  `--verbose=true`
- dispatch to functions based on command option
  `--action=...`
- helper functions for dealing with json files
2014-01-06 12:27:54 -08:00
Vojta Jina 4c21355940 chore: strict deps Karma and plugins
So that we have a better control when updating Karma.
2014-01-06 11:27:19 -08:00
Matias Niemelä 6f6cb5c8d8 chore(docs): remove uppercase heading styling
Closes #5593
2014-01-06 10:22:16 -05:00
Chris Chua 821ed310a7 refactor(animate): remove duplicate line 2014-01-06 00:07:44 -05:00
Igor Minar a7aa4cc0a9 revert: fix(closure): add Closure externs for angular.$q.Promise.finally
This reverts commit caeb740265.

The commit breaks Google apps because most don't use closure compiler
with the ES5 mode flag on. We are investigating a solution...
2014-01-05 01:19:35 -08:00
RoyLING e0ce9ed36d refactor(filterFilter): simplify code by a ternary op instead of if-else
- use only one IIFE and a ternary op in it, instead of invoking separate IIFEs in if-else
(this also completely fixed the same issue closed by PR #3597)
- also add a spec to verify usage of '$' property in expression object (e.g. `{$: 'a'}`)

Closes #5637
2014-01-05 00:36:04 -08:00
Daniel Aden caeb740265 fix(closure): add Closure externs for angular.$q.Promise.finally
Closes #4757
2014-01-05 00:27:38 -08:00
Kenneth Lynne 1bb33cccbe docs(rootScope): fix typo
Closes #5633
2014-01-04 20:51:58 -08:00
Igor Minar d9ed9c5ac1 docs(ng/filter/filter): make docs human readable 2014-01-04 00:14:38 -08:00
MikeMac 00cac6ed10 docs($http): makes clear $httpProvider.defaults are available at run-time
Clarifies some confusion around $http.defaults existing and able to be modified
at run-time, for when run-time services may be needed in a transformation.

Closes #5559
Closes #5630
2014-01-03 22:35:14 -08:00
Wojciech Krzystek 2e9d7cc6cb docs(ngRepeat): add info about aliasing special properties of ngRepeat
This will safe peoples' time, since ngRepeat's docs, not ngInit's, is the first
place where one would search for such info.

Closes #5622
2014-01-03 16:07:26 -08:00
Bastian Buchholz 32cc6cbb6f style($httpBackend): fix typo 2014-01-03 16:04:50 -08:00
Brian Nenninger 3b1a4fe0c8 fix($parse): fix CSP nested property evaluation, and issue that prevented its tests from failing
cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading
the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Closes #5591
Closes #5592
2014-01-03 14:33:54 -08:00
Brian Ford 9569778f2f chore(release): fix release name 2014-01-03 13:16:39 -08:00
Brian Ford 0f61316b24 chore(release): update cdn version 2014-01-03 13:09:26 -08:00
Tobias Bosch 86151b0cea chore(release): set next release name 2014-01-03 12:02:29 -08:00
Igor Minar 1b7a6c66f8 core(Scope): rename 'debugger' to 'web inspector' to avoid woes with g3 presubmits 2014-01-03 11:17:43 -08:00
chimney-sweeper 0ef76dde41 chore(release): start v1.2.8 2014-01-03 10:40:31 -08:00
chimney-sweeper c6d04b3a3d chore(release): cut v1.2.7 release 2014-01-03 10:28:30 -08:00
Matias Niemelä e31560cf6b docs(CHANGELOG): add v1.2.7 changes 2014-01-03 13:19:38 -05:00
Igor Minar 3d38fff8b4 fix($httpBackend): don't delete xhr.onreadystatechange otherwise Safari :-O 2014-01-03 09:51:05 -08:00
Matias Niemelä bc492c0fc1 fix($animate): ensure class-based animations are always skipped before structural post-digest tasks are run
Closes #5582
2014-01-03 12:14:15 -05:00
Vojta Jina 162144202c chore: set Karma version to 0.11.11
Temporary reverting Karma, as 0.11.12 is causing some problems.
2014-01-03 08:22:17 -08:00
royling 05596527ed docs($filter): fix wrong param order in doc
fix wrong param order in doc for filter comparator
doc function param for filter expression

Closes #5365
Closes #5611
2014-01-03 02:43:22 -08:00
Tiago Ribeiro 5fea3471e8 docs(\$sniffer): fix minor typo
Closes #5544
2014-01-02 23:10:38 -08:00
Gias Kay Lee 131e4014b8 fix($resource): prevent URL template from collapsing into an empty string
if url template would result in an empty string, we should make a request
to '/' instead.

Closes #5455
Closes #5493
2014-01-02 23:07:27 -08:00
Brian Ford 01c5be4681 fix(ngShow/ngHide, ngIf): functions with zero args should be truthy
Previously, expressions that were a function with one or more arguments evaluated to
true, but functions with zero arguments evaluated to false.

This behavior seems both unintentional and undesirable. This patch makes a function
truthy regardless of its number of arguments.

Closes #5414
2014-01-02 22:59:43 -08:00
Igor Minar fd9a03e147 fix(httpBackend): fix 'type mismatch' error on IE8 after each request 2014-01-02 22:47:39 -08:00
Igor Minar 6c17d02bc4 fix($httpBackend): use ActiveX XHR when making PATCH requests on IE8
IE8's native XHR doesn't support PATCH requests, but the ActiveX one does.

I'm also removing the noxhr error doc because nobody will ever get that error.

Closes #2518
Closes #5043
2014-01-02 22:04:32 -08:00
Drew Perttula 6a6f71f238 docs(error/ngRepeat/dupes): fix typo
Closes #5610
2014-01-02 21:34:34 -08:00
Sebastian K cf686285c2 fix($location): $location.path() behaviour when $locationChangeStart is triggered by the browser
Fixed inconsistency in $location.path() behaviour on the $locationChangeStart event when using
back/forward buttons in the browser or manually changing the url in the address bar.
$location.path() now returns the target url in these cases.

Closes #4989
Closes #5089
Closes #5118
Closes #5580
2014-01-02 21:30:25 -08:00
Igor Minar 7dfedb732d style($browser): remove ws, fix typo 2014-01-02 21:30:00 -08:00
Caitlin Potter 760f2fb731 fix($browser): remove base href domain when url begins with '//'
This change prevents an incorrect appBase url from being calculated when the
<base> href's domain begins with '//'.

Closes #5606
2014-01-02 16:36:31 -08:00
Gias Kay Lee c9705b7556 fix(ngRepeat): allow for more flexible coding style in ngRepeat expression
With this change it's possible to split the ng-repeat expression into multiple
lines at any point in the expression where white-space is expected.

Closes #5537
Closes #5598
2014-01-02 16:14:16 -08:00
David Burrows 53ec33f07f docs($compile): fix typo
Closes #5599
2014-01-02 16:08:51 -08:00
Igor Minar 884ef0dbcd fix(Scope): don't let watch deregistration mess up the dirty-checking digest loop
Closes #5525
2014-01-02 15:28:56 -08:00
Igor Minar 010413f90a test(rootScope): reorganize $watch deregistration specs into a describe 2014-01-02 15:28:56 -08:00
Tobias Bosch 4f57236614 fix($httpBackend): Ignore multiple calls to onreadystatechange with readyState=4
On mobile webkit `onreadystatechange` might by called multiple times
with `readyState===4`  caused by xhrs that are resolved while the app is
in the background.

 Fixes #5426.
2014-01-02 14:37:48 -08:00
Olivier Louvignes 50bf029625 fix(animate): remove trailing s 2014-01-02 11:00:31 -05:00
Igor Minar eff52ad877 docs: moar analytics for all md files 2014-01-01 20:51:45 -08:00
Igor Minar e9ee492d35 docs(README): add analytics 2014-01-01 20:41:55 -08:00
Igor Minar e415e916e8 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.
2013-12-31 01:39:19 -08:00
Igor Minar 07084e1c8b test(injector): add missing test for #5577
Add a missing test for fix that was merged via #5577
2013-12-31 01:24:41 -08:00
Matt Ginzton 186a591228 fix($injector): remove INSTANTIATING entry when done
getService flags services as INSTANTIATING while it calls their
provider factory, in order to detect circular dependencies. If
the service is instantiated correctly, the INSTANTIATING flag is
overwritten with the actual service. However, if the service is
not instantiated correctly, the INSTANTIATING flag should still
be removed, or all further requests for this service will be
mis-detected as a circular dependency.

Closes #4361
Closes #5577
2013-12-31 01:17:43 -08:00
Igor Minar a80049fd0a fix(input): use apply on change event only when one isn't already in progress
Closes #5293
2013-12-31 00:41:15 -08:00
Igor Minar d158dd131e chore(release.sh): push both the release commit and tag 2013-12-30 16:58:28 -08:00
Michał Gołębiowski 1147f21999 fix(input): prevent double $digest when using jQuery trigger.
If an event was performed natively, jQuery sets the isTrigger property.
When triggering event manually, the field is not present. Manually
triggered events are performed synchronously which causes the "$digest
already in progress" error.

Closes #5293
2013-12-30 15:09:49 -08:00
kimwz bddd46c8ec fix($location): re-assign history after BFCache back on Android browser
Closes #5425
2013-12-30 14:58:04 -08:00
Karl Seamon 80e7a45584 perf(Scope): limit propagation of $broadcast to scopes that have listeners for the event
Update $on and $destroy to maintain a count of event keys registered for each scope and its children.
$broadcast will not descend past a node that has a count of 0/undefined for the $broadcasted event key.

Closes #5341
Closes #5371
2013-12-27 23:31:00 -08:00
Caitlin Potter 498365f219 fix(ngRoute): instantiate controller when template is empty
Before this change, $route controllers are not instantiated if the template is falsy, which includes
the empty string. This change tests if the template is not undefined, rather than just falsy, in
order to ensure that templates are instantiated even when the template is empty, which people may
have some reason to do.

This "bug" was reported in http://robb.weblaws.org/2013/06/21/angularjs-vs-emberjs/, as a "gotcha"
for AngularJS / ngRoute.

Closes #5550
2013-12-27 22:45:46 -08:00
Brady Isom 056c849352 fix($sanitize): consider size attribute as valid/allowed attribute
The "size" attribute gets set on <font> elements when using HTML5 rich
text editors, or elements with the contenteditable attribute, that rely
on the 'fontSize' command (execCommand).

Closes #5522
2013-12-27 16:22:35 -08:00
Vojta Jina 7d6e5a2d01 chore: update Karma and SauceLabs launcher
This should improve stability as it contains capture timeout (if a browser does not capture in a given timeout it gets killed) and retry (if a browser fails to start, Karma will try n times before failing).
2013-12-23 17:54:05 -08:00
mkolodny d1c4766d14 docs(guide/forms): update example
Right now, non-integers such as 'aawefwae' are valid.
This ensures that only integers are valid. Hopefully that makes the example more powerful.

Closes #5501
2013-12-20 21:22:15 -08:00
mkolodny 98473835a2 docs(guide/forms): code style changes for an example
Closes #5499
2013-12-20 21:21:18 -08:00
sanfords 870232bd05 style($http): fix a semi-colon 2013-12-20 16:23:06 -08:00
Vojta Jina c31df32ca0 chore(release): update cdn version 2013-12-20 10:29:03 -08:00
Klaus Weiss df2b88e230 docs(guide): fix typo
Closes #5481
2013-12-19 16:12:24 -08:00
Brian Ford 83451d552e chore(release): add codename for 1.2.7 2013-12-19 16:11:36 -08:00
chimney-sweeper af7203e0b8 chore(release): start v1.2.7 2013-12-19 16:02:57 -08:00
113 changed files with 2895 additions and 2867 deletions
+166
View File
@@ -1,3 +1,166 @@
<a name="1.2.10"></a>
# 1.2.10 augmented-serendipity (2014-01-24)
## Bug Fixes
- **$parse:** do not use locals to resolve object properties
([f09b6aa5](https://github.com/angular/angular.js/commit/f09b6aa5b58c090e3b8f8811fb7735e38d4b7623),
[#5838](https://github.com/angular/angular.js/issues/5838), [#5862](https://github.com/angular/angular.js/issues/5862))
- **a:** don't call preventDefault on click when a SVGAElement has an xlink:href attribute
([e0209169](https://github.com/angular/angular.js/commit/e0209169bf1463465ad07484421620748a4d3908),
[#5896](https://github.com/angular/angular.js/issues/5896), [#5897](https://github.com/angular/angular.js/issues/5897))
- **input:** use Chromium's email validation regexp
([79e519fe](https://github.com/angular/angular.js/commit/79e519fedaec54390a8bdacfb1926bfce57a1eb6),
[#5899](https://github.com/angular/angular.js/issues/5899), [#5924](https://github.com/angular/angular.js/issues/5924))
- **ngRoute:** pipe preceding route param no longer masks ? or * operator
([fd6bac7d](https://github.com/angular/angular.js/commit/fd6bac7de56f728a89782dc80c78f7d5c21bbc65),
[#5920](https://github.com/angular/angular.js/issues/5920))
## Features
- **$animate:** provide support for a close callback
([ca6b7d0f](https://github.com/angular/angular.js/commit/ca6b7d0fa2e355ebd764230260758cee9a4ebe1e),
[#5685](https://github.com/angular/angular.js/issues/5685), [#5053](https://github.com/angular/angular.js/issues/5053), [#4993](https://github.com/angular/angular.js/issues/4993))
<a name="1.2.9"></a>
# 1.2.9 enchanted-articulacy (2014-01-15)
## Bug Fixes
- **$animate:**
- ensure the final closing timeout respects staggering animations
([ed53100a](https://github.com/angular/angular.js/commit/ed53100a0dbc9119d5dfc8b7248845d4f6989df2))
- prevent race conditions for class-based animations when animating on the same CSS class
([4aa9df7a](https://github.com/angular/angular.js/commit/4aa9df7a7ae533531dfae1e3eb9646245d6b5ff4),
[#5588](https://github.com/angular/angular.js/issues/5588))
- correctly detect and handle CSS transition changes during class addition and removal
([7d5d62da](https://github.com/angular/angular.js/commit/7d5d62dafe11620082c79da35958f8014eeb008c))
- avoid accidentally matching substrings when resolving the presence of className tokens
([524650a4](https://github.com/angular/angular.js/commit/524650a40ed20f01571e5466475749874ee67288))
- **$http:** ensure default headers PUT and POST are different objects
([e1cfb195](https://github.com/angular/angular.js/commit/e1cfb1957feaf89408bccf48fae6f529e57a82fe),
[#5742](https://github.com/angular/angular.js/issues/5742), [#5747](https://github.com/angular/angular.js/issues/5747), [#5764](https://github.com/angular/angular.js/issues/5764))
- **$rootScope:** prevent infinite $digest by checking if asyncQueue is empty when decrementing ttl
([2cd09c9f](https://github.com/angular/angular.js/commit/2cd09c9f0e7766bcd191662841b7b1ffc3b6dc3f),
[#2622](https://github.com/angular/angular.js/issues/2622))
## Features
- **$animate:**
- provide support for DOM callbacks
([dde1b294](https://github.com/angular/angular.js/commit/dde1b2949727c297e214c99960141bfad438d7a4))
- use requestAnimationFrame instead of a timeout to issue a reflow
([4ae3184c](https://github.com/angular/angular.js/commit/4ae3184c5915aac9aa00889aa2153c8e84c14966),
[#4278](https://github.com/angular/angular.js/issues/4278), [#4225](https://github.com/angular/angular.js/issues/4225))
<a name="1.2.8"></a>
# 1.2.8 interdimensional-cartography (2014-01-10)
## Bug Fixes
- **$http:**
- return responseText on IE8 for requests with responseType set
([a9cccbe1](https://github.com/angular/angular.js/commit/a9cccbe14f1bd9048f5dab4443f58c804d4259a1),
[#4464](https://github.com/angular/angular.js/issues/4464), [#4738](https://github.com/angular/angular.js/issues/4738), [#5636](https://github.com/angular/angular.js/issues/5636))
- Allow status code 0 from any protocol
([28fc80bb](https://github.com/angular/angular.js/commit/28fc80bba0107075ab371fd0a7634a38891626b2),
[#1356](https://github.com/angular/angular.js/issues/1356), [#5547](https://github.com/angular/angular.js/issues/5547))
- cancelled JSONP requests will not print error in the console
([95e1b2d6](https://github.com/angular/angular.js/commit/95e1b2d6121b4e26cf87dcf6746a7b8cb4c25e7f),
[#5615](https://github.com/angular/angular.js/issues/5615), [#5616](https://github.com/angular/angular.js/issues/5616))
- **$location:** return '/' for root path in hashbang mode
([63cd873f](https://github.com/angular/angular.js/commit/63cd873fef3207deef30c7a7ed66f4b8f647dc12),
[#5650](https://github.com/angular/angular.js/issues/5650), [#5712](https://github.com/angular/angular.js/issues/5712))
- **$parse:** fix CSP nested property evaluation, and issue that prevented its tests from failing
([3b1a4fe0](https://github.com/angular/angular.js/commit/3b1a4fe0c83c7898ecd7261ab4213998ee7be0ec),
[#5591](https://github.com/angular/angular.js/issues/5591), [#5592](https://github.com/angular/angular.js/issues/5592))
- **closure:** add Closure externs for angular.$q.Promise.finally
([caeb7402](https://github.com/angular/angular.js/commit/caeb7402651702cd13df2f1594e9827439a8b760),
[#4757](https://github.com/angular/angular.js/issues/4757))
- **ngMock window.inject:** Remove Error 'stack' property changes
([7e916455](https://github.com/angular/angular.js/commit/7e916455b36dc9ca4d4afc1e44cade90006d00e3))
## Features
- **select:** allow multiline ng-options
([43a2f3d0](https://github.com/angular/angular.js/commit/43a2f3d0bf435e3626cd679caff4281cfb3415bd),
[#5602](https://github.com/angular/angular.js/issues/5602))
<a name="1.2.7"></a>
# 1.2.7 emoji-clairvoyance (2014-01-03)
## Bug Fixes
- **$animate:**
- ensue class-based animations are always skipped before structural post-digest tasks are run
([bc492c0f](https://github.com/angular/angular.js/commit/bc492c0fc17257ddf2bc5964e205379aa766b3d8),
[#5582](https://github.com/angular/angular.js/issues/5582))
- remove trailing `s` from computed transition duration styles
([50bf0296](https://github.com/angular/angular.js/commit/50bf029625d603fc652f0f413e709f43803743db))
- **$http:**
([3d38fff8](https://github.com/angular/angular.js/commit/3d38fff8b4ea2fd60fadef2028ea4dcddfccb1a4))
- use ActiveX XHR when making PATCH requests on IE8
([6c17d02b](https://github.com/angular/angular.js/commit/6c17d02bc4cc02f478775d62e1f9f77da9da82ad),
[#2518](https://github.com/angular/angular.js/issues/2518), [#5043](https://github.com/angular/angular.js/issues/5043))
- fix 'type mismatch' error on IE8 after each request
([fd9a03e1](https://github.com/angular/angular.js/commit/fd9a03e147aac7e952c6dda1f381fd4662276ba2))
- Ignore multiple calls to onreadystatechange with readyState=4
([4f572366](https://github.com/angular/angular.js/commit/4f57236614415eea919221ea5f99c4d8689b3267),
[#5426](https://github.com/angular/angular.js/issues/5426))
- **$injector:** remove the `INSTANTIATING` flag properly when done
([186a5912](https://github.com/angular/angular.js/commit/186a5912288acfff0ee59dae29af83c37c987921),
[#4361](https://github.com/angular/angular.js/issues/4361), [#5577](https://github.com/angular/angular.js/issues/5577))
- **$location:**
- remove base href domain if the URL begins with '//'
([760f2fb7](https://github.com/angular/angular.js/commit/760f2fb73178e56c37397b3c5876f7dac96f0455),
[#5606](https://github.com/angular/angular.js/issues/5606))
- fix $location.path() behaviour when $locationChangeStart is triggered by the browser
([cf686285](https://github.com/angular/angular.js/commit/cf686285c22d528440e173fdb65ad1052d96df3c),
[#4989](https://github.com/angular/angular.js/issues/4989), [#5089](https://github.com/angular/angular.js/issues/5089), [#5118](https://github.com/angular/angular.js/issues/5118), [#5580](https://github.com/angular/angular.js/issues/5580))
- re-assign history after BFCache back on Android browser
([bddd46c8](https://github.com/angular/angular.js/commit/bddd46c8ecf49cfe6c999cd6b4a69b7d7e1f9a33),
[#5425](https://github.com/angular/angular.js/issues/5425))
- **$resource:** prevent URL template from collapsing into an empty string
([131e4014](https://github.com/angular/angular.js/commit/131e4014b831ac81b7979c4523da81ebc5861c70),
[#5455](https://github.com/angular/angular.js/issues/5455), [#5493](https://github.com/angular/angular.js/issues/5493))
- **$sanitize:** consider the `size` attribute as a valid/allowed attribute
([056c8493](https://github.com/angular/angular.js/commit/056c8493521988dbb330c6636135b505737da918),
[#5522](https://github.com/angular/angular.js/issues/5522))
- **Scope:** don't let watch deregistration mess up the dirty-checking digest loop
([884ef0db](https://github.com/angular/angular.js/commit/884ef0dbcdfe614cedc824d079361b53e675d033),
[#5525](https://github.com/angular/angular.js/issues/5525))
- **input:**
- use apply on the change event only when one isn't already in progress
([a80049fd](https://github.com/angular/angular.js/commit/a80049fd0ac858eeeb645a4209cb2a661d0b4c33),
[#5293](https://github.com/angular/angular.js/issues/5293))
- prevent double $digest when using jQuery trigger.
([1147f219](https://github.com/angular/angular.js/commit/1147f21999edf9a434cd8d24865a6455e744d858),
[#5293](https://github.com/angular/angular.js/issues/5293))
- **ngRepeat:** allow for more flexible coding style in ngRepeat expression
([c9705b75](https://github.com/angular/angular.js/commit/c9705b755645a4bfe066243f2ba15a733c3787e1),
[#5537](https://github.com/angular/angular.js/issues/5537), [#5598](https://github.com/angular/angular.js/issues/5598))
- **ngRoute:** instantiate controller when template is empty
([498365f2](https://github.com/angular/angular.js/commit/498365f219f65d6c29bdf2f03610a4d3646009bb),
[#5550](https://github.com/angular/angular.js/issues/5550))
- **ngShow/ngHide, ngIf:** functions with zero args should be truthy
([01c5be46](https://github.com/angular/angular.js/commit/01c5be4681e34cdc5f5c461b7a618fefe8038919),
[#5414](https://github.com/angular/angular.js/issues/5414))
## Performance Improvements
- **Scope:** limit propagation of $broadcast to scopes that have listeners for the event
([80e7a455](https://github.com/angular/angular.js/commit/80e7a4558490f7ffd33d142844b9153a5ed00e86),
[#5341](https://github.com/angular/angular.js/issues/5341), [#5371](https://github.com/angular/angular.js/issues/5371))
<a name="1.2.6"></a>
# 1.2.6 taco-salsafication (2013-12-19)
@@ -4384,3 +4547,6 @@ with the `$route` service
[module]: http://docs-next.angularjs.org/api/angular.mock.module
[guide2.di]: http://docs-next.angularjs.org/guide/dev_guide.di
[jqLite2]: http://docs.angularjs.org/#!/api/angular.element
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/CHANGELOG.md?pixel)](https://github.com/igrigorik/ga-beacon)
+3 -1
View File
@@ -80,7 +80,7 @@ Before you submit your pull request consider the following guidelines:
```
* Create your patch, including appropriate test cases.
* Follow our Coding Rules
* Follow our [Coding Rules](#coding-rules)
* 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](#commit-message-format) and our commit message presubmit hook
@@ -258,3 +258,5 @@ You can find out more detailed information about contributing in the
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[github-pr-helper]: https://chrome.google.com/webstore/detail/github-pr-helper/mokbklfnaddkkbolfldepnkfmanfhpen
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/CONTRIBUTING.md?pixel)](https://github.com/igrigorik/ga-beacon)
+8 -1
View File
@@ -101,6 +101,11 @@ module.exports = function(grunt) {
},
runprotractor: {
normal: 'protractor-conf.js'
},
clean: {
build: ['build'],
tmp: ['tmp']
@@ -283,13 +288,15 @@ module.exports = function(grunt) {
//alias tasks
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e']);
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e', 'webdriver', 'runprotractor:normal']);
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
grunt.registerTask('test:e2e', 'Run the end to end tests with Karma and keep a test server running in the background', ['connect:testserver', 'tests:end2end']);
// This should eventually replace test:e2e
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'runprotractor:normal']);
grunt.registerTask('test:docgen', ['jasmine_node']);
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']);
+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/
+5 -1
View File
@@ -7,7 +7,7 @@ syntax to express your applications components clearly and succinctly. It au
synchronizes data from your UI (view) with your JavaScript objects (model) through 2-way data
binding. To help you structure your application better and make it easy to test, AngularJS teaches
the browser how to do dependency injection and inversion of control. Oh yeah and it also helps with
server-side communication, taming async callbacks with promises and deferreds; and make client-side
server-side communication, taming async callbacks with promises and deferreds; and makes client-side
navigation and deeplinking with hashbang urls or HTML5 pushState a piece of cake. The best of all:
it makes development fun!
@@ -38,3 +38,7 @@ To execute end-to-end (e2e) tests, use:
To learn more about the grunt tasks, run `grunt --help` and also read our
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/README.md?pixel)](https://github.com/igrigorik/ga-beacon)
+2
View File
@@ -59,3 +59,5 @@ The following is done automatically and should not be done manually:
1. Unassign yourself from the issue
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/TRIAGING.md?pixel)](https://github.com/igrigorik/ga-beacon)
-17
View File
@@ -1,17 +0,0 @@
This file contains 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/
-1975
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -5,8 +5,8 @@
# AngularJS API Docs
Welcome to the AngularJS API docs page. These pages contain the AngularJS reference materials for version <strong ng-bind="version"></strong>.
The documentation is organized into **modules** which contain various components of an AngularJS application.
These components are directives, services, filters, providers, types, global APIs and testing mocks.
The documentation is organized into **{@link guide/module modules}** which contain various components of an AngularJS application.
These components are {@link guide/directive directives}, {@link guide/dev_guide.services services}, {@link guide/filter filters}, {@link guide/providers providers}, {@link guide/templates types}, global APIs and testing mocks.
<div class="alert alert-info">
**Angular Namespaces `$` and `$$`**
@@ -63,7 +63,7 @@ This module is provided by default and contains the core components of AngularJS
</td>
<td>
<p>
The core filters available in the ng module are used to transform template data before it is renders within directives and expressions.
The core filters available in the ng module are used to transform template data before it is rendered within directives and expressions.
</p>
<p>
Some examples include:
@@ -1,9 +0,0 @@
@ngdoc error
@name $httpBackend:noxhr
@fullName Unsupported XHR
@description
This error occurs in browsers that do not support XmlHttpRequest. AngularJS
supports Safari, Chrome, Firefox, Opera, IE8 and higher, and mobile browsers
(Android, Chrome Mobile, iOS Safari). To avoid this error, use an officially
supported browser.
+1 -1
View File
@@ -13,7 +13,7 @@ For example the issue can be triggered by this *invalid* code:
<div ng-repeat="value in [4, 4]"></div>
```
To resolve this error either ensure that the items in the collection have unique identity of use the `track by` syntax to specify how to track the association between models and DOM.
To resolve this error either ensure that the items in the collection have unique identity or use the `track by` syntax to specify how to track the association between models and DOM.
To resolve the example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
+7 -7
View File
@@ -21,19 +21,19 @@ Below is a quick example of animations being enabled for `ngShow` and `ngHide`:
<label>
<input type="checkbox" ng-model="checked" style="float:left; margin-right:10px;"> Is Visible...
</label>
<div class="check-element animate-show-hide" ng-show="checked" style="clear:both;">
<div class="check-element sample-show-hide" ng-show="checked" style="clear:both;">
Visible...
</div>
</div>
</file>
<file name="animations.css">
.animate-show-hide {
.sample-show-hide {
padding:10px;
border:1px solid black;
background:white;
}
.animate-show-hide.ng-hide-add, .animate-show-hide.ng-hide-remove {
.sample-show-hide.ng-hide-add, .sample-show-hide.ng-hide-remove {
-webkit-transition:all linear 0.5s;
-moz-transition:all linear 0.5s;
-o-transition:all linear 0.5s;
@@ -41,13 +41,13 @@ Below is a quick example of animations being enabled for `ngShow` and `ngHide`:
display:block!important;
}
.animate-show-hide.ng-hide-add.ng-hide-add-active,
.animate-show-hide.ng-hide-remove {
.sample-show-hide.ng-hide-add.ng-hide-add-active,
.sample-show-hide.ng-hide-remove {
opacity:0;
}
.animate-show-hide.ng-hide-add,
.animate-show-hide.ng-hide-remove.ng-hide-remove-active {
.sample-show-hide.ng-hide-add,
.sample-show-hide.ng-hide-remove.ng-hide-remove-active {
opacity:1;
}
</file>
+3 -3
View File
@@ -184,7 +184,7 @@ The following graphic shows how everything works together after we introduced th
# View independent business logic: Services
Right now, the `InvoiceController` contains all logic of our example. When the application grows it
is a good practise to move view independent logic from the controller into a so called
is a good practice to move view independent logic from the controller into a so called
<a name="service">"{@link dev_guide.services service}"</a>, so it can be reused by other parts
of the application as well. Later on, we could also change that service to load the exchange rates
from the web, e.g. by calling the Yahoo Finance API, without changing the controller.
@@ -272,8 +272,8 @@ including the configuration of all modules that this module depends on.
In the example above:
The template contains the directive `ng-app="invoice2"`. This tells Angular
to use the `invoice` module as the main module for the application.
The code snippet `angular.module('invoice', ['finance'])` specifies that the `invoice` module depends on the
`finance` module. By this, Angular uses the `InvoiceController` as well as the `currencyConverter` service.
The code snippet `angular.module('invoice2', ['finance2'])` specifies that the `invoice2` module depends on the
`finance2` module. By this, Angular uses the `InvoiceController` as well as the `currencyConverter` service.
Now that Angular knows of all the parts of the application, it needs to create them.
In the previous section we saw that controllers are created using a factory function.
+1 -1
View File
@@ -168,7 +168,7 @@ 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 (see the `chiliSpicy` method)
- The Controller methods and properties are available in the template (for the `<div>` element and
and its children).
its children).
## Spicy Arguments Example
@@ -19,7 +19,7 @@ testable.
To register a service, you must have a module that this service will be part of. Afterwards, you
can register the service with the module either via the {@link api/angular.Module Module api} or
by using the {@link api/AUTO.$provide $provide} service in the module configuration
function.The following pseudo-code shows both approaches:
function. The following pseudo-code shows both approaches:
Using the angular.Module api:
<pre>
@@ -55,7 +55,7 @@ of which depend on other services that are provided by the Angular framework:
function log() {
if (messageQueue.length) {
$log('batchLog messages: ', messageQueue);
$log.log('batchLog messages: ', messageQueue);
messageQueue = [];
}
}
@@ -163,7 +163,7 @@ function MyClass(xhr) {
This is the preferred method since the code makes no assumptions about the origin of `xhr` and cares
instead about whoever created the class responsible for passing it in. Since the creator of the
class should be different code than the user of the class, it separates the responsibility of
creation from the logic. This is dependency-injection is in a nutshell.
creation from the logic. This is dependency-injection in a nutshell.
The class above is testable, since in the test we can write:
<pre>
+11 -10
View File
@@ -55,7 +55,7 @@ The following also **matches** `ngModel`:
Angular **normalizes** an element's tag and attribute name to determine which elements match which
directives. We typically refer to directives by their case-sensitive
{@link http://en.wikipedia.org/wiki/CamelCase camelCase} **normalized** name (e.g. `ngModel`).
{@link http://en.wikipedia.org/wiki/CamelCase camelCase} **normalized** name (e.g. `ngModel`).
However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case
forms, typically using {@link http://en.wikipedia.org/wiki/Letter_case#Computers dash-delimited}
attributes on DOM elements (e.g. `ng-model`).
@@ -174,9 +174,9 @@ For example, we could fix the example above by instead writing:
## Creating Directives
First let's talk about the API for registering directives. Much like controllers, directives are
registered on modules. To register a directive, you use the `module.directive` API.
`module.directive` takes the
First let's talk about the {@link api/ng.$compileProvider#methods_directive API for registering directives}. Much like
controllers, directives are registered on modules. To register a directive, you use the
`module.directive` API. `module.directive` takes the
{@link guide/directive#creating-custom-directives_matching-directives normalized} directive name
followed by a **factory function.** This factory function should return an object with the different
options to tell `$compile` how the directive should behave when matched.
@@ -280,7 +280,7 @@ using `templateUrl` instead:
</example>
Great! But what if we wanted to have our directive match the tag name `<my-customer>` instead?
If we simply put a `<my-customer>` element into the HMTL, it doesn't work.
If we simply put a `<my-customer>` element into the HTML, it doesn't work.
<div class="alert alert-waring">
**Note:** When you create a directive, it is restricted to attribute only by default. In order to
@@ -527,7 +527,8 @@ where:
* `scope` is an Angular scope object.
* `element` is the jqLite-wrapped element that this directive matches.
* `attrs` is an object with the normalized attribute names and their corresponding values.
* `attrs` is a hash object with key-value pairs of normalized attribute names and their
corresponding attribute values.
In our `link` function, we want to update the displayed time once a second, or whenever a user
changes the time formatting string that our directive binds to. We will use the `$interval` service
@@ -734,13 +735,13 @@ own behavior to it.
We want to run the function we pass by invoking it from the directive's scope, but have it run
in the context of the scope where its registered.
We saw earlier how to use `=prop` in the `scope` option, but in the above example, we're using
`&prop` instead. `&` bindings expose a function to an isolated scope allowing the isolated scope
We saw earlier how to use `=attr` in the `scope` option, but in the above example, we're using
`&attr` instead. `&` bindings expose a function to an isolated scope allowing the isolated scope
to invoke it, but maintaining the original scope of the function. So when a user clicks the
`x` in the dialog, it runs `Ctrl`'s `close` function.
`x` in the dialog, it runs `Ctrl`'s `hideDialog` function.
<div class="alert alert-success">
**Best Practice:** use `&prop` in the `scope` option when you want your directive
**Best Practice:** use `&attr` in the `scope` option when you want your directive
to expose an API for binding to behaviors.
</div>
+3
View File
@@ -121,3 +121,6 @@ text upper-case.
</doc:source>
</doc:example>
## Testing custom filters
See the {@link http://docs.angularjs.org/tutorial/step_09#test phonecat tutorial} for an example.
+4 -4
View File
@@ -33,10 +33,10 @@ In addition it provides an {@link api/ng.directive:ngModel.NgModelController API
<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() {
@@ -116,7 +116,7 @@ This ensures that the user is not distracted with an error until after interacti
A form is an instance of {@link api/ng.directive:form.FormController FormController}.
The form instance can optionally be published into the scope using the `name` attribute.
Similarly, an input control that has the {@link api/ng.directive:ngModel} directive holds an
Similarly, an input control that has the {@link api/ng.directive:ngModel ngModel} directive holds an
instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
Such a control instance can be published as a property of the form instance using the `name` attribute
on the input control. The name attribute specifies the name of the property on the form instance.
@@ -235,7 +235,7 @@ In the following example we create two directives.
<script>
var app = angular.module('form-example1', []);
var INTEGER_REGEXP = /^\-?\d*$/;
var INTEGER_REGEXP = /^\-?\d+$/;
app.directive('integer', function() {
return {
require: 'ngModel',
+2 -2
View File
@@ -97,9 +97,9 @@ locale, it is fine to rely on the default currency symbol. However, if you antic
in other locales might use your app, you should provide your own currency symbol to make sure the
actual value is understood.
For example, if you want to display account balance of 1000 dollars with the following binding
For example, if you want to display an account balance of 1000 dollars with the following binding
containing currency filter: `{{ 1000 | currency }}`, and your app is currently in en-US locale.
'$1000.00' will be shown. However, if someone in a different local (say, Japan) views your app, her
'$1000.00' will be shown. However, if someone in a different local (say, Japan) views your app, their
browser will specify the locale as ja, and the balance of '¥1000.00' will be shown instead. This
will really upset your client.
+2 -2
View File
@@ -23,7 +23,7 @@ It is very unlikely that issues specific to IE7 or earlier will be given any tim
To make your Angular application work on IE please make sure that:
1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
1. You polyfill JSON.stringify for IE7 and below. You can use
[JSON2](https://github.com/douglascrockford/JSON-js) or
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
<pre>
@@ -51,7 +51,7 @@ To make your Angular application work on IE please make sure that:
3. you **do not** use custom element tags such as `<ng:view>` (use the attribute version
`<div ng-view>` instead), or
4. if you **do use** custom element tags, then you must take these steps to make IE happy:
4. if you **do use** custom element tags, then you must take these steps to make IE 8 and below happy:
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
+10
View File
@@ -87,6 +87,16 @@ grunt package
Administrator). This is because `grunt package` creates some symbolic links.
</div>
<div class="alert alert-warning">
**Note:** If you're using Linux, and npm install fails with the message
'Please try running this command again as root/Administrator.', you may need to globally install grunt and bower:
<ul>
<li>sudo npm install -g grunt-cli</li>
<li>sudo npm install -g bower</li>
</ul>
</div>
The build output can be located under the `build` directory. It consists of the following files and
directories:
+3 -4
View File
@@ -73,12 +73,11 @@ directory.</p></li>
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> and its plugins if you
don't have it already:</p>
<pre>
npm install -g karma
npm install
</pre></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>
to run a simple bundled http server: <code>node scripts/web-server.js</code>.</p></li>
</ol>
</div>
@@ -107,8 +106,8 @@ directory.</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>
already installed, you can use <code>node</code> to run a simple
bundled http server: <code>node scripts\web-server.js</code>.</p></li>
</ol>
</div>
+2 -2
View File
@@ -73,7 +73,7 @@ angular-seed, and run the application in the browser.
You can now see the page in your browser. It's not very exciting, but that's OK.
The HTML page that displays "Nothing here yet!" was constructed with the HTML code shown below.
The code contains some key Angular elements that we will need going forward.
The code contains some key Angular elements that we will need as we progress.
__`app/index.html`:__
<pre>
@@ -104,7 +104,7 @@ __`app/index.html`:__
The `ng-app` attribute represents an Angular directive named `ngApp` (Angular uses
`name-with-dashes` for its custom attributes and `camelCase` for the corresponding directives
that implements them).
which implement them).
This directive is used to flag the html element that Angular should consider to be the root element
of our application.
This gives application developers the freedom to tell Angular if the entire html page or only a
+9 -5
View File
@@ -191,8 +191,8 @@ You can do this by issuing `npm install` into your terminal.
To run the test, do the following:
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
`./scripts/test.sh` to start the Karma server (the config file necessary to start the server
is located at `./config/karma.conf.js`).
`./scripts/test.sh` (if you are on Windows, run scripts\test.bat) to start the Karma server (the
config file necessary to start the server is located at `./config/karma.conf.js`).
2. Karma will start a new instance of Chrome browser automatically. Just ignore it and let it run in
the background. Karma will use this browser for test execution.
@@ -206,7 +206,7 @@ is located at `./config/karma.conf.js`).
Yay! The test passed! Or not...
4. To rerun the tests, just change any of the source or test files. Karma will notice the change
4. To rerun the tests, just change any of the source or test .js files. Karma will notice the change
and will rerun the tests for you. Now isn't that sweet?
# Experiments
@@ -217,9 +217,13 @@ is located at `./config/karma.conf.js`).
* Create a new model property in the controller and bind to it from the template. For example:
$scope.hello = "Hello, World!"
$scope.name = "World";
Refresh your browser to make sure it says, "Hello, World!"
Then add a new binding to `index.html`:
<p>Hello, {{name}}!</p>
Refresh your browser and verify that it says "Hello, World!".
* Create a repeater that constructs a simple table:
+2 -2
View File
@@ -88,8 +88,8 @@ phonecatApp.controller('PhoneListCtrl', function ($scope) {
record. This property is used to order phones by age.
* We added a line to the controller that sets the default value of `orderProp` to `age`. If we had
not set the default value here, the model would stay uninitialized until our user picks an
option from the drop down menu.
not set a default value here, the `orderBy` filter would remain uninitialized until our
user picked an option from the drop down menu.
This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the
browser, "Newest" is selected in the drop down menu. This is because we set `orderProp` to `'age'`
+3
View File
@@ -170,6 +170,9 @@ describe('PhoneCat controllers', function() {
describe('PhoneListCtrl', function(){
var scope, ctrl, $httpBackend;
// Load our app module definition before each test.
beforeEach(module('phonecatApp'));
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
+2 -2
View File
@@ -121,7 +121,7 @@ view, Angular will use the `phone-list.html` template and the `PhoneListCtrl` co
We reused the `PhoneListCtrl` controller that we constructed in previous steps and we added a new,
empty `PhoneDetailCtrl` controller to the `app/js/controllers.js` file for the phone details view.
`$route.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when the browser
`$routeProvider.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when the browser
address doesn't match either of our routes.
Note the use of the `:phoneId` parameter in the second route declaration. The `$route` service uses
@@ -177,7 +177,7 @@ route into the layout template. This makes it a perfect fit for our `index.html`
<div class="alert alert-info">
**Note:** Starting with AngularJS version 1.2, `ngRoute` is in its own module and must be loaded by loading
the `angular-route.js` file distributed with Angular. The easist way to load the file is to add a `<script>`
the `angular-route.js` file distributed with Angular. The easiest way to load the file is to add a `<script>`
tag to your `index.html` file as shown below.
</div>
+48 -36
View File
@@ -293,8 +293,7 @@ Let's add another animation to our application. Switching to our `phone-detail.h
we see that we have a nice thumbnail swapper. By clicking on the thumbnails listed on the page,
the profile phone image changes. But how can we change this around to add animations?
Lets think about it first,
basically when you click on a thumbnail image, you're changing the state of the profile image to reflect the newly
Let's think about it first. Basically, when you click on a thumbnail image, you're changing the state of the profile image to reflect the newly
selected thumbnail image.
The best way to specify state changes within HTML is to use classes.
Much like before, how we used a CSS class to specify
@@ -341,45 +340,58 @@ Although we could do that, let's take the opportunity to learn how to create Jav
__`app/js/animations.js`.__
<pre>
angular.module('phonecatAnimations', ['ngAnimate'])
var phonecatAnimations = angular.module('phonecatAnimations', ['ngAnimate']);
.animation('.phone', function() {
return {
addClass : function(element, className, done) {
if(className != 'active') {
return;
}
element.css({
position: 'absolute',
top: 500,
left: 0,
display: 'block'
});
jQuery(element).animate({
top: 0
}, done);
phonecatAnimations.animation('.phone', function() {
return function(cancel) {
if(cancel) element.stop();
};
},
removeClass : function(element, className, done) {
if(className != 'active') return;
element.css({
position: 'absolute',
left: 0,
top: 0
});
jQuery(element).animate({
top: -500
}, done);
var animateUp = function(element, className, done) {
if(className != 'active') {
return;
}
element.css({
position: 'absolute',
top: 500,
left: 0,
display: 'block'
});
return function(cancel) {
if(cancel) element.stop();
};
jQuery(element).animate({
top: 0
}, done);
return function(cancel) {
if(cancel) {
element.stop();
}
};
});
}
var animateDown = function(element, className, done) {
if(className != 'active') {
return;
}
element.css({
position: 'absolute',
left: 0,
top: 0
});
jQuery(element).animate({
top: -500
}, done);
return function(cancel) {
if(cancel) {
element.stop();
}
};
}
return {
addClass: animateUp,
removeClass: animateDown
};
});
</pre>
Note that we're using {@link http://jquery.com/ jQuery} to implement the animation. jQuery
+29
View File
@@ -1,5 +1,7 @@
var ngdoc = require('../src/ngdoc.js');
var DOM = require('../src/dom.js').DOM;
var gruntUtil = require('../../lib/grunt/utils.js');
describe('ngdoc', function() {
var Doc = ngdoc.Doc;
@@ -287,6 +289,33 @@ describe('ngdoc', function() {
});
});
describe('api section', function() {
it('should render a "view source" button with link to the source in master', function() {
var doc = new Doc({
id: 'ng.abc',
name: 'ng.abc',
section: 'api',
ngdoc: 'service',
file: 'fooService.js',
line: '333'
});
if (gruntUtil.getVersion().full.indexOf('-') === -1) {
expect(doc.html().match(/^(<a .*?<\/a>)/)[1]).toMatch(
/<a href="http:\/\/github\.com\/angular\/angular\.js\/tree\/v\d+\.\d+\.\d+\/fooService\.js#L333" class="view-source/
);
} else {
expect(doc.html().match(/^(<a .*?<\/a>)/)[1]).toMatch(
/<a href="http:\/\/github\.com\/angular\/angular\.js\/tree\/[a-z0-9]{7}\/fooService\.js#L333" class="view-source/
);
}
});
});
////////////////////////////////////////
describe('TAG', function() {
+16 -3
View File
@@ -6,7 +6,8 @@ var makeUnique = {
'script.js': true,
'unit.js': true,
'spec.js': true,
'scenario.js': true
'scenario.js': true,
'protractorTest.js': true
}
function ids(list) {
@@ -14,7 +15,7 @@ function ids(list) {
};
exports.Example = function(scenarios) {
exports.Example = function(scenarios, protractorTests) {
this.module = '';
this.deps = ['angular.js'];
this.html = [];
@@ -24,6 +25,8 @@ exports.Example = function(scenarios) {
this.unit = [];
this.scenario = [];
this.scenarios = scenarios;
this.protractorTest = [];
this.protractorTests = protractorTests;
}
exports.Example.prototype.setModule = function(module) {
@@ -44,6 +47,10 @@ exports.Example.prototype.addSource = function(name, content) {
var ext = name == 'scenario.js' ? 'scenario' : name.split('.')[1],
id = name;
if (name == 'protractorTest.js') {
ext = 'protractorTest';
}
if (makeUnique[name] && usedIds[id]) {
id = name + '-' + (seqCount++);
}
@@ -56,6 +63,9 @@ exports.Example.prototype.addSource = function(name, content) {
if (ext == 'scenario') {
this.scenarios.push(content);
}
if (ext == 'protractorTest') {
this.protractorTests.push(content);
}
};
exports.Example.prototype.enableAnimations = function() {
@@ -92,6 +102,7 @@ exports.Example.prototype.toHtmlEdit = function() {
out.push(' source-edit-json="' + ids(this.json) + '"');
out.push(' source-edit-unit="' + ids(this.unit) + '"');
out.push(' source-edit-scenario="' + ids(this.scenario) + '"');
out.push(' source-edit-protractor="' + ids(this.protractorTest) + '"');
out.push('></div>\n');
return out.join('');
};
@@ -107,6 +118,7 @@ exports.Example.prototype.toHtmlTabs = function() {
htmlTabs(this.json);
htmlTabs(this.unit);
htmlTabs(this.scenario);
htmlTabs(this.protractorTest);
out.push('</div>');
return out.join('');
@@ -119,7 +131,8 @@ exports.Example.prototype.toHtmlTabs = function() {
if (name === 'index.html') {
wrap = ' ng-html-wrap="' + self.module + ' ' + self.deps.join(' ') + '"';
}
if (name == 'scenario.js') name = 'End to end test';
if (name == 'scenario.js') name = 'ngScenario e2e test';
if (name == 'protractorTest.js') name = 'Protractor e2e test';
out.push(
'<div class="tab-pane" title="' + name + '">\n' +
+6
View File
@@ -17,6 +17,8 @@ writer.makeDir('build/docs/', true).then(function() {
return writer.makeDir('build/docs/components/bootstrap');
}).then(function() {
return writer.makeDir('build/docs/components/font-awesome');
}).then(function() {
return writer.makeDir('build/docs/e2etests');
}).then(function() {
console.log('Generating AngularJS Reference Documentation...');
return reader.collect();
@@ -53,6 +55,10 @@ writer.makeDir('build/docs/', true).then(function() {
var id = doc.id.replace('angular.Module', 'angular.IModule');
fileFutures.push(writer.output('partials/' + doc.section + '/' + id + '.html', doc.html()));
// If it has a sample Protractor test, output that as well.
if (doc.protractorTests.length) {
fileFutures.push(writer.output('ptore2e/' + doc.section + '/' + id + '_test.js', ngdoc.writeProtractorTest(doc)));
}
});
ngdoc.checkBrokenLinks(docs);
+31 -3
View File
@@ -35,6 +35,7 @@ var lookupMinerrMsg = function (doc) {
exports.trim = trim;
exports.metadata = metadata;
exports.scenarios = scenarios;
exports.writeProtractorTest = writeProtractorTest;
exports.merge = merge;
exports.checkBrokenLinks = checkBrokenLinks;
exports.Doc = Doc;
@@ -155,6 +156,7 @@ function Doc(text, file, line) {
this.line = line;
}
this.scenarios = this.scenarios || [];
this.protractorTests = this.protractorTests || [];
this.requires = this.requires || [];
this.param = this.param || [];
this.properties = this.properties || [];
@@ -292,7 +294,7 @@ Doc.prototype = {
replace(/<example(?:\s+module="([^"]*)")?(?:\s+deps="([^"]*)")?(\s+animations="true")?>([\s\S]*?)<\/example>/gmi,
function(_, module, deps, animations, content) {
var example = new Example(self.scenarios);
var example = new Example(self.scenarios, self.protractorTests);
if(animations) {
example.enableAnimations();
example.addDeps('angular-animate.js');
@@ -329,7 +331,7 @@ Doc.prototype = {
}).
replace(/^<doc:example(\s+[^>]*)?>([\s\S]*)<\/doc:example>/mi, function(_, attrs, content) {
var html, script, scenario,
example = new Example(self.scenarios);
example = new Example(self.scenarios, self.protractorTests);
example.setModule((attrs||'module=""').match(/^\s*module=["'](.*)["']\s*$/)[1]);
content.
@@ -347,6 +349,8 @@ Doc.prototype = {
}).
replace(/(<doc:scenario>)([\s\S]*)(<\/doc:scenario>)/mi, function(_, before, content){
example.addSource('scenario.js', content);
}).replace(/(<doc:protractor>)([\s\S]*)(<\/doc:protractor>)/mi, function(_, before, content){
example.addSource('protractorTest.js', content);
});
return placeholder(example.toHtml());
@@ -548,7 +552,7 @@ Doc.prototype = {
minerrMsg;
var gitTagFromFullVersion = function(version) {
var match = version.match(/-(\w{7})/);
var match = version.match(/sha\.(\w{7})/);
if (match) {
// git sha
@@ -1106,6 +1110,22 @@ function scenarios(docs){
}
}
function writeProtractorTest(doc){
var lines = [];
lines.push('describe("' + doc.section + '/' + doc.id + '", function() {');
lines.push(' beforeEach(function() {');
lines.push(' browser.get("index-nocache.html#!/' + doc.section + '/' + doc.id + '");');
lines.push(' });');
lines.push('');
doc.protractorTests.forEach(function(test){
lines.push(indentCode(trim(test), 2));
lines.push('');
});
lines.push('});');
lines.push('');
return lines.join('\n');
}
//////////////////////////////////////////////////////////
function metadata(docs){
@@ -1381,6 +1401,14 @@ function explainModuleInstallation(moduleName){
modulePackage = 'angular-' + moduleName,
modulePackageFile = modulePackage + '.js';
// Deal with inconsistent ngMock naming - doing it verbosely and explicitly here
// rather than cleverly interweaving it in the previous lines to make it obvious
// what is going on
if ( moduleName == 'mock' ) {
modulePackage = 'angular-mocks';
modulePackageFile = modulePackage + '.js';
}
return '<h1>Installation</h1>' +
'<p>First include <code>' + modulePackageFile +'</code> in your HTML:</p><pre><code>' +
' &lt;script src=&quot;angular.js&quot;&gt;\n' +
+9
View File
@@ -167,6 +167,11 @@
margin-top: .5em;
}
.content h6 {
text-transform:none;
color:black;
}
ul.parameters > li > p,
.returns > p {
display: inline;
@@ -241,6 +246,10 @@ ul.events > li > h3 {
text-decoration: none;
}
.tutorial-nav li {
margin-right: 5px;
}
.clear {
clear: both;
}
+26 -10
View File
@@ -5,11 +5,19 @@ var docsApp = {
filter: {}
};
docsApp.controller.DocsVersionsCtrl = ['$scope', '$window', 'NG_VERSIONS', 'NG_VERSION', function($scope, $window, NG_VERSIONS, NG_VERSION) {
docsApp.controller.DocsVersionsCtrl = ['$scope', '$rootScope', '$window', 'NG_VERSIONS', 'NG_VERSION', function($scope, $rootScope, $window, NG_VERSIONS, NG_VERSION) {
$scope.docs_versions = NG_VERSIONS;
$scope.docs_version = NG_VERSIONS[0];
$scope.jumpToDocsVersion = function(version) {
$window.location = version.url;
var currentPagePath = '';
// preserve URL path when switching between doc versions
if (angular.isObject($rootScope.currentPage) && $rootScope.currentPage.section && $rootScope.currentPage.id) {
currentPagePath = '/' + $rootScope.currentPage.section + '/' + $rootScope.currentPage.id;
}
$window.location = version.url + currentPagePath;
};
}];
@@ -137,11 +145,19 @@ docsApp.directive.docsSearchInput = ['$document',function($document) {
var ESCAPE_KEY_KEYCODE = 27,
FORWARD_SLASH_KEYCODE = 191;
angular.element($document[0].body).bind('keydown', function(event) {
var input = element[0];
if(event.keyCode == FORWARD_SLASH_KEYCODE && document.activeElement != input) {
event.stopPropagation();
event.preventDefault();
input.focus();
if(event.keyCode == FORWARD_SLASH_KEYCODE && document.activeElement) {
var activeElement = document.activeElement;
var activeTagName = activeElement.nodeName.toLowerCase();
var hasInputFocus = activeTagName == 'input' || activeTagName == 'select' ||
activeTagName == 'option' || activeTagName == 'textarea' ||
activeElement.hasAttribute('contenteditable');
if(!hasInputFocus) {
event.stopPropagation();
event.preventDefault();
var input = element[0];
input.focus();
}
}
});
@@ -645,7 +661,7 @@ docsApp.serviceFactory.sections = ['NG_PAGES', function sections(NG_PAGES) {
}];
docsApp.controller.DocsController = function($scope, $location, $window, $cookies, sections) {
docsApp.controller.DocsController = function($scope, $rootScope, $location, $window, $cookies, sections) {
$scope.fold = function(url) {
if(url) {
$scope.docs_fold = '/notes/' + url;
@@ -736,9 +752,9 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
sectionName = SECTION_NAME[sectionId] || sectionId,
page = sections.getPage(sectionId, partialId);
$scope.currentPage = sections.getPage(sectionId, partialId);
$rootScope.currentPage = sections.getPage(sectionId, partialId);
if (!$scope.currentPage) {
if (!$rootScope.currentPage) {
$scope.partialTitle = 'Error: Page Not Found!';
}
+1
View File
@@ -36,6 +36,7 @@ grunt test:unit --browsers $BROWSERS --reporters=dots,junit --no-colors --no-col
# END TO END TESTS #
grunt test:e2e --browsers $BROWSERS_E2E --reporters=dots,junit --no-colors --no-color
grunt test:protractor
# Promises/A+ TESTS #
grunt test:promises-aplus --no-color
+1 -1
View File
@@ -10,12 +10,12 @@ module.exports = function(config) {
'build/angular.js',
'build/angular-cookies.js',
'build/angular-mocks.js',
'build/angular-resource.js',
'build/angular-touch.js',
'build/angular-sanitize.js',
'build/angular-route.js',
'build/angular-animate.js',
'build/angular-mocks.js',
'build/docs/components/lunr.js',
'build/docs/components/google-code-prettify.js',
+4 -3
View File
@@ -36,13 +36,14 @@ module.exports = function(config, specificOptions) {
},
'SL_Firefox': {
base: 'SauceLabs',
browserName: 'firefox'
browserName: 'firefox',
version: '26'
},
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'Mac 10.8',
version: '6'
platform: 'OS X 10.9',
version: '7'
},
'SL_IE_8': {
base: 'SauceLabs',
+8
View File
@@ -61,6 +61,14 @@ module.exports = function(grunt) {
util.startKarma.call(util, this.data, false, this.async());
});
grunt.registerTask('webdriver', 'Update webdriver', function() {
util.updateWebdriver.call(util, this.async());
});
grunt.registerMultiTask('runprotractor', 'Run Protractor integration tests', function() {
util.startProtractor.call(util, this.data, this.async());
});
grunt.registerTask('collect-errors', 'Combine stripped error files', function () {
util.collectErrors();
});
+32
View File
@@ -84,6 +84,38 @@ module.exports = {
},
updateWebdriver: function(done){
var p = spawn('node', ['node_modules/protractor/bin/webdriver-manager', 'update']);
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
p.on('exit', function(code){
if(code !== 0) grunt.fail.warn('Webdriver failed to update');
done();
});
},
startProtractor: function(config, done){
var sauceUser = grunt.option('sauceUser');
var sauceKey = grunt.option('sauceKey');
var tunnelIdentifier = grunt.option('capabilities.tunnel-identifier');
var sauceBuild = grunt.option('capabilities.build');
var args = ['node_modules/protractor/bin/protractor', config];
if (sauceUser) args.push('--sauceUser=' + sauceUser);
if (sauceKey) args.push('--sauceKey=' + sauceKey);
if (tunnelIdentifier) args.push('--capabilities.tunnel-identifier=' + tunnelIdentifier);
if (sauceBuild) args.push('--capabilities.build=' + sauceBuild);
var p = spawn('node', args);
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
p.on('exit', function(code){
if(code !== 0) grunt.fail.warn('Protractor test(s) failed. Exit code: ' + code);
done();
});
},
wrap: function(src, name){
src.unshift('src/' + name + '.prefix');
src.push('src/' + name + '.suffix');
+13 -12
View File
@@ -1,8 +1,8 @@
{
"name": "angularjs",
"version": "1.2.6",
"cdnVersion": "1.2.5",
"codename": "taco-salsafication",
"version": "1.2.10",
"cdnVersion": "1.2.9",
"codename": "augmented-serendipity",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
@@ -20,14 +20,16 @@
"q-io": "~1.10.6",
"qq": "~0.3.5",
"shelljs": "~0.2.6",
"karma": "~0.11",
"karma-jasmine": "~0.1.0",
"karma-chrome-launcher": "~0.1.0",
"karma-firefox-launcher": "~0.1.0",
"karma-ng-scenario": "~0.1.0",
"karma-junit-reporter": "~0.2.1",
"karma-sauce-launcher": "~0.1.1",
"karma-script-launcher": "~0.1.0",
"karma": "0.11.12",
"karma-jasmine": "0.1.5",
"karma-chrome-launcher": "0.1.2",
"karma-firefox-launcher": "0.1.3",
"karma-ng-scenario": "0.1.0",
"karma-junit-reporter": "0.2.1",
"karma-sauce-launcher": "0.2.0",
"karma-script-launcher": "0.1.0",
"karma-browserstack-launcher": "0.0.7",
"protractor": "~0.16.1",
"yaml-js": "~0.0.8",
"marked": "0.2.9",
"rewire": "1.1.3",
@@ -39,7 +41,6 @@
"grunt-shell": "~0.4.0",
"semver": "~2.1.0",
"lodash": "~2.1.0",
"karma-browserstack-launcher": "git://github.com/karma-runner/karma-browserstack-launcher.git#master",
"browserstacktunnel-wrapper": "~1.1.1"
},
"licenses": [
+31
View File
@@ -0,0 +1,31 @@
exports.config = {
allScriptsTimeout: 11000,
specs: [
'build/docs/ptore2e/**/*.js',
'test/e2e/docsAppE2E.js'
],
capabilities: {
'browserName': 'chrome'
},
baseUrl: 'http://localhost:8000/build/docs/',
framework: 'jasmine',
onPrepare: function() {
// Disable animations so e2e tests run more quickly
var disableNgAnimate = function() {
angular.module('disableNgAnimate', []).run(function($animate) {
$animate.enabled(false);
});
};
browser.addMockModule('disableNgAnimate', disableNgAnimate);
},
jasmineNodeOpts: {
defaultTimeoutInterval: 30000
}
};
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
# Script for updating angular-phonecat repo from current local build.
echo "#################################"
echo "## Update angular-phonecat ###"
echo "#################################"
ARG_DEFS=(
"--action=(prepare|publish)"
"[--no-test=(true|false)]"
)
function init {
TMP_DIR=$(resolveDir ../../tmp)
BUILD_DIR=$(resolveDir ../../build)
REPO_DIR=$TMP_DIR/angular-phonecat
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
}
function prepare {
echo "-- Cloning angular-phonecat"
git clone git@github.com:angular/angular-phonecat.git $REPO_DIR
#
# copy the files from the build
#
echo "-- Updating angular-phonecat"
cd $REPO_DIR
./scripts/private/update-angular.sh $BUILD_DIR
# Test
if [[ $NO_TEST != "true" ]]; then
./scripts/private/test-all.sh
fi
# Generate demo
./scripts/private/snapshot-web.sh
git checkout gh-pages
git pull
rm -r step*
mv angular-phonecat-snapshots-web/step* .
git add step*
git commit -am "Angular $NEW_VERSION release"
}
function publish {
cd $REPO_DIR
echo "-- Pushing angular-phonecat"
git push origin master -f --tags
git push origin gh-pages -f
}
source $(dirname $0)/../utils.inc
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
# Script for updating angular-seed repo from current local build.
echo "#################################"
echo "## Update angular-seed ###"
echo "#################################"
ARG_DEFS=(
"--action=(prepare|publish)"
"[--no-test=(true|false)]"
)
function init {
TMP_DIR=$(resolveDir ../../tmp)
BUILD_DIR=$(resolveDir ../../build)
REPO_DIR=$TMP_DIR/angular-seed
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
}
function prepare {
echo "-- Cloning angular-seed"
git clone git@github.com:angular/angular-seed.git $REPO_DIR
#
# copy the files from the build
#
echo "-- Updating angular-seed"
cd $REPO_DIR
./scripts/update-angular.sh $BUILD_DIR
# Test
if [[ $NO_TEST != "true" ]]; then
./scripts/test-all.sh
fi
}
function publish {
cd $REPO_DIR
echo "-- Pushing angular-seed"
git push origin master
}
source $(dirname $0)/../utils.inc
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
echo "############################################"
echo "## Remove "-snapshot" from version ########"
echo "############################################"
ARG_DEFS=()
function run {
cd ../..
replaceJsonProp "package.json" "version" "(.*)-snapshot" "\2"
VERSION=$(readJsonProp "package.json" "version")
git add package.json
git commit -m "chore(release): cut v$VERSION release"
git tag -m "v$VERSION" v$VERSION
}
source $(dirname $0)/../utils.inc
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
echo "############################################"
echo "## Increment version, add "-snapshot" and set version name ##"
echo "############################################"
ARG_DEFS=(
"--next-version-type=(patch|minor|major)"
"--next-version-name=(.+)"
)
function run {
cd ../..
grunt bump:$NEXT_VERSION_TYPE
NEXT_VERSION=$(readJsonProp "package.json" "version")
replaceJsonProp "package.json" "version" "(.*)" "\2-snapshot"
replaceJsonProp "package.json" "codename" ".*" "$NEXT_VERSION_NAME"
git add package.json
git commit -m "chore(release): start v$NEXT_VERSION ($NEXT_VERSION)"
}
source $(dirname $0)/../utils.inc
+30
View File
@@ -0,0 +1,30 @@
#!/bin/sh
# Script for updating cdnVersion of angular.js
echo "###################################"
echo "## Update angular.js cdnVersion ###"
echo "###################################"
ARG_DEFS=(
"--cdn-version=(.*)"
"--action=(prepare|publish)"
)
function init {
cd ../..
}
function prepare {
replaceJsonProp "package.json" "cdnVersion" "(.*)" "$CDN_VERSION"
git add package.json
git commit -m "chore(release): update cdn version"
}
function publish {
BRANCH=$(git rev-parse --abbrev-ref HEAD)
# push the commits to github
git push origin $BRANCH
}
source $(dirname $0)/../utils.inc
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
# Script for updating angular.js repo from current local build.
echo "#################################"
echo "## Update angular.js ###"
echo "#################################"
ARG_DEFS=(
"--action=(prepare|publish)"
"--next-version-type=(patch|minor|major)"
"--next-version-name=(.+)"
"[--no-test=(true|false)]"
)
function init {
cd ../..
}
function prepare() {
./scripts/angular.js/finalize-version.sh
# Build
if [[ $NO_TEST == "true" ]]; then
npm install --color false
grunt ci-checks package --no-color
else
./jenkins_build.sh
fi
./scripts/angular.js/initialize-new-version.sh --next-version-type=$NEXT_VERSION_TYPE --next-version-name=$NEXT_VERSION_NAME
}
function publish() {
BRANCH=$(git rev-parse --abbrev-ref HEAD)
# push the commits to github
git push origin $BRANCH
# push the release tag
git push origin v`cat build/version.txt`
}
source $(dirname $0)/../utils.inc
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh
# Script for updating angularjs.org repo
echo "#################################"
echo "##### Update angularjs.org ######"
echo "#################################"
ARG_DEFS=(
"--action=(prepare|publish)"
"--cdn-version=(.*)"
)
function init {
TMP_DIR=$(resolveDir ../../tmp)
REPO_DIR=$TMP_DIR/angularjs.org
}
function prepare {
echo "-- Cloning angularjs.org"
git clone git@github.com:angular/angularjs.org.git $REPO_DIR
#
# update files
#
echo "-- Updating angularjs.org"
cd $REPO_DIR
VERSION_REGEX="[a-z0-9\-\.\+]+"
replaceInFile "index.html" "(ajax\/libs\/angularjs\/)$VERSION_REGEX" "\1$CDN_VERSION"
replaceInFile "index.html" "(<span class=\"version\">[^<]*<span>)$VERSION_REGEX" "\1$CDN_VERSION"
replaceInFile "index.html" "(code.angularjs.org\/)$VERSION_REGEX" "\1$CDN_VERSION"
replaceInFile "js/homepage.js" "($scope.CURRENT_STABLE_VERSION[ ]*=[ ]*')$VERSION_REGEX" "\1$CDN_VERSION"
replaceInFile "js/homepage.js" "($scope.CURRENT_UNSTABLE_VERSION[ ]*=[ ]*')$VERSION_REGEX" "\1$CDN_VERSION"
git add index.html
git add js/homepage.js
git commit -m "update(version): update angular version to $CDN_VERSION"
}
function publish {
cd $REPO_DIR
echo "-- Pushing angularjs.org"
git push origin master
}
source $(dirname $0)/../utils.inc
-15
View File
@@ -1,15 +0,0 @@
# Angular Bower Script
Script for updating the Angular bower repos from current local build.
## Instructions
`grunt package`: Build angular locally
```shell
./publish.sh
```
## License
MIT
+87 -74
View File
@@ -1,88 +1,101 @@
#!/bin/bash
# Script for updating the Angular bower repos from current local build.
echo "#################################"
echo "#### Update bower ###############"
echo "#################################"
# Enable tracing and exit on first failure
set -xe
# Normalize working dir to script dir
cd `dirname $0`
SCRIPT_DIR=`pwd`
TMP_DIR=../../tmp
BUILD_DIR=../../build
NEW_VERSION=`cat $BUILD_DIR/version.txt`
REPOS=(
angular \
angular-animate \
angular-cookies \
angular-i18n \
angular-loader \
angular-mocks \
angular-route \
angular-resource \
angular-sanitize \
angular-scenario \
angular-touch \
ARG_DEFS=(
"--action=(prepare|publish)"
)
#
# clone repos
#
for repo in "${REPOS[@]}"
do
echo "-- Cloning bower-$repo"
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
done
function init {
TMP_DIR=$(resolveDir ../../tmp)
BUILD_DIR=$(resolveDir ../../build)
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
REPOS=(
angular
angular-animate
angular-cookies
angular-i18n
angular-loader
angular-mocks
angular-route
angular-resource
angular-sanitize
angular-scenario
angular-touch
)
}
#
# move the files from the build
#
for repo in "${REPOS[@]}"
do
if [ -f $BUILD_DIR/$repo.js ] # ignore i18l
then
echo "-- Updating files in bower-$repo"
cd $TMP_DIR/bower-$repo
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd $SCRIPT_DIR
cp $BUILD_DIR/$repo.* $TMP_DIR/bower-$repo/
fi
done
# move i18n files
cp $BUILD_DIR/i18n/*.js $TMP_DIR/bower-angular-i18n/
# move csp.css
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
function prepare {
#
# clone repos
#
for repo in "${REPOS[@]}"
do
echo "-- Cloning bower-$repo"
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
done
#
# update bower.json
# tag each repo
#
#
# move the files from the build
#
for repo in "${REPOS[@]}"
do
echo "-- Updating version in bower-$repo to $NEW_VERSION"
cd $TMP_DIR/bower-$repo
sed -i .tmp -E 's/"(version)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
sed -i .tmp -E 's/"(angular.*)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
# delete tmp files
rm *.tmp
git add -A
for repo in "${REPOS[@]}"
do
if [ -f $BUILD_DIR/$repo.js ] # ignore i18l
then
echo "-- Updating files in bower-$repo"
cd $TMP_DIR/bower-$repo
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd $SCRIPT_DIR
cp $BUILD_DIR/$repo.* $TMP_DIR/bower-$repo/
fi
done
echo "-- Committing, tagging and pushing bower-$repo"
git commit -m "v$NEW_VERSION"
git tag v$NEW_VERSION
git push origin master
git push origin v$NEW_VERSION
cd $SCRIPT_DIR
done
# move i18n files
cp $BUILD_DIR/i18n/*.js $TMP_DIR/bower-angular-i18n/
# move csp.css
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
#
# update bower.json
# tag each repo
#
for repo in "${REPOS[@]}"
do
echo "-- Updating version in bower-$repo to $NEW_VERSION"
cd $TMP_DIR/bower-$repo
replaceJsonProp "bower.json" "version" ".*" "$NEW_VERSION"
replaceJsonProp "bower.json" "angular.*" ".*" "$NEW_VERSION"
git add -A
echo "-- Committing and tagging bower-$repo"
git commit -m "v$NEW_VERSION"
git tag v$NEW_VERSION
cd $SCRIPT_DIR
done
}
function publish {
for repo in "${REPOS[@]}"
do
echo "-- Pushing bower-$repo"
cd $TMP_DIR/bower-$repo
git push origin master
git push origin v$NEW_VERSION
cd $SCRIPT_DIR
done
}
source $(dirname $0)/../utils.inc
-18
View File
@@ -1,18 +0,0 @@
# code.angular.js.org Script
Script for updating code.angularjs.org repo from current local build.
Note: For a snapshot build, this will fetch the data from the ci server
and NOT take the local build!
## Instructions
`grunt package`: Build angular locally
```shell
./publish.sh
```
## License
MIT
+59 -48
View File
@@ -1,62 +1,73 @@
#!/bin/bash
# Script for updating code.angularjs.org repo from current local build.
echo "#################################"
echo "## Update code.angular.js.org ###"
echo "#################################"
# Enable tracing and exit on first failure
set -xe
# Normalize working dir to script dir
cd `dirname $0`
ARG_DEFS=(
"--action=(prepare|publish)"
)
TMP_DIR=../../tmp
REPO_DIR=$TMP_DIR/code.angularjs.org
BUILD_DIR=../../build
SCRIPT_DIR=`pwd`
NEW_VERSION=`cat $BUILD_DIR/version.txt`
function init {
TMP_DIR=$(resolveDir ../../tmp)
BUILD_DIR=$(resolveDir ../../build)
REPO_DIR=$TMP_DIR/code.angularjs.org
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
if [[ "$NEW_VERSION" =~ sha ]]; then
IS_SNAPSHOT_BUILD=true
else
IS_SNAPSHOT_BUILD=
fi
}
#
# Snapshot builds are kept in a temp directory in code.angularjs.org
# that is filled by calling a php script there.
#
if [[ "$NEW_VERSION" =~ sha ]] ;then
echo "-- updating snapshot version"
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
exit 0;
fi
function prepare {
if [[ $IS_SNAPSHOT_BUILD ]]; then
# nothing to prepare for snapshot builds as
# code.angularjs.org will fetch the current snapshot from
# the build server during publish
exit 0
fi
#
# clone
#
echo "-- Cloning code.angularjs.org"
git clone git@github.com:angular/code.angularjs.org.git $REPO_DIR
echo "-- Cloning code.angularjs.org"
git clone git@github.com:angular/code.angularjs.org.git $REPO_DIR
#
# copy the files from the build
#
echo "-- Updating code.angularjs.org"
mkdir $REPO_DIR/$NEW_VERSION
cd $REPO_DIR
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd $SCRIPT_DIR
cp -r $BUILD_DIR/* $REPO_DIR/$NEW_VERSION/
#
# copy the files from the build
#
#
# commit
#
echo "-- Committing code.angularjs.org"
cd $REPO_DIR
git add -A
git commit -m "v$NEW_VERSION"
}
echo "-- Updating code.angularjs.org"
mkdir $REPO_DIR/$NEW_VERSION
cd $REPO_DIR
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd $SCRIPT_DIR
cp -r $BUILD_DIR/* $REPO_DIR/$NEW_VERSION/
function publish {
if [[ $IS_SNAPSHOT_BUILD ]]; then
echo "-- Updating snapshot version"
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
exit 0;
fi
#
# commit and push
#
echo "-- Committing and pushing code.angularjs.org"
cd $REPO_DIR
git add -A
git commit -m "v$NEW_VERSION"
git push origin master
cd $SCRIPT_DIR
cd $REPO_DIR
echo "-- Pushing code.angularjs.org"
git push origin master
#
# refresh code.angularjs.org from github
#
curl http://code.angularjs.org/gitFetchSite.php
echo "-- Refreshing code.angularjs.org"
curl http://code.angularjs.org/gitFetchSite.php
}
source $(dirname $0)/../utils.inc
-25
View File
@@ -1,25 +0,0 @@
#!/bin/bash
echo "############################################"
echo "## Increment version and add "-snapshot" ##"
echo "############################################"
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
echo "Please specify the next version type: patch|minor|major"
exit 1
fi
BUMP_TYPE=$1
# Enable tracing and exit on first failure
set -xe
# Normalize working dir to script dir
cd `dirname $0`/../..
echo "-- increment version "
grunt bump:$BUMP_TYPE
NEXT_VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
sed -i .tmp -E 's/"version": "(.*)"/"version": "\1-snapshot"/' package.json
echo "-- new version: `grep '"version"' package.json`"
echo "-- commit"
git add package.json
git commit -m "chore(release): start v$NEXT_VERSION"
-20
View File
@@ -1,20 +0,0 @@
#!/bin/bash
echo "############################################"
echo "## Remove "-snapshot" from version ########"
echo "############################################"
# Enable tracing and exit on first failure
set -xe
# Normalize working dir to script dir
cd `dirname $0`/../..
echo "-- old version: `grep '"version"' package.json`"
sed -i .tmp -E 's/"version": "(.*)-snapshot"/"version": "\1"/' package.json
VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
echo "-- local version: $VERSION"
echo "-- commit and tag with v$VERSION"
git add package.json
git commit -m "chore(release): cut v$VERSION release"
git tag -m "v$VERSION" v$VERSION
+37 -15
View File
@@ -4,22 +4,44 @@ echo "#################################"
echo "#### Update master ##############"
echo "#################################"
# Enable tracing and exit on first failure
set -xe
ARG_DEFS=(
"[--no-test=(true|false)]"
)
cd `dirname $0`/../..
function init {
if [[ ! $VERBOSE ]]; then
VERBOSE=false
fi
VERBOSE_ARG="--verbose=$VERBOSE"
}
echo "#################################"
echo "#### Jenkins Build ############"
echo "#################################"
./jenkins_build.sh
function build {
cd ../..
echo "#################################"
echo "## Update code.angular.js.org ###"
echo "#################################"
./scripts/code.angularjs.org/publish.sh
if [[ $NO_TEST == "true" ]]; then
npm install --color false
grunt ci-checks package --no-color
else
./jenkins_build.sh
fi
echo "#################################"
echo "#### Update bower ###############"
echo "#################################"
./scripts/bower/publish.sh
cd $SCRIPT_DIR
}
function phase {
ACTION_ARG="--action=$1"
../code.angularjs.org/publish.sh $ACTION_ARG $VERBOSE_ARG
../bower/publish.sh $ACTION_ARG $VERBOSE_ARG
}
function run {
build
# First prepare all scripts (build, test, commit, tag, ...),
# so we are sure everything is all right
phase prepare
# only then publish to github
phase publish
}
source $(dirname $0)/../utils.inc
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
ARG_DEFS=(
# require the git dryrun flag so the script can't be run without
# thinking about this!
"--git-push-dryrun=(true|false)"
"--cdn-version=(.*)"
)
function init {
NG_ARGS=("$@")
if [[ ! $VERBOSE ]]; then
VERBOSE=false
fi
VERBOSE_ARG="--verbose=$VERBOSE"
}
function phase {
ACTION_ARG="--action=$1"
CDN_VERSION_ARG="--cdn-version=$CDN_VERSION"
./scripts/angular.js/publish-cdn-version.sh $ACTION_ARG $CDN_VERSION_ARG $VERBOSE_ARG
./scripts/angularjs.org/publish.sh $ACTION_ARG $CDN_VERSION_ARG $VERBOSE_ARG
}
function checkCdn {
STATUS=$(curl http://ajax.googleapis.com/ajax/libs/angularjs/$CDN_VERSION/angular.min.js --write-out '%{http_code}' -o /dev/null -silent)
if [[ $STATUS != 200 ]]; then
echo "Could not find release $CDN_VERSION on CDN"
exit 1
fi
}
function run {
cd ../..
checkCdn
phase prepare
phase publish
}
source $(dirname $0)/../utils.inc
+36 -32
View File
@@ -4,39 +4,43 @@ echo "#################################"
echo "#### Cut release ################"
echo "#################################"
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
echo "Please specify the next version type: patch|minor|major"
exit 1
fi
BUMP_TYPE=$1
ARG_DEFS=(
"--next-version-type=(patch|minor|major)"
"--next-version-name=(.+)"
# require the git dryrun flag so the script can't be run without
# thinking about this!
"--git-push-dryrun=(true|false)"
"[--no-test=(true|false)]"
)
# Enable tracing and exit on first failure
set -xe
function init {
NG_ARGS=("$@")
if [[ ! $VERBOSE ]]; then
VERBOSE=false
fi
if [[ ! $NO_TEST ]]; then
NO_TEST=false
fi
VERBOSE_ARG="--verbose=$VERBOSE"
NO_TEST_ARG="--no_test=$NO_TEST"
}
# Jump onto the master branch and make sure we are using the latest
git checkout -f master
git merge --ff-only origin/master
function phase {
ACTION_ARG="--action=$1"
../angular.js/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG \
--next-version-type=$NEXT_VERSION_TYPE --next-version-name=$NEXT_VERSION_NAME
../code.angularjs.org/publish.sh $ACTION_ARG $VERBOSE_ARG
../bower/publish.sh $ACTION_ARG $VERBOSE_ARG
../angular-seed/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG
../angular-phonecat/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG
}
function run {
# First prepare all scripts (build, test, commit, tag, ...),
# so we are sure everything is all right
phase prepare
# only then publish to github
phase publish
}
# Normalize working dir to script dir
cd `dirname $0`/../..
# Bump versions: remove "-snapshot" suffix
./scripts/jenkins/bump-remove-snapshot.sh
# Build
./jenkins_build.sh
# Bump versions: Increment version and add "-snapshot"
./scripts/jenkins/bump-increment.sh $BUMP_TYPE
echo "-- push to Github"
# push to github
git push --all
# Update code.angularjs.org
./scripts/code.angularjs.org/publish.sh
# Update bower
./scripts/bower/publish.sh
source $(dirname $0)/../utils.inc
+4
View File
@@ -11,6 +11,10 @@ if [ $JOB = "unit" ]; then
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
elif [ $JOB = "e2e" ]; then
grunt test:e2e --browsers SL_Chrome --reporters dots
grunt test:protractor --sauceUser $SAUCE_USERNAME \
--sauceKey $SAUCE_ACCESS_KEY \
--capabilities.tunnel-identifier=$TRAVIS_JOB_NUMBER \
--capabilities.build=$TRAVIS_BUILD_NUMBER
else
echo "Unknown job type. Please set JOB=unit or JOB=e2e."
fi
+279
View File
@@ -0,0 +1,279 @@
# This file provides:
# - a default control flow
# * initializes the environment
# * able to mock "git push" in your script and in all sub scripts
# * call a function in your script based on the arguments
# - named argument parsing and automatic generation of the "usage" for your script
# - intercepting "git push" in your script and all sub scripts
# - utility functions
#
# Usage:
# - define the variable ARGS_DEF (see below) with the arguments for your script
# - include this file using `source utils.inc` at the end of your script.
#
# Default control flow:
# 0. Set the current directory to the directory of the script. By this
# the script can be called from anywhere.
# 1. Parse the named arguments
# 2. If the parameter "git_push_dryrun" is set, all calls the `git push` in this script
# or in child scripts will be intercepted so that the `--dry-run` and `--porcelain` is added
# to show what the push would do but not actually do it.
# 3. If the parameter "verbose" is set, the `-x` flag will be set in bash.
# 4. The function "init" will be called if it exists
# 5. If the parameter "action" is set, it will call the function with the name of that parameter.
# Otherwise the function "run" will be called.
#
# Named Argument Parsing:
# - The variable ARGS_DEF defines the valid command arguments
# * Required args syntax: --paramName=paramRegex
# * Optional args syntax: [--paramName=paramRegex]
# * e.g. ARG_DEFS=("--required_param=(.+)" "[--optional_param=(.+)]")
# - Checks that:
# * all arguments match to an entry in ARGS_DEF
# * all required arguments are present
# * all arguments match their regex
# - Afterwards, every paramter value will be stored in a variable
# with the name of the parameter in upper case (with dash converted to underscore).
#
# Special arguments that are always available:
# - "--action=.*": This parameter will be used to dispatch to a function with that name when the
# script is started
# - "--git_push_dryrun=true": This will intercept all calls to `git push` in this script
# or in child scripts so that the `--dry-run` and `--porcelain` is added
# to show what the push would do but not actually do it.
# - "--verbose=true": This will set the `-x` flag in bash so that all calls will be logged
#
# Utility functions:
# - readJsonProp
# - replaceJsonProp
# - resolveDir
# - getVar
# - serVar
# - isFunction
# always stop on errors
set -e
function usage {
echo "Usage: ${0} ${ARG_DEFS[@]}"
exit 1
}
function parseArgs {
local REQUIRED_ARG_NAMES=()
# -- helper functions
function varName {
# everything to upper case and dash to underscore
echo ${1//-/_} | tr '[:lower:]' '[:upper:]'
}
function readArgDefs {
local ARG_DEF
local AD_OPTIONAL
local AD_NAME
local AD_RE
# -- helper functions
function parseArgDef {
local ARG_DEF_REGEX="(\[?)--([^=]+)=(.*)"
if [[ ! $1 =~ $ARG_DEF_REGEX ]]; then
echo "Internal error: arg def has wrong format: $ARG_DEF"
exit 1
fi
AD_OPTIONAL="${BASH_REMATCH[1]}"
AD_NAME="${BASH_REMATCH[2]}"
AD_RE="${BASH_REMATCH[3]}"
if [[ $AD_OPTIONAL ]]; then
# Remove last bracket for optional args.
# Can't put this into the ARG_DEF_REGEX somehow...
AD_RE=${AD_RE%?}
fi
}
# -- run
for ARG_DEF in "${ARG_DEFS[@]}"
do
parseArgDef $ARG_DEF
local AD_NAME_UPPER=$(varName $AD_NAME)
setVar "${AD_NAME_UPPER}_OPTIONAL" "$AD_OPTIONAL"
setVar "${AD_NAME_UPPER}_RE" "$AD_RE"
if [[ ! $AD_OPTIONAL ]]; then
REQUIRED_ARG_NAMES+=($AD_NAME)
fi
done
}
function readAndValidateArgs {
local ARG_NAME
local ARG_VALUE
local ARG_NAME_UPPER
# -- helper functions
function parseArg {
local ARG_REGEX="--([^=]+)=?(.*)"
if [[ ! $1 =~ $ARG_REGEX ]]; then
echo "Can't parse argument $i"
usage
fi
ARG_NAME="${BASH_REMATCH[1]}"
ARG_VALUE="${BASH_REMATCH[2]}"
ARG_NAME_UPPER=$(varName $ARG_NAME)
}
function validateArg {
local AD_RE=$(getVar ${ARG_NAME_UPPER}_RE)
if [[ ! $AD_RE ]]; then
echo "Unknown option: $ARG_NAME"
usage
fi
if [[ ! $ARG_VALUE =~ ^${AD_RE}$ ]]; then
echo "Wrong format: $ARG_NAME"
usage;
fi
# validate that the "action" option points to a valid function
if [[ $ARG_NAME == "action" ]] && ! isFunction $ARG_VALUE; then
echo "No action $ARG_VALUE defined in this script"
usage;
fi
}
# -- run
for i in "$@"
do
parseArg $i
validateArg
setVar "${ARG_NAME_UPPER}" "$ARG_VALUE"
done
}
function checkMissingArgs {
local ARG_NAME
for ARG_NAME in "${REQUIRED_ARG_NAMES[@]}"
do
ARG_VALUE=$(getVar $(varName $ARG_NAME))
if [[ ! $ARG_VALUE ]]; then
echo "Missing: $ARG_NAME"
usage;
fi
done
}
# -- run
readArgDefs
readAndValidateArgs "$@"
checkMissingArgs
}
# getVar(varName)
function getVar {
echo ${!1}
}
# setVar(varName, varValue)
function setVar {
eval "$1=\"$2\""
}
# isFunction(name)
# - to be used in an if, so return 0 if successful and 1 if not!
function isFunction {
if [[ $(type -t $1) == "function" ]]; then
return 0
else
return 1
fi
}
# readJsonProp(jsonFile, property)
# - restriction: property needs to be on an own line!
function readJsonProp {
echo $(sed -En 's/.*"'$2'"[ ]*:[ ]*"(.*)".*/\1/p' $1)
}
# replaceJsonProp(jsonFile, propertyRegex, valueRegex, replacePattern)
# - note: propertyRegex will be automatically placed into a
# capturing group! -> all other groups start at index 2!
function replaceJsonProp {
replaceInFile $1 '"('$2')"[ ]*:[ ]*"'$3'"' '"\1": "'$4'"'
}
# replaceInFile(file, findPattern, replacePattern)
function replaceInFile {
sed -i .tmp -E "s/$2/$3/" $1
rm $1.tmp
}
# resolveDir(relativeDir)
# - resolves a directory relative to the current script
function resolveDir {
echo $(cd $SCRIPT_DIR; cd $1; pwd)
}
function git_push_dryrun_proxy {
echo "## git push dryrun proxy enabled!"
export ORIGIN_GIT=$(which git)
function git {
local ARGS=("$@")
local RC
if [[ $1 == "push" ]]; then
ARGS+=("--dry-run" "--porcelain")
echo "####### START GIT PUSH DRYRUN #######"
echo "${ARGS[@]}"
fi
if [[ $1 == "commit" ]]; then
echo "${ARGS[@]}"
fi
$ORIGIN_GIT "${ARGS[@]}"
RC=$?
if [[ $1 == "push" ]]; then
echo "####### END GIT PUSH DRYRUN #######"
fi
return $RC
}
export -f git
}
function main {
# normalize the working dir to the directory of the script
cd $(dirname $0);SCRIPT_DIR=$(pwd)
ARG_DEFS+=("[--git-push-dryrun=(true|false)]" "[--verbose=(true|false)]")
parseArgs "$@"
# --git_push_dryrun argument
if [[ $GIT_PUSH_DRYRUN == "true" ]]; then
git_push_dryrun_proxy
fi
# --verbose argument
if [[ $VERBOSE == "true" ]]; then
set -x
fi
if isFunction init; then
init "$@"
fi
# jump to the function denoted by the --action argument,
# otherwise call the "run" function
if [[ $ACTION ]]; then
$ACTION "$@"
else
run "$@"
fi
}
main "$@"
+5 -2
View File
@@ -192,7 +192,8 @@ function isArrayLike(obj) {
* is the value of an object property or an array element and `key` is the object property key or
* array element index. Specifying a `context` for the function is optional.
*
* Note: this function was previously known as `angular.foreach`.
* It is worth nothing that `.forEach` does not iterate over inherited properties because it filters
* using the `hasOwnProperty` method.
*
<pre>
var values = {name: 'misko', gender: 'male'};
@@ -959,7 +960,9 @@ function fromJson(json) {
function toBoolean(value) {
if (value && value.length !== 0) {
if (typeof value === 'function') {
value = true;
} else if (value && value.length !== 0) {
var v = lowercase("" + value);
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
} else {
+24 -16
View File
@@ -354,11 +354,9 @@ function annotate(fn) {
* @param {(Object|function())} provider If the provider is:
*
* - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
* {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be
* created.
* - `Constructor`: a new instance of the provider will be created using
* {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as
* `object`.
* {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
* - `Constructor`: a new instance of the provider will be created using
* {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
*
* @returns {Object} registered provider instance
@@ -474,7 +472,7 @@ function annotate(fn) {
* constructor function that will be used to instantiate the service instance.
*
* You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service
* as a type/class. This is common when using {@link http://coffeescript.org CoffeeScript}.
* as a type/class.
*
* @param {string} name The name of the instance.
* @param {Function} constructor A class (constructor function) that will be instantiated.
@@ -482,20 +480,25 @@ function annotate(fn) {
*
* @example
* Here is an example of registering a service using
* {@link AUTO.$provide#methods_service $provide.service(class)} that is defined as a CoffeeScript class.
* {@link AUTO.$provide#methods_service $provide.service(class)}.
* <pre>
* class Ping
* constructor: (@$http) ->
* send: () =>
* @$http.get('/ping')
*
* $provide.service('ping', ['$http', Ping])
* $provide.service('ping', ['$http', function($http) {
* var Ping = function() {
* this.$http = $http;
* };
*
* Ping.prototype.send = function() {
* return this.$http.get('/ping');
* };
*
* return Ping;
* }]);
* </pre>
* You would then inject and use this service like this:
* <pre>
* someModule.controller 'Ctrl', ['ping', (ping) ->
* ping.send()
* ]
* someModule.controller('Ctrl', ['ping', function(ping) {
* ping.send();
* }]);
* </pre>
*/
@@ -740,6 +743,11 @@ function createInjector(modulesToLoad) {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
}
throw err;
} finally {
path.shift();
}
+7 -6
View File
@@ -148,8 +148,9 @@ function Browser(window, document, $log, $sniffer) {
* @param {boolean=} replace Should new url replace current history record ?
*/
self.url = function(url, replace) {
// Android Browser BFCache causes location reference to become stale.
// Android Browser BFCache causes location, history reference to become stale.
if (location !== window.location) location = window.location;
if (history !== window.history) history = window.history;
// setter
if (url) {
@@ -201,7 +202,7 @@ function Browser(window, document, $log, $sniffer) {
* @description
* Register callback function that will be called, when url changes.
*
* It's only called when the url is changed by outside of angular:
* It's only called when the url is changed from outside of angular:
* - user types different url into address bar
* - user clicks on history (forward/back) button
* - user clicks on a link
@@ -243,7 +244,7 @@ function Browser(window, document, $log, $sniffer) {
/**
* @name ng.$browser#baseHref
* @methodOf ng.$browser
*
*
* @description
* Returns current <base href>
* (always relative - without domain)
@@ -252,7 +253,7 @@ function Browser(window, document, $log, $sniffer) {
*/
self.baseHref = function() {
var href = baseElement.attr('href');
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
};
//////////////////////////////////////////////////////////////
@@ -274,13 +275,13 @@ function Browser(window, document, $log, $sniffer) {
* It is not meant to be used directly, use the $cookie service instead.
*
* The return values vary depending on the arguments that the method was called with as follows:
*
*
* - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
* it
* - cookies(name, value) -> set name to value, if value is undefined delete the cookie
* - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
* way)
*
*
* @returns {Object} Hash of all cookies (if called without any parameter)
*/
self.cookies = function(name, value) {
+2 -2
View File
@@ -24,7 +24,7 @@
* @function
*
* @description
* Compiles a piece of HTML string or DOM into a template and produces a template function, which
* Compiles an HTML string or DOM into a template and produces a template function, which
* can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
*
* The compilation is a process of walking the DOM tree and matching DOM elements to
@@ -1957,7 +1957,7 @@ function directiveNormalize(name) {
*
*
* @param {string} name Normalized element attribute name of the property to modify. The name is
* revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
* reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
* property to the original name.
* @param {string} value Value to set the attribute to. The value can be an interpolated string.
*/
+5 -2
View File
@@ -32,11 +32,14 @@ var htmlAnchorDirective = valueFn({
element.append(document.createComment('IE fix'));
}
if (!attr.href && !attr.name) {
if (!attr.href && !attr.xlinkHref && !attr.name) {
return function(scope, element) {
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
'xlink:href' : 'href';
element.on('click', function(event){
// if we have no href url, then don't navigate anywhere.
if (!element.attr('href')) {
if (!element.attr(href)) {
event.preventDefault();
}
});
+4 -6
View File
@@ -336,12 +336,10 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
ngAttributeAliasDirectives[normalized] = function() {
return {
priority: 100,
compile: function() {
return function(scope, element, attr) {
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
attr.$set(attrName, !!value);
});
};
link: function(scope, element, attr) {
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
attr.$set(attrName, !!value);
});
}
};
};
+4 -4
View File
@@ -249,10 +249,10 @@ function FormController(element, attrs) {
*
*
* # CSS classes
* - `ng-valid` Is set if the form is valid.
* - `ng-invalid` Is set if the form is invalid.
* - `ng-pristine` Is set if the form is pristine.
* - `ng-dirty` Is set if the form is dirty.
* - `ng-valid` is set if the form is valid.
* - `ng-invalid` is set if the form is invalid.
* - `ng-pristine` is set if the form is pristine.
* - `ng-dirty` is set if the form is dirty.
*
*
* # Submitting a form and preventing the default action
+40 -70
View File
@@ -9,7 +9,7 @@
*/
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,6}$/;
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
var inputType = {
@@ -309,6 +309,8 @@ var inputType = {
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
* @param {string} ngValue Angular expression which sets the value to which the expression should
* be set when selected.
*
* @example
<doc:example>
@@ -316,21 +318,26 @@ var inputType = {
<script>
function Ctrl($scope) {
$scope.color = 'blue';
$scope.specialValue = {
"id": "12345",
"value": "green"
};
}
</script>
<form name="myForm" ng-controller="Ctrl">
<input type="radio" ng-model="color" value="red"> Red <br/>
<input type="radio" ng-model="color" value="green"> Green <br/>
<input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
<input type="radio" ng-model="color" value="blue"> Blue <br/>
<tt>color = {{color}}</tt><br/>
<tt>color = {{color | json}}</tt><br/>
</form>
Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
</doc:source>
<doc:scenario>
it('should change state', function() {
expect(binding('color')).toEqual('blue');
expect(binding('color')).toEqual('"blue"');
input('color').select('red');
expect(binding('color')).toEqual('red');
expect(binding('color')).toEqual('"red"');
});
</doc:scenario>
</doc:example>
@@ -390,6 +397,12 @@ var inputType = {
'reset': noop
};
// A helper function to call $setValidity and return the value / undefined,
// a pattern that is repeated a lot in the input validation logic.
function validate(ctrl, validatorName, validity, value){
ctrl.$setValidity(validatorName, validity);
return validity ? value : undefined;
}
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
// In composition mode, users are still inputing intermediate text buffer,
@@ -419,9 +432,13 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
}
if (ctrl.$viewValue !== value) {
scope.$apply(function() {
if (scope.$$phase) {
ctrl.$setViewValue(value);
});
} else {
scope.$apply(function() {
ctrl.$setViewValue(value);
});
}
}
};
@@ -470,22 +487,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
patternValidator,
match;
var validate = function(regexp, value) {
if (ctrl.$isEmpty(value) || regexp.test(value)) {
ctrl.$setValidity('pattern', true);
return value;
} else {
ctrl.$setValidity('pattern', false);
return undefined;
}
};
if (pattern) {
var validateRegex = function(regexp, value) {
return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
};
match = pattern.match(/^\/(.*)\/([gim]*)$/);
if (match) {
pattern = new RegExp(match[1], match[2]);
patternValidator = function(value) {
return validate(pattern, value);
return validateRegex(pattern, value);
};
} else {
patternValidator = function(value) {
@@ -496,7 +506,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
patternObj, startingTag(element));
}
return validate(patternObj, value);
return validateRegex(patternObj, value);
};
}
@@ -508,13 +518,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.ngMinlength) {
var minlength = int(attr.ngMinlength);
var minLengthValidator = function(value) {
if (!ctrl.$isEmpty(value) && value.length < minlength) {
ctrl.$setValidity('minlength', false);
return undefined;
} else {
ctrl.$setValidity('minlength', true);
return value;
}
return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
};
ctrl.$parsers.push(minLengthValidator);
@@ -525,13 +529,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.ngMaxlength) {
var maxlength = int(attr.ngMaxlength);
var maxLengthValidator = function(value) {
if (!ctrl.$isEmpty(value) && value.length > maxlength) {
ctrl.$setValidity('maxlength', false);
return undefined;
} else {
ctrl.$setValidity('maxlength', true);
return value;
}
return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
};
ctrl.$parsers.push(maxLengthValidator);
@@ -560,13 +558,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.min) {
var minValidator = function(value) {
var min = parseFloat(attr.min);
if (!ctrl.$isEmpty(value) && value < min) {
ctrl.$setValidity('min', false);
return undefined;
} else {
ctrl.$setValidity('min', true);
return value;
}
return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
};
ctrl.$parsers.push(minValidator);
@@ -576,13 +568,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.max) {
var maxValidator = function(value) {
var max = parseFloat(attr.max);
if (!ctrl.$isEmpty(value) && value > max) {
ctrl.$setValidity('max', false);
return undefined;
} else {
ctrl.$setValidity('max', true);
return value;
}
return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
};
ctrl.$parsers.push(maxValidator);
@@ -590,14 +576,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
}
ctrl.$formatters.push(function(value) {
if (ctrl.$isEmpty(value) || isNumber(value)) {
ctrl.$setValidity('number', true);
return value;
} else {
ctrl.$setValidity('number', false);
return undefined;
}
return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
});
}
@@ -605,13 +584,7 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
var urlValidator = function(value) {
if (ctrl.$isEmpty(value) || URL_REGEXP.test(value)) {
ctrl.$setValidity('url', true);
return value;
} else {
ctrl.$setValidity('url', false);
return undefined;
}
return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
};
ctrl.$formatters.push(urlValidator);
@@ -622,13 +595,7 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
var emailValidator = function(value) {
if (ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value)) {
ctrl.$setValidity('email', true);
return value;
} else {
ctrl.$setValidity('email', false);
return undefined;
}
return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
};
ctrl.$formatters.push(emailValidator);
@@ -1228,7 +1195,10 @@ var ngModelDirective = function() {
* @name ng.directive:ngChange
*
* @description
* Evaluate given expression when user changes the input.
* Evaluate the given expression when the user changes the input.
* The expression is evaluated immediately, unlike the JavaScript onchange event
* which only triggers at the end of a change (usually, when the user leaves the
* form element or presses the return key).
* The expression is not evaluated when the value change is coming from the model.
*
* Note, this directive requires `ngModel` to be present.
+21 -5
View File
@@ -9,6 +9,7 @@
* an element is clicked.
*
* @element ANY
* @priority 0
* @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
* click. (Event object is available as `$event`)
*
@@ -20,13 +21,13 @@
</button>
count: {{count}}
</doc:source>
<doc:scenario>
<doc:protractor>
it('should check ng-click', function() {
expect(binding('count')).toBe('0');
element('.doc-example-live :button').click();
expect(binding('count')).toBe('1');
expect(element(by.binding('count')).getText()).toMatch('0');
element(by.css('.doc-example-live button')).click();
expect(element(by.binding('count')).getText()).toMatch('1');
});
</doc:scenario>
</doc:protractor>
</doc:example>
*/
/*
@@ -65,6 +66,7 @@ forEach(
* The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
*
* @element ANY
* @priority 0
* @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
* a dblclick. (The Event object is available as `$event`)
*
@@ -88,6 +90,7 @@ forEach(
* The ngMousedown directive allows you to specify custom behavior on mousedown event.
*
* @element ANY
* @priority 0
* @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
* mousedown. (Event object is available as `$event`)
*
@@ -111,6 +114,7 @@ forEach(
* Specify custom behavior on mouseup event.
*
* @element ANY
* @priority 0
* @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
* mouseup. (Event object is available as `$event`)
*
@@ -133,6 +137,7 @@ forEach(
* Specify custom behavior on mouseover event.
*
* @element ANY
* @priority 0
* @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
* mouseover. (Event object is available as `$event`)
*
@@ -156,6 +161,7 @@ forEach(
* Specify custom behavior on mouseenter event.
*
* @element ANY
* @priority 0
* @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
* mouseenter. (Event object is available as `$event`)
*
@@ -179,6 +185,7 @@ forEach(
* Specify custom behavior on mouseleave event.
*
* @element ANY
* @priority 0
* @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
* mouseleave. (Event object is available as `$event`)
*
@@ -202,6 +209,7 @@ forEach(
* Specify custom behavior on mousemove event.
*
* @element ANY
* @priority 0
* @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
* mousemove. (Event object is available as `$event`)
*
@@ -225,6 +233,7 @@ forEach(
* Specify custom behavior on keydown event.
*
* @element ANY
* @priority 0
* @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.)
*
@@ -246,6 +255,7 @@ forEach(
* Specify custom behavior on keyup event.
*
* @element ANY
* @priority 0
* @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.)
*
@@ -292,6 +302,7 @@ forEach(
* attribute**.
*
* @element form
* @priority 0
* @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
*
* @example
@@ -341,6 +352,7 @@ forEach(
* Specify custom behavior on focus event.
*
* @element window, input, select, textarea, a
* @priority 0
* @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
* focus. (Event object is available as `$event`)
*
@@ -356,6 +368,7 @@ forEach(
* Specify custom behavior on blur event.
*
* @element window, input, select, textarea, a
* @priority 0
* @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
* blur. (Event object is available as `$event`)
*
@@ -371,6 +384,7 @@ forEach(
* Specify custom behavior on copy event.
*
* @element window, input, select, textarea, a
* @priority 0
* @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
* copy. (Event object is available as `$event`)
*
@@ -391,6 +405,7 @@ forEach(
* Specify custom behavior on cut event.
*
* @element window, input, select, textarea, a
* @priority 0
* @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
* cut. (Event object is available as `$event`)
*
@@ -411,6 +426,7 @@ forEach(
* Specify custom behavior on paste event.
*
* @element window, input, select, textarea, a
* @priority 0
* @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
* paste. (Event object is available as `$event`)
*
+7
View File
@@ -15,6 +15,13 @@
* should use {@link guide/controller controllers} rather than `ngInit`
* to initialize values on a scope.
* </div>
* <div class="alert alert-warning">
* **Note**: If you have assignment in `ngInit` along with {@link api/ng.$filter `$filter`}, make
* sure you have parenthesis for correct precedence:
* <pre class="prettyprint">
* <div ng-init="test1 = (data | orderBy:'name')"></div>
* </pre>
* </div>
*
* @priority 450
*
+4 -2
View File
@@ -20,6 +20,8 @@
* | `$even` | {@type boolean} | true if the iterator position `$index` is even (otherwise false). |
* | `$odd` | {@type boolean} | true if the iterator position `$index` is odd (otherwise false). |
*
* Creating aliases for these properties is possible with {@link api/ng.directive:ngInit `ngInit`}.
* This may be useful when, for instance, nesting ngRepeats.
*
* # Special repeat start and end points
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
@@ -203,7 +205,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
$$tlb: true,
link: function($scope, $element, $attr, ctrl, $transclude){
var expression = $attr.ngRepeat;
var match = expression.match(/^\s*(.+)\s+in\s+([\r\n\s\S]*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
lhs, rhs, valueIdentifier, keyIdentifier,
hashFnLocals = {$id: hashKey};
@@ -215,7 +217,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
lhs = match[1];
rhs = match[2];
trackByExp = match[4];
trackByExp = match[3];
if (trackByExp) {
trackByExpGetter = $parse(trackByExp);
+10
View File
@@ -52,6 +52,11 @@
*
* Just remember to include the important flag so the CSS override will function.
*
* <div class="alert alert-warning">
* **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
* "f" / "0" / "false" / "no" / "n" / "[]"
* </div>
*
* ## A note about animations with ngShow
*
* Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
@@ -200,6 +205,11 @@ var ngShowDirective = ['$animate', function($animate) {
* </pre>
*
* Just remember to include the important flag so the CSS override will function.
*
* <div class="alert alert-warning">
* **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
* "f" / "0" / "false" / "no" / "n" / "[]"
* </div>
*
* ## A note about animations with ngHide
*
+3 -5
View File
@@ -168,11 +168,9 @@ var ngSwitchWhenDirective = ngDirective({
transclude: 'element',
priority: 800,
require: '^ngSwitch',
compile: function(element, attrs) {
return function(scope, element, attr, ctrl, $transclude) {
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
};
link: function(scope, element, attrs, ctrl, $transclude) {
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
}
});
+7 -3
View File
@@ -6,10 +6,14 @@
* @restrict E
*
* @description
* Load content of a script tag, with type `text/ng-template`, into `$templateCache`, so that the
* template can be used by `ngInclude`, `ngView` or directive templates.
* Load the content of a `<script>` element into {@link api/ng.$templateCache `$templateCache`}, so that the
* template can be used by {@link api/ng.directive:ngInclude `ngInclude`},
* {@link api/ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
* `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
* assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
*
* @param {'text/ng-template'} type must be set to `'text/ng-template'`
* @param {'text/ng-template'} type Must be set to `'text/ng-template'`.
* @param {string} id Cache name of the template.
*
* @example
<doc:example>
+11 -4
View File
@@ -19,14 +19,21 @@ var ngOptionsMinErr = minErr('ngOptions');
* represented by the selected option will be bound to the model identified by the `ngModel`
* directive.
*
* <div class="alert alert-warning">
* **Note:** `ngModel` compares by reference, not value. This is important when binding to an
* array of objects. See an example {@link http://jsfiddle.net/qWzTb/ in this jsfiddle}.
* </div>
*
* Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
* be nested into the `<select>` element. This element will then represent the `null` or "not selected"
* option. See example below for demonstration.
*
* Note: `ngOptions` provides iterator facility for `<option>` element which should be used instead
* <div class="alert alert-warning">
* **Note:** `ngOptions` provides iterator facility for `<option>` element which should be used instead
* of {@link ng.directive:ngRepeat ngRepeat} when you want the
* `select` model to be bound to a non-string value. This is because an option element can only
* be bound to string values at present.
* </div>
*
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
@@ -128,8 +135,8 @@ var ngOptionsMinErr = minErr('ngOptions');
var ngOptionsDirective = valueFn({ terminal: true });
// jshint maxlen: false
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
//0000111110000000000022220000000000000000000000333300000000000000444444444444444000000000555555555555555000000066666666666666600000000000000007777000000000000000000088888
var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/,
//000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
nullModelCtrl = {$setViewValue: noop};
// jshint maxlen: 100
@@ -430,7 +437,7 @@ 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++) {
key = index;
if (keyName) {
key = keys[index];
+1 -2
View File
@@ -6,8 +6,7 @@
* @requires $window
*
* @description
* A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
* element.
* A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
*/
function $DocumentProvider(){
this.$get = ['$window', function(window){
+12 -23
View File
@@ -14,8 +14,8 @@
*
* Can be one of:
*
* - `string`: Predicate that results in a substring match using the value of `expression`
* string. All strings or objects with string properties in `array` that contain this string
* - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
* the contents of the `array`. All strings or objects with string properties in `array` that contain this string
* will be returned. The predicate can be negated by prefixing the string with `!`.
*
* - `Object`: A pattern object can be used to filter specific properties on objects contained
@@ -25,21 +25,21 @@
* property of the object. That's equivalent to the simple substring match with a `string`
* as described above.
*
* - `function`: A predicate function can be used to write arbitrary filters. The function is
* - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
* called for each element of `array`. The final result is an array of those elements that
* the predicate returned true for.
*
* @param {function(expected, actual)|true|undefined} comparator Comparator which is used in
* @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
* determining if the expected value (from the filter expression) and actual value (from
* the object in the array) should be considered a match.
*
* Can be one of:
*
* - `function(expected, actual)`:
* - `function(actual, expected)`:
* The function will be given the object value and the predicate value to compare and
* should return true if the item should be included in filtered result.
*
* - `true`: A shorthand for `function(expected, actual) { return angular.equals(expected, actual)}`.
* - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
* this is essentially strict comparison of expected and actual.
*
* - `false|undefined`: A short hand for a function which will look for a substring match in case
@@ -173,23 +173,12 @@ function filterFilter() {
case "object":
// jshint +W086
for (var key in expression) {
if (key == '$') {
(function() {
if (!expression[key]) return;
var path = key;
predicates.push(function(value) {
return search(value, expression[path]);
});
})();
} else {
(function() {
if (typeof(expression[key]) == 'undefined') { return; }
var path = key;
predicates.push(function(value) {
return search(getter(value,path), expression[path]);
});
})();
}
(function(path) {
if (typeof expression[path] == 'undefined') return;
predicates.push(function(value) {
return search(path == '$' ? value : getter(value, path), expression[path]);
});
})(key);
}
break;
case 'function':
+25 -30
View File
@@ -111,9 +111,9 @@ function $HttpProvider() {
common: {
'Accept': 'application/json, text/plain, */*'
},
post: CONTENT_TYPE_APPLICATION_JSON,
put: CONTENT_TYPE_APPLICATION_JSON,
patch: CONTENT_TYPE_APPLICATION_JSON
post: copy(CONTENT_TYPE_APPLICATION_JSON),
put: copy(CONTENT_TYPE_APPLICATION_JSON),
patch: copy(CONTENT_TYPE_APPLICATION_JSON)
},
xsrfCookieName: 'XSRF-TOKEN',
@@ -222,32 +222,15 @@ 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.
* When unit testing (using {@link api/ngMock ngMock}), it is necessary to call
* {@link api/ngMock.$httpBackend#methods_flush $httpBackend.flush()} to flush each pending
* request using trained responses.
*
* ```
* $httpBackend.expectGET(...);
* $scope.$apply(function() {
* $http.get(...);
* });
* $http.get(...);
* $httpBackend.flush();
* ```
*
@@ -291,7 +274,15 @@ function $HttpProvider() {
* `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
*
* The defaults can also be set at runtime via the `$http.defaults` object in the same
* fashion. In addition, you can supply a `headers` property in the config object passed when
* fashion. For example:
*
* ```
* module.run(function($http) {
* $http.defaults.headers.common.Authentication = 'Basic YmVlcDpib29w'
* });
* ```
*
* In addition, you can supply a `headers` property in the config object passed when
* calling `$http(config)`, which overrides the defaults without changing them globally.
*
*
@@ -315,7 +306,9 @@ function $HttpProvider() {
* properties. These properties are by default an array of transform functions, which allows you
* to `push` or `unshift` a new transformation function into the transformation chain. You can
* also decide to completely override any default transformations by assigning your
* transformation functions to these properties directly without the array wrapper.
* transformation functions to these properties directly without the array wrapper. These defaults
* are again available on the $http factory at run-time, which may be useful if you have run-time
* services you wish to be involved in your transformations.
*
* Similarly, to locally override the request/response transforms, augment the
* `transformRequest` and/or `transformResponse` properties of the configuration object passed
@@ -409,19 +402,20 @@ function $HttpProvider() {
* return responseOrNewPromise
* }
* return $q.reject(rejection);
* };
* }
* }
* };
* });
*
* $httpProvider.interceptors.push('myHttpInterceptor');
*
*
* // register the interceptor via an anonymous factory
* // alternatively, register the interceptor via an anonymous factory
* $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
* return {
* 'request': function(config) {
* // same as above
* },
*
* 'response': function(response) {
* // same as above
* }
@@ -528,7 +522,8 @@ function $HttpProvider() {
* for added security.
*
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
* properties of either $httpProvider.defaults, or the per-request config object.
* properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
* or the per-request config object.
*
*
* @param {object} config Object describing the request to be made and how it should be
+28 -18
View File
@@ -1,12 +1,12 @@
'use strict';
var XHR = window.XMLHttpRequest || function() {
function createXhr(method) {
// IE8 doesn't support PATCH method, but the ActiveX object does
/* global ActiveXObject */
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
};
return (msie <= 8 && lowercase(method) === 'patch')
? new ActiveXObject('Microsoft.XMLHTTP')
: new window.XMLHttpRequest();
}
/**
@@ -28,11 +28,11 @@ var XHR = window.XMLHttpRequest || function() {
*/
function $HttpBackendProvider() {
this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, $document[0]);
return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
}];
}
function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument) {
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
var ABORTED = -1;
// TODO(vojta): fix the signature
@@ -54,10 +54,12 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
} else {
completeRequest(callback, status || -2);
}
delete callbacks[callbackId];
callbacks[callbackId] = angular.noop;
});
} else {
var xhr = new XHR();
var xhr = createXhr(method);
xhr.open(method, url, true);
forEach(headers, function(value, key) {
if (isDefined(value)) {
@@ -69,17 +71,25 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
// response is in the cache. the promise api will ensure that to the app code the api is
// always async
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
// xhrs that are resolved while the app is in the background (see #5426).
// since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
// continuing
//
// we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
// Safari respectively.
if (xhr && xhr.readyState == 4) {
var responseHeaders = null,
response = null;
if(status !== ABORTED) {
responseHeaders = xhr.getAllResponseHeaders();
response = xhr.responseType ? xhr.response : xhr.responseText;
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
response = ('response' in xhr) ? xhr.response : xhr.responseText;
}
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
completeRequest(callback,
status || xhr.status,
response,
@@ -112,14 +122,14 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
}
function completeRequest(callback, status, response, headersString) {
var protocol = urlResolve(url).protocol;
// cancel timeout and subsequent timeout promise resolution
timeoutId && $browserDefer.cancel(timeoutId);
jsonpDone = xhr = null;
// fix status code for file protocol (it's always 0)
status = (protocol == 'file' && status === 0) ? (response ? 200 : 404) : status;
// fix status code when it is 0 (0 status is undocumented).
// Occurs when accessing file resources.
// On Android 4.1 stock browser it occurs while retrieving files from application cache.
status = (status === 0) ? (response ? 200 : 404) : status;
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
status = status == 1223 ? 204 : status;
+3 -3
View File
@@ -24,7 +24,7 @@ function $IntervalProvider() {
* In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
* move forward by `millis` milliseconds and trigger any functions scheduled to run in that
* time.
*
*
* <div class="alert alert-warning">
* **Note**: Intervals created by this service must be explicitly destroyed when you are finished
* with them. In particular they are not automatically destroyed when a controller's scope or a
@@ -137,8 +137,8 @@ function $IntervalProvider() {
promise = deferred.promise,
iteration = 0,
skipApply = (isDefined(invokeApply) && !invokeApply);
count = isDefined(count) ? count : 0,
count = isDefined(count) ? count : 0;
promise.then(null, null, fn);
+8 -7
View File
@@ -576,7 +576,7 @@ function $LocationProvider(){
* Broadcasted before a URL will change. This change can be prevented by calling
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
* details about event object. Upon successful change
* {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
* {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
*
* @param {Object} angularEvent Synthetic event object.
* @param {string} newUrl New URL
@@ -659,16 +659,17 @@ function $LocationProvider(){
// update $location when $browser url changes
$browser.onUrlChange(function(newUrl) {
if ($location.absUrl() != newUrl) {
if ($rootScope.$broadcast('$locationChangeStart', newUrl,
$location.absUrl()).defaultPrevented) {
$browser.url($location.absUrl());
return;
}
$rootScope.$evalAsync(function() {
var oldUrl = $location.absUrl();
$location.$$parse(newUrl);
afterLocationChange(oldUrl);
if ($rootScope.$broadcast('$locationChangeStart', newUrl,
oldUrl).defaultPrevented) {
$location.$$parse(oldUrl);
$browser.url(oldUrl);
} else {
afterLocationChange(oldUrl);
}
});
if (!$rootScope.$$phase) $rootScope.$digest();
}
+17 -9
View File
@@ -707,7 +707,7 @@ Parser.prototype = {
var getter = getterFn(field, this.options, this.text);
return extend(function(scope, locals, self) {
return getter(self || object(scope, locals), locals);
return getter(self || object(scope, locals));
}, {
assign: function(scope, value, locals) {
return setter(object(scope, locals), field, value, parser.text, parser.options);
@@ -894,16 +894,20 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
if (pathVal == null) return key1 ? undefined : pathVal;
if (!key1) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key1];
if (pathVal == null) return key2 ? undefined : pathVal;
if (!key2) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key2];
if (pathVal == null) return key3 ? undefined : pathVal;
if (!key3) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key3];
if (pathVal == null) return key4 ? undefined : pathVal;
if (!key4) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key4];
return pathVal;
@@ -924,8 +928,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key1 ? undefined : pathVal;
if (!key1) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key1];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -936,8 +941,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key2 ? undefined : pathVal;
if (!key2) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key2];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -948,8 +954,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key3 ? undefined : pathVal;
if (!key3) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key3];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -960,8 +967,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key4 ? undefined : pathVal;
if (!key4) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key4];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
+3 -3
View File
@@ -16,9 +16,9 @@
* asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
*
* <pre>
* // for the purpose of this example let's assume that variables `$q` and `scope` are
* // available in the current lexical scope (they could have been injected or passed in).
*
* // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
* // are available in the current lexical scope (they could have been injected or passed in).
*
* function asyncGreet(name) {
* var deferred = $q.defer();
*
+33 -7
View File
@@ -133,6 +133,7 @@ function $RootScopeProvider(){
this.$$asyncQueue = [];
this.$$postDigestQueue = [];
this.$$listeners = {};
this.$$listenerCount = {};
this.$$isolateBindings = {};
}
@@ -185,13 +186,14 @@ function $RootScopeProvider(){
} else {
ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
// the name it does not become random set of chars. This will then show up as class
// name in the debugger.
// name in the web inspector.
ChildScope.prototype = this;
child = new ChildScope();
child.$id = nextUid();
}
child['this'] = child;
child.$$listeners = {};
child.$$listenerCount = {};
child.$parent = this;
child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
child.$$prevSibling = this.$$childTail;
@@ -285,7 +287,7 @@ function $RootScopeProvider(){
// No digest has been run so the counter will be zero
expect(scope.foodCounter).toEqual(0);
// Run the digest but since food has not changed cout will still be zero
// Run the digest but since food has not changed count will still be zero
scope.$digest();
expect(scope.foodCounter).toEqual(0);
@@ -351,6 +353,7 @@ function $RootScopeProvider(){
return function() {
arrayRemove(array, watcher);
lastDirtyWatch = null;
};
},
@@ -629,7 +632,7 @@ function $RootScopeProvider(){
// `break traverseScopesLoop;` takes us to here
if(dirty && !(ttl--)) {
if((dirty || asyncQueue.length) && !(ttl--)) {
clearPhase();
throw $rootScopeMinErr('infdig',
'{0} $digest() iterations reached. Aborting!\n' +
@@ -696,6 +699,8 @@ function $RootScopeProvider(){
this.$$destroyed = true;
if (this === $rootScope) return;
forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
@@ -885,8 +890,18 @@ function $RootScopeProvider(){
}
namedListeners.push(listener);
var current = this;
do {
if (!current.$$listenerCount[name]) {
current.$$listenerCount[name] = 0;
}
current.$$listenerCount[name]++;
} while ((current = current.$parent));
var self = this;
return function() {
namedListeners[indexOf(namedListeners, listener)] = null;
decrementListenerCount(self, 1, name);
};
},
@@ -998,8 +1013,7 @@ function $RootScopeProvider(){
listeners, i, length;
//down while you can, then up and next sibling or up and next sibling until back at root
do {
current = next;
while ((current = next)) {
event.currentScope = current;
listeners = current.$$listeners[name] || [];
for (i=0, length = listeners.length; i<length; i++) {
@@ -1021,12 +1035,14 @@ function $RootScopeProvider(){
// Insanity Warning: scope depth-first traversal
// yes, this code is a bit crazy, but it works and we have tests to prove it!
// this piece should be kept in sync with the traversal in $digest
if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
// (though it differs due to having the extra check for $$listenerCount)
if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
(current !== target && current.$$nextSibling)))) {
while(current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
} while ((current = next));
}
return event;
}
@@ -1055,6 +1071,16 @@ function $RootScopeProvider(){
return fn;
}
function decrementListenerCount(current, count, name) {
do {
current.$$listenerCount[name] -= count;
if (current.$$listenerCount[name] === 0) {
delete current.$$listenerCount[name];
}
} while ((current = current.$parent));
}
/**
* function used as an initial value for watchers.
* because it's unique we can easily tell it apart from other values
+8 -8
View File
@@ -275,7 +275,7 @@ function $SceDelegateProvider() {
*
* @description
* Returns an object that is trusted by angular for use in specified strict
* contextual escaping contexts (such as ng-html-bind-unsafe, ng-include, any src
* contextual escaping contexts (such as ng-bind-html, ng-include, any src
* attribute interpolation, any dom event binding attribute interpolation
* such as for onclick, etc.) that uses the provided value.
* See {@link ng.$sce $sce} for enabling strict contextual escaping.
@@ -321,7 +321,7 @@ function $SceDelegateProvider() {
*
* @param {*} value The result of a prior {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}
* call or anything else.
* @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs
* @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#methods_trustAs
* `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns
* `value` unchanged.
*/
@@ -502,8 +502,8 @@ function $SceDelegateProvider() {
* It's important to remember that SCE only applies to interpolation expressions.
*
* If your expressions are constant literals, they're automatically trusted and you don't need to
* call `$sce.trustAs` on them. (e.g.
* `<div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div>`) just works.
* call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
* `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
*
* Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
* through {@link ng.$sce#methods_getTrusted $sce.getTrusted}. SCE doesn't play a role here.
@@ -563,7 +563,7 @@ function $SceDelegateProvider() {
* matched against the **entire** *normalized / absolute URL* of the resource being tested
* (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags
* present on the RegExp (such as multiline, global, ignoreCase) are ignored.
* - If you are generating your Javascript from some other templating engine (not
* - If you are generating your JavaScript from some other templating engine (not
* recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
* remember to escape your regular expression (and be aware that you might need more than
* one level of escaping depending on your templating engine and the way you interpolated
@@ -580,7 +580,7 @@ function $SceDelegateProvider() {
* ## Show me an example using SCE.
*
* @example
<example module="mySceApp">
<example module="mySceApp" deps="angular-sanitize.js">
<file name="index.html">
<div ng-controller="myAppController as myCtrl">
<i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
@@ -805,8 +805,8 @@ function $SceProvider() {
*
* @description
* Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. As such,
* returns an objectthat is trusted by angular for use in specified strict contextual
* escaping contexts (such as ng-html-bind-unsafe, ng-include, any src attribute
* returns an object that is trusted by angular for use in specified strict contextual
* escaping contexts (such as ng-bind-html, ng-include, any src attribute
* interpolation, any dom event binding attribute interpolation such as for onclick, etc.)
* that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual
* escaping.
+1 -1
View File
@@ -59,7 +59,7 @@ function $SnifferProvider() {
// http://code.google.com/p/android/issues/detail?id=17471
// https://github.com/angular/angular.js/issues/904
// older webit browser (533.9) on Boxee box has exactly the same problem as Android has
// older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
// so let's not use the history API also
// We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
// jshint -W018
+145 -34
View File
@@ -248,6 +248,26 @@ angular.module('ngAnimate', ['ng'])
* Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
*
*/
.factory('$$animateReflow', ['$window', '$timeout', function($window, $timeout) {
var requestAnimationFrame = $window.requestAnimationFrame ||
$window.webkitRequestAnimationFrame ||
function(fn) {
return $timeout(fn, 10, false);
};
var cancelAnimationFrame = $window.cancelAnimationFrame ||
$window.webkitCancelAnimationFrame ||
function(timer) {
return $timeout.cancel(timer);
};
return function(fn) {
var id = requestAnimationFrame(fn);
return function() {
cancelAnimationFrame(id);
};
};
}])
.config(['$provide', '$animateProvider', function($provide, $animateProvider) {
var noop = angular.noop;
var forEach = angular.forEach;
@@ -295,6 +315,10 @@ angular.module('ngAnimate', ['ng'])
return classNameFilter.test(className);
};
function async(fn) {
return $timeout(fn, 0, false);
}
function lookup(name) {
if (name) {
var matches = [],
@@ -586,6 +610,8 @@ angular.module('ngAnimate', ['ng'])
//best to catch this early on to prevent any animation operations from occurring
if(!node || !isAnimatableClassName(classes)) {
fireDOMOperation();
fireBeforeCallbackAsync();
fireAfterCallbackAsync();
closeAnimation();
return;
}
@@ -605,14 +631,21 @@ angular.module('ngAnimate', ['ng'])
//NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case a NO animation is not found.
if (animationsDisabled(element, parentElement) || matches.length === 0) {
fireDOMOperation();
fireBeforeCallbackAsync();
fireAfterCallbackAsync();
closeAnimation();
return;
}
var animations = [];
//only add animations if the currently running animation is not structural
//or if there is no animation running at all
if(!ngAnimateState.running || !(isClassBased && ngAnimateState.structural)) {
var allowAnimations = isClassBased ?
!ngAnimateState.disabled && (!ngAnimateState.running || !ngAnimateState.structural) :
true;
if(allowAnimations) {
forEach(matches, function(animation) {
//add the animation to the queue to if it is allowed to be cancelled
if(!animation.allowCancel || animation.allowCancel(element, animationEvent, className)) {
@@ -638,14 +671,17 @@ angular.module('ngAnimate', ['ng'])
//animation do it's thing and close this one early
if(animations.length === 0) {
fireDOMOperation();
fireBeforeCallbackAsync();
fireAfterCallbackAsync();
fireDoneCallbackAsync();
return;
}
var ONE_SPACE = ' ';
//this value will be searched for class-based CSS className lookup. Therefore,
//we prefix and suffix the current className value with spaces to avoid substring
//lookups of className tokens
var futureClassName = ' ' + currentClassName + ' ';
var futureClassName = ONE_SPACE + currentClassName + ONE_SPACE;
if(ngAnimateState.running) {
//if an animation is currently running on the element then lets take the steps
//to cancel that animation and fire any required callbacks
@@ -653,12 +689,23 @@ angular.module('ngAnimate', ['ng'])
cleanup(element);
cancelAnimations(ngAnimateState.animations);
//in the event that the CSS is class is quickly added and removed back
//then we don't want to wait until after the reflow to add/remove the CSS
//class since both class animations may run into a race condition.
//The code below will check to see if that is occurring and will
//immediately remove the former class before the reflow so that the
//animation can snap back to the original animation smoothly
var isFullyClassBasedAnimation = isClassBased && !ngAnimateState.structural;
var isRevertingClassAnimation = isFullyClassBasedAnimation &&
ngAnimateState.className == className &&
animationEvent != ngAnimateState.event;
//if the class is removed during the reflow then it will revert the styles temporarily
//back to the base class CSS styling causing a jump-like effect to occur. This check
//here ensures that the domOperation is only performed after the reflow has commenced
if(ngAnimateState.beforeComplete) {
if(ngAnimateState.beforeComplete || isRevertingClassAnimation) {
(ngAnimateState.done || noop)(true);
} else if(isClassBased && !ngAnimateState.structural) {
} else if(isFullyClassBasedAnimation) {
//class-based animations will compare element className values after cancelling the
//previous animation to see if the element properties already contain the final CSS
//class and if so then the animation will be skipped. Since the domOperation will
@@ -666,8 +713,8 @@ angular.module('ngAnimate', ['ng'])
//will be invalid. Therefore the same string manipulation that would occur within the
//DOM operation will be performed below so that the class comparison is valid...
futureClassName = ngAnimateState.event == 'removeClass' ?
futureClassName.replace(ngAnimateState.className, '') :
futureClassName + ngAnimateState.className + ' ';
futureClassName.replace(ONE_SPACE + ngAnimateState.className + ONE_SPACE, ONE_SPACE) :
futureClassName + ngAnimateState.className + ONE_SPACE;
}
}
@@ -675,10 +722,12 @@ angular.module('ngAnimate', ['ng'])
//(on addClass) or doesn't contain (on removeClass) the className being animated.
//The reason why this is being called after the previous animations are cancelled
//is so that the CSS classes present on the element can be properly examined.
var classNameToken = ' ' + className + ' ';
var classNameToken = ONE_SPACE + className + ONE_SPACE;
if((animationEvent == 'addClass' && futureClassName.indexOf(classNameToken) >= 0) ||
(animationEvent == 'removeClass' && futureClassName.indexOf(classNameToken) == -1)) {
fireDOMOperation();
fireBeforeCallbackAsync();
fireAfterCallbackAsync();
fireDoneCallbackAsync();
return;
}
@@ -719,6 +768,10 @@ angular.module('ngAnimate', ['ng'])
}
function invokeRegisteredAnimationFns(animations, phase, allAnimationFnsComplete) {
phase == 'after' ?
fireAfterCallbackAsync() :
fireBeforeCallbackAsync();
var endFnName = phase + 'End';
forEach(animations, function(animation, index) {
var animationPhaseCompleted = function() {
@@ -755,8 +808,30 @@ angular.module('ngAnimate', ['ng'])
}
}
function fireDOMCallback(animationPhase) {
element.triggerHandler('$animate:' + animationPhase, {
event : animationEvent,
className : className
});
}
function fireBeforeCallbackAsync() {
async(function() {
fireDOMCallback('before');
});
}
function fireAfterCallbackAsync() {
async(function() {
fireDOMCallback('after');
});
}
function fireDoneCallbackAsync() {
doneCallback && $timeout(doneCallback, 0, false);
async(function() {
fireDOMCallback('close');
doneCallback && doneCallback();
});
}
//it is less complicated to use a flag than managing and cancelling
@@ -780,9 +855,9 @@ angular.module('ngAnimate', ['ng'])
if(isClassBased) {
cleanup(element);
} else {
data.closeAnimationTimeout = $timeout(function() {
data.closeAnimationTimeout = async(function() {
cleanup(element);
}, 0, false);
});
element.data(NG_ANIMATE_STATE, data);
}
}
@@ -806,10 +881,10 @@ angular.module('ngAnimate', ['ng'])
function cancelAnimations(animations) {
var isCancelledFlag = true;
forEach(animations, function(animation) {
if(!animations.beforeComplete) {
if(!animation.beforeComplete) {
(animation.beforeEnd || noop)(isCancelledFlag);
}
if(!animations.afterComplete) {
if(!animation.afterComplete) {
(animation.afterEnd || noop)(isCancelledFlag);
}
});
@@ -855,7 +930,8 @@ angular.module('ngAnimate', ['ng'])
}
}]);
$animateProvider.register('', ['$window', '$sniffer', '$timeout', function($window, $sniffer, $timeout) {
$animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow',
function($window, $sniffer, $timeout, $$animateReflow) {
// Detect proper transitionend/animationend event names.
var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
@@ -900,11 +976,13 @@ angular.module('ngAnimate', ['ng'])
var parentCounter = 0;
var animationReflowQueue = [];
var animationElementQueue = [];
var animationTimer;
var cancelAnimationReflow;
var closingAnimationTime = 0;
var timeOut = false;
function afterReflow(element, callback) {
$timeout.cancel(animationTimer);
if(cancelAnimationReflow) {
cancelAnimationReflow();
}
animationReflowQueue.push(callback);
@@ -913,15 +991,19 @@ angular.module('ngAnimate', ['ng'])
animationElementQueue.push(element);
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
closingAnimationTime = Math.max(closingAnimationTime,
(elementData.maxDelay + elementData.maxDuration) * CLOSING_TIME_BUFFER * ONE_SECOND);
var stagger = elementData.stagger;
var staggerTime = elementData.itemIndex * (Math.max(stagger.animationDelay, stagger.transitionDelay) || 0);
var animationTime = (elementData.maxDelay + elementData.maxDuration) * CLOSING_TIME_BUFFER;
closingAnimationTime = Math.max(closingAnimationTime, (staggerTime + animationTime) * ONE_SECOND);
//by placing a counter we can avoid an accidental
//race condition which may close an animation when
//a follow-up animation is midway in its animation
elementData.animationCount = animationCounter;
animationTimer = $timeout(function() {
cancelAnimationReflow = $$animateReflow(function() {
forEach(animationReflowQueue, function(fn) {
fn();
});
@@ -942,11 +1024,11 @@ angular.module('ngAnimate', ['ng'])
animationReflowQueue = [];
animationElementQueue = [];
animationTimer = null;
cancelAnimationReflow = null;
lookupCache = {};
closingAnimationTime = 0;
animationCounter++;
}, 10, false);
});
}
function closeAllAnimations(elements, count) {
@@ -1037,13 +1119,13 @@ angular.module('ngAnimate', ['ng'])
return parentID + '-' + extractElementNode(element).className;
}
function animateSetup(element, className) {
function animateSetup(element, className, calculationDecorator) {
var cacheKey = getCacheKey(element);
var eventCacheKey = cacheKey + ' ' + className;
var stagger = {};
var ii = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
if(ii > 0) {
if(itemIndex > 0) {
var staggerClassName = className + '-stagger';
var staggerCacheKey = cacheKey + ' ' + staggerClassName;
var applyClasses = !lookupCache[staggerCacheKey];
@@ -1055,9 +1137,16 @@ angular.module('ngAnimate', ['ng'])
applyClasses && element.removeClass(staggerClassName);
}
/* the animation itself may need to add/remove special CSS classes
* before calculating the anmation styles */
calculationDecorator = calculationDecorator ||
function(fn) { return fn(); };
element.addClass(className);
var timings = getElementAnimationDetails(element, eventCacheKey);
var timings = calculationDecorator(function() {
return getElementAnimationDetails(element, eventCacheKey);
});
/* there is no point in performing a reflow if the animation
timeout is empty (this would cause a flicker bug normally
@@ -1089,7 +1178,7 @@ angular.module('ngAnimate', ['ng'])
classes : className + ' ' + activeClassName,
timings : timings,
stagger : stagger,
ii : ii
itemIndex : itemIndex
});
return true;
@@ -1134,30 +1223,30 @@ angular.module('ngAnimate', ['ng'])
var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * ONE_SECOND;
var startTime = Date.now();
var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
var ii = elementData.ii;
var itemIndex = elementData.itemIndex;
var style = '', appliedStyles = [];
if(timings.transitionDuration > 0) {
var propertyStyle = timings.transitionPropertyStyle;
if(propertyStyle.indexOf('all') == -1) {
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ';';
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + 's;';
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ';';
appliedStyles.push(CSS_PREFIX + 'transition-property');
appliedStyles.push(CSS_PREFIX + 'transition-duration');
}
}
if(ii > 0) {
if(itemIndex > 0) {
if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
var delayStyle = timings.transitionDelayStyle;
style += CSS_PREFIX + 'transition-delay: ' +
prepareStaggerDelay(delayStyle, stagger.transitionDelay, ii) + '; ';
prepareStaggerDelay(delayStyle, stagger.transitionDelay, itemIndex) + '; ';
appliedStyles.push(CSS_PREFIX + 'transition-delay');
}
if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
style += CSS_PREFIX + 'animation-delay: ' +
prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, ii) + '; ';
prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, itemIndex) + '; ';
appliedStyles.push(CSS_PREFIX + 'animation-delay');
}
}
@@ -1222,8 +1311,8 @@ angular.module('ngAnimate', ['ng'])
return style;
}
function animateBefore(element, className) {
if(animateSetup(element, className)) {
function animateBefore(element, className, calculationDecorator) {
if(animateSetup(element, className, calculationDecorator)) {
return function(cancelled) {
cancelled && animateClose(element, className);
};
@@ -1318,7 +1407,18 @@ angular.module('ngAnimate', ['ng'])
},
beforeAddClass : function(element, className, animationCompleted) {
var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'));
var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'), function(fn) {
/* when a CSS class is added to an element then the transition style that
* is applied is the transition defined on the element when the CSS class
* is added at the time of the animation. This is how CSS3 functions
* outside of ngAnimate. */
element.addClass(className);
var timings = fn();
element.removeClass(className);
return timings;
});
if(cancellationMethod) {
afterReflow(element, function() {
unblockTransitions(element);
@@ -1335,7 +1435,18 @@ angular.module('ngAnimate', ['ng'])
},
beforeRemoveClass : function(element, className, animationCompleted) {
var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'));
var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'), function(fn) {
/* when classes are removed from an element then the transition style
* that is applied is the transition defined on the element without the
* CSS class being there. This is how CSS3 functions outside of ngAnimate.
* http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
var klass = element.attr('class');
element.removeClass(className);
var timings = fn();
element.attr('class', klass);
return timings;
});
if(cancellationMethod) {
afterReflow(element, function() {
unblockTransitions(element);
+53 -4
View File
@@ -379,7 +379,7 @@ angular.mock.$LogProvider = function() {
*
* @example
* <pre>
* $log.log('Some Error');
* $log.error('Some Error');
* var first = $log.error.logs.unshift();
* </pre>
*/
@@ -756,6 +756,36 @@ angular.mock.TzDate = function (offset, timestamp) {
angular.mock.TzDate.prototype = Date.prototype;
/* jshint +W101 */
// TODO(matias): remove this IMMEDIATELY once we can properly detect the
// presence of a registered module
var animateLoaded;
try {
angular.module('ngAnimate');
animateLoaded = true;
} catch(e) {}
if(animateLoaded) {
angular.module('ngAnimate').config(['$provide', function($provide) {
var reflowQueue = [];
$provide.value('$$animateReflow', function(fn) {
reflowQueue.push(fn);
return angular.noop;
});
$provide.decorator('$animate', function($delegate) {
$delegate.triggerReflow = function() {
if(reflowQueue.length === 0) {
throw new Error('No animation reflows present');
}
angular.forEach(reflowQueue, function(fn) {
fn();
});
reflowQueue = [];
};
return $delegate;
});
}]);
}
angular.mock.animate = angular.module('mock.animate', ['ng'])
.config(['$provide', function($provide) {
@@ -1572,6 +1602,10 @@ function MockHttpExpectation(method, url, data, headers) {
};
}
function createMockXhr() {
return new MockXhr();
}
function MockXhr() {
// hack for testing $http, $httpBackend
@@ -1695,7 +1729,7 @@ angular.mock.$RootElementProvider = function() {
* In addition, ngMock also extends various core ng services such that they can be
* inspected and controlled in a synchronous manner within test code.
*
* {@installModule mocks}
* {@installModule mock}
*
* <div doc-module-components="ngMock"></div>
*
@@ -1909,7 +1943,6 @@ angular.mock.clearDataCache = function() {
};
if(window.jasmine || window.mocha) {
var currentSpec = null,
@@ -2075,6 +2108,20 @@ if(window.jasmine || window.mocha) {
*
* @param {...Function} fns any number of functions which will be injected using the injector.
*/
var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
this.message = e.message;
this.name = e.name;
if (e.line) this.line = e.line;
if (e.sourceId) this.sourceId = e.sourceId;
if (e.stack && errorForStack)
this.stack = e.stack + '\n' + errorForStack.stack;
if (e.stackArray) this.stackArray = e.stackArray;
};
ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
window.inject = angular.mock.inject = function() {
var blockFns = Array.prototype.slice.call(arguments, 0);
var errorForStack = new Error('Declaration Location');
@@ -2095,7 +2142,9 @@ if(window.jasmine || window.mocha) {
injector.invoke(blockFns[i] || angular.noop, this);
/* jshint +W040 */
} catch (e) {
if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack;
if (e.stack && errorForStack) {
throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
}
throw e;
} finally {
errorForStack = null;
+2 -2
View File
@@ -90,7 +90,7 @@ function shallowClearAndCopy(src, dst) {
* when a param value needs to be obtained for a request (unless the param was overridden).
*
* Each key value in the parameter object is first bound to url template if present and then any
* excess keys are appended to the url seapph query after the `?`.
* excess keys are appended to the url search query after the `?`.
*
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
* URL `/path/greet?salutation=Hello`.
@@ -401,7 +401,7 @@ angular.module('ngResource', ['ng']).
});
// strip trailing slashes and set the url
url = url.replace(/\/+$/, '');
url = url.replace(/\/+$/, '') || '/';
// then replace collapse `/.` if found in the last URL path segment before the query
// E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
+10 -1
View File
@@ -26,6 +26,15 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
*
* @scope
* @priority 400
* @param {string=} onload Expression to evaluate whenever the view updates.
*
* @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
* $anchorScroll} to scroll the viewport after the view is updated.
*
* - If the attribute is not set, disable scrolling.
* - If the attribute is set without value, enable scrolling.
* - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
* as an expression yields a truthy value.
* @example
<example module="ngViewExample" deps="angular-route.js" animations="true">
<file name="index.html">
@@ -199,7 +208,7 @@ function ngViewFactory( $route, $anchorScroll, $animate) {
var locals = $route.current && $route.current.locals,
template = locals && locals.$template;
if (template) {
if (angular.isDefined(template)) {
var newScope = scope.$new();
var current = $route.current;
+2 -2
View File
@@ -185,7 +185,7 @@ function $RouteProvider(){
path = path
.replace(/([().])/g, '\\$1')
.replace(/(\/)?:(\w+)([\?|\*])?/g, function(_, slash, key, option){
.replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){
var optional = option === '?' ? option : null;
var star = option === '*' ? option : null;
keys.push({ name: key, optional: !!optional });
@@ -370,7 +370,7 @@ function $RouteProvider(){
* @eventType broadcast on root scope
* @description
* Broadcasted before a route change. At this point the route services starts
* resolving all of the dependencies needed for the route change to occurs.
* resolving all of the dependencies needed for the route change to occur.
* Typically this involves fetching the view template as well as any dependencies
* defined in `resolve` route property. Once all of the dependencies are resolved
* `$routeChangeSuccess` is fired.
+1 -1
View File
@@ -206,7 +206,7 @@ var validAttrs = angular.extend({}, uriAttrs, makeMap(
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
'scope,scrolling,shape,span,start,summary,target,title,type,'+
'scope,scrolling,shape,size,span,start,summary,target,title,type,'+
'valign,value,vspace,width'));
function makeMap(str) {
+2 -1
View File
@@ -239,7 +239,8 @@ function callerFile(offset) {
* To work around this we instead use our own handler that fires a real event.
*/
(function(fn){
var parentTrigger = fn.trigger;
// We need a handle to the original trigger function for input tests.
var parentTrigger = fn._originalTrigger = fn.trigger;
fn.trigger = function(type) {
if (/(click|change|keydown|blur|input|mousedown|mouseup)/.test(type)) {
var processDefaults = [];
+11
View File
@@ -74,6 +74,17 @@ describe('injector', function() {
});
it('should not corrupt the cache when an object fails to get instantiated', function() {
expect(function() {
injector.get('idontexist');
}).toThrowMinErr("$injector", "unpr", "Unknown provider: idontexistProvider <- idontexist");
expect(function() {
injector.get('idontexist');
}).toThrowMinErr("$injector", "unpr", "Unknown provider: idontexistProvider <- idontexist");
});
it('should provide path to the missing provider', function() {
providers('a', function(idontexist) {return 1;});
providers('b', function(a) {return 2;});
+40
View File
@@ -0,0 +1,40 @@
describe('docs.angularjs.org', function () {
describe('App', function () {
// it('should filter the module list when searching', function () {
// browser.get();
// browser.waitForAngular();
// var search = element(by.input('q'));
// search.clear();
// search.sendKeys('ngBind');
// var firstModule = element(by.css('.search-results a'));
// expect(firstModule.getText()).toEqual('ngBind');
// });
it('should change the page content when clicking a link to a service', function () {
browser.get('');
var ngBindLink = element(by.css('.definition-table td a[href="api/ng.directive:ngClick"]'));
ngBindLink.click();
var pageBody = element(by.css('.content h1 code'));
expect(pageBody.getText()).toEqual('ngClick');
});
it('should show the functioning input directive example', function () {
browser.get('index-nocache.html#!/api/ng.directive:input');
//Wait for animation
browser.sleep(500);
var nameInput = element(by.input('user.name'));
nameInput.click();
nameInput.sendKeys('!!!');
var code = element(by.css('.doc-example-live tt'));
expect(code.getText()).toContain('guest!!!');
});
});
})
+5
View File
@@ -609,5 +609,10 @@ describe('browser', function() {
fakeDocument.basePath = 'http://host.com/base/path/index.html';
expect(browser.baseHref()).toEqual('/base/path/index.html');
});
it('should remove domain from <base href> beginning with \'//\'', function() {
fakeDocument.basePath = '//google.com/base/path/';
expect(browser.baseHref()).toEqual('/base/path/');
});
});
});
+8 -3
View File
@@ -202,9 +202,14 @@ describe('$compile', function() {
if (msie < 9) return;
element = jqLite('<div>{{1+2}}</div>');
element[0].childNodes[1] = {nodeType: 3, nodeName: 'OBJECT', textContent: 'fake node'};
if (!element[0].childNodes[1]) return; //browser doesn't support this kind of mocking
try {
element[0].childNodes[1] = {nodeType: 3, nodeName: 'OBJECT', textContent: 'fake node'};
} catch(e) {
} finally {
if (!element[0].childNodes[1]) return; //browser doesn't support this kind of mocking
}
expect(element[0].childNodes[1].textContent).toBe('fake node');
$compile(element)($rootScope);
@@ -4243,7 +4248,7 @@ describe('$compile', function() {
expect(element.attr('test2')).toBe('Misko');
expect(element.attr('test3')).toBe('Misko');
}));
it('should work with the "href" attribute', inject(function($compile, $rootScope) {
$rootScope.value = 'test';
element = $compile('<a ng-attr-href="test/{{value}}"></a>')($rootScope);
+67
View File
@@ -84,4 +84,71 @@ describe('a', function() {
expect(jq.prototype.on).not.toHaveBeenCalled();
});
if (isDefined(window.SVGElement)) {
describe('SVGAElement', function() {
it('should prevent default action to be executed when href is empty', function() {
var orgLocation = document.location.href,
preventDefaultCalled = false,
event,
child;
element = $compile('<svg><a xlink:href="">empty link</a></svg>')($rootScope);
child = element.children('a');
if (msie < 9) {
event = document.createEventObject();
expect(event.returnValue).not.toBeDefined();
child[0].fireEvent('onclick', event);
expect(event.returnValue).toEqual(false);
} else {
event = document.createEvent('MouseEvent');
event.initMouseEvent(
'click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
event.preventDefaultOrg = event.preventDefault;
event.preventDefault = function() {
preventDefaultCalled = true;
if (this.preventDefaultOrg) this.preventDefaultOrg();
};
child[0].dispatchEvent(event);
expect(preventDefaultCalled).toEqual(true);
}
expect(document.location.href).toEqual(orgLocation);
});
it('should not link and hookup an event if xlink:href is present at compile', function() {
var jq = jQuery || jqLite;
element = jq('<svg><a xlink:href="bobby">hello@you</a></svg>');
var linker = $compile(element);
spyOn(jq.prototype, 'on');
linker($rootScope);
expect(jq.prototype.on).not.toHaveBeenCalled();
});
it('should not link and hookup an event if name is present at compile', function() {
var jq = jQuery || jqLite;
element = jq('<svg><a name="bobby">hello@you</a></svg>');
var linker = $compile(element);
spyOn(jq.prototype, 'on');
linker($rootScope);
expect(jq.prototype.on).not.toHaveBeenCalled();
});
});
}
});
+21 -3
View File
@@ -533,6 +533,23 @@ describe('input', function() {
'event so that form auto complete works',function() {
assertBrowserSupportsChangeEvent(true);
});
if (!_jqLiteMode) {
it('should not cause the double $digest when triggering an event using jQuery', function() {
$sniffer.hasEvent = function(eventName) {
return eventName !== 'input';
};
compileInput('<input type="text" ng-model="name" name="alias" ng-change="change()" />');
scope.field = 'fake field';
scope.$watch('field', function() {
// We need to use _originalTrigger since trigger is modified by Angular Scenario.
inputElm._originalTrigger('change');
});
scope.$apply();
});
}
});
describe('"paste" and "cut" events', function() {
@@ -707,7 +724,7 @@ describe('input', function() {
describe('minlength', function() {
it('should invalid shorter than given minlenght', function() {
it('should invalid shorter than given minlength', function() {
compileInput('<input type="text" ng-model="value" ng-minlength="3" />');
changeInputValueTo('aa');
@@ -721,7 +738,7 @@ describe('input', function() {
describe('maxlength', function() {
it('should invalid shorter than given maxlenght', function() {
it('should invalid shorter than given maxlength', function() {
compileInput('<input type="text" ng-model="value" ng-maxlength="5" />');
changeInputValueTo('aaaaaaaa');
@@ -927,7 +944,8 @@ describe('input', function() {
it('should validate email', function() {
expect(EMAIL_REGEXP.test('a@b.com')).toBe(true);
expect(EMAIL_REGEXP.test('a@b.museum')).toBe(true);
expect(EMAIL_REGEXP.test('a@B.c')).toBe(false);
expect(EMAIL_REGEXP.test('a@B.c')).toBe(true);
expect(EMAIL_REGEXP.test('a@.b.c')).toBe(false);
});
});
});

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