Compare commits

...

35 Commits

Author SHA1 Message Date
Peter Bacon Darwin 59205d7809 chore(bower/publish): run local precommit script if available
Closes #11164
2015-02-24 17:22:45 +00:00
Martin Staffa 0cf170df16 chore(grunt): use path.normalize in grunt shell:npm-install
This makes the command runnable on Windows clients.
2015-02-23 20:51:37 +01:00
Tero Parviainen 05a3b088fd docs(ngRepeat): extend description of tracking and duplicates
Add a section to the documentation on how tracking between items and DOM
elements is done, and why duplicates are not allowed in the collection.

Describe how the default tracking behaviour can be substituted with track by.

Tweak the wording in the `track by` section to discuss “tracking expressions”
instead of “tracking functions”.

Closes #8153
2015-02-23 20:17:09 +01:00
Martin Staffa 65df5da07a docs(ngDisabled): clarify the explanation of attributes & interpolation
Closes #11032
Closes #11133
2015-02-22 22:17:22 +01:00
Igor Minar 0689c3697f chore(npm): update dependencies 2015-02-21 19:03:50 -08:00
Igor Minar 0f53c29954 chore(travis,grunt): extract the npm install and cache busting logic into install-dependencies.sh
So now we are DRY.

Added extra error checking and improved the grunt file init setup so that stdio is visible in console.

Closes #11110
2015-02-21 18:55:19 -08:00
Igor Minar 11bfe85598 chore(grunt): blow away cached node_modules when npm-shrinkwrap.json changes
this replicates the travis setup in grunt from the previous commit

the reason why we duplicate this rather than having just a single place for this code is so that
we can individually time the actions on travis
2015-02-21 18:55:07 -08:00
Igor Minar 93c503fa16 chore(travis): don't break the build when travis cache is empty
`du` returns error code 2 when any of the directories don't exist which breaks the build.

this scenario is common when the cache was emptied or when travis is building forks that don't have travis cache enabled
2015-02-21 18:54:55 -08:00
Igor Minar 9d4e948e82 chore(travis): blow away cached node_modules when npm-shrinkwrap.json changes
`npm install` blindly accepts the node_modules cache and doesn't verify if it matches requirements in the current npm-shrinkwrap.json.

This means that if we are using travis cache and npm-shrinkwrap.json changes npm will keep on using the old dependencies, in spite of the guarantees that shrinkwrap claims to offer.

https://github.com/angular/angular.js/pull/11110#issuecomment-75302946

With this change, we will blow away the node_modules directory if the shrinkwrap changes compared to the one
used to populate node_modules.
2015-02-21 18:54:24 -08:00
Igor Minar 26f19d0399 chore(karma): use karma 0.12.31 instead of a custom fork
Previously Vojta set us up to use a custom fork of Karma that used socket.io 1.3.4. This change moves us to an official release of Karma but downgrades socket.io back to 0.9.16.

We now need to hurry up and finish the socket.io upgrade in karma which was blocked on shrinkwrap issues in Angular that are resolved with the previous few commits in this PR.

Conflicts:
	npm-shrinkwrap.clean.json
	npm-shrinkwrap.json
2015-02-21 18:54:08 -08:00
Igor Minar 5cd2e2291b chore(clean-shrinkwrap): drop from property from the clean shrinkwrap
it usually contains urls to temp directories which are not interesting, the info
we do want to preserve is in the `resolved` property and we do keep that one.

Conflicts:
	npm-shrinkwrap.clean.json
2015-02-21 18:41:10 -08:00
Igor Minar 69bbbe675e chore(clean-shrinkwrap): preserve git+https:// resolved property
previously we thought that git:// was enough, but we also want git+https:// otherwise we can miss important info
in clean shrinkwrap file

Conflicts:
	npm-shrinkwrap.clean.json
2015-02-21 18:40:11 -08:00
Igor Minar 825de1cdf2 chore(npm/travis): upgrade to npm 2.5 and require it via package.json
currently karma's dependencies don't install on node 0.12 or io.js so we'll just update npm in hope that that
this will mitigate "cb() never called!" erorrs. See: https://travis-ci.org/angular/angular.js/jobs/51474043#L2181
2015-02-21 18:40:11 -08:00
Igor Minar e5318c61ee chore(npm): don't clean npm-shrinkwrap.json instead generate npm-shrinkwrap.clean.json
Previously we would clean up npm-shrinkwarp.json file in order to achieve serialization
stability, which would then allow us to create human readable diffs that allow code reviews
of npm-shrinkwrap to be meaningful.

This cleanup process does have an impact on the functionality of npm which was only recently
discovered by Vojta, when we tried to update to new Karma version. See: Automattic/engine.io-client#370

According to Julie, the root cause of these issues is npm/npm/#3581.

The workaround implemented in this commit is not to interfere with npm-shrinkwrap.json file, but instead
preserve the cleaned up version of its content in npm-shrinkwrap.clean.json which can then be used to
produce human readable diffs for code reviews of npm dependency updates.
2015-02-21 18:37:56 -08:00
Igor Minar 67b40a19fb chore(travis): turn on caching for node_modules and bower_components directories
The cache behavior is documented at http://docs.travis-ci.com/user/caching/

This commit also disabled our custom caching via npm-bundler-deps.sh
2015-02-21 18:36:37 -08:00
Martin Staffa 5fbac749c9 docs($resource): fix list level
Closes #11055
2015-02-13 23:54:11 +01:00
Julie Ralph 0daadeb3d3 chore(ci): make all browserstack tests allowed failures 2015-02-13 10:20:34 -08:00
Peter Bacon Darwin 6b7625a095 fix(ngModel): fix issues when parserName is same as validator key
For $validate(), it is necessary to store the parseError state
in the controller. Otherwise, if the parser name equals a validator
key, $validate() will assume a parse error occured if the validator
is invalid.

Also, setting the validity for the parser now happens after setting
validity for the validator key. Otherwise, the parse key is set,
and then immediately afterwards the validator key is unset
(because parse errors remove all other validations).

Fixes #10698
Closes #10850
Closes #11046
2015-02-13 12:34:44 +00:00
Rouven Weßling ab7e0cd100 refactor(ngSanitize): remove workarounds for IE8
Closes #10758
2015-02-13 11:52:05 +00:00
Peter Bacon Darwin dee5f7fea5 test(ngSanitize): add tests for decodeEntities 2015-02-13 11:52:05 +00:00
Julie Ralph 140d149cee chore(ci): update to use the latest sauce connect (4.3 to 4.3.6) 2015-02-12 13:19:42 -08:00
Peter Bacon Darwin 4d65ddddf8 docs(FAQ): update the zipped file size 2015-02-12 11:59:53 +00:00
Tobyee abfce5327c fix(input): create max and/or min validator regardless of initial value
Also adds corresponding tests for ngMin / ngMax.

