Compare commits

...

79 Commits

Author SHA1 Message Date
Georgios Kalpakas 70724e3918 test($log): fix up to work with IE8 2016-12-07 15:18:07 +02:00
Peter Bacon Darwin 9a0156d258 test($log): fix up to work with Safari 9
On Safari 9.0.2, you are not allowed to write to `sourceUrl` or `line`
on a native Error object.

This commit uses a custom error instead.
2016-12-07 14:39:42 +02:00
Peter Bacon Darwin 5730c665e8 docs(CHANGELOG): add 1.2.32 release notes 2016-10-11 22:49:02 +01:00
Peter Bacon Darwin b8a0ecdd61 fix($compile): ensure that hidden input values are correct after history.back
Due to the nature of some browser's PageCache/BFCache, returning to an Angular
app sometimes causes `input[hidden]` elements to retain the last value
that was stored before the page was navigated away from previously.

This is particularly problematic if the input has an interpolated value.
E.g. `<input type="hidden" value="{{ 1 + 2 }}">` since when the browser
returns, instead of the original interpolation template, the HTML contains
the previous value `<input type="hidden" value="3">`.

This commit instructs the browser not to attempt to reinstate the previous
value when navigating back in history by setting `autocomplete="off"` on
the hidden input element element.
2016-10-11 13:48:38 +01:00
Peter Bacon Darwin ed44dd0659 revert:fix(input): ensure that hidden input values are correct after history.back
This reverts commit 7ec663fc70.
There was a regression against angular-material that relied upon the input directive.
2016-10-11 13:39:13 +01:00
Peter Bacon Darwin a5f4d32d01 chore(bower): fix up URL to closure compiler 2016-10-11 07:48:26 +01:00
Peter Bacon Darwin e4fcf9244b docs(CHANGELOG): update with 1.2.30 and 1.2.31 changes 2016-10-10 23:05:24 +01:00
Peter Bacon Darwin 7ec663fc70 fix(input): ensure that hidden input values are correct after history.back
Due to the nature of some browser's PageCache/BFCache, returning to an Angular
app sometimes causes `input[hidden]` elements to retain the last value
that was stored before the page was navigated away from previously.

This is particularly problematic if the input has an interpolated value.
E.g. `<input type="hidden" value="{{ 1 + 2 }}">` since when the browser
returns, instead of the original interpolation template, the HTML contains
the previous value `<input type="hidden" value="3">`.

This commit instructs the browser not to attempt to reinstate the previous
value when navigating back in history by setting `autocomplete="off"` on
the hidden input element element.
2016-10-10 23:01:20 +01:00
Georgios Kalpakas 2687c26140 fix($compile): detect <a> elements inside <svg> 2016-07-20 23:17:37 +03:00
Igor Minar f2fa1ed83d fix($compile): properly sanitize xlink:href attribute interoplation
Closes #12524
2016-07-20 19:14:51 +03:00
Raphael Jamet f35f334bd3 fix($compile): secure link[href] as a RESOURCE_URLs in $sce.
User-controlled imports or stylesheets can run script in your origin,
which warrants that we require that they are safe `RESOURCE_URL`s.

Closes #14687

BREAKING CHANGE

`link[href]` attributes are now protected via `$sce`, which prevents interpolated
values that fail the `RESOURCE_URL` context tests from being used in interpolation.

For example if the application is running at `https://docs.angularjs.org` then the
following will fail:

```
<link href="{{ 'http://mydomain.org/unsafe.css' }}" rel="stylesheet">
```

By default, `RESOURCE_URL` safe URLs are only allowed from the same domain and protocol
as the application document.

To use URLs from other domains and/or protocols, you may either whitelist them or
wrap it into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
2016-07-20 19:09:47 +03:00
Georgios Kalpakas dd4ce50392 chore(ci): update Safari to v8 2016-07-13 14:14:12 +03:00
Georgios Kalpakas ac0d5286b8 fix($sanitize): blacklist the attribute usemap as it can be used as a security exploit
Backport of 234053f.

Closes #14903

BREAKING CHANGE:

The `$sanitize` service will now remove instances of the `usemap` attribute from any elements passed
to it.

This attribute is used to reference another element by `name` or `id`. Since the `name` and `id`
attributes are already blacklisted, a sanitized `usemap` attribute could only reference unsanitized
content, which is a security risk.
2016-07-13 14:13:27 +03:00
Matias Niemelä 8d83b56334 fix(ngAnimate): do not use event.timeStamp anymore for time tracking
Due to recent changes in Chrome, Firefox and Webkit use of the
event.timeStamp value will lead to unpredictable behaviour due to
precision changes. Therefore it's best to stick entirely to use
`Date.now()` when it comes to confirming the end of transition-
ending values. See #13494 for more info.

Applies to 1.2, 1.3, 1.4 and 1.5.

Closes #13494
Closes #13495
2016-01-05 13:09:20 +00:00
Peter Bacon Darwin b31234e3b1 chore(Gruntfile): replace double quotes with single quotes 2015-12-17 23:00:56 +00:00
Peter Bacon Darwin ffee742a78 chore(GruntFile): fix whitespace in lists 2015-12-17 23:00:56 +00:00
Peter Bacon Darwin 1346b0a562 chore(GruntFile): move validate-angular-files task into its own file
Closes #13569
2015-12-17 23:00:46 +00:00
Matias Niemelä 5fec3da64d chore(build): add a validation step for angularFiles
Closes #13553
2015-12-17 22:59:42 +00:00
Peter Bacon Darwin d662a17e57 chore(angularFiles): add documentation only file to list of files
This prevents errors when checking `validate-angular-files`
2015-12-17 22:40:54 +00:00
Peter Bacon Darwin 07f3ba5d66 chore(npm-shrinkwrap): install glob package 2015-12-17 22:40:51 +00:00
Peter Bacon Darwin eacd9ad853 chore(jenkins): remove unused argument definition 2015-12-17 14:15:43 +00:00
Peter Bacon Darwin 84dc5edd65 chore(jenkins): run Jenkins builds on Node 4 (via nvm)
Closes #13568
2015-12-17 14:12:22 +00:00
Peter Bacon Darwin de8e1121cf chore(jenkins): move jenkins_build.sh to scripts/jenkins/build.sh 2015-12-16 14:23:15 +00:00
Peter Bacon Darwin fb8f1ddd58 chore(travis): update to use node 4.x 2015-12-16 11:17:45 +00:00
Martin Staffa 34e5623542 chore(travis): add a new job that runs ci-checks
Previously, ddescribe, merge-conflicts, jshint, and jscs would run
after unit & e2e tests ran. The order was orginally changed as part of
https://github.com/angular/angular.js/pull/9792.

While the logic is sound that style errors shouldn't block tests from
running, ddescribe should always run. This was not guaraneteed; when
Travis exits with a warning after some browsers have run, ddescribe
doesn't get run and it doesn't become apparent that not
all tests have run.

Additionally, a separate job clearly separates style from test errors,
which e.g. means you can open a PR that includes an iit to speed up
the job, and see immediately if the test passes, because the ddescribe
error is in another job.
2015-12-16 10:30:28 +00:00
Matias Niemelä c95f8677e1 chore(CHANGELOG): update with changes for 1.2.29 2015-09-29 13:18:52 -07:00
Igor Minar 788885c611 build(travis): make sauce connect process query a bit more specific 2015-09-23 14:02:01 -07:00
Igor Minar d58c3778b6 build(travis): fix typo in a comment 2015-09-23 11:00:31 -07:00
Igor Minar b7eaa956e4 build(travis): gracefully shut down the sauce connect tunnel after the tests are done running
This is to prevent sauce connect tunnel leaks.

Closes #12921
2015-09-23 09:40:57 -07:00
Lucas Mirelmann 3d7846bdab style(test): fix style in one test 2015-09-20 21:34:27 +02:00
Lucas Mirelmann c4817cdca4 test($parse): fix test for IE 2015-09-20 19:59:16 +02:00
Lucas Mirelmann afb65c11e5 fix($parse): do not convert to string computed properties multiple times
Do not convert to string properties multiple times.
2015-09-20 13:48:21 +02:00
Peter Bacon Darwin 9d5ac2eb84 chore(travis): upgrade CI builds to latest 2015-09-17 12:17:08 +01:00
Peter Bacon Darwin 19bb53d929 test(privateMocks): fix for the latest version of Safari 2015-09-17 12:16:39 +01:00
Peter Bacon Darwin a4c5fc0a8f chore(bower/publish): move DIST_TAG so that it gets the correct value
In the position that DIST_TAG was being assigned it was trying to get the
`distTag` value from the wrong (i.e. a bower-...) repository.
2015-09-16 23:13:26 +01:00
Peter Bacon Darwin b94a47b1b5 chore(scripts/publish): get dist-tag from package.json
Closes #12722
2015-09-14 21:49:11 +01:00
Lucas Galfaso e6cbd4faa2 fix($parse): throw error when accessing a restricted property indirectly
When accessing an instance thru a computed member and the property is an array,
then also check the string value of the array.

Closes #12833
2015-09-14 21:46:15 +01:00
Scott Davidson fccce96d44 fix($compile): workaround for IE11 MutationObserver
Backport #11796 to 1.2 branch.
IE11 MutationObserver breaks consecutive text nodes into several text nodes.
This patch merges consecutive text nodes into a single node before looking for interpolations.
Also had to modify npm-shrinkwrap.json because i@0.3.2 was unpublished from npm.

Closes #11781
Closes #12613
2015-09-01 17:47:53 +02:00
Matias Niemelä b041b66475 fix(ngAnimate): ensure that minified repaint code isn't removed
Closes #9936
2015-03-31 14:02:40 -07:00
Peter Bacon Darwin 996c7a0904 chore(bower/publish): run local precommit script if available
Closes #11164
2015-02-24 17:23:22 +00:00
Thibault Leruitte e81b2f726c fix($location): strip off empty hash segments when comparing
Backported from e93710fe0e

The url is the same whether or not there is an empty `#` marker at the end.
This prevents unwanted calls to update the browser, since the browser is
automatically applying an empty hash if necessary to prevent page reloads.

Closes #9635
Closes #10748
2015-02-04 14:20:26 +00:00
Julie Ralph 14c50a12a3 chore(testing): bump protractor to version 1.6.0 2015-01-12 11:52:09 -08:00
Rus1 3cbf542af0 docs(ngInclude): replace <tt> with <code>
Using obsolete <tt> HTML tag may not be good for Angular examples

Closes #10594
2014-12-30 15:48:36 -05:00
David Souther d60fbcc8e6 test($exceptionHandlerProvider): call inject() to run tests
In the current angular-mocksSpec, the tests for $exceptionHandlerProvider
call `module` to run tests on `$exceptionHandlerProvider.mode()`, but do
not call `inject()` to pump the module definitions.