Fixes #10307
Closes #10327
2015-02-10 23:39:49 +01:00
Martin Staffa 944c150e6c fix(ngAria): correctly set "checked" attr for checkboxes and radios
Make sure the checked attribute is set correctly for:
- checkboxes with string and integer models using ngTrueValue /
ngFalseValue
- radios with integer models
- radios with boolean models using ngValue

Fixes #10389
Fixes #10212
2015-02-10 22:35:36 +01:00
Peter Bacon Darwin d8dc53d215 chore(CHANGELOG): add release name! 2015-02-09 11:16:46 +00:00
Peter Bacon Darwin 0ec206f5a6 chore(CHANGELOG): update to 1.4.0-beta.4 and 1.3.13 2015-02-09 10:39:03 +00:00
Lucas Galfaso ce49d4d61b fix(sanitize): handle newline characters inside <script> for IE
Tweak the regex used match characters inside <script> and <style> to a IE
compatible regex.
2015-02-07 19:21:53 +01:00
Marcy Sutton 69ee593fd2 fix(ngAria): ensure native controls fire a single click
Closes #10388
Closes #10766
2015-02-07 10:27:29 +00:00
Shahar Talmi 39ddef6829 fix(ngMock): handle cases where injector is created before tests
This caused an exception for people who created an injector before the tests actually began to run. Since the array was initialized only in beforeEach, anyone accessing it before that would throw. This is solved easily but initializing the array immediately.

Closes #10967
2015-02-06 03:47:32 +02:00
Lucas Galfaso 11aedbd741 fix(sanitize): handle newline characters inside special tags
Handle newlines characters when they are present inside <script> and <style> tags.

Closes #10943
2015-02-04 15:28:49 +01:00
Lukas Elmer e4d1e12f7f chore(docs): fix nav scrolling for non-mobile screens
Closes #10936
2015-02-04 13:37:28 +00:00
Morris Singer 9c2b32d6f3 docs(guide/forms): improve wording
Closes #01937
2015-02-04 13:17:07 +00:00
dtritus 4b3a590b00 fix($location): prevent page reload if initial url has empty hash at the end
If initial url has empty hash at the end, $location replaces it with url
without hash causing an unwanted page reload.