Closes #10563
2014-12-23 18:10:53 +00:00
gokulkrishh b19353580d docs(guide/*): spelling/grammar improvements
Closes #10552
2014-12-22 10:49:33 -05:00
Caitlin Potter 77131c0cf6 docs($rootScope): remove erroneous closing parenthesis
Closes #10549
2014-12-22 08:35:17 -05:00
Kevin Primat 643e7ea9aa docs(guide/location): add missing definite article
The sentence was missing a definite article so was unclear. Added one to clarify.

Closes #10547
2014-12-22 08:25:40 -05:00
Peter Bacon Darwin d232151664 refactor(limitTo): no need for all those checks if we use slice
Closes #10537
2014-12-21 14:39:42 +00:00
Peter Bacon Darwin 8d6c594a56 docs($httpBackend): correct grammar
Closes #10496
2014-12-21 10:40:40 +00:00
sandeep b79f583055 docs(guide/index): add book Responsive Web Design with AngularJS
This book explores the AngularJS features that can help a developer for building a responsive application.

Merçi beaucoup~

Closes #10513
2014-12-18 23:58:58 -05:00
Ben Nelson c5eb0b710c docs(api/index): grammar is important and so should you
I changed the word "into" to "within".
Original description underneath ngAnimate reads: "Use ngAnimate to enable animation features into your application".
I changed the text to read: "Use ngAnimate to enable animation features within your application".
The change in wording makes the description read better and gives it a more professional feel.

Closes #10517
2014-12-18 13:50:00 -05:00
Jeff Cross 97a91199ad test(browser): change mock location definition to use defineProperty
The original fix for which this mock location logic was written fixes
a bug in master which also exists in 1.2.x. Cherry-picking the fix
to the 1.2.x branch was difficult because the mock location object
used ES5 get/set syntax, which is not supported in IE8.

This fix changes the implementation to work with IE8 and modern
browsers.

IE8's defineProperty only works on certain types of objects, such as
DOM elements. So the mock location is a div element in this
implementation.
2014-12-17 01:53:07 -08:00
Peter Bacon Darwin 9845cee63e fix($browser): prevent infinite digests when clearing the hash of a url
By using `location.hash` to update the current browser location when only
the hash has changed, we prevent the browser from attempting to reload.

Closes #9629
Closes #9635
Closes #10228
Closes #10308
2014-12-16 22:28:37 -08:00
Jack Kingsman 5f52957503 docs(error/badcfg): add missing "but"
Sentence meaning was unclear; added what I assumed should have been a "but"

Closes #10473
2014-12-16 14:36:08 +00:00
marmalade bfafdd2b63 docs(guide/Scopes): fix capitalization
This sentence should begin with a capital 'R', not a lower case one.

Closes #10472
2014-12-16 14:36:07 +00:00
Peter Bacon Darwin 5bc09b6370 docs(guide/E2E Testing): add '-' to 'end-to-end'
Closes #10458
2014-12-16 14:35:53 +00:00
Zachary Lopez d8a95a9d02 docs(angular.identity): add @param and @returns tags
Closes #10457
2014-12-16 14:35:17 +00:00
Alexander Tseung 8802d5198a docs(tutorial/index): improve capitalization
Improve capitalization in acronyms for better clarity.
2014-12-16 14:34:02 +00:00
Peter Bacon Darwin f2c87672c5 docs(guide/expression): update diff list between JavaScript and Angular expressions
add paragraphs about function declaration, comma and void operators and
RegExp to the diff list in the beginning of articule

Closes #10418
Closes #10452
2014-12-16 14:33:40 +00:00
Peter Bacon Darwin efd0490d9c docs(CHANGELOG): remove reverted commit 2014-12-16 07:56:39 +00:00
Peter Bacon Darwin a0f8a4b257 chore(CHANGELOG): update with changes for 1.2.28 2014-12-15 21:41:40 +00:00
Wes 37310e024d docs(Courses): fix syntax issue in developer guide
The courses section should use commas between links to differentiate the instances of each link

Closes #10448
2014-12-13 21:28:02 -05:00
Caitlin Potter 306e626196 revert feat($compile): add support for ng-attr with camelCased attributes
This reverts commit a1e7eb6360.

This change broke the stable branch builds.

/CC @petebacondarwin / @wesleycho
2014-12-13 20:39:15 -05:00
Dan Tennery-Spalding f31c7492ec docs(API Reference): corrected two typos - two missing commas
In the ngAnimate section, there were two commas missing from two sentences. This is inconsistent with the grammar used in the rest of the API documentation and made the document (slightly) more difficult to read. The two sentences are shown below, with the new commas added:

1. "Once defined, the animation can be triggered"
                           ^
                    comma added

2. "Once registered, the animation can be triggered"
                              ^
                    comma added

Closes #10447
2014-12-13 20:20:40 -05:00
Wesley Cho a1e7eb6360 feat($compile): add support for ng-attr with camelCased attributes
SVG attributes are case sensitive and some have upper case letters in them
This change ensures that we can identify these, when being used with the `ng-attr`
directive, by encoding upper case letters with a preceding underscore.

For example to apply `ng-attr` to the `viewBox` attribute we could write
`ng-attr-view_box` - or any of the other variants: `ng:attr:view_box`,
`data-ng-attr-view_box`, etc.

Closes #9845
Closes #10194
2014-12-09 12:06:04 +00:00
Tobias Davis 169e5326d1 docs($interval): correcting example code indentation
Bueno!

Closes #10372
2014-12-08 16:30:05 -05:00
Georgios Kalpakas bb3b65374d chore(changelog): add test for addition of trailing newline
Adds tests for the functionality added by #9550.

Closes #10358
2014-12-08 13:05:32 -05:00
Giuseppe Caruso ac9336b35a docs(guide/controllers): Just a typo
Gingerbreak would break testing. :)

Oh my gosh he's right, it totally w/ould. That is so embarrassing!

Closes #10353
2014-12-08 10:51:05 -05:00
Ciro Nunes 75787446ee docs(compile): document $attrs.$normalize
Closes #10345
2014-12-05 14:19:46 -05:00
Caitlin Potter 14409d7a7f style(ngHref): make jscs happy ;-; 2014-11-28 22:29:05 -06:00
Sagar Ranglani 370676d4d0 docs(ngHref): fix poor paragraph construction
It was bad.

In order to improve the docs, the inclusion of the last sentence would help define `ngHref` well.

Closes #10254
2014-11-28 22:10:28 -06:00
Caitlin Potter 4c218de4d3 style(*): IE is a real browser, and chakra is pretty solid
- IE9+ do not have issues with Function.prototype.apply() on builtin fns (asked Brian Terlson)
  (NOTE: there may still be corner cases where builtins will not have `apply()` --- this may
  need to be reverted on complaint).
- HTMLScriptElement#text is an IDL-spec'd attribute, and we use it in all cases --- so the
  comment was sort of nonsense.
- The value of `msie` does not depend on whether the user is using a "real" browser or not.

Closes #10242
2014-11-26 14:39:23 -06:00
Lucas Galfaso 929dd15b9b fix(linky): encode double quotes when serializing email addresses
Email addresses can (under certain restrictions) include double quote
characters. See http://tools.ietf.org/html/rfc3696#section-3.

For example, `"Jo Bloggs"@abc.com` is a valid email address.

When serializing emails to the `href` attribute of an anchor element,
we must HTML encode these double quote characters. See
http://www.w3.org/TR/html-markup/syntax.html#syntax-attr-double-quoted

This commit does not attempt to improve the functionality (i.e. regex)
that attempts to identify email addresses in a general string.

Closes #8945
Closes #8964
Closes #5946
Closes #10090
Closes #9256
2014-11-23 22:23:41 +00:00
Georgios Kalpakas 1b9e408ddb fix($route): fix redirection with optional/eager params
Fixes #9742
Closes #10202
2014-11-23 19:24:39 +01:00
thorn0 7505d126fa chore(docs): regroup version selector options into major branches and latest
Before this change we grouped by the  discontinued stable/unstable distinction.

Closes #10053
2014-11-23 14:50:31 +00:00
Caitlin Potter 7044e55feb style($http): make jscs happy 2014-11-21 00:27:45 -05:00
Dustin Chilson bd9e894fb7 docs($http): describe how to remove a header on a per request basis
Closes #10144
2014-11-21 00:27:38 -05:00
Brian Ford ba7e24ec6c chore(scripts): correctly update package.json 2014-11-20 15:21:33 -08:00
Brian Ford e1f98773c7 chore(scripts): fix 1.2.x tag name 2014-11-20 15:02:40 -08:00
71 changed files with 11587 additions and 1216 deletions
+31 -12
View File
@@ -1,6 +1,13 @@
language: node_js
sudo: false
node_js:
- '0.10'
- '4.2'
cache:
directories:
- node_modules
- bower_components
- docs/bower_components
branches:
except:
@@ -8,35 +15,47 @@ branches:
env:
matrix:
- JOB=unit
- JOB=e2e TEST_TARGET=jqlite
- JOB=e2e TEST_TARGET=jquery
- JOB=ci-checks
- JOB=unit BROWSER_PROVIDER=saucelabs
- JOB=docs-e2e BROWSER_PROVIDER=saucelabs
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=saucelabs
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=saucelabs
global:
- CXX=g++-4.8 # node 4 likes the G++ v4.8 compiler
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- LOGS_DIR=/tmp/angular-build/logs
- BROWSER_PROVIDER_READY_FILE=/tmp/sauce-connect-ready
- BROWSER_PROVIDER_READY_FILE=/tmp/browsersprovider-tunnel-ready
# node 4 likes the G++ v4.8 compiler
# see https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
install:
# Check the size of caches
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
# - npm config set registry http://23.251.144.68
# Disable the spinner, it looks bad on Travis
- npm config set spin false
# Log HTTP requests
- npm config set loglevel http
- time ./scripts/travis/npm-bundle-deps.sh
- time npm install
#- npm install -g npm@2.5
# Install npm dependencies and ensure that npm cache is not stale
- npm install
before_script:
- mkdir -p $LOGS_DIR
- ./lib/sauce/sauce_connect_setup.sh
- npm install -g grunt-cli
- grunt package
- ./scripts/travis/wait_for_browser_provider.sh
- ./scripts/travis/before_build.sh
script:
- ./scripts/travis/build.sh
after_script:
- ./scripts/travis/tear_down_browser_provider.sh
- ./scripts/travis/print_logs.sh
notifications:
+120
View File
@@ -1,3 +1,123 @@
<a name="1.2.32"></a>
# 1.2.32 alternation-intention (2016-10-10)
This release reverts the fix in 1.2.31 and provides an alternative fix that doesn't break Angular Material.
## Reverts
- **input:** ensure that hidden input values are correct after history back
([ed44dd065](https://github.com/angular/angular.js/commit/ed44dd0659f346ced78a112e4a2b30d3af4fd572))
## Bug Fixes
- **$compile:** ensure that hidden input values are correct after history back
([b8a0ecdd6](https://github.com/angular/angular.js/commit/b8a0ecdd6189fb111734eb5b6d4d473d0dcf4c36))
<a name="1.2.31"></a>
# 1.2.31 barking-moustache (2016-10-10)
## Bug Fixes
- **input:** ensure that hidden input values are correct after history back
([7ec663fc](https://github.com/angular/angular.js/commit/7ec663fc708aa7a9a9ce62d2306f24d7a733a86d))
<a name="1.2.30"></a>
# 1.2.30 patronal-resurrection (2016-07-21)
_**Note:** This release contains some security fixes that required breaking changes. Since the
legacy 1.2.x branch is the only version branch that supports IE8, it was necessary to introduce a
couple of low-impact breaking changes in a patch release - something we generally avoid - in order
to make the fixes available to people that still need IE8 support._
## Bug Fixes
- **$compile:**
- secure `link[href]` as a `RESOURCE_URL`s in `$sce`
([f35f334b](https://github.com/angular/angular.js/commit/f35f334bd3197585bdf034f4b6d9ffa3122dac62),
[#14687](https://github.com/angular/angular.js/issues/14687))
- properly sanitize `xlink:href` attribute interpolation
([f2fa1ed8](https://github.com/angular/angular.js/commit/f2fa1ed83d18d4e79a36f8c0db1c2524d762e513),
[2687c261](https://github.com/angular/angular.js/commit/2687c26140585d9e3716f9f559390f5d8d598fdf))
- **ngSanitize:** blacklist the attribute `usemap` as it can be used as a security exploit
([ac0d5286](https://github.com/angular/angular.js/commit/ac0d5286b8931633d774080d6396fb4825d8be33),
[#14903](https://github.com/angular/angular.js/issues/14903))
- **ngAnimate:** do not use event.timeStamp anymore for time tracking
([8d83b563](https://github.com/angular/angular.js/commit/8d83b5633471c847d58f337426fe069797dd49d9),
[#13494](https://github.com/angular/angular.js/issues/13494), [#13495](https://github.com/angular/angular.js/issues/13495))
## Breaking Changes
- **$compile:** due to [f35f334b](https://github.com/angular/angular.js/commit/f35f334bd3197585bdf034f4b6d9ffa3122dac62),
`link[href]` attributes are now protected via `$sce`, which prevents interpolated values that fail
the `RESOURCE_URL` context tests from being used in interpolation. For example if the application is
running at `https://mydomain.org/` then the following will fail:
```html
<link rel="stylesheet" href="{{ 'https://otherdomain.org/unsafe.css' }}" />
```
By default, `RESOURCE_URL` safe URLs are only allowed from the same domain and protocol as the
application document. To use URLs from other domains and/or protocols, you may either whitelist them
using `$sceDelegateProvider.resourceUrlWhitelist(...)` or wrap them into a trusted value by calling
`$sce.trustAsResourceUrl(url)`.
- **ngSanitize:** due to [234053fc](https://github.com/angular/angular.js/commit/234053fc9ad90e0d05be7e8359c6af66be94c094),
The `$sanitize` service will now remove instances of the `usemap` attribute from any elements passed
to it.
This attribute is used to reference another element by `name` or `id`. Since the `name` and `id`
attributes are already blacklisted, a sanitized `usemap` attribute could only reference unsanitized
content, which is a security risk.
<a name="1.2.29"></a>
# 1.2.29 ultimate-deprecation (2015-09-29)
## Bug Fixes
- **$browser:** prevent infinite digests when clearing the hash of a url
([9845cee6](https://github.com/angular/angular.js/commit/9845cee63eda3ad5024622c792c5e745b59ec5cb),
[#9629](https://github.com/angular/angular.js/issues/9629), [#9635](https://github.com/angular/angular.js/issues/9635), [#10228](https://github.com/angular/angular.js/issues/10228), [#10308](https://github.com/angular/angular.js/issues/10308))
- **$compile:** workaround for IE11 MutationObserver
([fccce96d](https://github.com/angular/angular.js/commit/fccce96d444f442ba5ecfb67201505a445d0c209),
[#11781](https://github.com/angular/angular.js/issues/11781), [#12613](https://github.com/angular/angular.js/issues/12613))
- **$location:** strip off empty hash segments when comparing
([e81b2f72](https://github.com/angular/angular.js/commit/e81b2f726cacd08bcf91500183a7ea3f71961718),
[#9635](https://github.com/angular/angular.js/issues/9635), [#10748](https://github.com/angular/angular.js/issues/10748))
- **$parse:**
- do not convert to string computed properties multiple times
([afb65c11](https://github.com/angular/angular.js/commit/afb65c11e5e3425f8431ad5b82308ff6b8ecbc64))
- throw error when accessing a restricted property indirectly
([e6cbd4fa](https://github.com/angular/angular.js/commit/e6cbd4faa211b2c0c8879c255e3194fb0717dcec),
[#12833](https://github.com/angular/angular.js/issues/12833))
- **ngAnimate:** ensure that minified repaint code isn't removed
([b041b664](https://github.com/angular/angular.js/commit/b041b664752e34a42bbc65e02bf0009f0836c50c),
[#9936](https://github.com/angular/angular.js/issues/9936))
## Breaking Changes
<a name="1.2.28"></a>
# finnish-disembarkation (2014-12-15)
## Bug Fixes
- **$route:** fix redirection with optional/eager params
([1b9e408d](https://github.com/angular/angular.js/commit/1b9e408ddbe48a6d3db27f501515d6efad01f42d),
[#9742](https://github.com/angular/angular.js/issues/9742), [#10202](https://github.com/angular/angular.js/issues/10202))
- **linky:** encode double quotes when serializing email addresses
([929dd15b](https://github.com/angular/angular.js/commit/929dd15b9b65034350f18abe6c56a8d956f4b978),
[#8945](https://github.com/angular/angular.js/issues/8945), [#8964](https://github.com/angular/angular.js/issues/8964), [#5946](https://github.com/angular/angular.js/issues/5946), [#10090](https://github.com/angular/angular.js/issues/10090), [#9256](https://github.com/angular/angular.js/issues/9256))
<a name="1.2.27"></a>
# 1.2.27 prime-factorization (2014-11-20)
+9 -7
View File
@@ -209,7 +209,7 @@ module.exports = function(grunt) {
},
"promises-aplus-adapter": {
dest:'tmp/promises-aplus-adapter++.js',
src:['src/ng/q.js','lib/promises-aplus/promises-aplus-test-adapter.js']
src:['src/ng/q.js', 'lib/promises-aplus/promises-aplus-test-adapter.js']
}
},
@@ -226,7 +226,7 @@ module.exports = function(grunt) {
},
"ddescribe-iit": {
'ddescribe-iit': {
files: [
'src/**/*.js',
'test/**/*.js',
@@ -236,7 +236,7 @@ module.exports = function(grunt) {
]
},
"merge-conflict": {
'merge-conflict': {
files: [
'src/**/*',
'test/**/*',
@@ -293,8 +293,10 @@ module.exports = function(grunt) {
});
//alias tasks
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:protractor']);
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package', 'test:unit', 'test:promises-aplus', 'tests:docs', 'test:protractor']);
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']);
@@ -304,11 +306,11 @@ module.exports = function(grunt) {
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', ['connect:testserver', 'protractor:travis']);
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', ['webdriver', 'connect:testserver', 'protractor:jenkins']);
grunt.registerTask('test:e2e', 'Alias for test:protractor', ['test:protractor']);
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']);
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter', 'shell:promises-aplus-tests']);
grunt.registerTask('minify', ['bower','clean', 'build', 'minall']);
grunt.registerTask('minify', ['bower', 'clean', 'build', 'minall']);
grunt.registerTask('webserver', ['connect:devserver']);
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('package', ['bower', 'validate-angular-files', 'clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'jscs']);
grunt.registerTask('default', ['package']);
};
+1
View File
@@ -31,6 +31,7 @@ var angularFiles = {
'src/ng/q.js',
'src/ng/raf.js',
'src/ng/rootScope.js',
'src/ng/rootElement.js',
'src/ng/sanitizeUri.js',
'src/ng/sce.js',
'src/ng/sniffer.js',
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "AngularJS",
"devDependencies": {
"jquery": "1.10.2",
"closure-compiler": "https://closure-compiler.googlecode.com/files/compiler-20130603.zip",
"closure-compiler": "https://dl.google.com/closure-compiler/compiler-20130603.zip",
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip"
}
}
+1
View File
@@ -202,6 +202,7 @@ var generate = function(version, file) {
// publish for testing
exports.parseRawCommit = parseRawCommit;
exports.printSection = printSection;
// hacky start if not run by jasmine :-D
if (process.argv.join('').indexOf('jasmine-node') === -1) {
+62 -1
View File
@@ -1,4 +1,4 @@
/* global describe: false, it: false, expect: false */
/* global describe: false, beforeEach: false, afterEach: false, it: false, expect: false */
'use strict';
@@ -44,4 +44,65 @@ describe('changelog.js', function() {
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
});
});
describe('printSection', function() {
var output;
var streamMock = {
write: function(str) {
output += str;
}
};
beforeEach(function() {
output = '';
});
it('should add a new line at the end of each breaking change list item ' +
'when there is 1 item per component', function() {
var title = 'test';
var printCommitLinks = false;
var section = {
module1: [{subject: 'breaking change 1'}],
module2: [{subject: 'breaking change 2'}]
};
var expectedOutput =
'\n' + '## test\n\n' +
'- **module1:** breaking change 1\n' +
'- **module2:** breaking change 2\n' +
'\n';
ch.printSection(streamMock, title, section, printCommitLinks);
expect(output).toBe(expectedOutput);
});
it('should add a new line at the end of each breaking change list item ' +
'when there are multiple items per component', function() {
var title = 'test';
var printCommitLinks = false;
var section = {
module1: [
{subject: 'breaking change 1.1'},
{subject: 'breaking change 1.2'}
],
module2: [
{subject: 'breaking change 2.1'},
{subject: 'breaking change 2.2'}
]
};
var expectedOutput =
'\n' + '## test\n\n' +
'- **module1:**\n' +
' - breaking change 1.1\n' +
' - breaking change 1.2\n' +
'- **module2:**\n' +
' - breaking change 2.1\n' +
' - breaking change 2.2\n' +
'\n';
ch.printSection(streamMock, title, section, printCommitLinks);
expect(output).toBe(expectedOutput);
});
});
});
+4 -2
View File
@@ -1,7 +1,10 @@
"use strict";
angular.module('versions', [])
.controller('DocsVersionsCtrl', ['$scope', '$location', '$window', 'NG_VERSIONS', function($scope, $location, $window, NG_VERSIONS) {
$scope.docs_version = NG_VERSIONS[0];
$scope.docs_versions = NG_VERSIONS;
for(var i=0, minor = NaN; i < NG_VERSIONS.length; i++) {
var version = NG_VERSIONS[i];
@@ -13,9 +16,8 @@ angular.module('versions', [])
minor = version.minor;
}
$scope.docs_versions = NG_VERSIONS;
$scope.getGroupName = function(v) {
return v.isLatest ? 'Latest' : (v.isStable ? 'Stable' : 'Unstable');
return v.isLatest ? 'Latest' : ('v' + v.major + '.' + v.minor + '.x');
};
$scope.jumpToDocsVersion = function(version) {
+3 -3
View File
@@ -128,7 +128,7 @@ Use ngRoute to enable URL routing to your application. The ngRoute module suppor
## {@link ngAnimate ngAnimate}
Use ngAnimate to enable animation features into your application. Various core ng directives will provide
Use ngAnimate to enable animation features within your application. Various core ng directives will provide
animation hooks into your application when ngAnimate is included. Animations are defined by using CSS transitions/animations
or JavaScript callbacks.
@@ -148,7 +148,7 @@ or JavaScript callbacks.
{@link ngAnimate CSS-based animations}
</td>
<td>
Follow ngAnimates CSS naming structure to reference CSS transitions / keyframe animations in AngularJS. Once defined the animation can be triggered by referencing the CSS class within the HTML template code.
Follow ngAnimates CSS naming structure to reference CSS transitions / keyframe animations in AngularJS. Once defined, the animation can be triggered by referencing the CSS class within the HTML template code.
</td>
</tr>
<tr>
@@ -156,7 +156,7 @@ or JavaScript callbacks.
{@link ngAnimate JS-based animations}
</td>
<td>
Use {@link angular.Module#animation module.animation()} to register a JavaScript animation. Once registered the animation can be triggered by referencing the CSS class within the HTML template code.
Use {@link angular.Module#animation module.animation()} to register a JavaScript animation. Once registered, the animation can be triggered by referencing the CSS class within the HTML template code.
</td>
</tr>
</table>
+1 -1
View File
@@ -3,7 +3,7 @@
@fullName Response does not match configured parameter
@description
This error occurs when the {@link ngResource.$resource `$resource`} service expects a response that can be deserialized as an array, receives an object, or vice versa.
This error occurs when the {@link ngResource.$resource `$resource`} service expects a response that can be deserialized as an array but receives an object, or vice versa.
By default, all resource actions expect objects, except `query` which expects arrays.
To resolve this error, make sure your `$resource` configuration matches the actual format of the data returned from the server.
+1 -1
View File
@@ -35,7 +35,7 @@ var users = [ { name: 'Hank' }, { name: 'Francisco' } ];
$scope.getUsers = function() {
return users;
});
};
```
The maximum number of allowed iterations of the `$digest` cycle is controlled via TTL setting which can be configured via {@link ng.$rootScopeProvider $rootScopeProvider}.
+1 -1
View File
@@ -353,7 +353,7 @@ legacy browsers and hashbang links in modern browser:
Here you can see two `$location` instances, both in **Html5 mode**, but on different browsers, so
that you can see the differences. These `$location` services are connected to a fake browsers. Each
input represents address bar of the browser.
input represents the address bar of the browser.
Note that when you type hashbang url into first browser (or vice versa) it doesn't rewrite /
redirect to regular / hashbang url, as this conversion happens only during parsing the initial URL
+1 -1
View File
@@ -326,7 +326,7 @@ describe('state', function() {
expect(childScope.timeOfDay).toBe('morning');
expect(childScope.name).toBe('Mattie');
expect(grandChildScope.timeOfDay).toBe('evening');
expect(grandChildScope.name).toBe('Gingerbreak Baby');
expect(grandChildScope.name).toBe('Gingerbread Baby');
});
});
```
+5 -5
View File
@@ -6,7 +6,7 @@
# E2E Testing
<div class="alert alert-danger">
**Note:** In the past, end to end testing could be done with a deprecated tool called
**Note:** In the past, end-to-end testing could be done with a deprecated tool called
[Angular Scenario Runner](http://code.angularjs.org/1.2.16/docs/guide/e2e-testing). That tool
is now in maintenance mode.
</div>
@@ -14,7 +14,7 @@ is now in maintenance mode.
As applications grow in size and complexity, it becomes unrealistic to rely on manual testing to
verify the correctness of new features, catch bugs and notice regressions. End to end tests
are the first line of defense for catching bugs, but sometimes issues come up with integration
between components which can't be captured in a unit test. End to end tests are made to find
between components which can't be captured in a unit test. End-to-end tests are made to find
these problems.
We have built [Protractor](https://github.com/angular/protractor), an end
@@ -23,7 +23,7 @@ Angular application.
## Using Protractor
Protractor is a [Node.js](http://nodejs.org) program, and runs end to end tests that are also
Protractor is a [Node.js](http://nodejs.org) program, and runs end-to-end tests that are also
written in JavaScript and run with node. Protractor uses [WebDriver](https://code.google.com/p/selenium/wiki/GettingStarted)
to control browsers and simulate user actions.
@@ -76,8 +76,8 @@ filter the list of items.
## Example
See the [angular-seed](https://github.com/angular/angular-seed) project for more examples, or look
at the embedded examples in the Angular documentation (For example, [$http](http://docs.angularjs.org/api/ng/service/$http)
has an end to end test in the example under the `protractor.js` tag).
at the embedded examples in the Angular documentation (For example, {@link $http $http}
has an end-to-end test in the example under the `protractor.js` tag).
## Caveats
+15 -1
View File
@@ -26,8 +26,16 @@ Angular expressions are like JavaScript expressions with the following differenc
* **Forgiving:** In JavaScript, trying to evaluate undefined properties generates `ReferenceError`
or `TypeError`. In Angular, expression evaluation is forgiving to `undefined` and `null`.
* **No Control Flow Statements:** you cannot use the following in an Angular expression:
* **No Control Flow Statements:** You cannot use the following in an Angular expression:
conditionals, loops, or exceptions.
* **No Function Declarations:** You cannot decleare functions in an Angular expression.
Even inside `ng-init` directive
* **No RegExp Creation With Literal Notation:** You cannot create regular expressions
in an Angular expression.
* **No Comma And Void Operators:** You cannot use `,` or `void` in an Angular expression.
* **Filters:** You can use {@link guide/filter filters} within expressions to format data before
displaying it.
@@ -164,6 +172,12 @@ expression. The reason behind this is core to the Angular philosophy that applic
be in controllers, not the views. If you need a real conditional, loop, or to throw from a view
expression, delegate to a JavaScript method instead.
## No function declarations or RegExp creation with literal notation
You can't declare functions or create regular expressions from within AngularJS expressions. This is
to avoid complex model transformation logic inside templates. Such logic is better placed in a
controller or in a dedicated filter where it can be tested properly.
## `$event`
Directives like {@link ng.directive:ngClick `ngClick`} and {@link ng.directive:ngFocus `ngFocus`}
+3 -2
View File
@@ -107,6 +107,7 @@ This is a short list of libraries with specific support and documentation for wo
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
* [Responsive Web Design with AngularJS](http://www.amazon.com/Responsive-Design-AngularJS-Sandeep-Kumar/dp/178439842X) by Sandeep Kumar Patel
###Videos:
* [egghead.io](http://egghead.io/)
@@ -115,12 +116,12 @@ This is a short list of libraries with specific support and documentation for wo
### Courses
* **Free online:**
[thinkster.io](http://thinkster.io),
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1)
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1),
[CodeSchool](https://www.codeschool.com/courses/shaping-up-with-angular-js)
* **Paid online:**
[Pluralsite (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=angularjs),
[Tuts+](https://tutsplus.com/course/easier-js-apps-with-angular/),
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html)
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html),
[WintellectNOW (4 lessons)](http://www.wintellectnow.com/Course/Detail/mastering-angularjs)
* **Paid onsite:**
[angularbootcamp.com](http://angularbootcamp.com/)
+4 -4
View File
@@ -390,7 +390,7 @@ of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanit
module is not loaded) and the bound expression evaluates to a value that is not trusted an
exception is thrown.
When using this directive you can either include `ngSanitize` in your module's dependencis (See the
When using this directive you can either include `ngSanitize` in your module's dependencies (See the
example at the {@link ngBindHtml} reference) or use the {@link $sce} service to set the value as
trusted.
@@ -647,10 +647,10 @@ freely available to JavaScript code (as before).
Angular expressions execute in a limited context. They do not have
direct access to the global scope, `window`, `document` or the Function
constructor. However, they have direct access to names/properties on
the scope chain. It has been a long standing best practice to keep
constructor. However, they have direct access to names/properties on
the scope chain. It has been a long standing best practice to keep
sensitive APIs outside of the scope chain (in a closure or your
controller.) That's easier said that done for two reasons:
controller.) That's easier said than done for two reasons:
1. JavaScript does not have a notion of private properties so if you need
someone on the scope chain for JavaScript use, you also expose it to
+1 -1
View File
@@ -177,7 +177,7 @@ for example, only a portion of the view needs to be controlled by Angular.
To examine the scope in the debugger:
1. right click on the element of interest in your browser and select 'inspect element'. You
1. Right click on the element of interest in your browser and select 'inspect element'. You
should see the browser debugger with the element you clicked on highlighted.
2. The debugger allows you to access the currently selected element in the console as `$0`
+3 -3
View File
@@ -16,8 +16,8 @@ about the phones in the catalog.
## Data
Note that the `phones.json` file contains unique ids and image urls for each of the phones. The
urls point to the `app/img/phones/` directory.
Note that the `phones.json` file contains unique IDs and image URLs for each of the phones. The
URLs point to the `app/img/phones/` directory.
__`app/phones/phones.json`__ (sample snippet):
@@ -59,7 +59,7 @@ the element attribute.
We also added phone images next to each record using an image tag with the {@link
ng.directive:ngSrc ngSrc} directive. That directive prevents the
browser from treating the Angular `{{ expression }}` markup literally, and initiating a request to
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
invalid URL `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
specified an attribute binding in a regular `src` attribute (`<img src="{{phone.imageUrl}}">`).
Using the `ngSrc` directive prevents the browser from making an http request to an invalid location.
+2 -2
View File
@@ -45,8 +45,8 @@ module.exports = function(config, specificOptions) {
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.9',
version: '7'
platform: 'OS X 10.10',
version: '8'
},
'SL_IE_8': {
base: 'SauceLabs',
-1
View File
@@ -1 +0,0 @@
node ./lib/browser-stack/start-tunnel.js &
@@ -5,9 +5,10 @@ var http = require('http');
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
var HOSTNAME = 'localhost';
var PORTS = require('../grunt/utils').availablePorts;
var PORTS = [9876, 8000];
var ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY;
var READY_FILE = process.env.SAUCE_CONNECT_READY_FILE;
var READY_FILE = process.env.BROWSER_PROVIDER_READY_FILE;
var TUNNEL_IDENTIFIER = process.env.TRAVIS_JOB_NUMBER;
// We need to start fake servers, otherwise the tunnel does not start.
var fakeServers = [];
@@ -24,6 +25,7 @@ PORTS.forEach(function(port) {
var tunnel = new BrowserStackTunnel({
key: ACCESS_KEY,
tunnelIdentifier: TUNNEL_IDENTIFIER,
hosts: hosts
});
+3
View File
@@ -0,0 +1,3 @@
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
node ./lib/browserstack/start_tunnel.js &
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
set -e -o pipefail
echo "Shutting down Browserstack tunnel"
echo "TODO: implement me"
exit 1
+58
View File
@@ -0,0 +1,58 @@
'use strict';
var path = require('path');
var fs = require('fs');
var glob = require("glob");
var _ = require('lodash');
var files = require('../../angularFiles').files;
module.exports = function(grunt) {
grunt.registerTask('validate-angular-files', function() {
var combinedFiles = _.clone(files.angularModules);
combinedFiles.ng = files.angularSrc;
combinedFiles.angularLoader = files.angularLoader;
var errorsDetected = false;
var directories = [];
var detectedFiles = {};
for (var section in combinedFiles) {
var sectionFiles = combinedFiles[section];
if (section != 'angularLoader') {
directories.push('src/' + section);
}
grunt.log.debug('Validating ' + sectionFiles.length + ' files from the "' + section + '" module.');
sectionFiles.forEach(function(file) {
detectedFiles[file] = true;
if (!fs.existsSync(file)) {
grunt.log.error(file + ' does not exist in the local file structure.');
errorsDetected = true;
}
});
}
directories.forEach(function(directory) {
glob.sync(directory + '/**/*').forEach(function(filePath) {
if (!fs.lstatSync(filePath).isDirectory()) {
var fileName = path.basename(filePath);
var isHiddenFile = fileName[0] == '.';
if (!isHiddenFile && !detectedFiles[filePath]) {
grunt.log.error(filePath + ' exists in the local file structure but isn\'t used by any module.');
errorsDetected = true;
}
}
});
});
if (errorsDetected) {
throw new Error('Not all files were properly detected in the local file structure.');
} else {
grunt.log.ok('All files were detected successfully!');
}
});
};
@@ -12,9 +12,9 @@ set -e
# before_script:
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3-linux.tar.gz"
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.7-linux.tar.gz"
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
CONNECT_DOWNLOAD="sc-4.3-linux.tar.gz"
CONNECT_DOWNLOAD="sc-4.3.7-linux.tar.gz"
CONNECT_LOG="$LOGS_DIR/sauce-connect"
CONNECT_STDOUT="$LOGS_DIR/sauce-connect.stdout"
@@ -46,5 +46,5 @@ echo "Starting Sauce Connect in the background, logging into:"
echo " $CONNECT_LOG"
echo " $CONNECT_STDOUT"
echo " $CONNECT_STDERR"
sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS -v \
sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS \
--logfile $CONNECT_LOG 2> $CONNECT_STDERR 1> $CONNECT_STDOUT &
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
set -e -o pipefail
echo "Shutting down Sauce Connect tunnel"
killall sc
while [[ -n `ps -ef | grep "sauce-connect-" | grep -v "grep"` ]]; do
printf "."
sleep .5
done
echo ""
echo "Sauce Connect tunnel has been shut down"
-11
View File
@@ -91,15 +91,6 @@ var getTaggedVersion = function() {
return null;
};
/**
* Stable versions have an even minor version and have no prerelease
* @param {SemVer} version The version to test
* @return {Boolean} True if the version is stable
*/
var isStable = function(version) {
return semver.satisfies(version, '1.0 || 1.2') && version.prerelease.length === 0;
};
/**
* Get a collection of all the previous versions sorted by semantic version
* @return {Array.<SemVer>} The collection of previous versions
@@ -119,8 +110,6 @@ var getPreviousVersions = function() {
})
.filter()
.map(function(version) {
version.isStable = isStable(version);
version.docsUrl = 'http://code.angularjs.org/' + version.version + '/docs';
// Versions before 1.0.2 had a different docs folder name
if ( version.major < 1 || (version.major === 1 && version.minor === 0 && version.dot < 2 ) ) {
File diff suppressed because it is too large Load Diff
+5075 -984
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -1,6 +1,7 @@
{
"name": "angularjs",
"branchVersion": "1.2.*",
"distTag": "ie8_compat",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
@@ -11,9 +12,11 @@
"bower": "~1.3.9",
"browserstacktunnel-wrapper": "~1.1.1",
"canonical-path": "0.0.2",
"cheerio": "^0.17.0",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.10.0",
"event-stream": "~3.1.0",
"glob": "^6.0.1",
"grunt": "~0.4.2",
"grunt-bump": "~0.0.13",
"grunt-contrib-clean": "~0.5.0",
@@ -52,7 +55,7 @@
"marked": "~0.3.0",
"node-html-encoder": "0.0.2",
"promises-aplus-tests": "~1.3.2",
"protractor": "1.4.0",
"protractor": "^1.6.0",
"q": "~1.0.0",
"q-io": "^1.10.9",
"qq": "^0.3.5",
+2 -2
View File
@@ -20,8 +20,8 @@ config.multiCapabilities = [{
'version': '28'
}, {
browserName: 'safari',
'platform': 'OS X 10.9',
'version': '7',
'platform': 'OS X 10.10',
'version': '8',
'name': 'Angular E2E',
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
'build': process.env.TRAVIS_BUILD_NUMBER
+21 -13
View File
@@ -27,6 +27,8 @@ function init {
angular-scenario
angular-touch
)
# get the npm dist-tag from a custom property (distTag) in package.json
DIST_TAG=$(readJsonProp "package.json" "distTag")
}
@@ -61,6 +63,21 @@ function prepare {
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
#
# Run local precommit script if there is one
#
for repo in "${REPOS[@]}"
do
if [ -f $TMP_DIR/bower-$repo/precommit.sh ]
then
echo "-- Running precommit.sh script for bower-$repo"
cd $TMP_DIR/bower-$repo
$TMP_DIR/bower-$repo/precommit.sh
cd $SCRIPT_DIR
fi
done
#
# update bower.json
# tag each repo
@@ -71,6 +88,8 @@ function prepare {
cd $TMP_DIR/bower-$repo
replaceJsonProp "bower.json" "version" ".*" "$NEW_VERSION"
replaceJsonProp "bower.json" "angular.*" ".*" "$NEW_VERSION"
replaceJsonProp "package.json" "version" ".*" "$NEW_VERSION"
replaceJsonProp "package.json" "angular.*" ".*" "$NEW_VERSION"
git add -A
@@ -91,19 +110,8 @@ function publish {
# don't publish every build to npm
if [ "${NEW_VERSION/+sha}" = "$NEW_VERSION" ] ; then
if [ "${NEW_VERSION/-}" = "$NEW_VERSION" ] ; then
if [[ $NEW_VERSION =~ ^1\.2\.[0-9]+$ ]] ; then
# publish 1.2.x releases with the appropriate tag
# this ensures that `npm install` by default will not grab `1.2.x` releases
npm publish --tag=1.2.x
else
# publish releases as "latest"
npm publish
fi
else
# publish prerelease builds with the beta tag
npm publish --tag=beta
fi
echo "-- Publishing to npm as $DIST_TAG"
npm publish --tag=$DIST_TAG
fi
cd $SCRIPT_DIR
@@ -7,7 +7,9 @@ echo "#################################"
# Enable tracing and exit on first failure
set -xe
# Define reasonable set of browsers in case we are running manually from commandline
scripts/jenkins/set-node-version.sh
# This is the default set of browsers to use on the CI server unless overridden via env variable
if [[ -z "$BROWSERS" ]]
then
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh"
@@ -19,6 +21,7 @@ rm -f angular.js.size
# BUILD #
npm install -g grunt-cli
npm install --color false
grunt ci-checks package --no-color
+2 -11
View File
@@ -4,9 +4,7 @@ echo "#################################"
echo "#### Update master ##############"
echo "#################################"
ARG_DEFS=(
"[--no-test=(true|false)]"
)
ARG_DEFS=()
function init {
if [[ ! $VERBOSE ]]; then
@@ -17,14 +15,7 @@ function init {
function build {
cd ../..
if [[ $NO_TEST == "true" ]]; then
npm install --color false
grunt ci-checks package --no-color
else
./jenkins_build.sh
fi
scripts/jenkins/build.sh
cd $SCRIPT_DIR
}
+2
View File
@@ -35,8 +35,10 @@ function init {
}
function build {
./set-node-version.sh
cd ../..
npm install -g grunt-cli
npm install --color false
grunt ci-checks package --no-color
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
# Install nvm for this shell
source ~/.nvm/nvm.sh
# Use node.js at 4.2.x
nvm install 4.2
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env node
/**
* this script is just a temporary solution to deal with the issue of npm outputting the npm
* shrinkwrap file in an unstable manner.
*
* See: https://github.com/npm/npm/issues/3581
*/
var _ = require('lodash');
var sorted = require('sorted-object');
var fs = require('fs');
var path = require('path');
function cleanModule(module, name) {
// keep `resolve` properties for git dependencies, delete otherwise
delete module.from;
if (!(module.resolved && module.resolved.match(/^git(\+[a-z]+)?:\/\//))) {
delete module.resolved;
}
_.forEach(module.dependencies, function(mod, name) {
cleanModule(mod, name);
});
}
console.log('Reading npm-shrinkwrap.json');
var shrinkwrap = require('../../npm-shrinkwrap.json');
console.log('Cleaning shrinkwrap object');
cleanModule(shrinkwrap, shrinkwrap.name);
var cleanShrinkwrapPath = path.join(__dirname, '..', '..', 'npm-shrinkwrap.clean.json');
console.log('Writing cleaned to', cleanShrinkwrapPath);
fs.writeFileSync(cleanShrinkwrapPath, JSON.stringify(sorted(shrinkwrap), null, 2) + "\n");
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
set -e
SHRINKWRAP_FILE=npm-shrinkwrap.json
SHRINKWRAP_CACHED_FILE=node_modules/npm-shrinkwrap.cached.json
if diff -q $SHRINKWRAP_FILE $SHRINKWRAP_CACHED_FILE; then
echo 'No shrinkwrap changes detected. npm install will be skipped...';
else
echo 'Blowing away node_modules and reinstalling npm dependencies...'
rm -rf node_modules
npm install
cp $SHRINKWRAP_FILE $SHRINKWRAP_CACHED_FILE
echo 'npm install successful!'
fi
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
set -e
mkdir -p $LOGS_DIR
if [ $JOB != "ci-checks" ]; then
echo "start_browser_provider"
./scripts/travis/start_browser_provider.sh
fi
npm install -g grunt-cli
if [ $JOB != "ci-checks" ]; then
grunt package
echo "wait_for_browser_provider"
./scripts/travis/wait_for_browser_provider.sh
fi
+17 -4
View File
@@ -2,20 +2,33 @@
set -e
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
if [ $JOB = "unit" ]; then
if [ $JOB = "ci-checks" ]; then
grunt ci-checks
elif [ $JOB = "unit" ]; then
if [ "$BROWSER_PROVIDER" == "browserstack" ]; then
BROWSERS="BS_Chrome,BS_Firefox,BS_Safari,BS_IE_8,BS_IE_9,BS_IE_10,BS_IE_11"
else
BROWSERS="SL_Chrome,SL_Firefox,SL_Safari,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11"
fi
grunt test:promises-aplus
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
grunt tests:docs --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
grunt test:unit --browsers $BROWSERS --reporters dots
grunt tests:docs --browsers $BROWSERS --reporters dots
elif [ $JOB = "docs-e2e" ]; then
grunt test:travis-protractor --specs "docs/app/e2e/**/*.scenario.js"
elif [ $JOB = "e2e" ]; then
if [ $TEST_TARGET = "jquery" ]; then
export USE_JQUERY=1
fi
export TARGET_SPECS="build/docs/ptore2e/**/default_test.js"
if [ $TEST_TARGET = "jquery" ]; then
TARGET_SPECS="build/docs/ptore2e/**/jquery_test.js"
fi
grunt test:travis-protractor --specs "$TARGET_SPECS"
else
echo "Unknown job type. Please set JOB=unit or JOB=e2e-*."
echo "Unknown job type. Please set JOB=ci-checks, JOB=unit or JOB=e2e-*."
fi
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# Has to be run from project root directory.
if [ "$BROWSER_PROVIDER" == "browserstack" ]; then
echo "Using BrowserStack"
elif [ "$BROWSER_PROVIDER" == "saucelabs" ]; then
echo "Using SauceLabs"
else
echo "Invalid BROWSER_PROVIDER. Please set env var BROWSER_PROVIDER to 'saucelabs' or 'browserstack'."
exit 1
fi
./lib/${BROWSER_PROVIDER}/start_tunnel.sh
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
# Has to be run from project root directory.
./lib/${BROWSER_PROVIDER}/teardown_tunnel.sh
@@ -2,6 +2,18 @@
# Wait for Connect to be ready before exiting
# Time out if we wait for more than 2 minutes, so that we can print logs.
let "counter=0"
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
let "counter++"
if [ $counter -gt 240 ]; then
echo "Timed out after 2 minutes waiting for browser provider ready file"
# We must manually print logs here because travis will not run
# after_script commands if the failure occurs before the script
# phase.
./scripts/travis/print_logs.sh
exit 5
fi
sleep .5
done
+4 -2
View File
@@ -155,8 +155,8 @@ if ('i' !== 'I'.toLowerCase()) {
}
var /** holds major version number for IE or NaN for real browsers */
msie,
var
msie, // holds major version number for IE, or NaN if UA is not IE.
jqLite, // delay binding since jQuery could be loaded after us.
jQuery, // delay binding
slice = [].slice,
@@ -403,6 +403,8 @@ noop.$inject = [];
return (transformationFn || angular.identity)(value);
};
```
* @param {*} value to be returned.
* @returns {*} the value passed in.
*/
function identity($) {return $;}
identity.$inject = [];
+8 -1
View File
@@ -62,6 +62,11 @@ function Browser(window, document, $log, $sniffer) {
}
}
function getHash(url) {
var index = url.indexOf('#');
return index === -1 ? '' : url.substr(index + 1);
}
/**
* @private
* Note: this method is used only by scenario runner
@@ -173,8 +178,10 @@ function Browser(window, document, $log, $sniffer) {
}
if (replace) {
location.replace(url);
} else {
} else if (!sameBase) {
location.href = url;
} else {
location.hash = getHash(url);
}
}
return self;
+38 -10
View File
@@ -653,6 +653,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
};
Attributes.prototype = {
/**
* @ngdoc method
* @name $compile.directive.Attributes#$normalize
* @kind function
*
* @description
* Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
* `data-`) to its normalized, camelCase form.
*
* Also there is special case for Moz prefix starting with upper case letter.
*
* For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
*
* @param {string} name Name to normalize
*/
$normalize: directiveNormalize,
@@ -750,10 +765,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
nodeName = nodeName_(this.$$element);
// SVG elements' `nodeName` can be lowercase
nodeName = nodeName_(this.$$element).toUpperCase();
// sanitize a[href] and img[src] values
if ((nodeName === 'A' && key === 'href') ||
if ((nodeName === 'A' && (key === 'href' || key === 'xlinkHref')) ||
(nodeName === 'IMG' && key === 'src')) {
this[key] = value = $$sanitizeUri(value, key === 'src');
}
@@ -1014,13 +1030,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var nodeType = node.nodeType,
attrsMap = attrs.$attr,
match,
nodeName,
className;
switch(nodeType) {
case 1: /* Element */
nodeName = nodeName_(node).toLowerCase();
// use the node name: <directive>
addDirective(directives,
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
directiveNormalize(nodeName), 'E', maxPriority, ignoreDirective);
// iterate over the attributes
for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
@@ -1060,6 +1080,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
if (nodeName === 'input' && node.getAttribute('type') === 'hidden') {
// Hidden input elements can have strange behaviour when navigating back to the page
// This tells the browser not to try to cache and reinstate previous values
node.setAttribute('autocomplete', 'off');
}
// use class as directive
className = node.className;
if (isString(className) && className !== '') {
@@ -1073,6 +1099,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
break;
case 3: /* Text Node */
if (msie === 11) {
// Workaround for #11781
while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === 3 /* Text Node */) {
node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
node.parentNode.removeChild(node.nextSibling);
}
}
addTextInterpolateDirective(directives, node.nodeValue);
break;
case 8: /* Comment */
@@ -1858,6 +1891,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// maction[xlink:href] can source SVG. It's not limited to <maction>.
if (attrNormalizedName == "xlinkHref" ||
(tag == "FORM" && attrNormalizedName == "action") ||
// links can be stylesheets or imports, which can run script in the current origin
(tag == "LINK" && attrNormalizedName == "href") ||
(tag != "IMG" && (attrNormalizedName == "src" ||
attrNormalizedName == "ngSrc"))) {
return $sce.RESOURCE_URL;
@@ -1986,13 +2021,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
/**
* Converts all accepted directives format into proper directive name.
* All of these will become 'myDirective':
* my:Directive
* my-directive
* x-my-directive
* data-my:directive
*
* Also there is special case for Moz prefix starting with upper case letter.
* @param name Name to normalize
*/
function directiveNormalize(name) {
+2 -3
View File
@@ -11,9 +11,8 @@
* make the link go to the wrong URL if the user clicks it before
* Angular has a chance to replace the `{{hash}}` markup with its
* value. Until Angular replaces the markup the link will be broken
* and will most likely return a 404 error.
*
* The `ngHref` directive solves this problem.
* and will most likely return a 404 error. The `ngHref` directive
* solves this problem.
*
* The wrong way to write it:
* ```html
+1 -1
View File
@@ -49,7 +49,7 @@
<select ng-model="template" ng-options="t.name for t in templates">
<option value="">(blank)</option>
</select>
url of the template: <tt>{{template.url}}</tt>
url of the template: <code>{{template.url}}</code>
<hr/>
<div class="slide-animate-container">
<div class="slide-animate" ng-include="template.url"></div>
-1
View File
@@ -40,7 +40,6 @@ var scriptDirective = ['$templateCache', function($templateCache) {
compile: function(element, attr) {
if (attr.type == 'text/ng-template') {
var templateUrl = attr.id,
// IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
text = element[0].text;
$templateCache.put(templateUrl, text);
+4 -29
View File
@@ -81,36 +81,11 @@ function limitToFilter(){
limit = int(limit);
}
if (isString(input)) {
//NaN check on limit
if (limit) {
return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
} else {
return "";
}
}
var out = [],
i, n;
// if abs(limit) exceeds maximum length, trim it
if (limit > input.length)
limit = input.length;
else if (limit < -input.length)
limit = -input.length;
if (limit > 0) {
i = 0;
n = limit;
//NaN check on limit
if (limit) {
return limit > 0 ? input.slice(0, limit) : input.slice(limit);
} else {
i = input.length + limit;
n = input.length;
return isString(input) ? "" : [];
}
for (; i<n; i++) {
out.push(input[i]);
}
return out;
};
}
+15
View File
@@ -317,6 +317,21 @@ function $HttpProvider() {
* 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.
*
* To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
* Use the `headers` property, setting the desired header to `undefined`. For example:
*
* ```js
* var req = {
* method: 'POST',
* url: 'http://example.com',
* headers: {
* 'Content-Type': undefined
* },
* data: { test: 'test' },
* }
*
* $http(req).success(function(){...}).error(function(){...});
* ```
*
* # Transforming Requests and Responses
*
+24 -24
View File
@@ -57,33 +57,33 @@ function $IntervalProvider() {
* // Don't start a new fight if we are already fighting
* if ( angular.isDefined(stop) ) return;
*
* stop = $interval(function() {
* if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
* $scope.blood_1 = $scope.blood_1 - 3;
* $scope.blood_2 = $scope.blood_2 - 4;
* } else {
* $scope.stopFight();
* stop = $interval(function() {
* if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
* $scope.blood_1 = $scope.blood_1 - 3;
* $scope.blood_2 = $scope.blood_2 - 4;
* } else {
* $scope.stopFight();
* }
* }, 100);
* };
*
* $scope.stopFight = function() {
* if (angular.isDefined(stop)) {
* $interval.cancel(stop);
* stop = undefined;
* }
* }, 100);
* };
* };
*
* $scope.stopFight = function() {
* if (angular.isDefined(stop)) {
* $interval.cancel(stop);
* stop = undefined;
* }
* };
* $scope.resetFight = function() {
* $scope.blood_1 = 100;
* $scope.blood_2 = 120;
* };
*
* $scope.resetFight = function() {
* $scope.blood_1 = 100;
* $scope.blood_2 = 120;
* };
*
* $scope.$on('$destroy', function() {
* // Make sure that the interval is destroyed too
* $scope.stopFight();
* });
* }])
* $scope.$on('$destroy', function() {
* // Make sure that the interval is destroyed too
* $scope.stopFight();
* });
* }])
* // Register the 'myCurrentTime' directive factory method.
* // We inject $interval and dateFilter service since the factory method is DI.
* .directive('myCurrentTime', ['$interval', 'dateFilter',
+7 -2
View File
@@ -68,6 +68,10 @@ function stripHash(url) {
return index == -1 ? url : url.substr(0, index);
}
function trimEmptyHash(url) {
return url.replace(/(#.+)|#$/, '$1');
}
function stripFile(url) {
return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
@@ -724,10 +728,11 @@ function $LocationProvider(){
// update browser
var changeCounter = 0;
$rootScope.$watch(function $locationWatch() {
var oldUrl = $browser.url();
var oldUrl = trimEmptyHash($browser.url());
var newUrl = trimEmptyHash($location.absUrl());
var currentReplace = $location.$$replace;
if (!changeCounter || oldUrl != $location.absUrl()) {
if (!changeCounter || oldUrl != newUrl) {
changeCounter++;
$rootScope.$evalAsync(function() {
if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
+23 -4
View File
@@ -34,7 +34,26 @@ function ensureSafeMemberName(name, fullExpression) {
|| name === "__proto__") {
throw $parseMinErr('isecfld',
'Attempting to access a disallowed field in Angular expressions! '
+'Expression: {0}', fullExpression);
+ 'Expression: {0}', fullExpression);
}
return name;
}
function getStringValue(name, fullExpression) {
// From the JavaScript docs:
// Property names must be strings. This means that non-string objects cannot be used
// as keys in an object. Any non-string object, including a number, is typecasted
// into a string via the toString method.
//
// So, to ensure that we are checking the same `name` that JavaScript would use,
// we cast it to a string, if possible.
// Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
// this is, this will handle objects that misbehave.
name = name + '';
if (!isString(name)) {
throw $parseMinErr('iseccst',
'Cannot convert object to primitive value! '
+ 'Expression: {0}', fullExpression);
}
return name;
}
@@ -713,7 +732,7 @@ Parser.prototype = {
return extend(function(self, locals) {
var o = obj(self, locals),
i = indexFn(self, locals),
i = getStringValue(indexFn(self, locals), parser.text),
v, p;
ensureSafeMemberName(i, parser.text);
@@ -730,7 +749,7 @@ Parser.prototype = {
return v;
}, {
assign: function(self, value, locals) {
var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
var key = ensureSafeMemberName(getStringValue(indexFn(self, locals), parser.text), parser.text);
// prevent overwriting of Function.constructor which would break ensureSafeObject check
var o = ensureSafeObject(obj(self, locals), parser.text);
if (!o) obj.assign(self, o = {});
@@ -762,7 +781,7 @@ Parser.prototype = {
ensureSafeObject(context, parser.text);
ensureSafeFunction(fnPtr, parser.text);
// IE stupidity! (IE doesn't have apply for some native functions)
// IE doesn't have apply for some native functions
var v = fnPtr.apply
? fnPtr.apply(context, args)
: fnPtr(args[0], args[1], args[2], args[3], args[4]);
+7 -5
View File
@@ -290,9 +290,11 @@ angular.module('ngAnimate', ['ng'])
//so that all the animated elements within the animation frame
//will be properly updated and drawn on screen. This is
//required to perform multi-class CSS based animations with
//Firefox. DO NOT REMOVE THIS LINE.
var a = bod.offsetWidth + 1;
fn();
//Firefox. DO NOT REMOVE THIS LINE. DO NOT OPTIMIZE THIS LINE.
//THE MINIFIER WILL REMOVE IT OTHERWISE WHICH WILL RESULT IN AN
//UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND WILL
//TAKE YEARS AWAY FROM YOUR LIFE!
fn(bod.offsetWidth);
});
};
}])
@@ -1484,7 +1486,7 @@ angular.module('ngAnimate', ['ng'])
function onAnimationProgress(event) {
event.stopPropagation();
var ev = event.originalEvent || event;
var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
var timeStamp = ev.$manualTimeStamp || Date.now();
/* Firefox (or possibly just Gecko) likes to not round values up
* when a ms measurement is used for the animation */
@@ -1492,7 +1494,7 @@ angular.module('ngAnimate', ['ng'])
/* $manualTimeStamp is a mocked timeStamp value which is set
* within browserTrigger(). This is only here so that tests can
* mock animations properly. Real events fallback to event.timeStamp,
* mock animations properly. Real events fallback to Date.now(),
* or, if they don't, then a timeStamp is automatically created for them.
* We're checking to see if the timeStamp surpasses the expected delay,
* but we're using elapsedTime instead of the timeStamp on the 2nd
+8 -8
View File
@@ -1838,7 +1838,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
* object and returns true if the headers match the current definition.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
* controls how a matched request is handled.
*
* - respond
* `{function([status,] data[, headers, statusText])
@@ -1861,7 +1861,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @param {string|RegExp} url HTTP url.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
* controls how a matched request is handled.
*/
/**
@@ -1874,7 +1874,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @param {string|RegExp} url HTTP url.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
* controls how a matched request is handled.
*/
/**
@@ -1887,7 +1887,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @param {string|RegExp} url HTTP url.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
* controls how a matched request is handled.
*/
/**
@@ -1901,7 +1901,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
* controls how a matched request is handled.
*/
/**
@@ -1915,7 +1915,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
* controls how a matched request is handled.
*/
/**
@@ -1929,7 +1929,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
* controls how a matched request is handled.
*/
/**
@@ -1941,7 +1941,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
*
* @param {string|RegExp} url HTTP url.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
* controls how a matched request is handled.
*/
angular.mock.e2e = {};
angular.mock.e2e.$httpBackendDecorator =
+1 -1
View File
@@ -577,7 +577,7 @@ function $RouteProvider(){
if (i === 0) {
result.push(segment);
} else {
var segmentMatch = segment.match(/(\w+)(.*)/);
var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/);
var key = segmentMatch[1];
result.push(params[key]);
result.push(segmentMatch[2] || '');
+3 -3
View File
@@ -141,9 +141,9 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
html.push(target);
html.push('" ');
}
html.push('href="');
html.push(url);
html.push('">');
html.push('href="',
url.replace('"', '&quot;'),
'">');
addText(text);
html.push('</a>');
}
+1 -1
View File
@@ -204,7 +204,7 @@ var validElements = angular.extend({},
optionalEndTagElements);
//Attributes that have href and hence need to be sanitized
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
var uriAttrs = makeMap("background,cite,href,longdesc,src");
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,'+
+1 -1
View File
@@ -786,7 +786,7 @@ describe('angular', function() {
it('should bootstrap using class name', function() {
var appElement = jqLite('<div class="ng-app: ABC;"></div>')[0];
angularInit(jqLite('<div></div>').append(appElement)[0], bootstrapSpy);
angularInit(appElement, bootstrapSpy);
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
});
+16 -9
View File
@@ -9,22 +9,29 @@ describe('private mocks', function() {
var doc = $document[0];
var count = doc.styleSheets.length;
var stylesheet = createMockStyleSheet($document, $window);
expect(doc.styleSheets.length).toBe(count + 1);
var elm;
runs(function() {
expect(doc.styleSheets.length).toBe(count + 1);
angular.element(doc.body).append($rootElement);
angular.element(doc.body).append($rootElement);
var elm = $compile('<div class="padded">...</div>')($rootScope);
$rootElement.append(elm);
elm = $compile('<div class="padded">...</div>')($rootScope);
$rootElement.append(elm);
expect(getStyle(elm, 'paddingTop')).toBe('0px');
expect(getStyle(elm, 'paddingTop')).toBe('0px');
stylesheet.addRule('.padded', 'padding-top:2px');
stylesheet.addRule('.padded', 'padding-top:2px');
});
expect(getStyle(elm, 'paddingTop')).toBe('2px');
waitsFor(function() {
return getStyle(elm, 'paddingTop') === '2px';
});
stylesheet.destroy();
runs(function() {
stylesheet.destroy();
expect(getStyle(elm, 'paddingTop')).toBe('0px');
expect(getStyle(elm, 'paddingTop')).toBe('0px');
});
function getStyle(element, key) {
var node = element[0];
+54 -6
View File
@@ -1,8 +1,18 @@
'use strict';
function MockWindow() {
/* global getHash:true, stripHash:true */
var historyEntriesLength;
var sniffer = {};
function MockWindow(options) {
if (typeof options !== 'object') {
options = {};
}
var events = {};
var timeouts = this.timeouts = [];
var locationHref = 'http://server/';
var mockWindow = this;
this.setTimeout = function(fn) {
return timeouts.push(fn) - 1;
@@ -35,10 +45,37 @@ function MockWindow() {
});
};
this.location = {
href: 'http://server/',
replace: noop
//IE8 hack. defineProperty doesn't work with POJS, just with certain DOM elements
this.location = document.createElement('div');
this.location.href = {};
this.location.hash = {};
this.location.replace = function(url) {
locationHref = url;
mockWindow.history.state = null;
};
Object.defineProperty(this.location, 'href', {
enumerable: false,
configurable: true,
set: function(value) {
locationHref = value;
mockWindow.history.state = null;
historyEntriesLength++;
},
get: function() {
return locationHref;
}
});
Object.defineProperty(this.location, 'hash', {
enumerable: false,
configurable: true,
set: function(value) {
locationHref = stripHash(locationHref) + '#' + value;
},
get: function() {
return getHash(locationHref);
}
});
this.history = {
replaceState: noop,
@@ -89,7 +126,6 @@ describe('browser', function() {
warn: function() { logs.warn.push(slice.call(arguments)); },
info: function() { logs.info.push(slice.call(arguments)); },
error: function() { logs.error.push(slice.call(arguments)); }};
browser = new Browser(fakeWindow, fakeDocument, fakeLog, sniffer);
});
@@ -451,6 +487,17 @@ describe('browser', function() {
expect(locationReplace).not.toHaveBeenCalled();
});
it("should retain the # character when the only change is clearing the hash fragment, to prevent page reload", function() {
sniffer.history = true;
browser.url('http://server/#123');
expect(fakeWindow.location.href).toEqual('http://server/#123');
browser.url('http://server/');
expect(fakeWindow.location.href).toEqual('http://server/#');
});
it('should use location.replace when history.replaceState not available', function() {
sniffer.history = false;
browser.url('http://new.org', true);
@@ -462,6 +509,7 @@ describe('browser', function() {
expect(fakeWindow.location.href).toEqual('http://server/');
});
it('should use location.replace and not use replaceState when the url only changed in the hash fragment to please IE10/11', function() {
sniffer.history = true;
browser.url('http://server/#123', true);
@@ -473,6 +521,7 @@ describe('browser', function() {
expect(fakeWindow.location.href).toEqual('http://server/');
});
it('should return $browser to allow chaining', function() {
expect(browser.url('http://any.com')).toBe(browser);
});
@@ -835,7 +884,6 @@ describe('browser', function() {
expect(browser.url()).toBe(newUrl);
$rootScope.$digest();
expect(browser.url()).toBe(newUrl);
expect(fakeWindow.location.href).toBe(current);
});
});
+81
View File
@@ -2214,6 +2214,23 @@ describe('$compile', function() {
'</select>');
}));
it('should handle consecutive text elements as a single text element', inject(function($rootScope, $compile) {
// No point it running the test, if there is no MutationObserver
if (!window.MutationObserver) return;
// Create and register the MutationObserver
var observer = new window.MutationObserver(noop);
observer.observe(document.body, {childList: true, subtree: true});
// Run the actual test
var base = jqLite('<div>&mdash; {{ "This doesn\'t." }}</div>');
element = $compile(base)($rootScope);
$rootScope.$digest();
expect(element.text()).toBe("— This doesn't.");
// Unregister the MutationObserver (and hope it doesn't mess up with subsequent tests)
observer.disconnect();
}));
it('should support custom start/end interpolation symbols in template and directive template',
function() {
@@ -4770,6 +4787,39 @@ describe('$compile', function() {
});
});
it('should use $$sanitizeUri when declared via ng-href', function() {
var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri');
module(function($provide) {
$provide.value('$$sanitizeUri', $$sanitizeUri);
});
inject(function($compile, $rootScope) {
element = $compile('<a ng-href="{{testUrl}}"></a>')($rootScope);
$rootScope.testUrl = "someUrl";
$$sanitizeUri.andReturn('someSanitizedUrl');
$rootScope.$apply();
expect(element.attr('href')).toBe('someSanitizedUrl');
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false);
});
});
it('should use $$sanitizeUri when working with svg and xlink:href', function() {
if (!window.SVGElement) return;
var $$sanitizeUri = jasmine.createSpy('$$sanitizeUri');
module(function($provide) {
$provide.value('$$sanitizeUri', $$sanitizeUri);
});
inject(function($compile, $rootScope) {
element = $compile('<svg><a xlink:href="" ng-href="{{ testUrl }}"></a></svg>')($rootScope);
$rootScope.testUrl = "evilUrl";
$$sanitizeUri.andReturn('someSanitizedUrl');
$rootScope.$apply();
expect(element.find('a').prop('href').baseVal).toBe('someSanitizedUrl');
expect($$sanitizeUri).toHaveBeenCalledWith($rootScope.testUrl, false);
});
});
});
describe('interpolation on HTML DOM event handler attributes onclick, onXYZ, formaction', function() {
@@ -4896,6 +4946,7 @@ describe('$compile', function() {
"loading resource from url not allowed by $sceDelegate policy. URL: javascript:doTrustedStuff()");
}));
it('should pass through $sce.trustAs() values in action attribute', inject(function($compile, $rootScope, $sce) {
/* jshint scripturl:true */
element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
@@ -4906,6 +4957,36 @@ describe('$compile', function() {
}));
});
describe('link[href]', function() {
it('should reject invalid RESOURCE_URLs', inject(function($compile, $rootScope) {
element = $compile('<link href="{{testUrl}}" rel="stylesheet" />')($rootScope);
$rootScope.testUrl = "https://evil.example.org/css.css";
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
"$interpolate", "interr", "Can't interpolate: {{testUrl}}\nError: [$sce:insecurl] Blocked " +
"loading resource from url not allowed by $sceDelegate policy. URL: " +
"https://evil.example.org/css.css");
}));
it('should accept valid RESOURCE_URLs', inject(function($compile, $rootScope, $sce) {
element = $compile('<link href="{{testUrl}}" rel="stylesheet" />')($rootScope);
$rootScope.testUrl = "./css1.css";
$rootScope.$apply();
expect(element.attr('href')).toContain('css1.css');
$rootScope.testUrl = $sce.trustAsResourceUrl('https://elsewhere.example.org/css2.css');
$rootScope.$apply();
expect(element.attr('href')).toContain('https://elsewhere.example.org/css2.css');
}));
it('should accept valid constants', inject(function($compile, $rootScope) {
element = $compile('<link href="https://elsewhere.example.org/css2.css" rel="stylesheet" />')($rootScope);
$rootScope.$apply();
expect(element.attr('href')).toContain('https://elsewhere.example.org/css2.css');
}));
});
if (!msie || msie >= 11) {
describe('iframe[srcdoc]', function() {
it('should NOT set iframe contents for untrusted values', inject(function($compile, $rootScope, $sce) {
+14
View File
@@ -550,6 +550,20 @@ describe('$location', function() {
};
}
describe('location watch', function() {
beforeEach(initService({supportHistory: true}));
beforeEach(inject(initBrowser({url:'http://new.com/a/b#'})));
it('should not update browser if only the empty hash fragment is cleared by updating the search', inject(function($rootScope, $browser, $location) {
$rootScope.$digest();
$browser.url('http://new.com/a/b#');
var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();
$rootScope.$digest();
expect($browserUrl).not.toHaveBeenCalled();
}));
});
describe('wiring', function() {
beforeEach(initService({html5Mode:false,hashPrefix: '!',supportHistory: true}));
+22 -9
View File
@@ -144,16 +144,29 @@ describe('$log', function() {
describe('$log.error', function() {
var e, $log, errorArgs;
beforeEach(function() {
e = new Error('');
e.message = undefined;
e.sourceURL = undefined;
e.line = undefined;
e.stack = undefined;
function TestErrorPrototype() {}
TestErrorPrototype.prototype = Error.prototype;
$log = new $LogProvider().$get[1]({console:{error:function() {
errorArgs = [].slice.call(arguments, 0);
}}});
function TestError() {
Error.prototype.constructor.apply(this, arguments);
this.message = undefined;
this.sourceURL = undefined;
this.line = undefined;
this.stack = undefined;
}
TestError.prototype = new TestErrorPrototype();
TestError.prototype.constructor = TestError;
beforeEach(function() {
e = new TestError('');
var mockWindow = {
console: {
error: function() {
errorArgs = [].slice.call(arguments, 0);
}
}
};
$log = new $LogProvider().$get[1](mockWindow);
});
+35
View File
@@ -987,6 +987,20 @@ describe('parser', function() {
scope.$eval('{}["__proto__"].foo = 1');
}).toThrowMinErr('$parse', 'isecfld');
expect(function() {
scope.$eval('{}[["__proto__"]]');
}).toThrowMinErr('$parse', 'isecfld');
expect(function() {
scope.$eval('{}[["__proto__"]].foo = 1');
}).toThrowMinErr('$parse', 'isecfld');
expect(function() {
scope.$eval('0[["__proto__"]]');
}).toThrowMinErr('$parse', 'isecfld');
expect(function() {
scope.$eval('0[["__proto__"]].foo = 1');
}).toThrowMinErr('$parse', 'isecfld');
scope.a = "__pro";
scope.b = "to__";
expect(function() {
@@ -1105,6 +1119,27 @@ describe('parser', function() {
expect(count).toBe(1);
});
it('should prevent the exploit', function() {
try {
scope.$eval('(1)[{0: "__proto__", 1: "__proto__", 2: "__proto__", 3: "safe", length: 4, toString: [].pop}].foo = 1');
} catch(e) { /* ignore */ }
if (!msie || msie > 10) {
expect((1)['__proto__'].foo).toBeUndefined();
}
});
it('should prevent the exploit', function() {
expect(function() {
scope.$eval('' +
' "".sub.call.call(' +
'({})["constructor"].getOwnPropertyDescriptor("".sub.__proto__, "constructor").value,' +
'null,' +
'"alert(1)"' +
')()' +
'');
}).toThrow();
});
it('should call the function once when it is part of the context on array lookups', function() {
var count = 0;
+20 -13
View File
@@ -588,22 +588,29 @@ describe('ngMock', function() {
}));
it('should log exceptions', module(function($exceptionHandlerProvider){
$exceptionHandlerProvider.mode('log');
var $exceptionHandler = $exceptionHandlerProvider.$get();
$exceptionHandler('MyError');
expect($exceptionHandler.errors).toEqual(['MyError']);
it('should log exceptions', function() {
module(function($exceptionHandlerProvider) {
$exceptionHandlerProvider.mode('log');
});
inject(function($exceptionHandler) {
$exceptionHandler('MyError');
expect($exceptionHandler.errors).toEqual(['MyError']);
$exceptionHandler('MyError', 'comment');
expect($exceptionHandler.errors[1]).toEqual(['MyError', 'comment']);
}));
$exceptionHandler('MyError', 'comment');
expect($exceptionHandler.errors[1]).toEqual(['MyError', 'comment']);
});
});
it('should throw on wrong argument', function() {
module(function($exceptionHandlerProvider) {
expect(function() {
$exceptionHandlerProvider.mode('XXX');
}).toThrow("Unknown mode 'XXX', only 'log'/'rethrow' modes are allowed!");
});
inject(); // Trigger the tests in `module`
});
it('should throw on wrong argument', module(function($exceptionHandlerProvider) {
expect(function() {
$exceptionHandlerProvider.mode('XXX');
}).toThrow("Unknown mode 'XXX', only 'log'/'rethrow' modes are allowed!");
}));
});
+25 -2
View File
@@ -219,13 +219,13 @@ describe('$route', function() {
expect($route.current).toBeUndefined();
}));
it('matches literal *', inject(function($route, $location, $rootScope) {
it('matches literal .', inject(function($route, $location, $rootScope) {
$location.path('/$testX23/foo*(bar)/222');
$rootScope.$digest();
expect($route.current).toBeUndefined();
}));
it('matches literal .', inject(function($route, $location, $rootScope) {
it('matches literal *', inject(function($route, $location, $rootScope) {
$location.path('/$test.23/foooo(bar)/222');
$rootScope.$digest();
expect($route.current).toBeUndefined();
@@ -830,6 +830,29 @@ describe('$route', function() {
});
it('should properly interpolate optional and eager route vars ' +
'when redirecting from path with trailing slash', function() {
module(function($routeProvider) {
$routeProvider.when('/foo/:id?/:subid?', {templateUrl: 'foo.html'});
$routeProvider.when('/bar/:id*/:subid', {templateUrl: 'bar.html'});
});
inject(function($location, $rootScope, $route) {
$location.path('/foo/id1/subid2/');
$rootScope.$digest();
expect($location.path()).toEqual('/foo/id1/subid2');
expect($route.current.templateUrl).toEqual('foo.html');
$location.path('/bar/id1/extra/subid2/');
$rootScope.$digest();
expect($location.path()).toEqual('/bar/id1/extra/subid2');
expect($route.current.templateUrl).toEqual('bar.html');
});
});
it('should allow custom redirectTo function to be used', function() {
function customRedirectFn(routePathParams, path, search) {
expect(routePathParams).toEqual({id: 'id3'});
+4
View File
@@ -29,6 +29,10 @@ describe('linky', function() {
toEqual('my email is &#34;<a href="mailto:me@example.com">me@example.com</a>&#34;');
});
it('should handle quotes in the email', function() {
expect(linky('foo@"bar.com')).toEqual('<a href="mailto:foo@&#34;bar.com">foo@&#34;bar.com</a>');
});
it('should handle target:', function() {
expect(linky("http://example.com", "_blank")).
toEqual('<a target="_blank" href="http://example.com">http://example.com</a>');
+1
View File
@@ -174,6 +174,7 @@ describe('HTML', function() {
it('should remove unsafe value', function() {
expectHTML('<a href="javascript:alert()">').toEqual('<a></a>');
expectHTML('<img src="foo.gif" usemap="#foomap">').toEqual('<img src="foo.gif"/>');
});
it('should handle self closed elements', function() {