Closes #10397
Closes #10960
2015-02-04 12:49:20 +00:00
Peter Bacon Darwin 7f50e97628 docs(CHANGELOG): update changelog for 1.4.0-beta.3 and 1.3.12 2015-02-03 20:53:22 +00:00
Peter Bacon Darwin e5ee6123fc docs(CHANGELOG): update changelog for 1.4.0-beta.3 and 1.3.12 2015-02-02 20:26:52 +00:00
30 changed files with 12861 additions and 1591 deletions
+14 -2
View File
@@ -2,6 +2,12 @@ language: node_js
node_js:
- '0.10'
cache:
directories:
- node_modules
- bower_components
- docs/bower_components
branches:
except:
- /^g3_.*$/
@@ -27,15 +33,21 @@ env:
matrix:
allow_failures:
- env: "JOB=unit BROWSER_PROVIDER=browserstack"
- env: "JOB=docs-e2e BROWSER_PROVIDER=browserstack"
- env: "JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=browserstack"
- env: "JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=browserstack"
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
# Instal npm dependecies and ensure that npm cache is not stale
- scripts/npm/install-dependencies.sh
before_script:
- mkdir -p $LOGS_DIR
+151
View File
@@ -1,3 +1,154 @@
<a name="1.4.0-beta.4"></a>
# 1.4.0-beta.4 overlyexplosive-poprocks (2015-02-09)
## Bug Fixes
- **$location:** prevent page reload if initial url has empty hash at the end
([a509e9aa](https://github.com/angular/angular.js/commit/a509e9aa149d0f88cc39f703d539f7ffd4cd6103),
[#10397](https://github.com/angular/angular.js/issues/10397), [#10960](https://github.com/angular/angular.js/issues/10960))
- **$parse:** Initialize elements in an array from left to right
([966f6d83](https://github.com/angular/angular.js/commit/966f6d831f9469a917601f9a10604612cd7bd792))
- **ngAria:** ensure native controls fire a single click
([9d53e5a3](https://github.com/angular/angular.js/commit/9d53e5a38dd369dec82d82e13e078df3d6054c8a),
[#10388](https://github.com/angular/angular.js/issues/10388), [#10766](https://github.com/angular/angular.js/issues/10766))
- **ngMock:** handle cases where injector is created before tests
([898714df](https://github.com/angular/angular.js/commit/898714df9ea38f9ef700015ced5ddea52f096b77),
[#10967](https://github.com/angular/angular.js/issues/10967))
- **sanitize:** handle newline characters inside special tags
([cc8755cd](https://github.com/angular/angular.js/commit/cc8755cda6efda0b52954388e8a8d5306e4bfbca),
[030a42e7](https://github.com/angular/angular.js/commit/030a42e79dec8a4bb73053762f7a54d797a058f6)
[#10943](https://github.com/angular/angular.js/issues/10943))
## Features
- **ng-jq:** adds the ability to force jqLite or a specific jQuery version
([09ee82d8](https://github.com/angular/angular.js/commit/09ee82d84dcbea4a6e8d85903af82dcd087a78a7))
<a name="1.3.13"></a>
# 1.3.13 meticulous-riffleshuffle (2015-02-09)
## Bug Fixes
- **$location:** prevent page reload if initial url has empty hash at the end
([4b3a590b](https://github.com/angular/angular.js/commit/4b3a590b009d7fdceda7f52e7ba0352a271b3256),
[#10397](https://github.com/angular/angular.js/issues/10397), [#10960](https://github.com/angular/angular.js/issues/10960))
- **ngAria:** ensure native controls fire a single click
([69ee593f](https://github.com/angular/angular.js/commit/69ee593fd2cb5f1d7757efbe6b256e4458752fd7),
[#10388](https://github.com/angular/angular.js/issues/10388), [#10766](https://github.com/angular/angular.js/issues/10766))
- **ngMock:** handle cases where injector is created before tests
([39ddef68](https://github.com/angular/angular.js/commit/39ddef682971d3b7282bf9d08f6eaf97b7f4bca4),
[#10967](https://github.com/angular/angular.js/issues/10967))
- **sanitize:** handle newline characters inside special tags
([11aedbd7](https://github.com/angular/angular.js/commit/11aedbd741ccddba060a9805adba1779391731da),
[ce49d4d6](https://github.com/angular/angular.js/commit/ce49d4d61bd02464b6c6376af8048f6eb09330a8)
[#10943](https://github.com/angular/angular.js/issues/10943))
<a name="1.4.0-beta.3"></a>
# 1.4.0-beta.3 substance-mimicry (2015-02-02)
## Bug Fixes
- **$compile:**
- do not initialize optional '&' binding if attribute not specified
([6a38dbfd](https://github.com/angular/angular.js/commit/6a38dbfd3c34c8f9efff503d17eb3cbeb666d422),
[#6404](https://github.com/angular/angular.js/issues/6404), [#9216](https://github.com/angular/angular.js/issues/9216))
- respect return value from controller constructor
([62d514b0](https://github.com/angular/angular.js/commit/62d514b06937cc7dd86e973ea11165c88343b42d))
- **$controller:** throw better error when controller expression is bad
([dda65e99](https://github.com/angular/angular.js/commit/dda65e992b72044c0fa0c8f5f33184028c0e3ad7),
[#10875](https://github.com/angular/angular.js/issues/10875), [#10910](https://github.com/angular/angular.js/issues/10910))
- **$parse:**
- handle null targets at assign
([2e5a7e52](https://github.com/angular/angular.js/commit/2e5a7e52a0385575bbb55a801471b009afafeca3))
- remove references to last arguments to a fn call
([e61eae1b](https://github.com/angular/angular.js/commit/e61eae1b1f2351c51bcfe4142749a4e68a2806ff),
[#10894](https://github.com/angular/angular.js/issues/10894))
- **a:** don't reload if there is only a name attribute
([d729fcf0](https://github.com/angular/angular.js/commit/d729fcf030be1d3ef37196d36ea3bf3249ee3318),
[#6273](https://github.com/angular/angular.js/issues/6273), [#10880](https://github.com/angular/angular.js/issues/10880))
- **angular.copy:** support copying `TypedArray`s
([aa0f6449](https://github.com/angular/angular.js/commit/aa0f64496a66d2a5d1a4d033f2eb075a8b084a78),
[#10745](https://github.com/angular/angular.js/issues/10745))
- **filter:** format timezone correctly in the case that UTC timezone is used
([8c469191](https://github.com/angular/angular.js/commit/8c46919199090a05634789774124b38983430c76),
[#9359](https://github.com/angular/angular.js/issues/9359))
- **ngRoute:** dont duplicate optional params into query
([27bf2ce4](https://github.com/angular/angular.js/commit/27bf2ce40c5adfb1494d69c9d0ac9cf433834a12),
[#10689](https://github.com/angular/angular.js/issues/10689))
- **ngScenario:** allow ngScenario to handle lazy-loaded and manually bootstrapped applications
([c69caa7b](https://github.com/angular/angular.js/commit/c69caa7beee4e920f8f587eb3e943be99864a14f),
[#10723](https://github.com/angular/angular.js/issues/10723))
- **validators:** maxlength should use viewValue for $isEmpty
([bfcf9946](https://github.com/angular/angular.js/commit/bfcf9946e16d21b55dde50d4d21c71c898b10215),
[#10898](https://github.com/angular/angular.js/issues/10898))
## Features
- **$compile:** allow using bindToController as object, support both new/isolate scopes
([35498d70](https://github.com/angular/angular.js/commit/35498d7045ba9138016464a344e2c145ce5264c1),
[#10420](https://github.com/angular/angular.js/issues/10420), [#10467](https://github.com/angular/angular.js/issues/10467))
- **filter:** support conversion to timezone other than UTC
([c6d8512a](https://github.com/angular/angular.js/commit/c6d8512a1d7345516d1bd9a039d81821b9518bff),
[#10858](https://github.com/angular/angular.js/issues/10858))
- **ngMocks:** cleanup $inject annotations after each test
([0baa17a3](https://github.com/angular/angular.js/commit/0baa17a3b7ad2b242df2b277b81cebdf75b04287))
## Performance Improvements
- **$scope:** Add a property $$watchersCount to scope
([c1500ea7](https://github.com/angular/angular.js/commit/c1500ea775c4cb130088b7d5bb5fb872bda50bae))
- **$parse** new and more performant parser
([0d42426](https://github.com/angular/angular.js/commit/0d424263ead16635afb582affab2b147f8e71626))
## Breaking Changes
- **$compile:** due to [6a38dbfd](https://github.com/angular/angular.js/commit/6a38dbfd3c34c8f9efff503d17eb3cbeb666d422),
Previously, '&' expressions would always set up a function in the isolate scope. Now, if the binding
is marked as optional and the attribute is not specified, no function will be added to the isolate scope.
<a name="1.3.12"></a>
# 1.3.12 outlandish-knitting (2015-02-02)
## Bug Fixes
- **$controller:** throw better error when controller expression is bad
([632b2ddd](https://github.com/angular/angular.js/commit/632b2ddd34c07b3b5a207bd83ca3a5e6e613e63b),
[#10875](https://github.com/angular/angular.js/issues/10875), [#10910](https://github.com/angular/angular.js/issues/10910))
- **$parse:** remove references to last arguments to a fn call
([7caad220](https://github.com/angular/angular.js/commit/7caad2205a6e9927890192a3638f55532bdaaf75),
[#10894](https://github.com/angular/angular.js/issues/10894))
- **ngRoute:** dont duplicate optional params into query
([f41ca4a5](https://github.com/angular/angular.js/commit/f41ca4a53ed53f172fb334911be56e42aad58794),
[#10689](https://github.com/angular/angular.js/issues/10689))
- **ngScenario:** Allow ngScenario to handle lazy-loaded and manually bootstrapped applications
([0bcd0872](https://github.com/angular/angular.js/commit/0bcd0872d8d2e37e6cb7aa5bc5cb0c742b4294f9),
[#10723](https://github.com/angular/angular.js/issues/10723))
- **validators:** maxlength should use viewValue for $isEmpty
([abd8e2a9](https://github.com/angular/angular.js/commit/abd8e2a9eb2d21ac67989c2f7b64c4c6547a1585),
[#10898](https://github.com/angular/angular.js/issues/10898))
## Features
- **ngMocks:** cleanup $inject annotations after each test
([6ec59460](https://github.com/angular/angular.js/commit/6ec5946094ee92b820bbacc886fa2367715e60b4))
<a name="1.4.0-beta.2"></a>
# 1.4.0-beta.2 holographic-rooster (2015-01-26)
+8 -4
View File
@@ -17,10 +17,6 @@ module.exports = function(grunt) {
NG_VERSION.cdn = versionInfo.cdnVersion;
var dist = 'angular-'+ NG_VERSION.full;
//global beforeEach
util.init();
//config
grunt.initConfig({
NG_VERSION: NG_VERSION,
@@ -285,6 +281,10 @@ module.exports = function(grunt) {
},
shell: {
"npm-install": {
command: path.normalize('scripts/npm/install-dependencies.sh')
},
"promises-aplus-tests": {
options: {
stdout: false,
@@ -311,6 +311,10 @@ module.exports = function(grunt) {
}
});
// global beforeEach task
if (!process.env.TRAVIS) {
grunt.task.run('shell:npm-install');
}
//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']);
+2 -1
View File
@@ -415,7 +415,7 @@ iframe.example {
.main-body-grid .side-navigation {
position:relative;
padding-bottom:50px;
padding-bottom:120px;
}
.main-body-grid .side-navigation.ng-hide {
@@ -631,6 +631,7 @@ ul.events > li {
}
.main-body-grid .side-navigation {
display:block!important;
padding-bottom:50px;
}
.main-body-grid .side-navigation.ng-hide {
display:none!important;
+9 -5
View File
@@ -37,6 +37,7 @@ Currently, ngAria interfaces with the following directives:
* {@link guide/accessibility#nghide ngHide}
* {@link guide/accessibility#ngclick ngClick}
* {@link guide/accessibility#ngdblclick ngDblClick}
* {@link guide/accessibility#ngmessages ngMessages}
<h2 id="ngmodel">ngModel</h2>
@@ -209,10 +210,14 @@ The default CSS for `ngHide`, the inverse method to `ngShow`, makes ngAria redun
`display: none`. See explanation for {@link guide/accessibility#ngshow ngShow} when overriding the default CSS.
<h2><span id="ngclick">ngClick</span> and <span id="ngdblclick">ngDblclick</span></h2>
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex` if it isn't there already.
Even with this, you must currently still add `ng-keypress` to non-interactive elements such as `div`
or `taco-button` to enable keyboard access. Conversation is currently ongoing about whether ngAria
should also bind `ng-keypress`.
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex="0"` if it isn't there
already.
For `ng-click`, keypress will also be bound to `div` and `li` elements. You can turn this
functionality on or off with the `bindKeypress` configuration option.
For `ng-dblclick`, you must manually add `ng-keypress` to non-interactive elements such as `div`
or `taco-button` to enable keyboard access.
<h3>Example</h3>
```html
@@ -223,7 +228,6 @@ Becomes:
```html
<div ng-click="toggleMenu()" tabindex="0"></div>
```
*Note: ngAria still requires `ng-keypress` to be added manually to non-native controls like divs.*
<h2 id="ngmessages">ngMessages</h2>
+6 -5
View File
@@ -6,11 +6,12 @@
Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
A Form is a collection of controls for the purpose of grouping related controls together.
Form and controls provide validation services, so that the user can be notified of invalid input.
This provides a better user experience, because the user gets instant feedback on how to
correct the error. Keep in mind that while client-side validation plays an important role
in providing good user experience, it can easily be circumvented and thus can not be trusted.
Server-side validation is still necessary for a secure application.
Form and controls provide validation services, so that the user can be notified of invalid input
before submitting a form. This provides a better user experience than server-side validation alone
because the user gets instant feedback on how to correct the error. Keep in mind that while
client-side validation plays an important role in providing good user experience, it can easily
be circumvented and thus can not be trusted. Server-side validation is still necessary for a
secure application.
# Simple form
+1 -1
View File
@@ -67,7 +67,7 @@ illustration we typically build snappy apps with hundreds or thousands of active
### How big is the angular.js file that I need to include?
The size of the file is < 36KB compressed and minified.
The size of the file is ~50KB compressed and minified.
### Can I use the open-source Closure Library with Angular?
-7
View File
@@ -14,13 +14,6 @@ var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP
module.exports = {
init: function() {
if (!process.env.TRAVIS) {
shell.exec('npm install');
}
},
startKarma: function(config, singleRun, done){
var browsers = grunt.option('browsers');
var reporters = grunt.option('reporters');
+2 -2
View File
@@ -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.6-linux.tar.gz"
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
CONNECT_DOWNLOAD="sc-4.3-linux.tar.gz"
CONNECT_DOWNLOAD="sc-4.3.6-linux.tar.gz"
CONNECT_LOG="$LOGS_DIR/sauce-connect"
CONNECT_STDOUT="$LOGS_DIR/sauce-connect.stdout"
File diff suppressed because it is too large Load Diff
+6031 -1453
View File
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -5,6 +5,11 @@
"type": "git",
"url": "https://github.com/angular/angular.js.git"
},
"engines": {
"node": "~0.10",
"npm": "~2.5"
},
"engineStrict": true,
"devDependencies": {
"angular-benchpress": "0.x.x",
"benchmark": "1.x.x",
@@ -38,7 +43,7 @@
"jasmine-node": "~1.14.5",
"jasmine-reporters": "~1.0.1",
"jshint-stylish": "~1.0.0",
"karma": "vojtajina/karma#socketio_10",
"karma": "~0.12.0",
"karma-browserstack-launcher": "0.1.2",
"karma-chrome-launcher": "0.1.5",
"karma-firefox-launcher": "0.1.3",
+15
View File
@@ -63,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
@@ -10,22 +10,17 @@
var _ = require('lodash');
var sorted = require('sorted-object');
var fs = require('fs');
var path = require('path');
function cleanModule(module, name) {
// keep `from` and `resolve` properties for git dependencies, delete otherwise
if (!(module.resolved && module.resolved.match(/^git:\/\//))) {
delete module.from;
// keep `resolve` properties for git dependencies, delete otherwise
delete module.from;
if (!(module.resolved && module.resolved.match(/^git(\+[a-z]+)?:\/\//))) {
delete module.resolved;
}
if (name === 'chokidar') {
if (module.version === '0.8.1') {
delete module.dependencies;
}
}
_.forEach(module.dependencies, function(mod, name) {
cleanModule(mod, name);
});
@@ -33,10 +28,11 @@ function cleanModule(module, name) {
console.log('Reading npm-shrinkwrap.json');
var shrinkwrap = require('./../npm-shrinkwrap.json');
var shrinkwrap = require('../../npm-shrinkwrap.json');
console.log('Cleaning shrinkwrap object');
cleanModule(shrinkwrap, shrinkwrap.name);
console.log('Writing cleaned npm-shrinkwrap.json');
fs.writeFileSync('./npm-shrinkwrap.json', JSON.stringify(sorted(shrinkwrap), null, 2) + "\n");
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
+12 -9
View File
@@ -159,20 +159,23 @@
*
* @description
*
* We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
* This directive sets the `disabled` attribute on the element if the
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
*
* A special directive is necessary because we cannot use interpolation inside the `disabled`
* attribute. The following example would make the button enabled on Chrome/Firefox
* but not on older IEs:
*
* ```html
* <div ng-init="scope = { isDisabled: false }">
* <button disabled="{{scope.isDisabled}}">Disabled</button>
* <div ng-init="isDisabled = false">
* <button disabled="{{isDisabled}}">Disabled</button>
* </div>
* ```
*
* The HTML specification does not require browsers to preserve the values of boolean attributes
* such as disabled. (Their presence means true and their absence means false.)
* This is because the HTML specification does not require browsers to preserve the values of
* boolean attributes such as `disabled` (Their presence means true and their absence means false.)
* If we put an Angular interpolation expression into such an attribute then the
* binding information would be lost when the browser removes the attribute.
* The `ngDisabled` directive solves this problem for the `disabled` attribute.
* This complementary directive is not removed by the browser and so provides
* a permanent reliable place to store the binding information.
*
* @example
<example>
@@ -191,7 +194,7 @@
*
* @element INPUT
* @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
* then special attribute "disabled" will be set on the element
* then the `disabled` attribute will be set on the element
*/
+2 -2
View File
@@ -1250,7 +1250,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
return value;
});
if (attr.min || attr.ngMin) {
if (isDefined(attr.min) || attr.ngMin) {
var minVal;
ctrl.$validators.min = function(value) {
return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
@@ -1266,7 +1266,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
});
}
if (attr.max || attr.ngMax) {
if (isDefined(attr.max) || attr.ngMax) {
var maxVal;
ctrl.$validators.max = function(value) {
return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
+14 -15
View File
@@ -244,6 +244,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
ngModelGet = parsedNgModel,
ngModelSet = parsedNgModelAssign,
pendingDebounce = null,
parserValid,
ctrl = this;
this.$$setOptions = function(options) {
@@ -516,16 +517,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
// the model although neither viewValue nor the model on the scope changed
var modelValue = ctrl.$$rawModelValue;
// Check if the there's a parse error, so we don't unset it accidentially
var parserName = ctrl.$$parserName || 'parse';
var parserValid = ctrl.$error[parserName] ? false : undefined;
var prevValid = ctrl.$valid;
var prevModelValue = ctrl.$modelValue;
var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
ctrl.$$runValidators(parserValid, modelValue, viewValue, function(allValid) {
ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
// If there was no change in validity, don't update the model
// This prevents changing an invalid modelValue to undefined
if (!allowInvalid && prevValid !== allValid) {
@@ -543,12 +540,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
};
this.$$runValidators = function(parseValid, modelValue, viewValue, doneCallback) {
this.$$runValidators = function(modelValue, viewValue, doneCallback) {
currentValidationRunId++;
var localValidationRunId = currentValidationRunId;
// check parser error
if (!processParseErrors(parseValid)) {
if (!processParseErrors()) {
validationDone(false);
return;
}
@@ -558,21 +555,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
}
processAsyncValidators();
function processParseErrors(parseValid) {
function processParseErrors() {
var errorKey = ctrl.$$parserName || 'parse';
if (parseValid === undefined) {
if (parserValid === undefined) {
setValidity(errorKey, null);
} else {
setValidity(errorKey, parseValid);
if (!parseValid) {
if (!parserValid) {
forEach(ctrl.$validators, function(v, name) {
setValidity(name, null);
});
forEach(ctrl.$asyncValidators, function(v, name) {
setValidity(name, null);
});
return false;
}
// Set the parse error last, to prevent unsetting it, should a $validators key == parserName
setValidity(errorKey, parserValid);
return parserValid;
}
return true;
}
@@ -667,7 +665,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
this.$$parseAndValidate = function() {
var viewValue = ctrl.$$lastCommittedViewValue;
var modelValue = viewValue;
var parserValid = isUndefined(modelValue) ? undefined : true;
parserValid = isUndefined(modelValue) ? undefined : true;
if (parserValid) {
for (var i = 0; i < ctrl.$parsers.length; i++) {
@@ -693,7 +691,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
// Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
// This can happen if e.g. $setViewValue is called from inside a parser
ctrl.$$runValidators(parserValid, modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
if (!allowInvalid) {
// Note: Don't check ctrl.$valid here, as we could have
// external validators (e.g. calculated on the server),
@@ -814,6 +812,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
// TODO(perf): why not move this to the action fn?
if (modelValue !== ctrl.$modelValue) {
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
parserValid = undefined;
var formatters = ctrl.$formatters,
idx = formatters.length;
@@ -826,7 +825,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
ctrl.$render();
ctrl.$$runValidators(undefined, modelValue, viewValue, noop);
ctrl.$$runValidators(modelValue, viewValue, noop);
}
}
+55 -6
View File
@@ -46,6 +46,55 @@
* when keys are deleted and reinstated.
*
*
* # Tracking and Duplicates
*
* When the contents of the collection change, `ngRepeat` makes the corresponding changes to the DOM:
*
* * When an item is added, a new instance of the template is added to the DOM.
* * When an item is removed, its template instance is removed from the DOM.
* * When items are reordered, their respective templates are reordered in the DOM.
*
* By default, `ngRepeat` does not allow duplicate items in arrays. This is because when
* there are duplicates, it is not possible to maintain a one-to-one mapping between collection
* items and DOM elements.
*
* If you do need to repeat duplicate items, you can substitute the default tracking behavior
* with your own using the `track by` expression.
*
* For example, you may track items by the index of each item in the collection, using the
* special scope property `$index`:
* ```html
* <div ng-repeat="n in [42, 42, 43, 43] track by $index">
* {{n}}
* </div>
* ```
*
* You may use arbitrary expressions in `track by`, including references to custom functions
* on the scope:
* ```html
* <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
* {{n}}
* </div>
* ```
*
* If you are working with objects that have an identifier property, you can track
* by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
* will not have to rebuild the DOM elements for items it has already rendered, even if the
* JavaScript objects in the collection have been substituted for new ones:
* ```html
* <div ng-repeat="model in collection track by model.id">
* {{model.name}}
* </div>
* ```
*
* When no `track by` expression is provided, it is equivalent to tracking by the built-in
* `$id` function, which tracks items by their identity:
* ```html
* <div ng-repeat="obj in collection track by $id(obj)">
* {{obj.prop}}
* </div>
* ```
*
* # 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
* the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
@@ -113,12 +162,12 @@
*
* For example: `(name, age) in {'adam':10, 'amalie':12}`.
*
* * `variable in expression track by tracking_expression` You can also provide an optional tracking function
* which can be used to associate the objects in the collection with the DOM elements. If no tracking function
* is specified the ng-repeat associates elements by identity in the collection. It is an error to have
* more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
* mapped to the same DOM element, which is not possible.) Filters should be applied to the expression,
* before specifying a tracking expression.
* * `variable in expression track by tracking_expression` You can also provide an optional tracking expression
* which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
* is specified, ng-repeat associates elements by identity. It is an error to have
* more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
* mapped to the same DOM element, which is not possible.) If filters are used in the expression, they should be
* applied before the tracking expression.
*
* For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
* will be associated by item identity in the array.
+1 -1
View File
@@ -879,7 +879,7 @@ function $LocationProvider() {
// rewrite hashbang url <> html5 url
if ($location.absUrl() != initialUrl) {
if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
$browser.url($location.absUrl(), true);
}
+15 -5
View File
@@ -100,7 +100,8 @@ function $AriaProvider() {
* - **ariaMultiline** `{boolean}` Enables/disables aria-multiline tags
* - **ariaValue** `{boolean}` Enables/disables aria-valuemin, aria-valuemax and aria-valuenow tags
* - **tabindex** `{boolean}` Enables/disables tabindex tags
* - **bindKeypress** `{boolean}` Enables/disables keypress event binding on ng-click
* - **bindKeypress** `{boolean}` Enables/disables keypress event binding on `&lt;div&gt;` and
* `&lt;li&gt;` elements with ng-click
*
* @description
* Enables/disables various ARIA attributes
@@ -128,6 +129,7 @@ function $AriaProvider() {
* @name $aria
*
* @description
* @priority 200
*
* The $aria service contains helper methods for applying common
* [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
@@ -204,6 +206,7 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
return {
restrict: 'A',
require: '?ngModel',
priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
link: function(scope, elem, attr, ngModel) {
var shape = getShape(attr, elem);
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem);
@@ -216,19 +219,19 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
if (needsTabIndex) {
needsTabIndex = false;
return function ngAriaRadioReaction(newVal) {
var boolVal = newVal === attr.value;
var boolVal = (attr.value == ngModel.$viewValue);
elem.attr('aria-checked', boolVal);
elem.attr('tabindex', 0 - !boolVal);
};
} else {
return function ngAriaRadioReaction(newVal) {
elem.attr('aria-checked', newVal === attr.value);
elem.attr('aria-checked', (attr.value == ngModel.$viewValue));
};
}
}
function ngAriaCheckboxReaction(newVal) {
elem.attr('aria-checked', !!newVal);
elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
}
switch (shape) {
@@ -303,11 +306,18 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
compile: function(elem, attr) {
var fn = $parse(attr.ngClick, /* interceptorFn */ null, /* expensiveChecks */ true);
return function(scope, elem, attr) {
function isNodeOneOf(elem, nodeTypeArray) {
if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) {
return true;
}
}
if ($aria.config('tabindex') && !elem.attr('tabindex')) {
elem.attr('tabindex', 0);
}
if ($aria.config('bindKeypress') && !attr.ngKeypress) {
if ($aria.config('bindKeypress') && !attr.ngKeypress && isNodeOneOf(elem, ['DIV', 'LI'])) {
elem.on('keypress', function(event) {
if (event.keyCode === 32 || event.keyCode === 13) {
scope.$apply(callback);
+1 -1
View File
@@ -2127,7 +2127,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
if (window.jasmine || window.mocha) {
var currentSpec = null,
annotatedFunctions,
annotatedFunctions = [],
isSpecRunning = function() {
return !!currentSpec;
};
+1
View File
@@ -208,6 +208,7 @@ function shallowClearAndCopy(src, dst) {
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
*
*
* Success callback is called with (value, responseHeaders) arguments. Error callback is called
* with (httpResponse) argument.
*
+6 -18
View File
@@ -336,7 +336,8 @@ function htmlParser(html, handler) {
}
} else {
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
// IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w].
html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
function(all, text) {
text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
@@ -410,7 +411,6 @@ function htmlParser(html, handler) {
}
var hiddenPre=document.createElement("pre");
var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
/**
* decodes all entities into regular string
* @param value
@@ -419,22 +419,10 @@ var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
function decodeEntities(value) {
if (!value) { return ''; }
// Note: IE8 does not preserve spaces at the start/end of innerHTML
// so we must capture them and reattach them afterward
var parts = spaceRe.exec(value);
var spaceBefore = parts[1];
var spaceAfter = parts[3];
var content = parts[2];
if (content) {
hiddenPre.innerHTML=content.replace(/</g,"&lt;");
// innerText depends on styling as it doesn't display hidden elements.
// Therefore, it's better to use textContent not to cause unnecessary
// reflows. However, IE<9 don't support textContent so the innerText
// fallback is necessary.
content = 'textContent' in hiddenPre ?
hiddenPre.textContent : hiddenPre.innerText;
}
return spaceBefore + content + spaceAfter;
hiddenPre.innerHTML = value.replace(/</g,"&lt;");
// innerText depends on styling as it doesn't display hidden elements.
// Therefore, it's better to use textContent not to cause unnecessary reflows.
return hiddenPre.textContent;
}
/**
+24 -4
View File
@@ -1869,12 +1869,17 @@ describe('input', function() {
});
it('should validate even if min value changes on-the-fly', function() {
$rootScope.min = 10;
$rootScope.min = undefined;
var inputElm = helper.compileInput('<input type="number" ng-model="value" name="alias" min="{{min}}" />');
expect(inputElm).toBeValid();
helper.changeInputValueTo('15');
expect(inputElm).toBeValid();
$rootScope.min = 10;
$rootScope.$digest();
expect(inputElm).toBeValid();
$rootScope.min = 20;
$rootScope.$digest();
expect(inputElm).toBeInvalid();
@@ -1910,12 +1915,17 @@ describe('input', function() {
});
it('should validate even if the ngMin value changes on-the-fly', function() {
$rootScope.min = 10;
$rootScope.min = undefined;
var inputElm = helper.compileInput('<input type="number" ng-model="value" name="alias" ng-min="min" />');
expect(inputElm).toBeValid();
helper.changeInputValueTo('15');
expect(inputElm).toBeValid();
$rootScope.min = 10;
$rootScope.$digest();
expect(inputElm).toBeValid();
$rootScope.min = 20;
$rootScope.$digest();
expect(inputElm).toBeInvalid();
@@ -1952,12 +1962,17 @@ describe('input', function() {
});
it('should validate even if max value changes on-the-fly', function() {
$rootScope.max = 10;
$rootScope.max = undefined;
var inputElm = helper.compileInput('<input type="number" ng-model="value" name="alias" max="{{max}}" />');
expect(inputElm).toBeValid();
helper.changeInputValueTo('5');
expect(inputElm).toBeValid();
$rootScope.max = 10;
$rootScope.$digest();
expect(inputElm).toBeValid();
$rootScope.max = 0;
$rootScope.$digest();
expect(inputElm).toBeInvalid();
@@ -1993,12 +2008,17 @@ describe('input', function() {
});
it('should validate even if the ngMax value changes on-the-fly', function() {
$rootScope.max = 10;
$rootScope.max = undefined;
var inputElm = helper.compileInput('<input type="number" ng-model="value" name="alias" ng-max="max" />');
expect(inputElm).toBeValid();
helper.changeInputValueTo('5');
expect(inputElm).toBeValid();
$rootScope.max = 10;
$rootScope.$digest();
expect(inputElm).toBeValid();
$rootScope.max = 0;
$rootScope.$digest();
expect(inputElm).toBeInvalid();
+90
View File
@@ -1221,6 +1221,96 @@ describe('ngModel', function() {
expect(ctrl.$validators.mock).toHaveBeenCalledWith('a', 'ab');
expect(ctrl.$validators.mock.calls.length).toEqual(2);
});
it('should validate correctly when $parser name equals $validator key', function() {
ctrl.$validators.parserOrValidator = function(value) {
switch (value) {
case 'allInvalid':
case 'parseValid-validatorsInvalid':
case 'stillParseValid-validatorsInvalid':
return false;
default:
return true;
}
};
ctrl.$validators.validator = function(value) {
switch (value) {
case 'allInvalid':
case 'parseValid-validatorsInvalid':
case 'stillParseValid-validatorsInvalid':
return false;
default:
return true;
}
};
ctrl.$$parserName = 'parserOrValidator';
ctrl.$parsers.push(function(value) {
switch (value) {
case 'allInvalid':
case 'stillAllInvalid':
case 'parseInvalid-validatorsValid':
case 'stillParseInvalid-validatorsValid':
return undefined;
default:
return value;
}
});
//Parser and validators are invalid
scope.$apply('value = "allInvalid"');
expect(scope.value).toBe('allInvalid');
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
ctrl.$validate();
expect(scope.value).toEqual('allInvalid');
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
ctrl.$setViewValue('stillAllInvalid');
expect(scope.value).toBeUndefined();
expect(ctrl.$error).toEqual({parserOrValidator: true});
ctrl.$validate();
expect(scope.value).toBeUndefined();
expect(ctrl.$error).toEqual({parserOrValidator: true});
//Parser is valid, validators are invalid
scope.$apply('value = "parseValid-validatorsInvalid"');
expect(scope.value).toBe('parseValid-validatorsInvalid');
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
ctrl.$validate();
expect(scope.value).toBe('parseValid-validatorsInvalid');
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
ctrl.$setViewValue('stillParseValid-validatorsInvalid');
expect(scope.value).toBeUndefined();
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
ctrl.$validate();
expect(scope.value).toBeUndefined();
expect(ctrl.$error).toEqual({parserOrValidator: true, validator: true});
//Parser is invalid, validators are valid
scope.$apply('value = "parseInvalid-validatorsValid"');
expect(scope.value).toBe('parseInvalid-validatorsValid');
expect(ctrl.$error).toEqual({});
ctrl.$validate();
expect(scope.value).toBe('parseInvalid-validatorsValid');
expect(ctrl.$error).toEqual({});
ctrl.$setViewValue('stillParseInvalid-validatorsValid');
expect(scope.value).toBeUndefined();
expect(ctrl.$error).toEqual({parserOrValidator: true});
ctrl.$validate();
expect(scope.value).toBeUndefined();
expect(ctrl.$error).toEqual({parserOrValidator: true});
});
});
});
+10
View File
@@ -673,6 +673,16 @@ describe('$location', function() {
}));
});
describe('rewrite hashbang url <> html5 url', function() {
beforeEach(initService({html5Mode: true, supportHistory: true}));
beforeEach(inject(initBrowser({url:'http://new.com/#', basePath: '/'})));
it('should not replace browser url if only the empty hash fragment is cleared', inject(function($browser, $location) {
expect($browser.url()).toBe('http://new.com/#');
expect($location.absUrl()).toBe('http://new.com/');
}));
});
describe('wiring', function() {
beforeEach(initService({html5Mode:false,hashPrefix: '!',supportHistory: true}));
+76 -5
View File
@@ -85,6 +85,28 @@ describe('$aria', function() {
expect(element.attr('aria-checked')).toBe('false');
});
it('should handle checkbox with string model values using ng(True|False)Value', function() {
var element = $compile('<input type="checkbox" ng-model="val" ng-true-value="\'yes\'" ' +
'ng-false-value="\'no\'">'
)(scope);
scope.$apply('val="yes"');
expect(element.eq(0).attr('aria-checked')).toBe('true');
scope.$apply('val="no"');
expect(element.eq(0).attr('aria-checked')).toBe('false');
});
it('should handle checkbox with integer model values using ngTrueValue', function() {
var element = $compile('<input type="checkbox" ng-model="val" ng-true-value="0">')(scope);
scope.$apply('val=0');
expect(element.eq(0).attr('aria-checked')).toBe('true');
scope.$apply('val=1');
expect(element.eq(0).attr('aria-checked')).toBe('false');
});
it('should attach itself to input type="radio"', function() {
var element = $compile('<input type="radio" ng-model="val" value="one">' +
'<input type="radio" ng-model="val" value="two">')(scope);
@@ -98,6 +120,36 @@ describe('$aria', function() {
expect(element.eq(1).attr('aria-checked')).toBe('true');
});
it('should handle radios with integer model values', function() {
var element = $compile('<input type="radio" ng-model="val" value="0">' +
'<input type="radio" ng-model="val" value="1">')(scope);
scope.$apply('val=0');
expect(element.eq(0).attr('aria-checked')).toBe('true');
expect(element.eq(1).attr('aria-checked')).toBe('false');
scope.$apply('val=1');
expect(element.eq(0).attr('aria-checked')).toBe('false');
expect(element.eq(1).attr('aria-checked')).toBe('true');
});
it('should handle radios with boolean model values using ngValue', function() {
var element = $compile('<input type="radio" ng-model="val" ng-value="valExp">' +
'<input type="radio" ng-model="val" ng-value="valExp2">')(scope);
scope.$apply(function() {
scope.valExp = true;
scope.valExp2 = false;
scope.val = true;
});
expect(element.eq(0).attr('aria-checked')).toBe('true');
expect(element.eq(1).attr('aria-checked')).toBe('false');
scope.$apply('val = false');
expect(element.eq(0).attr('aria-checked')).toBe('false');
expect(element.eq(1).attr('aria-checked')).toBe('true');
});
it('should attach itself to role="radio"', function() {
scope.$apply("val = 'one'");
compileInput('<div role="radio" ng-model="val" value="{{val}}"></div>');
@@ -488,12 +540,24 @@ describe('$aria', function() {
it('should a trigger click from the keyboard', function() {
scope.someAction = function() {};
compileInput('<div ng-click="someAction()" tabindex="0"></div>');
var elements = $compile('<section>' +
'<div class="div-click" ng-click="someAction(\'div\')" tabindex="0"></div>' +
'<ul><li ng-click="someAction( \'li\')" tabindex="0"></li></ul>' +
'</section>')(scope);
scope.$digest();
clickFn = spyOn(scope, 'someAction');
element.triggerHandler({type: 'keypress', keyCode: 32});
var divElement = elements.find('div');
var liElement = elements.find('li');
expect(clickFn).toHaveBeenCalled();
divElement.triggerHandler({type: 'keypress', keyCode: 32});
liElement.triggerHandler({type: 'keypress', keyCode: 32});
expect(clickFn).toHaveBeenCalledWith('div');
expect(clickFn).toHaveBeenCalledWith('li');
});
it('should not override existing ng-keypress', function() {
@@ -526,6 +590,13 @@ describe('$aria', function() {
element.triggerHandler({ type: 'keypress', keyCode: 13 });
expect(element.text()).toBe('keypress13');
});
it('should not bind keypress to elements not in the default config', function() {
compileInput('<button ng-click="event = $event">{{event.type}}{{event.keyCode}}</button>');
expect(element.text()).toBe('');
element.triggerHandler({ type: 'keypress', keyCode: 13 });
expect(element.text()).toBe('');
});
});
describe('actions when bindKeypress set to false', function() {
@@ -534,11 +605,11 @@ describe('$aria', function() {
}));
beforeEach(injectScopeAndCompiler);
it('should not a trigger click from the keyboard', function() {
it('should not a trigger click', function() {
scope.someAction = function() {};
var clickFn = spyOn(scope, 'someAction');
element = $compile('<div ng-click="someAction()" tabindex="0">></div>')(scope);
element = $compile('<div ng-click="someAction()" tabindex="0"></div>')(scope);
element.triggerHandler({type: 'keypress', keyCode: 32});
+7
View File
@@ -1813,3 +1813,10 @@ describe('ngMockE2E', function() {
});
});
});
describe('make sure that we can create an injector outside of tests', function() {
//since some libraries create custom injectors outside of tests,
//we want to make sure that this is not breaking the internals of
//how we manage annotated function cleanup during tests. See #10967
angular.injector([function($injector) {}]);
});
+15 -32
View File
@@ -140,6 +140,10 @@ describe('HTML', function() {
expectHTML('a<SCRIPT>evil< / scrIpt >c.').toEqual('ac.');
});
it('should remove script that has newline characters', function() {
expectHTML('a<SCRIPT\n>\n\revil\n\r< / scrIpt\n >c.').toEqual('ac.');
});
it('should remove DOCTYPE header', function() {
expectHTML('<!DOCTYPE html>').toEqual('');
expectHTML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"\n"http://www.w3.org/TR/html4/strict.dtd">').toEqual('');
@@ -160,6 +164,10 @@ describe('HTML', function() {
expectHTML('a<STyle>evil</stYle>c.').toEqual('ac.');
});
it('should remove style that has newline characters', function() {
expectHTML('a<STyle \n>\n\revil\n\r</stYle\n>c.').toEqual('ac.');
});
it('should remove script and style', function() {
expectHTML('a<STyle>evil<script></script></stYle>c.').toEqual('ac.');
});
@@ -487,8 +495,7 @@ describe('HTML', function() {
});
describe('decodeEntities', function() {
var handler, text,
origHiddenPre = window.hiddenPre;
var handler, text;
beforeEach(function() {
text = '';
@@ -503,37 +510,13 @@ describe('decodeEntities', function() {
module('ngSanitize');
});
afterEach(function() {
window.hiddenPre = origHiddenPre;
it('should unescape text', function() {
htmlParser('a&lt;div&gt;&amp;&lt;/div&gt;c', handler);
expect(text).toEqual('a<div>&</div>c');
});
it('should use innerText if textContent is not available (IE<9)', function() {
window.hiddenPre = {
innerText: 'INNER_TEXT'
};
inject(function($sanitize) {
htmlParser('<tag>text</tag>', handler);
expect(text).toEqual('INNER_TEXT');
});
});
it('should use textContent if available', function() {
window.hiddenPre = {
textContent: 'TEXT_CONTENT',
innerText: 'INNER_TEXT'
};
inject(function($sanitize) {
htmlParser('<tag>text</tag>', handler);
expect(text).toEqual('TEXT_CONTENT');
});
});
it('should use textContent even if empty', function() {
window.hiddenPre = {
textContent: '',
innerText: 'INNER_TEXT'
};
inject(function($sanitize) {
htmlParser('<tag>text</tag>', handler);
expect(text).toEqual('');
});
it('should preserve whitespace', function() {
htmlParser(' a&amp;b ', handler);
expect(text).toEqual(' a&b ');
});
});