Compare commits

...

68 Commits

Author SHA1 Message Date
Erin Altenhof-Long eba192b863 docs(CHANGELOG): add v1.3.0-beta.15 and v1.2.20 changes 2014-07-11 11:26:39 -07:00
rodyhaddad 75099e6137 chore($parse): remove simpleGetter optimizations as they're no longer valid
Closes #8101
2014-07-10 15:17:41 -07:00
perek 172a40931b fix($http) - add ability to remove default headers
Fixes #5784
Closes #5785
2014-07-10 14:38:19 -07:00
Igor Minar 23e5109b64 chore(travis): disable our npm registry cache 2014-07-09 06:43:05 -07:00
Michał Gołębiowski cc84ce3bf5 chore(travis): disable npm spinner & enable HTTP logs; run npm install twice
It's good to have HTTP logs on Travis for debugging purposes and the spinner
doesn't integrate with Travis very well & messes the output.
2014-07-09 12:42:57 +02:00
Michał Gołębiowski bee2d1fbb9 chore(travis): declare Node.js version as '0.10', not 0.10 (which is 0.1) 2014-07-09 11:45:17 +02:00
fuqcool 7101a02c93 docs(error/$sce/insecurl): fix links to $sce and $sceDelegateProvider 2014-07-08 22:40:06 -07:00
Julie Ralph 888be00712 chore(tests): fix warning about a non-unique element locator in e2e tests 2014-07-08 16:28:12 -07:00
Julie Ralph 05597c24c7 chore(e2e): update protractor to 1.0.0-rc4
This change contains a stability improvement to use data URLs instead of
about:blank for resetting the URL.
2014-07-08 16:22:52 -07:00
Domenico Matteo bf55f23325 docs(guide/i18n): fix typo 2014-07-08 03:35:04 -07:00
Brian Ford ab051e78ea docs(select): update example to use a module 2014-07-08 02:32:21 -07:00
Brian Ford 87d46a84c3 docs(guide/expression): update examples to use modules 2014-07-08 02:32:21 -07:00
Brian Ford ae764f1844 docs(linky): update example to use a module 2014-07-08 02:32:21 -07:00
Brian Ford ad8092ed80 docs(angular.copy): update example to use a module 2014-07-08 02:32:21 -07:00
Brian Ford 55e1b3e1c8 docs($sanitize): update example to use a module 2014-07-08 02:32:20 -07:00
Brian Ford 6f465a2b26 docs(guide/scope): update examples to use modules 2014-07-08 02:32:20 -07:00
Brian Ford 3ecac62251 docs(guide/forms): update examples to use modules 2014-07-08 02:32:20 -07:00
Brian Ford c64610269d docs($location): update example to use a module 2014-07-08 02:32:20 -07:00
Brian Ford 5c2302949b docs($cookies): update examples to use modules 2014-07-08 02:32:20 -07:00
Brian Ford 7c84e2632f docs(orderBy): update examples to use modules 2014-07-08 02:32:20 -07:00
Brian Ford 18d18f07db docs(limitTo): update example to use a module 2014-07-08 02:32:20 -07:00
Brian Ford 9f5be534fc docs(ngTransclude): update example to use a module 2014-07-08 02:32:20 -07:00
Brian Ford 1cd7912614 docs($log): update example to use a module 2014-07-08 02:32:19 -07:00
Brian Ford 514da451fc docs(ngPluralize): update example to use a module 2014-07-08 02:32:19 -07:00
Brian Ford 2788cc4e12 docs(ngSwitch): update example to use a module 2014-07-08 02:32:19 -07:00
Brian Ford 7f6322df6a docs(ngInit): update example to use a module 2014-07-08 02:32:19 -07:00
Brian Ford 5bd8613168 docs(ngValue): update example to use a module 2014-07-08 02:32:19 -07:00
Brian Ford 32b507890e docs(ngList): update example to use a module 2014-07-08 02:32:19 -07:00
Brian Ford bfedafdede docs(ngInclude): update example to use a module 2014-07-08 02:32:19 -07:00
Brian Ford cdefbe3425 docs($interval): update example to use a module 2014-07-08 02:32:19 -07:00
Brian Ford f75f4bce82 docs(filters): update examples to use modules 2014-07-08 02:32:19 -07:00
Brian Ford 4349de3d41 docs(ngController): update examples to use modules 2014-07-08 02:32:18 -07:00
Brian Ford df545d7eed docs($window): update example to use a module 2014-07-08 02:32:18 -07:00
Brian Ford 3b5f346314 docs(ngSubmit): update example to use a module 2014-07-08 02:32:18 -07:00
Brian Ford 3aab87b381 docs(ngBind): update examples to use modules 2014-07-08 02:32:18 -07:00
Brian Ford 0973175058 docs($http): update example to use a module 2014-07-08 02:32:18 -07:00
Brian Ford 112da45c07 docs($document): update example to use a module 2014-07-08 02:32:18 -07:00
Brian Ford e3dc85841d docs(ngChange): update example to use a module 2014-07-08 02:32:18 -07:00
Brian Ford ef1c352bc9 docs(ngModel): update examples to use modules 2014-07-08 02:32:18 -07:00
Brian Ford a5b6444324 docs(formDirective): update example to use a module 2014-07-08 02:32:17 -07:00
Brian Ford dd18c00b1d docs($compile): update example to use a module 2014-07-08 02:32:17 -07:00
Shahar Talmi a0fad24dc2 chore(jshint): enforce jshint for tests
Closes #8023
Closes #8026
2014-07-08 00:34:50 -07:00
Shahar Talmi da0e3c99f5 fix(input): escape forward slash in email regexp
This messed up with syntax coloring and variable hovering in chrome developer tools and made debugging really difficult.

Closes #8096
2014-07-07 16:26:27 -04:00
Julie Ralph a41c58e285 chore(tests): increase timeout for navigation in ng-href tests to avoid timeouts
Previously, the timeout for ng-href tests waiting for the url change after a link
was clicked was only 1000 ms. This was causing some flaky timeouts, so increasing
the wait to 5000 ms.
2014-07-07 11:21:33 -07:00
Julie Ralph bce5b49133 chore(e2e): update protractor to 1.0.0-rc2 and add more logging
Use the new options from the reporter to add more logging to end to end tests,
and increase the Jasmine test timeout from 30 seconds to 60 seconds to allow for
legitimately long-lasting tests.
2014-07-07 11:07:48 -07:00
Kevin Brogan 816b84230c fix(input): modify email validation regexp to match rfc1035
Previously, domain parts which began with or ended with a dash, would be accepted as valid. This CL matches Angular's email validation with that of Chromium and Firefox.

Closes #6026
2014-07-07 13:51:58 -04:00
Caitlin Potter 873acf8fab fix(parseKeyValue): ignore properties in prototype chain.
Previously, properties (typically functions) in the prototype chain (Object.prototype) would shadow
query parameters, and cause them to be serialized incorrectly.

This CL guards against this by using hasOwnProperty() to ensure that only own properties are a concern.

Closes #8070
Fixes #8068
2014-07-03 21:58:10 -04:00
Matias Niemelä 9063a0c2e7 chore(ngAnimate): fix broken IE8 tests for ngAnimateChildren 2014-07-04 02:14:57 +03:00
Chris Kuehl 03cbc0d6b1 docs(error/$rootScope/inprog): fix $timeout typo
Closes #8071
2014-07-03 17:33:02 -04:00
Matias Niemelä 931789ec14 feat(ngAnimate): conditionally allow child animations to run in parallel with parent animations
By default ngAnimate prevents child animations from running when a parent is performing an animation.
However there are a cases when an application should allow all child animations to run without blocking
each other. By placing the `ng-animate-children` flag in the template, this effect can now be put to
use within the template.

Closes #7946
2014-07-03 19:35:17 +03:00
Peter Bacon Darwin 9bc807783f docs($httpProvider): revert removal of comments
Related to #7782
2014-07-03 13:29:24 +01:00
Cory Boyd 2d6ee651b1 docs($httpProvider): add missing documentation
Add documentation for $httpProvider default values

Closes #6682
2014-07-03 13:24:48 +01:00
Peter Bacon Darwin 7ca24a8264 chore(docs/css): add margin between ul and p elements
Bootstrap CSS was removing the margin after ul elements if they were
descendents of other ul elements. But if the ul was followed by a p
then this looked terrible.

Related to #5953
2014-07-03 12:51:21 +01:00
Peter Bacon Darwin 1d8e42070a docs(tutorial/step-0): remove hyphen and clarify items
Closes #5953
2014-07-03 12:51:21 +01:00
Robert Kielty fe6b2fbfc4 docs(tutorial/step-7): improve injector information
I attempted to tighten up the language around the DI overview so that it was clearer
and more explicit. The sole responsibilities sentence was semantically jarring and
I think looks better as a list.  Some minor grammar improvements.

Closes #7099
2014-07-03 12:24:15 +01:00
Peter Bacon Darwin 5a222244fb docs(guide/controller): tweak initial example 2014-07-03 12:13:49 +01:00
cranesandcaff 4026074aba docs(guide/controller): only show best practice controller creation
If it is not recommended to use a global function to create controllers,
why should it be shown as possible in the documentation?

One of the most common complaints about AngularJS is that it doesn't enforce
any convention. This is intentional and I generally like this.
However if we can avoid outright bad implementations in examples I believe
we should.

Closes #8011
2014-07-03 12:13:49 +01:00
Peter Bacon Darwin d9a596addd docs(guide/di): further clarification of what can be injected 2014-07-03 10:13:58 +01:00
Artiom Neganov 8c0898b21c docs(guide/di): clarify what "services" can be injected into .config() and .run()
Closes #8106
2014-07-03 10:13:58 +01:00
Mike Haas d9b693bb7a docs($compile): fix minor typo
Closes #8048
2014-07-03 09:51:40 +01:00
Peter Bacon Darwin da94ab2e63 docs($logProvider): debugEnabled is a method not a property
Closes #7824
2014-07-03 09:51:40 +01:00
Peter Bacon Darwin 2fd8dc7061 docs($sce): fix code samples and example
The code samples were using `<pre>` tags rather than code fences (```) so they were
not being displayed correctly.

The inline code example (defined by a `<example>` element) had been placed in an
`@example` jsdoc tag, so rather than appearing inline at the declaration point in
the text, they were being appended to the end of the document in the `Example` section.

Closes #8053
2014-07-03 07:05:32 +01:00
Caitlin Potter 01012a4d7a chore(watchr-docs): remove watchr-docs.rb
This file hasn't changed in forever, and doesn't seem to be in use any longer.

Closes #7978
2014-07-02 17:59:58 -04:00
jpsimons ce84429adf docs($location): update $location.search() jsdoc signature
Closes #8050
2014-07-02 13:55:24 -07:00
Sekib Omazic a26acb64fe fix($location): remove query args when passed in object
Query args will be removed from $location search object if they are passed in as null or undefined object properties

Closes #6565
2014-07-01 08:41:15 -07:00
Igor Minar 7088ed1ed3 docs($parse): add missing 'isecobj' error page 2014-07-01 06:36:50 -07:00
Martin Staffa 7027844d42 fix($http): don't remove content-type header if data is set by request transform
Fixes #7910
2014-06-30 16:58:15 -07:00
Carlo s A. Guillen 16c584ed7f docs(CHANGELOG.md): add changes for 1.3.0-beta.14 and 1.2.19 2014-06-30 16:58:15 -07:00
118 changed files with 2573 additions and 1480 deletions
+8 -3
View File
@@ -1,6 +1,6 @@
language: node_js
node_js:
- 0.10
- '0.10'
branches:
except:
@@ -19,8 +19,13 @@ env:
- BROWSER_PROVIDER_READY_FILE=/tmp/sauce-connect-ready
install:
- npm config set registry http://23.251.144.68
- npm install
# - 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
# Run npm install twice, because it is flaky.
- npm install || npm install
before_script:
- mkdir -p $LOGS_DIR
+543
View File
@@ -1,3 +1,546 @@
<a name="1.3.0-beta.15"></a>
# 1.3.0-beta.15 unbelievable-advancement (2014-07-11)
## Bug Fixes
- **$animate:**
- ensure that parallel class-based animations are all eventually closed
([f07af61f](https://github.com/angular/angular.js/commit/f07af61f050fcdcece15c13ee8c6a6d32f86d3a1),
[#7766](https://github.com/angular/angular.js/issues/7766))
- remove the ng-animate className after canceling animation
([e18db78d](https://github.com/angular/angular.js/commit/e18db78d7793b1e94d9b19ac15b89d39f21a5729),
[#7784](https://github.com/angular/angular.js/issues/7784), [#7801](https://github.com/angular/angular.js/issues/7801), [#7894](https://github.com/angular/angular.js/issues/7894))
- **$http:**
- don't remove content-type header if data is set by request transform
([c7c363cf](https://github.com/angular/angular.js/commit/c7c363cf8d4533f94c5534c83dd1c7135633ddd8),
[#7910](https://github.com/angular/angular.js/issues/7910))
- add ability to remove default headers
([172a4093](https://github.com/angular/angular.js/commit/172a40931be5fe47e7732e5ba173895a1d59c5cd),
[#5784](https://github.com/angular/angular.js/issues/5784))
- **$location:** remove query args when passed in object
([2c7d0857](https://github.com/angular/angular.js/commit/2c7d0857ccbdb3a0967acc20e4346a7e1a6be792),
[#6565](https://github.com/angular/angular.js/issues/6565))
- **input:**
- escape forward slash in email regexp
([a88c215f](https://github.com/angular/angular.js/commit/a88c215f17829c1cfdec36bc1ef40bae10c41dff),
[#8096](https://github.com/angular/angular.js/issues/8096))
- modify email validation regexp to match rfc1035
([af6f943a](https://github.com/angular/angular.js/commit/af6f943a22f26cf2968f0ae3a1fab2fd09b52a2b),
[#6026](https://github.com/angular/angular.js/issues/6026))
- **jqLite:**
- correctly dealoc svg elements in IE
([012ab1f8](https://github.com/angular/angular.js/commit/012ab1f8745c8985d3f132c2dfa8fd84e7dc7041))
- remove exposed dealoc method
([9c5b407f](https://github.com/angular/angular.js/commit/9c5b407fd1e296dd525c129743f2b2b47da4dc0d))
- **ngModel:** test & update correct model when running $validate
([f3cb2741](https://github.com/angular/angular.js/commit/f3cb2741161353f387d02725637ce4ba062a9bc0),
[#7836](https://github.com/angular/angular.js/issues/7836), [#7837](https://github.com/angular/angular.js/issues/7837))
- **parseKeyValue:** ignore properties in prototype chain
([cb42766a](https://github.com/angular/angular.js/commit/cb42766a14f8123aa288b6e20f879141970fb84d),
[#8070](https://github.com/angular/angular.js/issues/8070), [#8068](https://github.com/angular/angular.js/issues/8068))
- **select:** auto-select new option that is marked as selected
([b8ae73e1](https://github.com/angular/angular.js/commit/b8ae73e17c19d9aebf572a75c05a7d981dcac807),
[#6828](https://github.com/angular/angular.js/issues/6828))
## Features
- **$animate:** allow directives to cancel animation events
([ca752790](https://github.com/angular/angular.js/commit/ca752790d95480b7ad1125a7ddb52b726b987a24),
[#7722](https://github.com/angular/angular.js/issues/7722))
- **$controller:** disable using global controller constructors
([3f2232b5](https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018))
- **FormController:** add `$rollbackViewValue` to rollback all controls
([85b77314](https://github.com/angular/angular.js/commit/85b77314ed8e4b45d7365a24a47349ed94672aeb),
[#7595](https://github.com/angular/angular.js/issues/7595))
- **input:** support constant expressions for ngTrueValue/ngFalseValue
([c90cefe1](https://github.com/angular/angular.js/commit/c90cefe16142d973a123e945fc9058e8a874c357),
[#8041](https://github.com/angular/angular.js/issues/8041), [#5346](https://github.com/angular/angular.js/issues/5346), [#1199](https://github.com/angular/angular.js/issues/1199))
- **ngAnimate:** conditionally allow child animations to run in parallel with parent animations
([8252b8be](https://github.com/angular/angular.js/commit/8252b8be946367f1759065adf528adc908da00a2),
[#7946](https://github.com/angular/angular.js/issues/7946))
- **ngModel:** bind to getters/setters
([b9fcf017](https://github.com/angular/angular.js/commit/b9fcf017316d37e91959949f56692644ce09d54a),
[#768](https://github.com/angular/angular.js/issues/768))
## Performance Improvements
- **$compile:** no longer need nodeType filter when setting $scope data
([b0ca5195](https://github.com/angular/angular.js/commit/b0ca5195e88a42611e933c49d7d2768b181b2d1b),
[#7887](https://github.com/angular/angular.js/issues/7887))
## Breaking Changes
- **$controller:** due to [3f2232b5](https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018),
`$controller` will no longer look for controllers on `window`.
The old behavior of looking on `window` for controllers was originally intended
for use in examples, demos, and toy apps. We found that allowing global controller
functions encouraged poor practices, so we resolved to disable this behavior by
default.
To migrate, register your controllers with modules rather than exposing them
as globals:
Before:
```javascript
function MyController() {
// ...
}
```
After:
```javascript
angular.module('myApp', []).controller('MyController', [function() {
// ...
}]);
```
Although it's not recommended, you can re-enable the old behavior like this:
```javascript
angular.module('myModule').config(['$controllerProvider', function($controllerProvider) {
// this option might be handy for migrating old apps, but please don't use it
// in new ones!
$controllerProvider.allowGlobals();
}]);
```
- **input:** due to [c90cefe1](https://github.com/angular/angular.js/commit/c90cefe16142d973a123e945fc9058e8a874c357),
Previously, these attributes would always be treated as strings. However, they are now parsed as
expressions, and will throw if an expression is non-constant.
To convert non-constant strings into constant expressions, simply wrap them in an extra pair of quotes, like so:
<input type="checkbox" ng-model="..." ng-true-value="'truthyValue'">
Closes #8041
Closes #5346
Closes #1199
<a name="1.2.20"></a>
# 1.2.20 accidental-beautification (2014-07-11)
## Bug Fixes
- **$http:**
- don't remove content-type header if data is set by request transform
([7027844d](https://github.com/angular/angular.js/commit/7027844d42cd428cb799f38f9e9b303da013ac4f),
[#7910](https://github.com/angular/angular.js/issues/7910))
- add ability to remove default headers
([172a4093](https://github.com/angular/angular.js/commit/172a40931be5fe47e7732e5ba173895a1d59c5cd),
[#5784](https://github.com/angular/angular.js/issues/5784))
- **$location:** remove query args when passed in object
([a26acb64](https://github.com/angular/angular.js/commit/a26acb64fe2ed3e05bf21ac1c058d6ac59b89870),
[#6565](https://github.com/angular/angular.js/issues/6565))
- **input:**
- escape forward slash in email regexp
([da0e3c99](https://github.com/angular/angular.js/commit/da0e3c99f51c196f58758841d4d8492a9fa09e20),
[#8096](https://github.com/angular/angular.js/issues/8096))
- modify email validation regexp to match rfc1035
([816b8423](https://github.com/angular/angular.js/commit/816b84230cdd8273ba19e8dec3b6f2e800f76612),
[#6026](https://github.com/angular/angular.js/issues/6026))
- **parseKeyValue:** ignore properties in prototype chain
([873acf8f](https://github.com/angular/angular.js/commit/873acf8fab3eb41914920259e713e1916e3c4f38),
[#8070](https://github.com/angular/angular.js/issues/8070), [#8068](https://github.com/angular/angular.js/issues/8068))
## Features
- **ngAnimate:** conditionally allow child animations to run in parallel with parent animations
([931789ec](https://github.com/angular/angular.js/commit/931789ec1476e1d06739e63cb423eb87172b5ebc),
[#7946](https://github.com/angular/angular.js/issues/7946))
<a name="1.3.0-beta.14"></a>
# 1.3.0-beta.14 harmonious-cacophonies (2014-06-30)
This release contains security fixes for $parse that prevent arbitrary code execution via Angular
expressions under some very specific conditions. The only applications affected by these
vulnerabilities are those that match all of the following conditions:
- application mixes server-side and client-side templating
- the server-side templating contains XSS vulnerabilities
- the vulnerabilities in the server-side templating are being guarded by server-side XSS filters or
on the client-side via [CSP](http://en.wikipedia.org/wiki/Content_Security_Policy)
- the server-side XSS vulnerabilities can be used to augment the client-side template processed by
Angular
Applications not meeting all of the conditions are not vulnerable.
This fix is in both 1.3.0-beta.14 and 1.2.19 release.
The Angular team would like to thank [Jann Horn](http://thejh.net) for reporting these
vulnerabilities via [security@angularjs.org].
## Bug Fixes
- **$compile:** bind ng-attr-* even if unbound attribute follows ng-attr-*
([8b0258d8](https://github.com/angular/angular.js/commit/8b0258d878cac20cd25c0958fd6e136a08b97df6),
[#7739](https://github.com/angular/angular.js/issues/7739))
- **$http:**
- should not read statusText on IE<10 when request is aborted
([31ae3e71](https://github.com/angular/angular.js/commit/31ae3e71647eadbbe1df40f9dedb55e1e0715f98))
- add the PATCH shortcut back
([b28b5caa](https://github.com/angular/angular.js/commit/b28b5caab1529b3970f10f0a4de43c0c975e3886),
[#5894](https://github.com/angular/angular.js/issues/5894))
- **$injector:** check if a fn is an array explicitly
([b1a6baac](https://github.com/angular/angular.js/commit/b1a6baac2de84a1ecdc000085e8bbd016eb5c100),
[#7904](https://github.com/angular/angular.js/issues/7904), [#2653](https://github.com/angular/angular.js/issues/2653))
- **$interval:** when canceling, use clearInterval from $window instead of global scope.
([a4904c0f](https://github.com/angular/angular.js/commit/a4904c0f83838222b98a875c56779a7f1a4a650a))
- **$parse:**
- prevent invocation of Function's bind, call and apply
([77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5))
- forbid __proto__ properties in angular expressions
([6081f207](https://github.com/angular/angular.js/commit/6081f20769e64a800ee8075c168412b21f026d99))
- forbid __{define,lookup}{Getter,Setter}__ properties
([48fa3aad](https://github.com/angular/angular.js/commit/48fa3aadd546036c7e69f71046f659ab1de244c6))
- forbid referencing Object in angular expressions
([528be29d](https://github.com/angular/angular.js/commit/528be29d1662122a34e204dd607e1c0bd9c16bbc))
- handle constants as one-time binding expressions
([d9763f1b](https://github.com/angular/angular.js/commit/d9763f1bd355190b9d4e5723e4632cbc232f0543),
[#7970](https://github.com/angular/angular.js/issues/7970))
- **$timeout/$interval:** if invokeApply is false, do not use evalAsync
([19b6b343](https://github.com/angular/angular.js/commit/19b6b3433ae9f8523cbc72ae97dbcf0c06960148),
[#7999](https://github.com/angular/angular.js/issues/7999), [#7103](https://github.com/angular/angular.js/issues/7103))
- **Angular:** nodeName should always be lowercase
([dafb8a3c](https://github.com/angular/angular.js/commit/dafb8a3cd12e7c3247838f536c25eb796331658d),
[#3987](https://github.com/angular/angular.js/issues/3987))
- **Angular.copy:** preserve prototype chain when copying objects
([b59b04f9](https://github.com/angular/angular.js/commit/b59b04f98a0b59eead53f6a53391ce1bbcbe9b57),
[#5063](https://github.com/angular/angular.js/issues/5063), [#3767](https://github.com/angular/angular.js/issues/3767), [#4996](https://github.com/angular/angular.js/issues/4996))
- **core:** drop the toBoolean function
([bdfc9c02](https://github.com/angular/angular.js/commit/bdfc9c02d021e08babfbc966a007c71b4946d69d),
[#3969](https://github.com/angular/angular.js/issues/3969), [#4277](https://github.com/angular/angular.js/issues/4277), [#7960](https://github.com/angular/angular.js/issues/7960))
- **injector:** allow multiple loading of function modules
([2f0a4488](https://github.com/angular/angular.js/commit/2f0a4488731fdb0e8217325dbb52a576defd09bd),
[#7255](https://github.com/angular/angular.js/issues/7255))
- **input:**
- improve html5 validation support
([1f6a5a1a](https://github.com/angular/angular.js/commit/1f6a5a1a9255a2db19a1ea4c04cdbcdbb2850b6c),
[#7936](https://github.com/angular/angular.js/issues/7936), [#7937](https://github.com/angular/angular.js/issues/7937))
- escape forward slash in email regexp
([b775e2bc](https://github.com/angular/angular.js/commit/b775e2bca1093e9df62a269b5bda968555ea0ded),
[#7938](https://github.com/angular/angular.js/issues/7938))
- **jqLite:**
- never add to the cache for non-element/document nodes
([91754a76](https://github.com/angular/angular.js/commit/91754a76e0ef9a7456a5b9819d1c5807c0a575bb),
[#7966](https://github.com/angular/angular.js/issues/7966))
- don't attach event handlers to comments or text nodes
([462dbb20](https://github.com/angular/angular.js/commit/462dbb2016a218d84760b6da171f1b15c9e416c3),
[#7913](https://github.com/angular/angular.js/issues/7913), [#7942](https://github.com/angular/angular.js/issues/7942))
- convert NodeList to an Array to make PhantomJS 1.x happy
([ceaea861](https://github.com/angular/angular.js/commit/ceaea861ebec957c99bbca6fd88ed33fbc15afbf),
[#7851](https://github.com/angular/angular.js/issues/7851))
- **numberFilter:** correctly round fractions despite floating-point arithmetics issues in JS
([189cd064](https://github.com/angular/angular.js/commit/189cd064feeb710fe54ee2ca83449b3eaf82b403),
[#7870](https://github.com/angular/angular.js/issues/7870), [#7878](https://github.com/angular/angular.js/issues/7878))
- **testabilityPatch:** fix invocations of angular.mock.dump
([e8e07502](https://github.com/angular/angular.js/commit/e8e07502776e48bf48b83a836f7422d164cbb1d7))
## Features
- **NgModel:**
- port the email input type to use the validators pipeline
([67379242](https://github.com/angular/angular.js/commit/6737924210570e8369ab72415e3098c6df4d3f6b))
- port the URL input type to use the validators pipeline
([3ee65730](https://github.com/angular/angular.js/commit/3ee65730639fc61d76e1055a6ca74e35eb48b838))
- **jqLite:** support isDefaultPrevented for triggerHandler dummies
([7e71acd1](https://github.com/angular/angular.js/commit/7e71acd1781ed44a7306d94338388c90f4420a24),
[#8008](https://github.com/angular/angular.js/issues/8008))
## Performance Improvements
- **forEach:** use native for loop instead of forEach for Arrays
([36625de0](https://github.com/angular/angular.js/commit/36625de0d3ebc1fc091af474d942c6ce16b0a1c0))
## Breaking Changes
- **$parse:**
- due to [77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5),
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
This is to disallow changing the behaviour of existing functions
in an unforseen fashion.
- due to [6081f207](https://github.com/angular/angular.js/commit/6081f20769e64a800ee8075c168412b21f026d99),
The (deprecated) __proto__ propery does not work inside angular expressions
anymore.
- due to [48fa3aad](https://github.com/angular/angular.js/commit/48fa3aadd546036c7e69f71046f659ab1de244c6),
This prevents the use of __{define,lookup}{Getter,Setter}__ inside angular
expressions. If you really need them for some reason, please wrap/bind them to make them
less dangerous, then make them available through the scope object.
- due to [528be29d](https://github.com/angular/angular.js/commit/528be29d1662122a34e204dd607e1c0bd9c16bbc),
This prevents the use of `Object` inside angular expressions.
If you need Object.keys, make it accessible in the scope.
- **Angular.copy:** due to [b59b04f9](https://github.com/angular/angular.js/commit/b59b04f98a0b59eead53f6a53391ce1bbcbe9b57),
This changes `angular.copy` so that it applies the prototype of the original
object to the copied object. Previously, `angular.copy` would copy properties
of the original object's prototype chain directly onto the copied object.
This means that if you iterate over only the copied object's `hasOwnProperty`
properties, it will no longer contain the properties from the prototype.
This is actually much more reasonable behaviour and it is unlikely that
applications are actually relying on this.
If this behaviour is relied upon, in an app, then one should simply iterate
over all the properties on the object (and its inherited properties) and
not filter them with `hasOwnProperty`.
**Be aware that this change also uses a feature that is not compatible with
IE8.** If you need this to work on IE8 then you would need to provide a polyfill
for `Object.create` and `Object.getPrototypeOf`.
- **core:** due to [bdfc9c02](https://github.com/angular/angular.js/commit/bdfc9c02d021e08babfbc966a007c71b4946d69d),
values 'f', '0', 'false', 'no', 'n', '[]' are no longer
treated as falsy. Only JavaScript falsy values are now treated as falsy by the
expression parser; there are six of them: false, null, undefined, NaN, 0 and "".
Closes #3969
Closes #4277
Closes #7960
<a name="1.2.19"></a>
# 1.2.19 precognitive-flashbacks (2014-06-30)
## Bug Fixes
- **$compile:** bind ng-attr-* even if unbound attribute follows ng-attr-*
([ed59370d](https://github.com/angular/angular.js/commit/ed59370d805a88c9ac012a8e417faf2a9f902776))
- **$http:** should not read statusText on IE<10 when request is aborted
([0c80df21](https://github.com/angular/angular.js/commit/0c80df21b66f4b147b6b55c27ad794be5802b411))
- **$injector:** check if a fn is an array explicitly
([67c11b9a](https://github.com/angular/angular.js/commit/67c11b9a3914a24aaf72f36bbe038ba5efa7ddf3),
[#7904](https://github.com/angular/angular.js/issues/7904), [#2653](https://github.com/angular/angular.js/issues/2653))
- **$interval:** when canceling, use clearInterval from $window instead of global scope.
([f780ccfa](https://github.com/angular/angular.js/commit/f780ccfa1c9a8d4c6191b0756ff77dc5749cf8c5))
- **$parse:**
- make the window check in ensureSafeObject IE8 friendly
([ba62e975](https://github.com/angular/angular.js/commit/ba62e975f1a0cebf08dedbb1501f72b166af66db))
- prevent invocation of Function's bind, call and apply
([07fa87a8](https://github.com/angular/angular.js/commit/07fa87a8a82b8be155d8c898bb79e5d9277adfb4))
- forbid __proto__ properties in angular expressions
([cb713e60](https://github.com/angular/angular.js/commit/cb713e6045413a25b54ad3267476fa29efd70646))
- forbid __{define,lookup}{Getter,Setter}__ properties
([89ca8597](https://github.com/angular/angular.js/commit/89ca8597341aa5585bcf728fa677022b7ec9c071))
- forbid referencing Object in angular expressions
([bc6fb7cc](https://github.com/angular/angular.js/commit/bc6fb7cc94afddcb11b94f74d13812a6be1cdb64))
- **injector:** allow multiple loading of function modules
([d71f16e7](https://github.com/angular/angular.js/commit/d71f16e7459f1d3705ccf47a13227d4727be9670),
[#7255](https://github.com/angular/angular.js/issues/7255))
- **input:**
- improve html5 validation support
([ab2e83c8](https://github.com/angular/angular.js/commit/ab2e83c8c8fa60ca15b1a9539a6587dc363b20f1),
[#7937](https://github.com/angular/angular.js/issues/7937), [#7957](https://github.com/angular/angular.js/issues/7957))
- escape forward slash in email regexp
([2a45cea0](https://github.com/angular/angular.js/commit/2a45cea0baaf615b799b54897bfe40d32381e7a2),
[#7938](https://github.com/angular/angular.js/issues/7938))
- **jqLite:** change expando property to a more unique name
([74e1cc68](https://github.com/angular/angular.js/commit/74e1cc683be315f6db05e22e185b3d27460d132a))
- **numberFilter:** correctly round fractions despite floating-point arithmetics issues in JS
([e5f454c8](https://github.com/angular/angular.js/commit/e5f454c8afc15336dc1faa52704a483cedfacd4a),
[#7870](https://github.com/angular/angular.js/issues/7870), [#7878](https://github.com/angular/angular.js/issues/7878))
- **testabilityPatch:** fix invocations of angular.mock.dump
([5e944a1c](https://github.com/angular/angular.js/commit/5e944a1cf1356bd069d3616f24323a0cb3ace87c))
## Performance Improvements
- **jqLite:** don't use reflection to access expandoId
([a4faa5cd](https://github.com/angular/angular.js/commit/a4faa5cde722556bd41d75daf346c63a9b6962e9))
## Breaking Changes
- **$parse:**
- due to [07fa87a8](https://github.com/angular/angular.js/commit/07fa87a8a82b8be155d8c898bb79e5d9277adfb4),
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
This is to disallow changing the behaviour of existing functions
in an unforseen fashion.
- due to [cb713e60](https://github.com/angular/angular.js/commit/cb713e6045413a25b54ad3267476fa29efd70646),
The (deprecated) __proto__ propery does not work inside angular expressions
anymore.
- due to [89ca8597](https://github.com/angular/angular.js/commit/89ca8597341aa5585bcf728fa677022b7ec9c071),
This prevents the use of __{define,lookup}{Getter,Setter}__ inside angular
expressions. If you really need them for some reason, please wrap/bind them to make them
less dangerous, then make them available through the scope object.
- due to [bc6fb7cc](https://github.com/angular/angular.js/commit/bc6fb7cc94afddcb11b94f74d13812a6be1cdb64),
This prevents the use of `Object` inside angular expressions.
If you need Object.keys, make it accessible in the scope.
<a name="1.3.0-beta.13"></a>
# 1.3.0-beta.13 idiosyncratic-numerification (2014-06-16)
## Bug Fixes
- **jqLite:** change expando property to a more unique name
([20c3c9e2](https://github.com/angular/angular.js/commit/20c3c9e25f6417773333727549ed2ca2d3505b44))
<a name="1.3.0-beta.12"></a>
# 1.3.0-beta.12 ephemeral-acceleration (2014-06-13)
## Bug Fixes
- **$compile:**
- ensure transclude works at root of templateUrl
([398053c5](https://github.com/angular/angular.js/commit/398053c56352487751d14ea41b3b892960397019),
[#7183](https://github.com/angular/angular.js/issues/7183), [#7772](https://github.com/angular/angular.js/issues/7772))
- always error if two directives add isolate-scope and new-scope
([2cde927e](https://github.com/angular/angular.js/commit/2cde927e58c8d1588569d94a797e43cdfbcedaf9),
[#4402](https://github.com/angular/angular.js/issues/4402), [#4421](https://github.com/angular/angular.js/issues/4421))
- **$injector:** report circularity in circular dependency error message
([545d22b4](https://github.com/angular/angular.js/commit/545d22b47006c1efa420ba551d4850affdba8016),
[#7500](https://github.com/angular/angular.js/issues/7500))
- **$parse:** Handle one-time to `null`
([600a41a7](https://github.com/angular/angular.js/commit/600a41a7b65f2dd139664fca6331c40451db75be),
[#7743](https://github.com/angular/angular.js/issues/7743), [#7787](https://github.com/angular/angular.js/issues/7787))
- **NgModel:**
- ensure pattern and ngPattern use the same validator
([1be9bb9d](https://github.com/angular/angular.js/commit/1be9bb9d3527e0758350c4f7417a4228d8571440))
- make ngMinlength and ngMaxlength as standalone directives
([26d91b65](https://github.com/angular/angular.js/commit/26d91b653ac224d9d4166fea855346f5e4c4a7b4),
[#6750](https://github.com/angular/angular.js/issues/6750))
- make sure the ngMinlength and ngMaxlength validators use the $validators pipeline
([5b8e7ecf](https://github.com/angular/angular.js/commit/5b8e7ecfeb722cfc7a5d92f05b57950a2aa6158b),
[#6304](https://github.com/angular/angular.js/issues/6304))
- make sure the pattern validator uses the $validators pipeline
([e63d4253](https://github.com/angular/angular.js/commit/e63d4253d06ed7d344358e2c0b03311c548bc978))
- make sure the required validator uses the $validators pipeline
([e53554a0](https://github.com/angular/angular.js/commit/e53554a0e238cba7a150fd7ccf61e5e4cc0c0426),
[#5164](https://github.com/angular/angular.js/issues/5164))
- **jqLite:** data should store data only on Element and Document nodes
([a196c8bc](https://github.com/angular/angular.js/commit/a196c8bca82a28c08896d31f1863cf4ecd11401c))
- **ngResource:** don't convert literal values into Resource objects when isArray is true
([16dfcb61](https://github.com/angular/angular.js/commit/16dfcb61aed28cdef3bfbed540e2deea6d9e9632),
[#6314](https://github.com/angular/angular.js/issues/6314), [#7741](https://github.com/angular/angular.js/issues/7741))
## Features
- **NgModel:** introduce the $validators pipeline
([a8c7cb81](https://github.com/angular/angular.js/commit/a8c7cb81c9e67b52d5c649bf3d8cec06c5976852))
- **attrs:** trigger observers for specific ng-attributes
([d9b90d7c](https://github.com/angular/angular.js/commit/d9b90d7c10a8e1bacbee0aeb7e86093cca9e8ed2),
[#7758](https://github.com/angular/angular.js/issues/7758))
- **input:** add $touched and $untouched states
([adcc5a00](https://github.com/angular/angular.js/commit/adcc5a00bf582d2b291c18e99093bb0854f7217c))
- **ngInclude:** emit $includeContentError when HTTP request fails
([e4419daf](https://github.com/angular/angular.js/commit/e4419daf705d6d2d116ced573f72c24b5c53be1f),
[#5803](https://github.com/angular/angular.js/issues/5803))
## Performance Improvements
- **$compile:** move ng-binding class stamping for interpolation into compile phase
([35358fdd](https://github.com/angular/angular.js/commit/35358fddc10652ef78c72cba7b7c2d5a810631d5))
- **$http:** move xsrf cookie check to after cache check in $http
([dd1d189e](https://github.com/angular/angular.js/commit/dd1d189ee785a37fe1d9bddf3818152db6aa210a),
[#7717](https://github.com/angular/angular.js/issues/7717))
- **Scope:** change Scope#id to be a simple number
([8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d))
- **forEach:** cache array length
([55991e33](https://github.com/angular/angular.js/commit/55991e33af6fece07ea347a059da061b76fc95f5))
- **isArray:** use native Array.isArray
([751ebc17](https://github.com/angular/angular.js/commit/751ebc17f7fc7be26613db0a3cdee05fc401318b),
[#7735](https://github.com/angular/angular.js/issues/7735))
- **isWindow** optimize internal isWindow call
([b68ac4cb](https://github.com/angular/angular.js/commit/b68ac4cb4c172447ba0022fe6e7ce0ca4cb9407e))
- **jqLite:**
- cache collection length for all methods that work on a single element
([41d2eba5](https://github.com/angular/angular.js/commit/41d2eba5f8322903247280000bfc5e5e8a1c1a3e))
- improve performance of jqLite#text
([92489886](https://github.com/angular/angular.js/commit/92489886dcce3bca00fe827aeb0817297b8a175c))
- optimize adding nodes to a jqLite collection
([31faeaa7](https://github.com/angular/angular.js/commit/31faeaa7293716251ed437fa54432bb89d9d48de))
- optimize element dealocation
([e35abc9d](https://github.com/angular/angular.js/commit/e35abc9d2fac0471cbe8089dc0e33a72b8029ada))
- don't use reflection to access expandoId
([ea9a130a](https://github.com/angular/angular.js/commit/ea9a130a43d165f4f4389d01ac409dd3047efcb4))
- **ngBind:** set the ng-binding class during compilation instead of linking
([fd5f3896](https://github.com/angular/angular.js/commit/fd5f3896764107635310ae52df1d80a6e08fba31))
- **shallowCopy:** use Object.keys to improve performance
([04468db4](https://github.com/angular/angular.js/commit/04468db44185e3d7968abdb23d77bf623cb5021b))
## Breaking Changes
- **$compile:** due to [2cde927e](https://github.com/angular/angular.js/commit/2cde927e58c8d1588569d94a797e43cdfbcedaf9),
Requesting isolate scope and any other scope on a single element is an error.
Before this change, the compiler let two directives request a child scope
and an isolate scope if the compiler applied them in the order of non-isolate
scope directive followed by isolate scope directive.
Now the compiler will error regardless of the order.
If you find that your code is now throwing a `$compile:multidir` error,
check that you do not have directives on the same element that are trying
to request both an isolate and a non-isolate scope and fix your code.
Closes #4402
Closes #4421
- **NgModel:** due to [1be9bb9d](https://github.com/angular/angular.js/commit/1be9bb9d3527e0758350c4f7417a4228d8571440),
If an expression is used on ng-pattern (such as `ng-pattern="exp"`) or on the
pattern attribute (something like on `pattern="{{ exp }}"`) and the expression
itself evaluates to a string then the validator will not parse the string as a
literal regular expression object (a value like `/abc/i`). Instead, the entire
string will be created as the regular expression to test against. This means
that any expression flags will not be placed on the RegExp object. To get around
this limitation, use a regular expression object as the value for the expression.
//before
$scope.exp = '/abc/i';
//after
$scope.exp = /abc/i;
- **Scope:** due to [8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d),
Scope#$id is now of time number rather than string. Since the
id is primarily being used for debugging purposes this change should not affect
anyone.
- **forEach:** due to [55991e33](https://github.com/angular/angular.js/commit/55991e33af6fece07ea347a059da061b76fc95f5),
forEach will iterate only over the initial number of items in
the array. So if items are added to the array during the iteration, these won't
be iterated over during the initial forEach call.
This change also makes our forEach behave more like Array#forEach.
- **jqLite:** due to [a196c8bc](https://github.com/angular/angular.js/commit/a196c8bca82a28c08896d31f1863cf4ecd11401c),
previously it was possible to set jqLite data on Text/Comment
nodes, but now that is allowed only on Element and Document nodes just like in
jQuery. We don't expect that app code actually depends on this accidental feature.
<a name="1.2.18"></a>
# 1.2.18 ear-extendability (2014-06-13)
+3
View File
@@ -107,6 +107,9 @@ module.exports = function(grunt) {
options: {
jshintrc: true,
},
tests: {
files: { src: 'test/**/*.js' },
},
ng: {
files: { src: files['angularSrc'] },
},
+4
View File
@@ -211,6 +211,10 @@ code.highlighted {
color:maroon;
}
ul + p {
margin-top: 10px;
}
.docs-version-jump {
min-width:100%;
max-width:100%;
+11
View File
@@ -0,0 +1,11 @@
@ngdoc error
@name $parse:isecobj
@fullName Referencing Object Disallowed
@description
Occurs when an expression attempts to access the 'Object' object (Root object in JavaScript).
Angular bans access to Object from within expressions since access is a known way to modify
the behaviour of existing objects.
To resolve this error, avoid Object access.
+1 -1
View File
@@ -161,7 +161,7 @@ In this second scenario, we are already inside a `$digest` when the ngFocus dire
call to `$apply()`, causing this error to be thrown.
It is possible to workaround this problem by moving the call to set the focus outside of the digest,
by using `$timeOut(fn, 0, false)`, where the `false` value tells Angular not to wrap this `fn` in a
by using `$timeout(fn, 0, false)`, where the `false` value tells Angular not to wrap this `fn` in a
`$apply` block:
```
+3 -3
View File
@@ -15,9 +15,9 @@ By default, only URLs that belong to the same origin are trusted. These are urls
The {@link ng.directive:ngInclude ngInclude} directive and {@link guide/directive directives} that specify a `templateUrl` require a trusted resource URL.
To load templates from other domains and/or protocols, either adjust the {@link
api/ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
api/ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
api/ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
**Note**: The browser's [Same Origin
Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest) and
+12 -11
View File
@@ -622,23 +622,24 @@ The Angular's compiler currently does not support two-way binding for methods (s
to the $location object (using {@link input[text] ngModel} directive on an input
field), you will need to specify an extra model property (e.g. `locationPath`) with two {@link ng.$rootScope.Scope#$watch $watchers}
which push $location updates in both directions. For example:
<example>
<example module="locationExample">
<file name="index.html">
<div ng-controller="LocationController">
<input type="text" ng-model="locationPath" />
</div>
</file>
<file name="script.js">
function LocationController($scope, $location) {
$scope.$watch('locationPath', function(path) {
$location.path(path);
});
$scope.$watch(function() {
return $location.path();
}, function(path) {
$scope.locationPath = path;
});
}
angular.module('locationExample', [])
.controller('LocationController', ['$scope', '$location', function ($scope, $location) {
$scope.$watch('locationPath', function(path) {
$location.path(path);
});
$scope.$watch(function() {
return $location.path();
}, function(path) {
$scope.locationPath = path;
});
}]);
</file>
</example>
+18 -25
View File
@@ -37,27 +37,8 @@ The properties contain the **view model** (the model that will be presented by t
`$scope` properties will be available to the template at the point in the DOM where the Controller
is registered.
The following example shows a very simple constructor function for a Controller, `GreetingController`,
which attaches a `greeting` property containing the string `'Hola!'` to the `$scope`:
```js
function GreetingController($scope) {
$scope.greeting = 'Hola!';
}
```
Once the Controller has been attached to the DOM, the `greeting` property can be data-bound to the
template:
```js
<div ng-controller="GreetingController">
{{ greeting }}
</div>
```
**NOTE**: Although Angular allows you to create Controller functions in the global scope, this is
not recommended. In a real application you should use the `.controller` method of your
{@link module Angular Module} for your application as follows:
The following example demonstrates creating a `GreetingController`, which attaches a `greeting`
property containing the string `'Hola!'` to the `$scope`:
```js
var myApp = angular.module('myApp',[]);
@@ -67,9 +48,24 @@ myApp.controller('GreetingController', ['$scope', function($scope) {
}]);
```
We create an {@link module Angular Module}, `myApp`, for our application. Then we add the controller's
constructor function to the module using the `.controller()` method. This keeps the controller's
constructor function out of the global scope.
<div class="alert alert-info">
We have used an **inline injection annotation** to explicitly specify the dependency
of the Controller on the `$scope` service provided by Angular. See the guide on
[Dependency Injection](http://docs.angularjs.org/guide/di) for more information.
{@link guide/di Dependency Injection} for more information.
</div>
We attach our controller to the DOM using the `ng-controller` directive. The `greeting` property can
now be data-bound to the template:
```js
<div ng-controller="GreetingController">
{{ greeting }}
</div>
```
# Adding Behavior to a Scope Object
@@ -333,6 +329,3 @@ describe('state', function() {
});
});
```
+13 -6
View File
@@ -218,15 +218,22 @@ DI is pervasive throughout Angular. You can use it when defining components or w
and `config` blocks for a module.
- Components such as services, directives, filters and animations are defined by an injectable factory
method or constructor function. These components can be injected with "service" components as
dependencies.
- The `run` and `config` methods accept a function, which can also be injected with "service"
method or constructor function. These components can be injected with "service" and "value"
components as dependencies.
- The `run` method accepts a function, which can be injected with "service", "value" and "constant"
components as dependencies. Note that you cannot inject "providers" into `run` blocks.
- The `config` method accepts a function, which can be injected with "provider" and "constant"
components as dependencies. Note that you cannot inject "service" or "value" components into
configuration
- Controllers are defined by a constructor function, which can be injected with any of the "service"
components as dependencies, but they can also be provided with special dependencies. See "DI in
Controllers" below.
and "value" components as dependencies, but they can also be provided with special dependencies. See
{@link di#controllers Controllers} below for a list of these special dependencies.
See {@link module#module-loading-dependencies Modules} for more details about injecting dependencies
into `run` and `config` blocks.
### Factory Methods
+23 -21
View File
@@ -50,9 +50,9 @@ the method from your view. If you want to `eval()` an Angular expression yoursel
You can try evaluating different expressions here:
<example>
<example module="expressionExample">
<file name="index.html">
<div ng-controller="Cntl2" class="expressions">
<div ng-controller="ExampleController" class="expressions">
Expression:
<input type='text' ng-model="expr" size="80"/>
<button ng-click="addExp(expr)">Evaluate</button>
@@ -66,23 +66,24 @@ You can try evaluating different expressions here:
</file>
<file name="script.js">
function Cntl2($scope) {
var exprs = $scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
exprs.push(expr);
};
angular.module('expressionExample', [])
.controller('ExampleController', ['$scope', function($scope) {
var exprs = $scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
exprs.push(expr);
};
$scope.removeExp = function(index) {
exprs.splice(index, 1);
};
}
$scope.removeExp = function(index) {
exprs.splice(index, 1);
};
}]);
</file>
<file name="protractor.js" type="protractor">
it('should allow user expression testing', function() {
element(by.css('.expressions button')).click();
var lis = element(by.css('.expressions ul')).element.all(by.repeater('expr in exprs'));
var lis = element(by.css('.expressions ul')).all(by.repeater('expr in exprs'));
expect(lis.count()).toBe(1);
expect(lis.get(0).getText()).toEqual('[ X ] 3*10|currency => $30.00');
});
@@ -101,9 +102,9 @@ This restriction is intentional. It prevents accidental access to the global sta
Instead use services like `$window` and `$location` in functions called from expressions. Such services
provide mockable access to globals.
<example>
<example module="expressionExample">
<file name="index.html">
<div class="example2" ng-controller="Cntl1">
<div class="example2" ng-controller="ExampleController">
Name: <input ng-model="name" type="text"/>
<button ng-click="greet()">Greet</button>
<button ng-click="window.alert('Should not see me')">Won't greet</button>
@@ -111,13 +112,14 @@ provide mockable access to globals.
</file>
<file name="script.js">
function Cntl1($window, $scope){
$scope.name = 'World';
angular.module('expressionExample', [])
.controller('ExampleController', ['$window', '$scope', function($window, $scope) {
$scope.name = 'World';
$scope.greet = function() {
$window.alert('Hello ' + $scope.name);
};
}
$scope.greet = function() {
$window.alert('Hello ' + $scope.name);
};
}]);
</file>
<file name="protractor.js" type="protractor">
+41 -38
View File
@@ -16,9 +16,9 @@ The key directive in understanding two-way data-binding is {@link ng.directive:n
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
In addition it provides an {@link ngModel.NgModelController API} for other directives to augment its behavior.
<example>
<example module="formExample">
<file name="index.html">
<div ng-controller="Controller">
<div ng-controller="ExampleController">
<form novalidate class="simple-form">
Name: <input type="text" ng-model="user.name" /><br />
E-mail: <input type="email" ng-model="user.email" /><br />
@@ -32,19 +32,20 @@ In addition it provides an {@link ngModel.NgModelController API} for other direc
</div>
<script>
function Controller($scope) {
$scope.master = {};
angular.module('formExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.master = {};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset();
}
$scope.reset();
}]);
</script>
</file>
</example>
@@ -67,9 +68,9 @@ The following example uses the CSS to display validity of each form control.
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
<example>
<example module="formExample">
<file name="index.html">
<div ng-controller="Controller">
<div ng-controller="ExampleController">
<form novalidate class="css-form">
Name:
<input type="text" ng-model="user.name" required /><br />
@@ -92,19 +93,20 @@ This ensures that the user is not distracted with an error until after interacti
</style>
<script>
function Controller($scope) {
$scope.master = {};
angular.module('formExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.master = {};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset();
}
$scope.reset();
}]);
</script>
</file>
</example>
@@ -130,7 +132,7 @@ This allows us to extend the above example with these features:
- SAVE button is enabled only if form has some changes and is valid
- custom error messages for `user.email` and `user.agree`
<example>
<example module="formExample">
<file name="index.html">
<div ng-controller="Controller">
<form name="form" class="css-form" novalidate>
@@ -159,23 +161,24 @@ This allows us to extend the above example with these features:
</file>
<file name="script.js">
function Controller($scope) {
$scope.master = {};
angular.module('formExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.master = {};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.isUnchanged = function(user) {
return angular.equals(user, $scope.master);
};
$scope.isUnchanged = function(user) {
return angular.equals(user, $scope.master);
};
$scope.reset();
}
$scope.reset();
}]);
</file>
</example>
+1 -1
View File
@@ -114,7 +114,7 @@ You write the following binding using the currency filter:
If your app is currently in the `en-US` locale, the browser will show `$1000.00`. If someone in the
Japanese locale (`ja`) views your app, their browser will show a balance of `¥1000.00` instead.
This is problematinc because $1000 is not the same as ¥1000.
This is problematic because $1000 is not the same as ¥1000.
In this case, you need to override the default currency symbol by providing the
{@link ng.filter:currency} currency filter with a currency symbol as a parameter.
+27 -25
View File
@@ -42,15 +42,16 @@ arrangement isolates the controller from the directive as well as from DOM. This
point since it makes the controllers view agnostic, which greatly improves the testing story of
the applications.
<example>
<example module="scopeExample">
<file name="script.js">
function MyController($scope) {
$scope.username = 'World';
angular.module('scopeExample', [])
.controller('MyController', ['$scope', function($scope) {
$scope.username = 'World';
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.username + '!';
};
}
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.username + '!';
};
}]);
</file>
<file name="index.html">
<div ng-controller="MyController">
@@ -122,13 +123,13 @@ inheritance, and child scopes prototypically inherit from their parents.
This example illustrates scopes in application, and prototypical inheritance of properties. The example is followed by
a diagram depicting the scope boundaries.
<example>
<example module="scopeExample">
<file name="index.html">
<div class="show-scope-demo">
<div ng-controller="GreetCtrl">
<div ng-controller="GreetController">
Hello {{name}}!
</div>
<div ng-controller="ListCtrl">
<div ng-controller="ListController">
<ol>
<li ng-repeat="name in names">{{name}} from {{department}}</li>
</ol>
@@ -136,14 +137,14 @@ a diagram depicting the scope boundaries.
</div>
</file>
<file name="script.js">
function GreetCtrl($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
angular.module('scopeExample', [])
.controller('GreetController', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}])
.controller('ListController', ['$scope', function($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}]);
</file>
<file name="style.css">
.show-scope-demo.ng-scope,
@@ -190,14 +191,15 @@ Scopes can propagate events in similar fashion to DOM events. The event can be {
ng.$rootScope.Scope#$broadcast broadcasted} to the scope children or {@link
ng.$rootScope.Scope#$emit emitted} to scope parents.
<example>
<example module="eventExample">
<file name="script.js">
function EventController($scope) {
$scope.count = 0;
$scope.$on('MyEvent', function() {
$scope.count++;
});
}
angular.module('eventExample', [])
.controller('EventController', ['$scope', function($scope) {
$scope.count = 0;
$scope.$on('MyEvent', function() {
$scope.count++;
});
}]);
</file>
<file name="index.html">
<div ng-controller="EventController">
+4 -2
View File
@@ -88,8 +88,10 @@ being the element on which the `ngApp` directive was defined.
Nothing here {{'yet' + '!'}}
This line demonstrates the core feature of Angular's templating capabilities a binding, denoted
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
This line demonstrates two core features of Angular's templating capabilities:
* a binding, denoted by double-curlies `{{ }}`
* a simple expression `'yet' + '!'` used in this binding.
The binding tells Angular that it should evaluate an expression and insert the result into the
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
+11 -6
View File
@@ -78,12 +78,17 @@ utilize the browser's history (back and forward navigation) and bookmarks.
As you {@link tutorial/step_05 noticed}, {@link guide/di dependency injection} (DI) is at the core of
AngularJS, so it's important for you to understand a thing or two about how it works.
When the application bootstraps, Angular creates an injector that will be used for all DI stuff in
this app. The injector itself doesn't know anything about what `$http` or `$route` services do, in
fact it doesn't even know about the existence of these services unless it is configured with proper
module definitions. The sole responsibilities of the injector are to load specified module
definition(s), register all service providers defined in these modules, and when asked, inject
a specified function with dependencies (services) that it lazily instantiates via their providers.
When the application bootstraps, Angular creates an injector that will be used to find and inject all
of the services that are required by your app. The injector itself doesn't know anything about what
`$http` or `$route` services do, in fact it doesn't even know about the existence of these services
unless it is configured with proper module definitions.
The injector only carries out the following steps :
* load the module definition(s) that you specify in your app
* register all Providers defined in these module definitions
* when asked to do so, inject a specified function and any necessary dependencies (services) that
it lazily instantiates via their Providers.
Providers are objects that provide (create) instances of services and expose configuration APIs
that can be used to control the creation and runtime behavior of a service. In case of the `$route`
+106 -3
View File
@@ -2690,13 +2690,100 @@
}
},
"protractor": {
"version": "0.19.0",
"version": "1.0.0-rc4",
"dependencies": {
"request": {
"version": "2.36.0",
"dependencies": {
"qs": {
"version": "0.6.6"
},
"json-stringify-safe": {
"version": "5.0.0"
},
"mime": {
"version": "1.2.11"
},
"forever-agent": {
"version": "0.5.2"
},
"node-uuid": {
"version": "1.4.1"
},
"tough-cookie": {
"version": "0.12.1",
"dependencies": {
"punycode": {
"version": "1.2.4"
}
}
},
"form-data": {
"version": "0.1.4",
"dependencies": {
"combined-stream": {
"version": "0.0.5",
"dependencies": {
"delayed-stream": {
"version": "0.0.5"
}
}
},
"async": {
"version": "0.9.0"
}
}
},
"tunnel-agent": {
"version": "0.4.0"
},
"http-signature": {
"version": "0.10.0",
"dependencies": {
"assert-plus": {
"version": "0.1.2"
},
"asn1": {
"version": "0.1.11"
},
"ctype": {
"version": "0.5.2"
}
}
},
"oauth-sign": {
"version": "0.3.0"
},
"hawk": {
"version": "1.0.0",
"dependencies": {
"hoek": {
"version": "0.9.1"
},
"boom": {
"version": "0.4.2"
},
"cryptiles": {
"version": "0.2.2"
},
"sntp": {
"version": "0.2.4"
}
}
},
"aws-sign2": {
"version": "0.5.0"
}
}
},
"selenium-webdriver": {
"version": "2.39.0"
"version": "2.42.1"
},
"minijasminenode": {
"version": "0.2.7"
"version": "1.1.1"
},
"jasminewd": {
"version": "1.0.3"
},
"saucelabs": {
"version": "0.1.1"
@@ -2733,6 +2820,22 @@
"version": "0.0.8"
}
}
},
"lodash": {
"version": "2.4.1"
},
"source-map-support": {
"version": "0.2.6",
"dependencies": {
"source-map": {
"version": "0.1.32",
"dependencies": {
"amdefine": {
"version": "0.1.0"
}
}
}
}
}
}
},
+1 -1
View File
@@ -33,7 +33,7 @@
"karma-sauce-launcher": "0.2.0",
"karma-script-launcher": "0.1.0",
"karma-browserstack-launcher": "0.0.7",
"protractor": "~0.19.0",
"protractor": "1.0.0-rc4",
"yaml-js": "~0.0.8",
"rewire": "1.1.3",
"promises-aplus-tests": "~1.3.2",
+2 -1
View File
@@ -22,6 +22,7 @@ exports.config = {
},
jasmineNodeOpts: {
defaultTimeoutInterval: 30000
defaultTimeoutInterval: 60000,
showTiming: true
}
};
+16 -15
View File
@@ -731,9 +731,9 @@ function isLeafNode (node) {
* @returns {*} The copy or updated `destination`, if `destination` was specified.
*
* @example
<example>
<example module="copyExample">
<file name="index.html">
<div ng-controller="Controller">
<div ng-controller="ExampleController">
<form novalidate class="simple-form">
Name: <input type="text" ng-model="user.name" /><br />
E-mail: <input type="email" ng-model="user.email" /><br />
@@ -747,21 +747,22 @@ function isLeafNode (node) {
</div>
<script>
function Controller($scope) {
$scope.master= {};
angular.module('copyExample')
.controller('ExampleController', ['$scope', function($scope) {
$scope.master= {};
$scope.update = function(user) {
// Example with 1 argument
$scope.master= angular.copy(user);
};
$scope.update = function(user) {
// Example with 1 argument
$scope.master= angular.copy(user);
};
$scope.reset = function() {
// Example with 2 arguments
angular.copy($scope.master, $scope.user);
};
$scope.reset = function() {
// Example with 2 arguments
angular.copy($scope.master, $scope.user);
};
$scope.reset();
}
$scope.reset();
}]);
</script>
</file>
</example>
@@ -1105,7 +1106,7 @@ function parseKeyValue(/**string*/keyValue) {
key = tryDecodeURIComponent(key_value[0]);
if ( isDefined(key) ) {
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
if (!obj[key]) {
if (!hasOwnProperty.call(obj, key)) {
obj[key] = val;
} else if(isArray(obj[key])) {
obj[key].push(val);
+8 -9
View File
@@ -162,7 +162,7 @@
* local name. Given `<widget my-attr="count = count + value">` and widget definition of
* `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
* a function wrapper for the `count = count + value` expression. Often it's desirable to
* pass data from the isolated scope via an expression and to the parent scope, this can be
* pass data from the isolated scope via an expression to the parent scope, this can be
* done by passing a map of local variable names and values into the expression wrapper fn.
* For example, if the expression is `increment(amount)` then we can specify the amount value
* by calling the `localFn` as `localFn({amount: 22})`.
@@ -389,10 +389,10 @@
* to illustrate how `$compile` works.
* </div>
*
<example module="compile">
<example module="compileExample">
<file name="index.html">
<script>
angular.module('compile', [], function($compileProvider) {
angular.module('compileExample', [], function($compileProvider) {
// configure new 'compile' directive by passing a directive
// factory function. The factory function injects the '$compile'
$compileProvider.directive('compile', function($compile) {
@@ -416,15 +416,14 @@
}
);
};
})
});
function Ctrl($scope) {
});
})
.controller('GreeterController', ['$scope', function($scope) {
$scope.name = 'Angular';
$scope.html = 'Hello {{name}}';
}
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="GreeterController">
<input ng-model="name"> <br>
<textarea ng-model="html"></textarea> <br>
<div compile="html"></div>
+2 -2
View File
@@ -66,7 +66,7 @@
return browser.driver.getCurrentUrl().then(function(url) {
return url.match(/\/123$/);
});
}, 1000, 'page should navigate to /123');
}, 5000, 'page should navigate to /123');
});
xit('should execute ng-click but not reload when href empty string and name specified', function() {
@@ -94,7 +94,7 @@
return browser.driver.getCurrentUrl().then(function(url) {
return url.match(/\/6$/);
});
}, 1000, 'page should navigate to /6');
}, 5000, 'page should navigate to /6');
});
</file>
</example>
+6 -5
View File
@@ -314,12 +314,13 @@ function FormController(element, attrs, $scope, $animate) {
* </pre>
*
* @example
<example deps="angular-animate.js" animations="true" fixBase="true">
<example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.userType = 'guest';
}
angular.module('formExample', [])
.controller('FormController', ['$scope', function($scope) {
$scope.userType = 'guest';
}]);
</script>
<style>
.my-form {
@@ -331,7 +332,7 @@ function FormController(element, attrs, $scope, $animate) {
background: red;
}
</style>
<form name="myForm" ng-controller="Ctrl" class="my-form">
<form name="myForm" ng-controller="FormController" class="my-form">
userType: <input name="input" ng-model="userType" required>
<span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
<tt>userType = {{userType}}</tt><br>
+77 -66
View File
@@ -9,7 +9,7 @@
*/
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
var inputType = {
@@ -39,15 +39,16 @@ var inputType = {
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
*
* @example
<example name="text-input-directive">
<example name="text-input-directive" module="textInputExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.text = 'guest';
$scope.word = /^\s*\w*\s*$/;
}
angular.module('textInputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.text = 'guest';
$scope.word = /^\s*\w*\s*$/;
}]);
</script>
<form name="myForm" ng-controller="Ctrl">
<form name="myForm" ng-controller="ExampleController">
Single word: <input type="text" name="input" ng-model="text"
ng-pattern="word" required ng-trim="false">
<span class="error" ng-show="myForm.input.$error.required">
@@ -119,14 +120,15 @@ var inputType = {
* interaction with the input element.
*
* @example
<example name="number-input-directive">
<example name="number-input-directive" module="numberExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.value = 12;
}
angular.module('numberExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.value = 12;
}]);
</script>
<form name="myForm" ng-controller="Ctrl">
<form name="myForm" ng-controller="ExampleController">
Number: <input type="number" name="input" ng-model="value"
min="0" max="99" required>
<span class="error" ng-show="myForm.input.$error.required">
@@ -194,14 +196,15 @@ var inputType = {
* interaction with the input element.
*
* @example
<example name="url-input-directive">
<example name="url-input-directive" module="urlExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.text = 'http://google.com';
}
angular.module('urlExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.text = 'http://google.com';
}]);
</script>
<form name="myForm" ng-controller="Ctrl">
<form name="myForm" ng-controller="ExampleController">
URL: <input type="url" name="input" ng-model="text" required>
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
@@ -270,14 +273,15 @@ var inputType = {
* interaction with the input element.
*
* @example
<example name="email-input-directive">
<example name="email-input-directive" module="emailExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.text = 'me@example.com';
}
angular.module('emailExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.text = 'me@example.com';
}]);
</script>
<form name="myForm" ng-controller="Ctrl">
<form name="myForm" ng-controller="ExampleController">
Email: <input type="email" name="input" ng-model="text" required>
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
@@ -336,18 +340,19 @@ var inputType = {
* be set when selected.
*
* @example
<example name="radio-input-directive">
<example name="radio-input-directive" module="radioExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.color = 'blue';
$scope.specialValue = {
"id": "12345",
"value": "green"
};
}
angular.module('radioExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.color = 'blue';
$scope.specialValue = {
"id": "12345",
"value": "green"
};
}]);
</script>
<form name="myForm" ng-controller="Ctrl">
<form name="myForm" ng-controller="ExampleController">
<input type="radio" ng-model="color" value="red"> Red <br/>
<input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
<input type="radio" ng-model="color" value="blue"> Blue <br/>
@@ -386,15 +391,16 @@ var inputType = {
* interaction with the input element.
*
* @example
<example name="checkbox-input-directive">
<example name="checkbox-input-directive" module="checkboxExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.value1 = true;
$scope.value2 = 'YES'
}
angular.module('checkboxExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.value1 = true;
$scope.value2 = 'YES'
}]);
</script>
<form name="myForm" ng-controller="Ctrl">
<form name="myForm" ng-controller="ExampleController">
Value1: <input type="checkbox" ng-model="value1"> <br/>
Value2: <input type="checkbox" ng-model="value2"
ng-true-value="YES" ng-false-value="NO"> <br/>
@@ -794,14 +800,15 @@ function checkboxInputType(scope, element, attr, ctrl) {
* interaction with the input element.
*
* @example
<example name="input-directive">
<example name="input-directive" module="inputExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.user = {name: 'guest', last: 'visitor'};
}
angular.module('inputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.user = {name: 'guest', last: 'visitor'};
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<form name="myForm">
User name: <input type="text" name="userName" ng-model="user.name" required>
<span class="error" ng-show="myForm.userName.$error.required">
@@ -1319,12 +1326,13 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* </pre>
*
* @example
* <example deps="angular-animate.js" animations="true" fixBase="true">
* <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.val = '1';
}
angular.module('inputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.val = '1';
}]);
</script>
<style>
.my-input {
@@ -1339,7 +1347,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
</style>
Update input to see transitions when valid/invalid.
Integer is a valid value.
<form name="testForm" ng-controller="Ctrl">
<form name="testForm" ng-controller="ExampleController">
<input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
</form>
</file>
@@ -1383,17 +1391,18 @@ var ngModelDirective = function() {
* in input value.
*
* @example
* <example name="ngChange-directive">
* <example name="ngChange-directive" module="changeExample">
* <file name="index.html">
* <script>
* function Controller($scope) {
* $scope.counter = 0;
* $scope.change = function() {
* $scope.counter++;
* };
* }
* angular.module('changeExample', [])
* .controller('ExampleController', ['$scope', function($scope) {
* $scope.counter = 0;
* $scope.change = function() {
* $scope.counter++;
* };
* }]);
* </script>
* <div ng-controller="Controller">
* <div ng-controller="ExampleController">
* <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
* <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
* <label for="ng-change-example2">Confirmed</label><br />
@@ -1474,14 +1483,15 @@ var requiredDirective = function() {
* specified in form `/something/` then the value will be converted into a regular expression.
*
* @example
<example name="ngList-directive">
<example name="ngList-directive" module="listExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.names = ['igor', 'misko', 'vojta'];
}
angular.module('listExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.names = ['igor', 'misko', 'vojta'];
}]);
</script>
<form name="myForm" ng-controller="Ctrl">
<form name="myForm" ng-controller="ExampleController">
List: <input name="namesInput" ng-model="names" ng-list required>
<span class="error" ng-show="myForm.namesInput.$error.required">
Required!</span>
@@ -1573,15 +1583,16 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
* of the `input` element
*
* @example
<example name="ngValue-directive">
<example name="ngValue-directive" module="valueExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.names = ['pizza', 'unicorns', 'robots'];
$scope.my = { favorite: 'unicorns' };
}
angular.module('valueExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.names = ['pizza', 'unicorns', 'robots'];
$scope.my = { favorite: 'unicorns' };
}]);
</script>
<form ng-controller="Ctrl">
<form ng-controller="ExampleController">
<h2>Which is your favorite?</h2>
<label ng-repeat="name in names" for="{{name}}">
{{name}}
+21 -19
View File
@@ -26,14 +26,15 @@
*
* @example
* Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
<example>
<example module="bindExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.name = 'Whirled';
}
angular.module('bindExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.name = 'Whirled';
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
Enter name: <input type="text" ng-model="name"><br>
Hello <span ng-bind="name"></span>!
</div>
@@ -84,15 +85,16 @@ var ngBindDirective = ngDirective({
*
* @example
* Try it here: enter text in text box and watch the greeting change.
<example>
<example module="bindExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.salutation = 'Hello';
$scope.name = 'World';
}
angular.module('bindExample', [])
.controller('ExampleController', ['$scope', function ($scope) {
$scope.salutation = 'Hello';
$scope.name = 'World';
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
Salutation: <input type="text" ng-model="salutation"><br>
Name: <input type="text" ng-model="name"><br>
<pre ng-bind-template="{{salutation}} {{name}}!"></pre>
@@ -150,20 +152,20 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
* @example
Try it here: enter text in text box and watch the greeting change.
<example module="ngBindHtmlExample" deps="angular-sanitize.js">
<example module="bindHtmlExample" deps="angular-sanitize.js">
<file name="index.html">
<div ng-controller="ngBindHtmlCtrl">
<div ng-controller="ExampleController">
<p ng-bind-html="myHTML"></p>
</div>
</file>
<file name="script.js">
angular.module('ngBindHtmlExample', ['ngSanitize'])
.controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
$scope.myHTML =
'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
}]);
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.myHTML =
'I am an <code>HTML</code>string with ' +
'<a href="#">links!</a> and other <em>stuff</em>';
}]);
</file>
<file name="protractor.js" type="protractor">
+28 -22
View File
@@ -54,7 +54,7 @@
*
* This example demonstrates the `controller as` syntax.
*
* <example name="ngControllerAs">
* <example name="ngControllerAs" module="controllerAsExample">
* <file name="index.html">
* <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
* Name: <input type="text" ng-model="settings.name"/>
@@ -75,6 +75,9 @@
* </div>
* </file>
* <file name="app.js">
* angular.module('controllerAsExample', [])
* .controller('SettingsController1', SettingsController1);
*
* function SettingsController1() {
* this.name = "John Smith";
* this.contacts = [
@@ -103,29 +106,29 @@
* <file name="protractor.js" type="protractor">
* it('should check controller as', function() {
* var container = element(by.id('ctrl-as-exmpl'));
* expect(container.findElement(by.model('settings.name'))
* expect(container.element(by.model('settings.name'))
* .getAttribute('value')).toBe('John Smith');
*
* var firstRepeat =
* container.findElement(by.repeater('contact in settings.contacts').row(0));
* container.element(by.repeater('contact in settings.contacts').row(0));
* var secondRepeat =
* container.findElement(by.repeater('contact in settings.contacts').row(1));
* container.element(by.repeater('contact in settings.contacts').row(1));
*
* expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('408 555 1212');
*
* expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
* expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('john.smith@example.org');
*
* firstRepeat.findElement(by.linkText('clear')).click();
* firstRepeat.element(by.linkText('clear')).click();
*
* expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('');
*
* container.findElement(by.linkText('add')).click();
* container.element(by.linkText('add')).click();
*
* expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
* .findElement(by.model('contact.value'))
* expect(container.element(by.repeater('contact in settings.contacts').row(2))
* .element(by.model('contact.value'))
* .getAttribute('value'))
* .toBe('yourname@example.org');
* });
@@ -134,7 +137,7 @@
*
* This example demonstrates the "attach to `$scope`" style of controller.
*
* <example name="ngController">
* <example name="ngController" module="controllerExample">
* <file name="index.html">
* <div id="ctrl-exmpl" ng-controller="SettingsController2">
* Name: <input type="text" ng-model="name"/>
@@ -155,6 +158,9 @@
* </div>
* </file>
* <file name="app.js">
* angular.module('controllerExample', [])
* .controller('SettingsController2', ['$scope', SettingsController2]);
*
* function SettingsController2($scope) {
* $scope.name = "John Smith";
* $scope.contacts = [
@@ -184,28 +190,28 @@
* it('should check controller', function() {
* var container = element(by.id('ctrl-exmpl'));
*
* expect(container.findElement(by.model('name'))
* expect(container.element(by.model('name'))
* .getAttribute('value')).toBe('John Smith');
*
* var firstRepeat =
* container.findElement(by.repeater('contact in contacts').row(0));
* container.element(by.repeater('contact in contacts').row(0));
* var secondRepeat =
* container.findElement(by.repeater('contact in contacts').row(1));
* container.element(by.repeater('contact in contacts').row(1));
*
* expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('408 555 1212');
* expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
* expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('john.smith@example.org');
*
* firstRepeat.findElement(by.linkText('clear')).click();
* firstRepeat.element(by.linkText('clear')).click();
*
* expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('');
*
* container.findElement(by.linkText('add')).click();
* container.element(by.linkText('add')).click();
*
* expect(container.findElement(by.repeater('contact in contacts').row(2))
* .findElement(by.model('contact.value'))
* expect(container.element(by.repeater('contact in contacts').row(2))
* .element(by.model('contact.value'))
* .getAttribute('value'))
* .toBe('yourname@example.org');
* });
+14 -13
View File
@@ -313,21 +313,22 @@ forEach(
* ({@link guide/expression#-event- Event object is available as `$event`})
*
* @example
<example>
<example module="submitExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.list = [];
$scope.text = 'hello';
$scope.submit = function() {
if ($scope.text) {
$scope.list.push(this.text);
$scope.text = '';
}
};
}
angular.module('submitExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.list = [];
$scope.text = 'hello';
$scope.submit = function() {
if ($scope.text) {
$scope.list.push(this.text);
$scope.text = '';
}
};
}]);
</script>
<form ng-submit="submit()" ng-controller="Ctrl">
<form ng-submit="submit()" ng-controller="ExampleController">
Enter text and hit enter:
<input type="text" ng-model="text" name="text" />
<input type="submit" id="submit" value="Submit" />
@@ -339,7 +340,7 @@ forEach(
expect(element(by.binding('list')).getText()).toBe('list=[]');
element(by.css('#submit')).click();
expect(element(by.binding('list')).getText()).toContain('hello');
expect(element(by.input('text')).getAttribute('value')).toBe('');
expect(element(by.model('text')).getAttribute('value')).toBe('');
});
it('should ignore empty strings', function() {
expect(element(by.binding('list')).getText()).toBe('list=[]');
+11 -10
View File
@@ -43,9 +43,9 @@
* - Otherwise enable scrolling only if the expression evaluates to truthy value.
*
* @example
<example module="ngAnimate" deps="angular-animate.js" animations="true">
<example module="includeExample" deps="angular-animate.js" animations="true">
<file name="index.html">
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<select ng-model="template" ng-options="t.name for t in templates">
<option value="">(blank)</option>
</select>
@@ -57,12 +57,13 @@
</div>
</file>
<file name="script.js">
function Ctrl($scope) {
$scope.templates =
[ { name: 'template1.html', url: 'template1.html'},
{ name: 'template2.html', url: 'template2.html'} ];
$scope.template = $scope.templates[0];
}
angular.module('includeExample', ['ngAnimate'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.templates =
[ { name: 'template1.html', url: 'template1.html'},
{ name: 'template2.html', url: 'template2.html'} ];
$scope.template = $scope.templates[0];
}]);
</file>
<file name="template1.html">
Content of template1.html
@@ -125,7 +126,7 @@
return;
}
templateSelect.click();
templateSelect.element.all(by.css('option')).get(2).click();
templateSelect.all(by.css('option')).get(2).click();
expect(includeElem.getText()).toMatch(/Content of template2.html/);
});
@@ -135,7 +136,7 @@
return;
}
templateSelect.click();
templateSelect.element.all(by.css('option')).get(0).click();
templateSelect.all(by.css('option')).get(0).click();
expect(includeElem.isPresent()).toBe(false);
});
</file>
+6 -5
View File
@@ -29,14 +29,15 @@
* @param {expression} ngInit {@link guide/expression Expression} to eval.
*
* @example
<example>
<example module="initExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.list = [['a', 'b'], ['c', 'd']];
}
angular.module('initExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.list = [['a', 'b'], ['c', 'd']];
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<div ng-repeat="innerList in list" ng-init="outerIndex = $index">
<div ng-repeat="value in innerList" ng-init="innerIndex = $index">
<span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
+8 -7
View File
@@ -89,16 +89,17 @@
* @param {number=} offset Offset to deduct from the total number.
*
* @example
<example>
<example module="pluralizeExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.person1 = 'Igor';
$scope.person2 = 'Misko';
$scope.personCount = 1;
}
angular.module('pluralizeExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.person1 = 'Igor';
$scope.person2 = 'Misko';
$scope.personCount = 1;
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
+9 -8
View File
@@ -55,9 +55,9 @@
*
*
* @example
<example module="ngAnimate" deps="angular-animate.js" animations="true">
<example module="switchExample" deps="angular-animate.js" animations="true">
<file name="index.html">
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<select ng-model="selection" ng-options="item for item in items">
</select>
<tt>selection={{selection}}</tt>
@@ -71,10 +71,11 @@
</div>
</file>
<file name="script.js">
function Ctrl($scope) {
$scope.items = ['settings', 'home', 'other'];
$scope.selection = $scope.items[0];
}
angular.module('switchExample', ['ngAnimate'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.items = ['settings', 'home', 'other'];
$scope.selection = $scope.items[0];
}]);
</file>
<file name="animations.css">
.animate-switch-container {
@@ -117,11 +118,11 @@
expect(switchElem.getText()).toMatch(/Settings Div/);
});
it('should change to home', function() {
select.element.all(by.css('option')).get(1).click();
select.all(by.css('option')).get(1).click();
expect(switchElem.getText()).toMatch(/Home Span/);
});
it('should select default', function() {
select.element.all(by.css('option')).get(2).click();
select.all(by.css('option')).get(2).click();
expect(switchElem.getText()).toMatch(/default/);
});
</file>
+8 -9
View File
@@ -13,15 +13,10 @@
* @element ANY
*
* @example
<example module="transclude">
<example module="transcludeExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.title = 'Lorem Ipsum';
$scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
}
angular.module('transclude', [])
angular.module('transcludeExample', [])
.directive('pane', function(){
return {
restrict: 'E',
@@ -32,9 +27,13 @@
'<div ng-transclude></div>' +
'</div>'
};
});
})
.controller('ExampleController', ['$scope', function($scope) {
$scope.title = 'Lorem Ipsum';
$scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<input ng-model="title"><br>
<textarea ng-model="text"></textarea> <br/>
<pane title="{{title}}">{{text}}</pane>
+14 -13
View File
@@ -72,21 +72,22 @@ var ngOptionsMinErr = minErr('ngOptions');
* `value` variable (e.g. `value.propertyName`).
*
* @example
<example>
<example module="selectExample">
<file name="index.html">
<script>
function MyCntrl($scope) {
$scope.colors = [
{name:'black', shade:'dark'},
{name:'white', shade:'light'},
{name:'red', shade:'dark'},
{name:'blue', shade:'dark'},
{name:'yellow', shade:'light'}
];
$scope.myColor = $scope.colors[2]; // red
}
angular.module('selectExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.colors = [
{name:'black', shade:'dark'},
{name:'white', shade:'light'},
{name:'red', shade:'dark'},
{name:'blue', shade:'dark'},
{name:'yellow', shade:'light'}
];
$scope.myColor = $scope.colors[2]; // red
}]);
</script>
<div ng-controller="MyCntrl">
<div ng-controller="ExampleController">
<ul>
<li ng-repeat="color in colors">
Name: <input ng-model="color.name">
@@ -123,7 +124,7 @@ var ngOptionsMinErr = minErr('ngOptions');
<file name="protractor.js" type="protractor">
it('should check ng-options', function() {
expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
element.all(by.select('myColor')).first().click();
element.all(by.model('myColor')).first().click();
element.all(by.css('select[ng-model="myColor"] option')).first().click();
expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
element(by.css('.nullable select[ng-model="myColor"]')).click();
+7 -6
View File
@@ -9,18 +9,19 @@
* A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
*
* @example
<example>
<example module="documentExample">
<file name="index.html">
<div ng-controller="MainCtrl">
<div ng-controller="ExampleController">
<p>$document title: <b ng-bind="title"></b></p>
<p>window.document title: <b ng-bind="windowTitle"></b></p>
</div>
</file>
<file name="script.js">
function MainCtrl($scope, $document) {
$scope.title = $document[0].title;
$scope.windowTitle = angular.element(window.document)[0].title;
}
angular.module('documentExample', [])
.controller('ExampleController', ['$scope', '$document', function($scope, $document) {
$scope.title = $document[0].title;
$scope.windowTitle = angular.element(window.document)[0].title;
}]);
</file>
</example>
*/
+12 -10
View File
@@ -15,14 +15,15 @@
*
*
* @example
<example>
<example module="currencyExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.amount = 1234.56;
}
angular.module('currencyExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.amount = 1234.56;
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<input type="number" ng-model="amount"> <br>
default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
@@ -74,14 +75,15 @@ function currencyFilter($locale) {
* @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
*
* @example
<example>
<example module="numberFilterExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.val = 1234.56789;
}
angular.module('numberFilterExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.val = 1234.56789;
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
Enter number: <input ng-model='val'><br>
Default formatting: <span id='number-default'>{{val | number}}</span><br>
No fractions: <span>{{val | number:0}}</span><br>
+9 -8
View File
@@ -19,17 +19,18 @@
* had less than `limit` elements.
*
* @example
<example>
<example module="limitToExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.numbers = [1,2,3,4,5,6,7,8,9];
$scope.letters = "abcdefghi";
$scope.numLimit = 3;
$scope.letterLimit = 3;
}
angular.module('limitToExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.numbers = [1,2,3,4,5,6,7,8,9];
$scope.letters = "abcdefghi";
$scope.numLimit = 3;
$scope.letterLimit = 3;
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
<p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
+28 -27
View File
@@ -28,20 +28,21 @@
* @returns {Array} Sorted copy of the source array.
*
* @example
<example>
<example module="orderByExample">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.friends =
[{name:'John', phone:'555-1212', age:10},
{name:'Mary', phone:'555-9876', age:19},
{name:'Mike', phone:'555-4321', age:21},
{name:'Adam', phone:'555-5678', age:35},
{name:'Julie', phone:'555-8765', age:29}]
$scope.predicate = '-age';
}
angular.module('orderByExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.friends =
[{name:'John', phone:'555-1212', age:10},
{name:'Mary', phone:'555-9876', age:19},
{name:'Mike', phone:'555-4321', age:21},
{name:'Adam', phone:'555-5678', age:35},
{name:'Julie', phone:'555-8765', age:29}];
$scope.predicate = '-age';
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
<hr/>
[ <a href="" ng-click="predicate=''">unsorted</a> ]
@@ -69,7 +70,7 @@
* Example:
*
* @example
<example>
<example module="orderByExample">
<file name="index.html">
<div ng-controller="Ctrl">
<table class="friend">
@@ -89,21 +90,21 @@
</file>
<file name="script.js">
function Ctrl($scope, $filter) {
var orderBy = $filter('orderBy');
$scope.friends = [
{ name: 'John', phone: '555-1212', age: 10 },
{ name: 'Mary', phone: '555-9876', age: 19 },
{ name: 'Mike', phone: '555-4321', age: 21 },
{ name: 'Adam', phone: '555-5678', age: 35 },
{ name: 'Julie', phone: '555-8765', age: 29 }
];
$scope.order = function(predicate, reverse) {
$scope.friends = orderBy($scope.friends, predicate, reverse);
};
$scope.order('-age',false);
}
angular.module('orderByExample', [])
.controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
var orderBy = $filter('orderBy');
$scope.friends = [
{ name: 'John', phone: '555-1212', age: 10 },
{ name: 'Mary', phone: '555-9876', age: 19 },
{ name: 'Mike', phone: '555-4321', age: 21 },
{ name: 'Adam', phone: '555-5678', age: 35 },
{ name: 'Julie', phone: '555-8765', age: 29 }
];
$scope.order = function(predicate, reverse) {
$scope.friends = orderBy($scope.friends, predicate, reverse);
};
$scope.order('-age',false);
}]);
</file>
</example>
*/
+55 -28
View File
@@ -83,12 +83,39 @@ function isSuccess(status) {
}
/**
* @ngdoc provider
* @name $httpProvider
* @description
* Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
* */
function $HttpProvider() {
var JSON_START = /^\s*(\[|\{[^\{])/,
JSON_END = /[\}\]]\s*$/,
PROTECTION_PREFIX = /^\)\]\}',?\n/,
CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
/**
* @ngdoc property
* @name $httpProvider#defaults
* @description
*
* Object containing default values for all {@link ng.$http $http} requests.
*
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
* Defaults value is `'XSRF-TOKEN'`.
*
* - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
* XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
*
* - **`defaults.headers`** - {Object} - Default headers for all $http requests.
* Refer to {@link ng.$http#setting-http-headers $http} for documentation on
* setting default headers.
* - **`defaults.headers.common`**
* - **`defaults.headers.post`**
* - **`defaults.headers.put`**
* - **`defaults.headers.patch`**
**/
var defaults = this.defaults = {
// transform incoming response data
transformResponse: [function(data) {
@@ -578,9 +605,9 @@ function $HttpProvider() {
*
*
* @example
<example>
<example module="httpExample">
<file name="index.html">
<div ng-controller="FetchCtrl">
<div ng-controller="FetchController">
<select ng-model="method">
<option>GET</option>
<option>JSONP</option>
@@ -602,30 +629,32 @@ function $HttpProvider() {
</div>
</file>
<file name="script.js">
function FetchCtrl($scope, $http, $templateCache) {
$scope.method = 'GET';
$scope.url = 'http-hello.html';
angular.module('httpExample', [])
.controller('FetchController', ['$scope', '$http', '$templateCache',
function($scope, $http, $templateCache) {
$scope.method = 'GET';
$scope.url = 'http-hello.html';
$scope.fetch = function() {
$scope.code = null;
$scope.response = null;
$scope.fetch = function() {
$scope.code = null;
$scope.response = null;
$http({method: $scope.method, url: $scope.url, cache: $templateCache}).
success(function(data, status) {
$scope.status = status;
$scope.data = data;
}).
error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
};
$http({method: $scope.method, url: $scope.url, cache: $templateCache}).
success(function(data, status) {
$scope.status = status;
$scope.data = data;
}).
error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
};
$scope.updateModel = function(method, url) {
$scope.method = method;
$scope.url = url;
};
}
$scope.updateModel = function(method, url) {
$scope.method = method;
$scope.url = url;
};
}]);
</file>
<file name="http-hello.html">
Hello, $http!
@@ -679,7 +708,7 @@ function $HttpProvider() {
var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
// strip content-type if data is undefined
if (isUndefined(config.data)) {
if (isUndefined(reqData)) {
forEach(headers, function(value, header) {
if (lowercase(header) === 'content-type') {
delete headers[header];
@@ -748,10 +777,6 @@ function $HttpProvider() {
defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
// execute if header value is function
execHeaders(defHeaders);
execHeaders(reqHeaders);
// using for-in instead of forEach to avoid unecessary iteration after header has been found
defaultHeadersIteration:
for (defHeaderName in defHeaders) {
@@ -766,6 +791,8 @@ function $HttpProvider() {
reqHeaders[defHeaderName] = defHeaders[defHeaderName];
}
// execute if header value is a function for merged headers
execHeaders(reqHeaders);
return reqHeaders;
function execHeaders(headers) {
+38 -37
View File
@@ -42,25 +42,27 @@ function $IntervalProvider() {
* @returns {promise} A promise which will be notified on each iteration.
*
* @example
* <example module="time">
* <file name="index.html">
* <script>
* function Ctrl2($scope,$interval) {
* $scope.format = 'M/d/yy h:mm:ss a';
* $scope.blood_1 = 100;
* $scope.blood_2 = 120;
* <example module="intervalExample">
* <file name="index.html">
* <script>
* angular.module('intervalExample', [])
* .controller('ExampleController', ['$scope', '$interval',
* function($scope, $interval) {
* $scope.format = 'M/d/yy h:mm:ss a';
* $scope.blood_1 = 100;
* $scope.blood_2 = 120;
*
* var stop;
* $scope.fight = function() {
* // Don't start a new fight if we are already fighting
* if ( angular.isDefined(stop) ) return;
* var stop;
* $scope.fight = function() {
* // 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;
* $scope.blood_1 = $scope.blood_1 - 3;
* $scope.blood_2 = $scope.blood_2 - 4;
* } else {
* $scope.stopFight();
* $scope.stopFight();
* }
* }, 100);
* };
@@ -75,22 +77,21 @@ function $IntervalProvider() {
* $scope.resetFight = function() {
* $scope.blood_1 = 100;
* $scope.blood_2 = 120;
* }
* };
*
* $scope.$on('$destroy', function() {
* // Make sure that the interval is destroyed too
* // Make sure that the interval nis destroyed too
* $scope.stopFight();
* });
* }
*
* angular.module('time', [])
* // Register the 'myCurrentTime' directive factory method.
* // We inject $interval and dateFilter service since the factory method is DI.
* .directive('myCurrentTime', function($interval, dateFilter) {
* })
* // Register the 'myCurrentTime' directive factory method.
* // We inject $interval and dateFilter service since the factory method is DI.
* .directive('myCurrentTime', ['$interval', 'dateFilter',
* function($interval, dateFilter) {
* // return the directive link function. (compile function not needed)
* return function(scope, element, attrs) {
* var format, // date format
* stopTime; // so that we can cancel the time updates
* stopTime; // so that we can cancel the time updates
*
* // used to update the UI
* function updateTime() {
@@ -106,28 +107,28 @@ function $IntervalProvider() {
* stopTime = $interval(updateTime, 1000);
*
* // listen on DOM destroy (removal) event, and cancel the next UI update
* // to prevent updating time ofter the DOM element was removed.
* // to prevent updating time after the DOM element was removed.
* element.bind('$destroy', function() {
* $interval.cancel(stopTime);
* });
* }
* });
* </script>
* </script>
*
* <div>
* <div ng-controller="Ctrl2">
* Date format: <input ng-model="format"> <hr/>
* Current time is: <span my-current-time="format"></span>
* <hr/>
* Blood 1 : <font color='red'>{{blood_1}}</font>
* Blood 2 : <font color='red'>{{blood_2}}</font>
* <button type="button" data-ng-click="fight()">Fight</button>
* <button type="button" data-ng-click="stopFight()">StopFight</button>
* <button type="button" data-ng-click="resetFight()">resetFight</button>
* </div>
* <div>
* <div ng-controller="ExampleController">
* Date format: <input ng-model="format"> <hr/>
* Current time is: <span my-current-time="format"></span>
* <hr/>
* Blood 1 : <font color='red'>{{blood_1}}</font>
* Blood 2 : <font color='red'>{{blood_2}}</font>
* <button type="button" data-ng-click="fight()">Fight</button>
* <button type="button" data-ng-click="stopFight()">StopFight</button>
* <button type="button" data-ng-click="resetFight()">resetFight</button>
* </div>
* </div>
*
* </file>
* </file>
* </example>
*/
function interval(fn, delay, count, invokeApply) {
+10 -2
View File
@@ -427,14 +427,17 @@ LocationHashbangInHtml5Url.prototype =
* If the argument is a hash object containing an array of values, these values will be encoded
* as duplicate search parameters in the url.
*
* @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will
* override only a single search property.
* @param {(string|Array<string>|boolean)=} paramValue If `search` is a string, then `paramValue`
* will override only a single search property.
*
* If `paramValue` is an array, it will override the property of the `search` component of
* `$location` specified via the first argument.
*
* If `paramValue` is `null`, the property specified via the first argument will be deleted.
*
* If `paramValue` is `true`, the property specified via the first argument will be added with no
* value nor trailing equal sign.
*
* @return {Object} If called with no arguments returns the parsed `search` object. If called with
* one or more arguments returns `$location` object itself.
*/
@@ -446,6 +449,11 @@ LocationHashbangInHtml5Url.prototype =
if (isString(search)) {
this.$$search = parseKeyValue(search);
} else if (isObject(search)) {
// remove object undefined or null properties
forEach(search, function(value, key) {
if (value == null) delete search[key];
});
this.$$search = search;
} else {
throw $locationMinErr('isrcharg',
+8 -7
View File
@@ -15,15 +15,16 @@
* {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
*
* @example
<example>
<example module="logExample">
<file name="script.js">
function LogCtrl($scope, $log) {
$scope.$log = $log;
$scope.message = 'Hello World!';
}
angular.module('logExample', [])
.controller('LogController', ['$scope', '$log', function($scope, $log) {
$scope.$log = $log;
$scope.message = 'Hello World!';
}]);
</file>
<file name="index.html">
<div ng-controller="LogCtrl">
<div ng-controller="LogController">
<p>Reload this page with open console, enter text and hit the log button...</p>
Message:
<input type="text" ng-model="message"/>
@@ -47,7 +48,7 @@ function $LogProvider(){
self = this;
/**
* @ngdoc property
* @ngdoc method
* @name $logProvider#debugEnabled
* @description
* @param {boolean=} flag enable or disable debug level messages
+1 -26
View File
@@ -985,26 +985,6 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
};
}
function simpleGetterFn1(key0, fullExp) {
ensureSafeMemberName(key0, fullExp);
return function simpleGetterFn1(scope, locals) {
if (scope == null) return undefined;
return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
};
}
function simpleGetterFn2(key0, key1, fullExp) {
ensureSafeMemberName(key0, fullExp);
ensureSafeMemberName(key1, fullExp);
return function simpleGetterFn2(scope, locals) {
if (scope == null) return undefined;
scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
return scope == null ? undefined : scope[key1];
};
}
function getterFn(path, options, fullExp) {
// Check whether the cache has this getter already.
// We can use hasOwnProperty directly on the cache because we ensure,
@@ -1017,13 +997,8 @@ function getterFn(path, options, fullExp) {
pathKeysLength = pathKeys.length,
fn;
// When we have only 1 or 2 tokens, use optimized special case closures.
// http://jsperf.com/angularjs-parse-getter/6
if (!options.unwrapPromises && pathKeysLength === 1) {
fn = simpleGetterFn1(pathKeys[0], fullExp);
} else if (!options.unwrapPromises && pathKeysLength === 2) {
fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
} else if (options.csp) {
if (options.csp) {
if (pathKeysLength < 6) {
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
options);
+93 -92
View File
@@ -112,19 +112,21 @@ function adjustMatchers(matchers) {
*
* Here is what a secure configuration for this scenario might look like:
*
* <pre class="prettyprint">
* angular.module('myApp', []).config(function($sceDelegateProvider) {
* $sceDelegateProvider.resourceUrlWhitelist([
* // Allow same origin resource loads.
* 'self',
* // Allow loading from our assets domain. Notice the difference between * and **.
* 'http://srv*.assets.example.com/**']);
* ```
* angular.module('myApp', []).config(function($sceDelegateProvider) {
* $sceDelegateProvider.resourceUrlWhitelist([
* // Allow same origin resource loads.
* 'self',
* // Allow loading from our assets domain. Notice the difference between * and **.
* 'http://srv*.assets.example.com/**'
* ]);
*
* // The blacklist overrides the whitelist so the open redirect here is blocked.
* $sceDelegateProvider.resourceUrlBlacklist([
* 'http://myapp.example.com/clickThru**']);
* });
* </pre>
* // The blacklist overrides the whitelist so the open redirect here is blocked.
* $sceDelegateProvider.resourceUrlBlacklist([
* 'http://myapp.example.com/clickThru**'
* ]);
* });
* ```
*/
function $SceDelegateProvider() {
@@ -419,10 +421,10 @@ function $SceDelegateProvider() {
*
* Here's an example of a binding in a privileged context:
*
* <pre class="prettyprint">
* <input ng-model="userHtml">
* <div ng-bind-html="userHtml">
* </pre>
* ```
* <input ng-model="userHtml">
* <div ng-bind-html="userHtml"></div>
* ```
*
* Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE
* disabled, this application allows the user to render arbitrary HTML into the DIV.
@@ -462,15 +464,15 @@ function $SceDelegateProvider() {
* ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly
* simplified):
*
* <pre class="prettyprint">
* var ngBindHtmlDirective = ['$sce', function($sce) {
* return function(scope, element, attr) {
* scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
* element.html(value || '');
* });
* };
* }];
* </pre>
* ```
* var ngBindHtmlDirective = ['$sce', function($sce) {
* return function(scope, element, attr) {
* scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
* element.html(value || '');
* });
* };
* }];
* ```
*
* ## Impact on loading templates
*
@@ -574,66 +576,65 @@ function $SceDelegateProvider() {
*
* ## Show me an example using SCE.
*
* @example
<example module="mySceApp" deps="angular-sanitize.js">
<file name="index.html">
<div ng-controller="myAppController as myCtrl">
<i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
<b>User comments</b><br>
By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
$sanitize is available. If $sanitize isn't available, this results in an error instead of an
exploit.
<div class="well">
<div ng-repeat="userComment in myCtrl.userComments">
<b>{{userComment.name}}</b>:
<span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
<br>
</div>
</div>
</div>
</file>
<file name="script.js">
var mySceApp = angular.module('mySceApp', ['ngSanitize']);
mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
var self = this;
$http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
self.userComments = userComments;
});
self.explicitlyTrustedHtml = $sce.trustAsHtml(
'<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
'sanitization.&quot;">Hover over this text.</span>');
});
</file>
<file name="test_data.json">
[
{ "name": "Alice",
"htmlComment":
"<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
},
{ "name": "Bob",
"htmlComment": "<i>Yes!</i> Am I the only other one?"
}
]
</file>
<file name="protractor.js" type="protractor">
describe('SCE doc demo', function() {
it('should sanitize untrusted values', function() {
expect(element(by.css('.htmlComment')).getInnerHtml())
.toBe('<span>Is <i>anyone</i> reading this?</span>');
});
it('should NOT sanitize explicitly trusted values', function() {
expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
'<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
'sanitization.&quot;">Hover over this text.</span>');
});
});
</file>
</example>
* <example module="mySceApp" deps="angular-sanitize.js">
* <file name="index.html">
* <div ng-controller="myAppController as myCtrl">
* <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
* <b>User comments</b><br>
* By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
* $sanitize is available. If $sanitize isn't available, this results in an error instead of an
* exploit.
* <div class="well">
* <div ng-repeat="userComment in myCtrl.userComments">
* <b>{{userComment.name}}</b>:
* <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
* <br>
* </div>
* </div>
* </div>
* </file>
*
* <file name="script.js">
* var mySceApp = angular.module('mySceApp', ['ngSanitize']);
*
* mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
* var self = this;
* $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
* self.userComments = userComments;
* });
* self.explicitlyTrustedHtml = $sce.trustAsHtml(
* '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
* 'sanitization.&quot;">Hover over this text.</span>');
* });
* </file>
*
* <file name="test_data.json">
* [
* { "name": "Alice",
* "htmlComment":
* "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
* },
* { "name": "Bob",
* "htmlComment": "<i>Yes!</i> Am I the only other one?"
* }
* ]
* </file>
*
* <file name="protractor.js" type="protractor">
* describe('SCE doc demo', function() {
* it('should sanitize untrusted values', function() {
* expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
* .toBe('<span>Is <i>anyone</i> reading this?</span>');
* });
*
* it('should NOT sanitize explicitly trusted values', function() {
* expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
* '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
* 'sanitization.&quot;">Hover over this text.</span>');
* });
* });
* </file>
* </example>
*
*
*
@@ -647,13 +648,13 @@ function $SceDelegateProvider() {
*
* That said, here's how you can completely disable SCE:
*
* <pre class="prettyprint">
* angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
* // Completely disable SCE. For demonstration purposes only!
* // Do not use in new projects.
* $sceProvider.enabled(false);
* });
* </pre>
* ```
* angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
* // Completely disable SCE. For demonstration purposes only!
* // Do not use in new projects.
* $sceProvider.enabled(false);
* });
* ```
*
*/
/* jshint maxlen: 100 */
+8 -7
View File
@@ -16,17 +16,18 @@
* expression.
*
* @example
<example>
<example module="windowExample">
<file name="index.html">
<script>
function Ctrl($scope, $window) {
$scope.greeting = 'Hello, World!';
$scope.doGreeting = function(greeting) {
angular.module('windowExample', [])
.controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
$scope.greeting = 'Hello, World!';
$scope.doGreeting = function(greeting) {
$window.alert(greeting);
};
}
};
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
<input type="text" ng-model="greeting" />
<button ng-click="doGreeting(greeting)">ALERT</button>
</div>
+75 -19
View File
@@ -58,8 +58,22 @@
* <ANY class="slide" ng-include="..."></ANY>
* ```
*
* Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's
* animation has completed.
* Keep in mind that, by default, if an animation is running, any child elements cannot be animated
* until the parent element's animation has completed. This blocking feature can be overridden by
* placing the `ng-animate-children` attribute on a parent container tag.
*
* ```html
* <div class="slide-animation" ng-if="on" ng-animate-children>
* <div class="fade-animation" ng-if="on">
* <div class="explode-animation" ng-if="on">
* ...
* </div>
* </div>
* </div>
* ```
*
* When the `on` expression value changes and an animation is triggered then each of the elements within
* will all animate without the block being applied to child elements.
*
* <h2>CSS-defined Animations</h2>
* The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
@@ -249,6 +263,19 @@ angular.module('ngAnimate', ['ng'])
* Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
*
*/
.directive('ngAnimateChildren', function() {
var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
return function(scope, element, attrs) {
var val = attrs.ngAnimateChildren;
if(angular.isString(val) && val.length === 0) { //empty attribute
element.data(NG_ANIMATE_CHILDREN, true);
} else {
scope.$watch(val, function(value) {
element.data(NG_ANIMATE_CHILDREN, !!value);
});
}
};
})
//this private service is only used within CSS-enabled animations
//IE8 + IE9 do not support rAF natively, but that is fine since they
@@ -277,6 +304,7 @@ angular.module('ngAnimate', ['ng'])
var ELEMENT_NODE = 1;
var NG_ANIMATE_STATE = '$$ngAnimateState';
var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
var NG_ANIMATE_CLASS_NAME = 'ng-animate';
var rootAnimateState = {running: true};
@@ -326,6 +354,12 @@ angular.module('ngAnimate', ['ng'])
return classNameFilter.test(className);
};
function blockElementAnimations(element) {
var data = element.data(NG_ANIMATE_STATE) || {};
data.running = true;
element.data(NG_ANIMATE_STATE, data);
}
function lookup(name) {
if (name) {
var matches = [],
@@ -552,7 +586,7 @@ angular.module('ngAnimate', ['ng'])
parentElement = prepareElement(parentElement);
afterElement = prepareElement(afterElement);
this.enabled(false, element);
blockElementAnimations(element);
$delegate.enter(element, parentElement, afterElement);
$rootScope.$$postDigest(function() {
element = stripCommentsFromElement(element);
@@ -590,7 +624,7 @@ angular.module('ngAnimate', ['ng'])
leave : function(element, doneCallback) {
element = angular.element(element);
cancelChildAnimations(element);
this.enabled(false, element);
blockElementAnimations(element);
$rootScope.$$postDigest(function() {
performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
$delegate.leave(element);
@@ -634,7 +668,7 @@ angular.module('ngAnimate', ['ng'])
afterElement = prepareElement(afterElement);
cancelChildAnimations(element);
this.enabled(false, element);
blockElementAnimations(element);
$delegate.move(element, parentElement, afterElement);
$rootScope.$$postDigest(function() {
element = stripCommentsFromElement(element);
@@ -808,9 +842,12 @@ angular.module('ngAnimate', ['ng'])
//only allow animations if the currently running animation is not structural
//or if there is no animation running at all
var skipAnimations = runner.isClassBased ?
ngAnimateState.disabled || (lastAnimation && !lastAnimation.isClassBased) :
false;
var skipAnimations;
if (runner.isClassBased) {
skipAnimations = ngAnimateState.running ||
ngAnimateState.disabled ||
(lastAnimation && !lastAnimation.isClassBased);
}
//skip the animation if animations are disabled, a parent is already being animated,
//the element is not currently attached to the document body or then completely close
@@ -1027,30 +1064,49 @@ angular.module('ngAnimate', ['ng'])
}
function animationsDisabled(element, parentElement) {
if (rootAnimateState.disabled) return true;
if(isMatchingElement(element, $rootElement)) {
return rootAnimateState.disabled || rootAnimateState.running;
if (rootAnimateState.disabled) {
return true;
}
if (isMatchingElement(element, $rootElement)) {
return rootAnimateState.running;
}
var allowChildAnimations, parentRunningAnimation, hasParent;
do {
//the element did not reach the root element which means that it
//is not apart of the DOM. Therefore there is no reason to do
//any animations on it
if(parentElement.length === 0) break;
if (parentElement.length === 0) break;
var isRoot = isMatchingElement(parentElement, $rootElement);
var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
var result = state && (!!state.disabled || state.running || state.totalActive > 0);
if(isRoot || result) {
return result;
var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {});
if (state.disabled) {
return true;
}
if(isRoot) return true;
//no matter what, for an animation to work it must reach the root element
//this implies that the element is attached to the DOM when the animation is run
if (isRoot) {
hasParent = true;
}
//once a flag is found that is strictly false then everything before
//it will be discarded and all child animations will be restricted
if (allowChildAnimations !== false) {
var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN);
if(angular.isDefined(animateChildrenFlag)) {
allowChildAnimations = animateChildrenFlag;
}
}
parentRunningAnimation = parentRunningAnimation ||
state.running ||
(state.last && !state.last.isClassBased);
}
while(parentElement = parentElement.parent());
return true;
return !hasParent || (!allowChildAnimations && parentRunningAnimation);
}
}]);
+16 -14
View File
@@ -34,12 +34,13 @@ angular.module('ngCookies', ['ng']).
* @example
*
* ```js
* function ExampleController($cookies) {
* // Retrieving a cookie
* var favoriteCookie = $cookies.myFavorite;
* // Setting a cookie
* $cookies.myFavorite = 'oatmeal';
* }
* angular.module('cookiesExample', ['ngCookies'])
* .controller('ExampleController', ['$cookies', function($cookies) {
* // Retrieving a cookie
* var favoriteCookie = $cookies.myFavorite;
* // Setting a cookie
* $cookies.myFavorite = 'oatmeal';
* }]);
* ```
*/
factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
@@ -137,14 +138,15 @@ angular.module('ngCookies', ['ng']).
* @example
*
* ```js
* function ExampleController($cookies) {
* // Put cookie
* $cookieStore.put('myFavorite','oatmeal');
* // Get cookie
* var favoriteCookie = $cookieStore.get('myFavorite');
* // Removing a cookie
* $cookieStore.remove('myFavorite');
* }
* angular.module('cookieStoreExample', ['ngCookies'])
* .controller('ExampleController', ['$cookieStore', function($cookieStore) {
* // Put cookie
* $cookieStore.put('myFavorite','oatmeal');
* // Get cookie
* var favoriteCookie = $cookieStore.get('myFavorite');
* // Removing a cookie
* $cookieStore.remove('myFavorite');
* }]);
* ```
*/
factory('$cookieStore', ['$cookies', function($cookies) {
+12 -11
View File
@@ -21,20 +21,21 @@
<span ng-bind-html="linky_expression | linky"></span>
*
* @example
<example module="ngSanitize" deps="angular-sanitize.js">
<example module="linkyExample" deps="angular-sanitize.js">
<file name="index.html">
<script>
function Ctrl($scope) {
$scope.snippet =
'Pretty text with some links:\n'+
'http://angularjs.org/,\n'+
'mailto:us@somewhere.org,\n'+
'another@somewhere.org,\n'+
'and one more: ftp://127.0.0.1/.';
$scope.snippetWithTarget = 'http://angularjs.org/';
}
angular.module('linkyExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.snippet =
'Pretty text with some links:\n'+
'http://angularjs.org/,\n'+
'mailto:us@somewhere.org,\n'+
'another@somewhere.org,\n'+
'and one more: ftp://127.0.0.1/.';
$scope.snippetWithTarget = 'http://angularjs.org/';
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
<table>
<tr>
+12 -11
View File
@@ -52,20 +52,21 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
* @returns {string} Sanitized html.
*
* @example
<example module="ngSanitize" deps="angular-sanitize.js">
<example module="sanitizeExample" deps="angular-sanitize.js">
<file name="index.html">
<script>
function Ctrl($scope, $sce) {
$scope.snippet =
'<p style="color:blue">an html\n' +
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
'snippet</p>';
$scope.deliberatelyTrustDangerousSnippet = function() {
return $sce.trustAsHtml($scope.snippet);
};
}
angular.module('sanitizeExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', '$sce', function($scope, $sce) {
$scope.snippet =
'<p style="color:blue">an html\n' +
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
'snippet</p>';
$scope.deliberatelyTrustDangerousSnippet = function() {
return $sce.trustAsHtml($scope.snippet);
};
}]);
</script>
<div ng-controller="Ctrl">
<div ng-controller="ExampleController">
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
<table>
<tr>
+22 -23
View File
@@ -16,6 +16,7 @@
"sub": true,
"undef": true,
"browser": true,
"indent": 2,
"globals": {
/* auto/injector.js */
"createInjector": false,
@@ -42,7 +43,6 @@
"isArrayLike": false,
"forEach": false,
"sortedKeys": false,
"forEachSorted": false,
"reverseParams": false,
"nextUid": false,
"setHashKey": false,
@@ -103,9 +103,6 @@
"getBlockElements": false,
"VALIDITY_STATE_PROPERTY": true,
/* filters.js */
"getFirstThursdayOfYear": false,
/* AngularPublic.js */
"version": false,
"publishExternalAPI": false,
@@ -148,24 +145,6 @@
"urlResolve": false,
"urlIsSameOrigin": false,
/* ng/compile.js */
"directiveNormalize": false,
/* ng/parse.js */
"setter": false,
/* ng/directive/directives.js */
"ngDirective": false,
/* ng/directive/input.js */
"VALID_CLASS": false,
"INVALID_CLASS": false,
"PRISTINE_CLASS": false,
"DIRTY_CLASS": false,
/* ng/directive/form.js */
"nullFormCtrl": false,
/* jasmine / karma */
"it": false,
"iit": false,
@@ -176,10 +155,30 @@
"expect": false,
"jasmine": false,
"spyOn": false,
"waits": false,
"waitsFor": false,
"runs": false,
"dump": false,
/* e2e */
"browser": false,
"element": false,
"by": false,
/* testabilityPatch / matchers */
"inject": false,
"module": false,
"dealoc": false
"dealoc": false,
"dealoc": false,
"_jQuery": false,
"_jqLiteMode": false,
"sortedHtml": false,
"childrenTagsOf": false,
"assertHidden": false,
"assertVisible": false,
"provideLog": false,
"spyOnlyCallsWithArgs": false,
"createMockStyleSheet": false,
"browserTrigger": false
}
}
+33 -20
View File
@@ -118,7 +118,7 @@ describe('angular', function() {
it('should throw an exception when source and destination are equivalent', function() {
var src, dst;
src = dst = {key: 'value'};
src = dst = {key: 'value'};
expect(function() { copy(src, dst); }).toThrowMinErr("ng", "cpi", "Can't copy! Source and destination are identical.");
src = dst = [2, 4];
expect(function() { copy(src, dst); }).toThrowMinErr("ng", "cpi", "Can't copy! Source and destination are identical.");
@@ -223,7 +223,7 @@ describe('angular', function() {
it('should omit properties from prototype chain', function() {
var original, clone = {};
function Func() {};
function Func() {}
Func.prototype.hello = "world";
original = new Func();
@@ -349,6 +349,7 @@ describe('angular', function() {
});
it('should correctly test for keys that are present on Object.prototype', function() {
/* jshint -W001 */
// MS IE8 just doesn't work for this kind of thing, since "for ... in" doesn't return
// things like hasOwnProperty even if it is explicitly defined on the actual object!
if (msie<=8) return;
@@ -470,6 +471,13 @@ describe('angular', function() {
expect(parseKeyValue('flag1&flag1=value&flag1=value2&flag1')).
toEqual({flag1: [true,'value','value2',true]});
});
it('should ignore properties higher in the prototype chain', function() {
expect(parseKeyValue('toString=123')).toEqual({
'toString': '123'
});
});
});
describe('toKeyValue', function() {
@@ -490,7 +498,7 @@ describe('angular', function() {
expect(toKeyValue({key: [323,'value',true]})).toEqual('key=323&key=value&key');
expect(toKeyValue({key: [323,'value',true, 1234]})).
toEqual('key=323&key=value&key&key=1234');
});
});
});
@@ -505,13 +513,14 @@ describe('angular', function() {
var obj = new MyObj(),
log = [];
forEach(obj, function(value, key) { log.push(key + ':' + value)});
forEach(obj, function(value, key) { log.push(key + ':' + value); });
expect(log).toEqual(['bar:barVal', 'baz:bazVal']);
});
it('should not break if obj is an array we override hasOwnProperty', function() {
/* jshint -W001 */
var obj = [];
obj[0] = 1;
obj[1] = 2;
@@ -539,7 +548,7 @@ describe('angular', function() {
log = [];
forEach(nodeList, function(value, key) { log.push(key + ':' + value.innerHTML)});
forEach(nodeList, function(value, key) { log.push(key + ':' + value.innerHTML); });
expect(log).toEqual(['0:a', '1:b', '2:c']);
});
@@ -554,7 +563,7 @@ describe('angular', function() {
var htmlCollection = document.getElementsByName('x'),
log = [];
forEach(htmlCollection, function(value, key) { log.push(key + ':' + value.innerHTML)});
forEach(htmlCollection, function(value, key) { log.push(key + ':' + value.innerHTML); });
expect(log).toEqual(['0:a', '1:c']);
});
@@ -569,7 +578,7 @@ describe('angular', function() {
var htmlCollection = document.querySelectorAll('[name="x"]'),
log = [];
forEach(htmlCollection, function(value, key) { log.push(key + ':' + value.innerHTML)});
forEach(htmlCollection, function(value, key) { log.push(key + ':' + value.innerHTML); });
expect(log).toEqual(['0:a', '1:c']);
});
}
@@ -578,28 +587,28 @@ describe('angular', function() {
var args,
log = [];
(function(){ args = arguments}('a', 'b', 'c'));
(function(){ args = arguments; }('a', 'b', 'c'));
forEach(args, function(value, key) { log.push(key + ':' + value)});
forEach(args, function(value, key) { log.push(key + ':' + value); });
expect(log).toEqual(['0:a', '1:b', '2:c']);
});
it('should handle string values like arrays', function() {
var log = [];
forEach('bar', function(value, key) { log.push(key + ':' + value)});
forEach('bar', function(value, key) { log.push(key + ':' + value); });
expect(log).toEqual(['0:b', '1:a', '2:r']);
});
it('should handle objects with length property as objects', function() {
var obj = {
'foo' : 'bar',
'length': 2
},
log = [];
'foo' : 'bar',
'length': 2
},
log = [];
forEach(obj, function(value, key) { log.push(key + ':' + value)});
forEach(obj, function(value, key) { log.push(key + ':' + value); });
expect(log).toEqual(['foo:bar', 'length:2']);
});
@@ -607,13 +616,13 @@ describe('angular', function() {
it('should handle objects of custom types with length property as objects', function() {
function CustomType() {
this.length = 2;
this.foo = 'bar'
this.foo = 'bar';
}
var obj = new CustomType(),
log = [];
forEach(obj, function(value, key) { log.push(key + ':' + value)});
forEach(obj, function(value, key) { log.push(key + ':' + value); });
expect(log).toEqual(['length:2', 'foo:bar']);
});
});
@@ -783,7 +792,9 @@ describe('angular', function() {
expect(function() {
angularInit(appElement, bootstrap);
}).toThrowMatching(
/\[\$injector:modulerr] Failed to instantiate module doesntexist due to:\n.*\[\$injector:nomod] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it\./
new RegExp('\\[\\$injector:modulerr] Failed to instantiate module doesntexist due to:\\n' +
'.*\\[\\$injector:nomod] Module \'doesntexist\' is not available! You either ' +
'misspelled the module name or forgot to load it\\.')
);
});
@@ -811,7 +822,7 @@ describe('angular', function() {
);
dealoc(document);
})
});
});
@@ -972,7 +983,9 @@ describe('angular', function() {
expect(function() {
angular.bootstrap(element, ['doesntexist']);
}).toThrowMatching(
/\[\$injector:modulerr\] Failed to instantiate module doesntexist due to:\n.*\[\$injector:nomod\] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it\./);
new RegExp('\\[\\$injector:modulerr\\] Failed to instantiate module doesntexist due to:\\n' +
'.*\\[\\$injector:nomod\\] Module \'doesntexist\' is not available! You either ' +
'misspelled the module name or forgot to load it\\.'));
expect(element.html()).toBe('{{1+2}}');
dealoc(element);
+1 -1
View File
@@ -176,7 +176,7 @@ describe('Binder', function() {
var errorLogs = $exceptionHandler.errors;
$rootScope.error = {
'throw': function() {throw 'ErrorMsg1';}
'throw': function() {throw 'ErrorMsg1';}
};
$rootScope.$apply();
+32 -29
View File
@@ -110,6 +110,7 @@ describe('injector', function() {
function fn(a, b, c, d) {
/* jshint -W040 */
args = [this, a, b, c, d];
return a + b + c + d;
}
@@ -147,6 +148,7 @@ describe('injector', function() {
describe('annotation', function() {
/* global annotate: false */
it('should return $inject', function() {
function fn() {}
fn.$inject = ['a'];
@@ -159,6 +161,7 @@ describe('injector', function() {
it('should create $inject', function() {
var extraParans = angular.noop;
// keep the multi-line to make sure we can handle it
function $f_n0 /*
*/(
@@ -175,7 +178,7 @@ describe('injector', function() {
it('should strip leading and trailing underscores from arg name during inference', function() {
function beforeEachFn(_foo_) { /* foo = _foo_ */ };
function beforeEachFn(_foo_) { /* foo = _foo_ */ }
expect(annotate(beforeEachFn)).toEqual(['foo']);
});
@@ -239,10 +242,9 @@ describe('injector', function() {
describe('module', function() {
it('should provide $injector even when no module is requested', function() {
var $provide,
$injector = createInjector([
angular.extend(function(p) { $provide = p; }, {$inject: ['$provide']})
]);
var $provide, $injector = createInjector([
angular.extend(function(p) { $provide = p; }, {$inject: ['$provide']})
]);
expect($injector.get('$injector')).toBe($injector);
});
@@ -321,9 +323,9 @@ describe('injector', function() {
angular.module('a', [], function(){ log += 'a'; }).run(function() { log += 'A'; });
angular.module('b', ['a'], function(){ log += 'b'; }).run(function() { log += 'B'; });
createInjector([
'b',
valueFn(function() { log += 'C'; }),
[valueFn(function() { log += 'D'; })]
'b',
valueFn(function() { log += 'C'; }),
[valueFn(function() { log += 'D'; })]
]);
expect(log).toEqual('abABCD');
});
@@ -351,19 +353,19 @@ describe('injector', function() {
it('should create configuration injectable constants', function() {
var log = [];
createInjector([
function($provide){
$provide.constant('abc', 123);
$provide.constant({a: 'A', b:'B'});
return function(a) {
log.push(a);
}
},
function(abc) {
log.push(abc);
return function(b) {
log.push(b);
}
}
function($provide){
$provide.constant('abc', 123);
$provide.constant({a: 'A', b:'B'});
return function(a) {
log.push(a);
};
},
function(abc) {
log.push(abc);
return function(b) {
log.push(b);
};
}
]).get('abc');
expect(log).toEqual([123, 'A', 'B']);
});
@@ -445,7 +447,7 @@ describe('injector', function() {
it('should configure $provide provider type', function() {
function Type() {};
function Type() {}
Type.prototype.$get = function() {
expect(this instanceof Type).toBe(true);
return 'abc';
@@ -459,7 +461,7 @@ describe('injector', function() {
it('should configure $provide using an array', function() {
function Type(PREFIX) {
this.prefix = PREFIX;
};
}
Type.prototype.$get = function() {
return this.prefix + 'def';
};
@@ -550,7 +552,7 @@ describe('injector', function() {
return function(val) {
log.push('myService:' + val + ',' + dep1);
return 'origReturn';
}
};
}]);
$provide.decorator('myService', function($delegate) {
@@ -577,7 +579,7 @@ describe('injector', function() {
return function(val) {
log.push('myService:' + val);
return 'origReturn';
}
};
});
$provide.decorator('myService', function($delegate, dep1) {
@@ -727,7 +729,8 @@ describe('injector', function() {
})).toEqual('melville:moby');
expect($injector.invoke(function(book, author) {
expect(this).toEqual($injector);
return author + ':' + book;}, $injector)).toEqual('melville:moby');
return author + ':' + book;
}, $injector)).toEqual('melville:moby');
});
@@ -745,7 +748,7 @@ describe('injector', function() {
it('should invoke method which is annotated', function() {
expect($injector.invoke(extend(function(b, a) {
return a + ':' + b
return a + ':' + b;
}, {$inject:['book', 'author']}))).toEqual('melville:moby');
expect($injector.invoke(extend(function(b, a) {
expect(this).toEqual($injector);
@@ -878,10 +881,10 @@ describe('injector', function() {
it('should prevent instance lookup in module', function() {
function instanceLookupInModule(name) { throw Error('FAIL'); }
function instanceLookupInModule(name) { throw new Error('FAIL'); }
expect(function() {
createInjector([function($provide) {
$provide.value('name', 'angular')
$provide.value('name', 'angular');
}, instanceLookupInModule]);
}).toThrowMatching(/\[\$injector:unpr] Unknown provider: name/);
});
+4 -2
View File
@@ -1,10 +1,12 @@
'use strict';
describe('docs.angularjs.org', function () {
describe('App', function () {
// it('should filter the module list when searching', function () {
// browser.get();
// browser.waitForAngular();
// var search = element(by.input('q'));
// var search = element(by.model('q'));
// search.clear();
// search.sendKeys('ngBind');
@@ -32,7 +34,7 @@ describe('docs.angularjs.org', function () {
browser.switchTo().frame('example-input-directive');
var nameInput = element(by.input('user.name'));
var nameInput = element(by.model('user.name'));
nameInput.sendKeys('!!!');
var code = element(by.css('tt'));
+4 -2
View File
@@ -1,3 +1,5 @@
'use strict';
beforeEach(function() {
function cssMatcher(presentClasses, absentClasses) {
@@ -39,7 +41,7 @@ beforeEach(function() {
}
});
return hidden;
};
}
this.addMatchers({
toBeInvalid: cssMatcher('ng-invalid', 'ng-valid'),
@@ -128,7 +130,7 @@ beforeEach(function() {
this.message = function() {
if (this.actual.callCount != 1) {
if (this.actual.callCount == 0) {
if (this.actual.callCount === 0) {
return [
'Expected spy ' + this.actual.identity + ' to have been called once with ' +
jasmine.pp(expectedArgs) + ' but it was never called.',
+4 -2
View File
@@ -1,3 +1,5 @@
'use strict';
function createMockStyleSheet(doc, wind) {
doc = doc ? doc[0] : document;
wind = wind || window;
@@ -17,7 +19,7 @@ function createMockStyleSheet(doc, wind) {
try {
ss.addRule(selector, styles);
}
catch(e) {}
catch(e2) {}
}
},
@@ -25,4 +27,4 @@ function createMockStyleSheet(doc, wind) {
head.removeChild(node);
}
};
};
}
+3 -1
View File
@@ -1,3 +1,5 @@
'use strict';
describe('private mocks', function() {
describe('createMockStyleSheet', function() {
@@ -29,7 +31,7 @@ describe('private mocks', function() {
return node.currentStyle ?
node.currentStyle[key] :
$window.getComputedStyle(node)[key];
};
}
}));
});
+4 -3
View File
@@ -1,3 +1,4 @@
/* global jQuery: true, uid: true */
'use strict';
/**
@@ -150,7 +151,7 @@ function sortedHtml(element, showNgClass) {
var attr = attributes[i];
if(attr.name.match(/^ng[\:\-]/) ||
(attr.value || attr.value == '') &&
(attr.value || attr.value === '') &&
attr.value !='null' &&
attr.value !='auto' &&
attr.value !='false' &&
@@ -283,7 +284,7 @@ function provideLog($provide) {
var currentMessages = messages;
messages = [];
return currentMessages;
}
};
log.fn = function(msg) {
return function() {
@@ -299,7 +300,7 @@ function provideLog($provide) {
function pending() {
dump('PENDING');
};
}
function trace(name) {
dump(new Error(name).stack);
+1
View File
@@ -1,3 +1,4 @@
/* global $: false */
'use strict';
if (window.jQuery) {
+41 -38
View File
@@ -1,3 +1,5 @@
'use strict';
describe('jqLite', function() {
var scope, a, b, c;
@@ -57,7 +59,7 @@ describe('jqLite', function() {
it('should allow construction with html', function() {
var nodes = jqLite('<div>1</div><span>2</span>');
expect(nodes[0].parentNode).toBeDefined();
expect(nodes[0].parentNode.nodeType).toBe(11); /** Document Fragment **/;
expect(nodes[0].parentNode.nodeType).toBe(11); /** Document Fragment **/
expect(nodes[0].parentNode).toBe(nodes[1].parentNode);
expect(nodes.length).toEqual(2);
expect(nodes[0].innerHTML).toEqual('1');
@@ -68,7 +70,7 @@ describe('jqLite', function() {
it('should allow construction of html with leading whitespace', function() {
var nodes = jqLite(' \n\r \r\n<div>1</div><span>2</span>');
expect(nodes[0].parentNode).toBeDefined();
expect(nodes[0].parentNode.nodeType).toBe(11); /** Document Fragment **/;
expect(nodes[0].parentNode.nodeType).toBe(11); /** Document Fragment **/
expect(nodes[0].parentNode).toBe(nodes[1].parentNode);
expect(nodes.length).toBe(2);
expect(nodes[0].innerHTML).toBe('1');
@@ -473,7 +475,7 @@ describe('jqLite', function() {
span = div.find('span'),
log = '';
span.on('click', function() { log+= 'click;'});
span.on('click', function() { log+= 'click;'; });
browserTrigger(span);
expect(log).toEqual('click;');
@@ -945,21 +947,21 @@ describe('jqLite', function() {
if (jqLite.fn) return; // don't run in jQuery
var eventFn;
var window = {
document: {},
location: {},
alert: noop,
setInterval: noop,
length:10, // pretend you are an array
addEventListener: function(type, fn){
expect(type).toEqual('hashchange');
eventFn = fn;
},
removeEventListener: noop,
attachEvent: function(type, fn){
expect(type).toEqual('onhashchange');
eventFn = fn;
},
detachEvent: noop
document: {},
location: {},
alert: noop,
setInterval: noop,
length:10, // pretend you are an array
addEventListener: function(type, fn){
expect(type).toEqual('hashchange');
eventFn = fn;
},
removeEventListener: noop,
attachEvent: function(type, fn){
expect(type).toEqual('onhashchange');
eventFn = fn;
},
detachEvent: noop
};
var log;
var jWindow = jqLite(window).on('hashchange', function() {
@@ -1046,16 +1048,17 @@ describe('jqLite', function() {
if (window.jQuery) return;
var browserMoveTrigger = function(from, to){
var fireEvent = function(type, element, relatedTarget){
var msie = parseInt((/msie (\d+)/.exec(navigator.userAgent.toLowerCase()) || [])[1]);
var evnt, msie = parseInt((/msie (\d+)/.exec(navigator.userAgent.toLowerCase()) || [])[1]);
if (msie < 9){
var evnt = document.createEventObject();
evnt = document.createEventObject();
evnt.srcElement = element;
evnt.relatedTarget = relatedTarget;
element.fireEvent('on' + type, evnt);
return;
};
var evnt = document.createEvent('MouseEvents'),
originalPreventDefault = evnt.preventDefault,
}
evnt = document.createEvent('MouseEvents');
var originalPreventDefault = evnt.preventDefault,
appWindow = window,
fakeProcessDefault = true,
finalProcessDefault;
@@ -1657,25 +1660,25 @@ describe('jqLite', function() {
describe('camelCase', function() {
it('should leave non-dashed strings alone', function() {
expect(camelCase('foo')).toBe('foo');
expect(camelCase('')).toBe('');
expect(camelCase('fooBar')).toBe('fooBar');
});
it('should leave non-dashed strings alone', function() {
expect(camelCase('foo')).toBe('foo');
expect(camelCase('')).toBe('');
expect(camelCase('fooBar')).toBe('fooBar');
});
it('should covert dash-separated strings to camelCase', function() {
expect(camelCase('foo-bar')).toBe('fooBar');
expect(camelCase('foo-bar-baz')).toBe('fooBarBaz');
expect(camelCase('foo:bar_baz')).toBe('fooBarBaz');
});
it('should covert dash-separated strings to camelCase', function() {
expect(camelCase('foo-bar')).toBe('fooBar');
expect(camelCase('foo-bar-baz')).toBe('fooBarBaz');
expect(camelCase('foo:bar_baz')).toBe('fooBarBaz');
});
it('should covert browser specific css properties', function() {
expect(camelCase('-moz-foo-bar')).toBe('MozFooBar');
expect(camelCase('-webkit-foo-bar')).toBe('webkitFooBar');
expect(camelCase('-webkit-foo-bar')).toBe('webkitFooBar');
});
it('should covert browser specific css properties', function() {
expect(camelCase('-moz-foo-bar')).toBe('MozFooBar');
expect(camelCase('-webkit-foo-bar')).toBe('webkitFooBar');
expect(camelCase('-webkit-foo-bar')).toBe('webkitFooBar');
});
});
});
+1
View File
@@ -1,3 +1,4 @@
/* global _jQuery: true, _jqLiteMode: true */
'use strict';
var _jQuery = jQuery,
+1
View File
@@ -1,3 +1,4 @@
/* global _jQuery: true, _jqLiteMode: true */
'use strict';
var _jQuery = jQuery.noConflict(true),
+1 -1
View File
@@ -81,5 +81,5 @@ describe('module loader', function() {
it('should expose `$$minErr` on the `angular` object', function() {
expect(window.angular.$$minErr).toEqual(jasmine.any(Function));
})
});
});
+2
View File
@@ -1,3 +1,5 @@
'use strict';
describe('$anchorScroll', function() {
var elmSpy;
+4
View File
@@ -1,6 +1,10 @@
'use strict';
describe("$animate", function() {
describe("without animation", function() {
var element, $rootElement;
beforeEach(module(function() {
return function($compile, _$rootElement_, $rootScope) {
element = $compile('<div></div>')($rootScope);
+4 -4
View File
@@ -49,7 +49,7 @@ function MockWindow() {
function MockDocument() {
var self = this;
this[0] = window.document
this[0] = window.document;
this.basePath = '/';
this.find = function(name) {
@@ -62,15 +62,15 @@ function MockDocument() {
throw new Error(name);
}
}
}
};
} else {
throw new Error(name);
}
}
};
}
describe('browser', function() {
/* global Browser: false */
var browser, fakeWindow, fakeDocument, logs, scripts, removedScripts, sniffer;
beforeEach(function() {
+4 -1
View File
@@ -1,3 +1,5 @@
'use strict';
describe('$cacheFactory', function() {
it('should be injected', inject(function($cacheFactory) {
@@ -176,7 +178,7 @@ describe('$cacheFactory', function() {
describe('LRU cache', function() {
it('should create cache with defined capacity', inject(function($cacheFactory) {
cache = $cacheFactory('cache1', {capacity: 5});
var cache = $cacheFactory('cache1', {capacity: 5});
expect(cache.info().size).toBe(0);
for (var i=0; i<5; i++) {
@@ -193,6 +195,7 @@ describe('$cacheFactory', function() {
describe('eviction', function() {
var cache;
beforeEach(inject(function($cacheFactory) {
cache = $cacheFactory('cache1', {capacity: 2});
+129 -109
View File
@@ -82,13 +82,13 @@ describe('$compile', function() {
element.text('SUCCESS');
}
};
})
});
});
inject(function($compile, $rootScope, log) {
element = $compile('<div></div>')($rootScope);
expect(element.text()).toEqual('SUCCESS');
expect(log).toEqual('OK');
})
});
});
it('should allow registration of multiple directives with same name', function() {
@@ -282,7 +282,7 @@ describe('$compile', function() {
expect(attr).toBe(templateAttr);
expect(scope).toEqual($rootScope);
element.text('worked');
}
};
}
};
});
@@ -397,7 +397,7 @@ describe('$compile', function() {
expect(element.children().length).toBe(1);
expect(element.text()).toBe('Hello');
});
})
});
});
describe('compiler control', function() {
@@ -436,46 +436,46 @@ describe('$compile', function() {
describe('restrict', function() {
it('should allow restriction of attributes', function() {
module(function() {
forEach({div:'E', attr:'A', clazz:'C', all:'EAC'}, function(restrict, name) {
directive(name, function(log) {
return {
restrict: restrict,
compile: valueFn(function(scope, element, attr) {
log(name);
})
};
});
module(function() {
forEach({div:'E', attr:'A', clazz:'C', all:'EAC'}, function(restrict, name) {
directive(name, function(log) {
return {
restrict: restrict,
compile: valueFn(function(scope, element, attr) {
log(name);
})
};
});
});
inject(function($rootScope, $compile, log) {
dealoc($compile('<span div class="div"></span>')($rootScope));
expect(log).toEqual('');
log.reset();
});
inject(function($rootScope, $compile, log) {
dealoc($compile('<span div class="div"></span>')($rootScope));
expect(log).toEqual('');
log.reset();
dealoc($compile('<div></div>')($rootScope));
expect(log).toEqual('div');
log.reset();
dealoc($compile('<div></div>')($rootScope));
expect(log).toEqual('div');
log.reset();
dealoc($compile('<attr class=""attr"></attr>')($rootScope));
expect(log).toEqual('');
log.reset();
dealoc($compile('<attr class=""attr"></attr>')($rootScope));
expect(log).toEqual('');
log.reset();
dealoc($compile('<span attr></span>')($rootScope));
expect(log).toEqual('attr');
log.reset();
dealoc($compile('<span attr></span>')($rootScope));
expect(log).toEqual('attr');
log.reset();
dealoc($compile('<clazz clazz></clazz>')($rootScope));
expect(log).toEqual('');
log.reset();
dealoc($compile('<clazz clazz></clazz>')($rootScope));
expect(log).toEqual('');
log.reset();
dealoc($compile('<span class="clazz"></span>')($rootScope));
expect(log).toEqual('clazz');
log.reset();
dealoc($compile('<span class="clazz"></span>')($rootScope));
expect(log).toEqual('clazz');
log.reset();
dealoc($compile('<all class="all" all></all>')($rootScope));
expect(log).toEqual('all; all; all');
});
dealoc($compile('<all class="all" all></all>')($rootScope));
expect(log).toEqual('all; all; all');
});
});
});
@@ -658,7 +658,8 @@ describe('$compile', function() {
element = $compile('<div replace-with-interpolated-style></div>')($rootScope);
$rootScope.$digest();
expect(element.css('width')).toBe('2px');
}));
}
));
}
it('should merge interpolated css class', inject(function($compile, $rootScope) {
@@ -699,19 +700,19 @@ describe('$compile', function() {
return {
replace: true,
template: 'dada'
}
};
});
directive('multiRootElem', function() {
return {
replace: true,
template: '<div></div><div></div>'
}
};
});
directive('singleRootWithWhiteSpace', function() {
return {
replace: true,
template: ' <div></div> \n'
}
};
});
});
@@ -820,32 +821,38 @@ describe('$compile', function() {
beforeEach(module(
function() {
directive('hello', valueFn({
restrict: 'CAM', templateUrl: 'hello.html', transclude: true
restrict: 'CAM',
templateUrl: 'hello.html',
transclude: true
}));
directive('cau', valueFn({
restrict: 'CAM', templateUrl: 'cau.html'
restrict: 'CAM',
templateUrl: 'cau.html'
}));
directive('crossDomainTemplate', valueFn({
restrict: 'CAM', templateUrl: 'http://example.com/should-not-load.html'
}));
directive('trustedTemplate', function($sce) { return {
restrict: 'CAM',
templateUrl: function() {
return $sce.trustAsResourceUrl('http://example.com/trusted-template.html');
}};
templateUrl: 'http://example.com/should-not-load.html'
}));
directive('trustedTemplate', function($sce) {
return {
restrict: 'CAM',
templateUrl: function() {
return $sce.trustAsResourceUrl('http://example.com/trusted-template.html');
}
};
});
directive('cError', valueFn({
restrict: 'CAM',
templateUrl:'error.html',
compile: function() {
throw Error('cError');
throw new Error('cError');
}
}));
directive('lError', valueFn({
restrict: 'CAM',
templateUrl: 'error.html',
compile: function() {
throw Error('lError');
throw new Error('lError');
}
}));
@@ -866,7 +873,7 @@ describe('$compile', function() {
replace: true,
templateUrl:'error.html',
compile: function() {
throw Error('cError');
throw new Error('cError');
}
}));
directive('iLError', valueFn({
@@ -874,7 +881,7 @@ describe('$compile', function() {
replace: true,
templateUrl: 'error.html',
compile: function() {
throw Error('lError');
throw new Error('lError');
}
}));
@@ -919,23 +926,25 @@ describe('$compile', function() {
));
it('should not load cross domain templates by default', inject(
function($compile, $rootScope, $templateCache, $sce) {
expect(function() {
$templateCache.put('http://example.com/should-not-load.html', 'Should not load even if in cache.');
$compile('<div class="crossDomainTemplate"></div>')($rootScope);
}).toThrowMinErr('$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example.com/should-not-load.html');
}));
function($compile, $rootScope, $templateCache, $sce) {
expect(function() {
$templateCache.put('http://example.com/should-not-load.html', 'Should not load even if in cache.');
$compile('<div class="crossDomainTemplate"></div>')($rootScope);
}).toThrowMinErr('$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example.com/should-not-load.html');
}
));
it('should load cross domain templates when trusted', inject(
function($compile, $httpBackend, $rootScope, $sce) {
$httpBackend.expect('GET', 'http://example.com/trusted-template.html').respond('<span>example.com/trusted_template_contents</span>');
element = $compile('<div class="trustedTemplate"></div>')($rootScope);
expect(sortedHtml(element)).
toEqual('<div class="trustedTemplate"></div>');
$httpBackend.flush();
expect(sortedHtml(element)).
toEqual('<div class="trustedTemplate"><span>example.com/trusted_template_contents</span></div>');
}));
function($compile, $httpBackend, $rootScope, $sce) {
$httpBackend.expect('GET', 'http://example.com/trusted-template.html').respond('<span>example.com/trusted_template_contents</span>');
element = $compile('<div class="trustedTemplate"></div>')($rootScope);
expect(sortedHtml(element)).
toEqual('<div class="trustedTemplate"></div>');
$httpBackend.flush();
expect(sortedHtml(element)).
toEqual('<div class="trustedTemplate"><span>example.com/trusted_template_contents</span></div>');
}
));
it('should append template via $http and cache it in $templateCache', inject(
function($compile, $httpBackend, $templateCache, $rootScope, $browser) {
@@ -1293,15 +1302,15 @@ describe('$compile', function() {
function logDirective (name, priority, options) {
directive(name, function(log) {
return (extend({
priority: priority,
compile: function() {
log(name + '-C');
return {
pre: function() { log(name + '-PreL'); },
post: function() { log(name + '-PostL'); }
}
}
}, options || {}));
priority: priority,
compile: function() {
log(name + '-C');
return {
pre: function() { log(name + '-PreL'); },
post: function() { log(name + '-PostL'); }
};
}
}, options || {}));
});
}
@@ -1462,7 +1471,7 @@ describe('$compile', function() {
return {
replace: true,
templateUrl: 'template.html'
}
};
});
});
@@ -2078,9 +2087,9 @@ describe('$compile', function() {
post: function($scope, $element, $attrs) {
log('postLink=' + $attrs.myName);
}
}
};
}
}
};
});
});
module(function() {
@@ -2094,7 +2103,7 @@ describe('$compile', function() {
}
};
}
}
};
});
});
inject(function($rootScope, $compile, log) {
@@ -2191,7 +2200,7 @@ describe('$compile', function() {
it('should translate {{}} in terminal nodes', inject(function($rootScope, $compile) {
element = $compile('<select ng:model="x"><option value="">Greet {{name}}!</option></select>')($rootScope)
element = $compile('<select ng:model="x"><option value="">Greet {{name}}!</option></select>')($rootScope);
$rootScope.$digest();
expect(sortedHtml(element).replace(' selected="true"', '')).
toEqual('<select ng:model="x">' +
@@ -2257,7 +2266,7 @@ describe('$compile', function() {
log(val);
});
}
}
};
});
});
@@ -2270,7 +2279,7 @@ describe('$compile', function() {
expect(log).toEqual(['carrot']);
});
})
});
});
@@ -2283,7 +2292,7 @@ describe('$compile', function() {
return {
restrict: 'ECA',
compile: function() {
log('t' + uppercase(name))
log('t' + uppercase(name));
return {
pre: function() {
log('pre' + uppercase(name));
@@ -2424,7 +2433,7 @@ describe('$compile', function() {
template: {element: templateElement, attr:templateAttr},
link: {element: element, attr: attr}
});
}
};
}
}),
second: valueFn({
@@ -2435,7 +2444,7 @@ describe('$compile', function() {
template: {element: templateElement, attr:templateAttr},
link: {element: element, attr: attr}
});
}
};
}
})
});
@@ -2590,7 +2599,7 @@ describe('$compile', function() {
link: function(scope) {
regularScope = scope;
}
}
};
});
}));
@@ -2602,7 +2611,7 @@ describe('$compile', function() {
});
expect(element.find('input').val()).toBe('from-parent');
expect(componentScope).not.toBe(regularScope);
expect(componentScope.$parent).toBe(regularScope)
expect(componentScope.$parent).toBe(regularScope);
}));
@@ -2637,7 +2646,7 @@ describe('$compile', function() {
});
inject(function($rootScope, $templateCache) {
$templateCache.put('other.html', 'value: {{value}}')
$templateCache.put('other.html', 'value: {{value}}');
compile('<div my-component other-tpl-dir>');
$rootScope.$apply(function() {
@@ -2716,14 +2725,14 @@ describe('$compile', function() {
componentScope.ref = 'misko';
$rootScope.$apply();
expect($rootScope.name).toEqual({mark:123})
expect($rootScope.name).toEqual({mark:123});
expect(componentScope.ref).toBe($rootScope.name);
expect(componentScope.refAlias).toBe($rootScope.name);
$rootScope.name = 'igor';
componentScope.ref = {};
$rootScope.$apply();
expect($rootScope.name).toEqual('igor')
expect($rootScope.name).toEqual('igor');
expect(componentScope.ref).toBe($rootScope.name);
expect(componentScope.refAlias).toBe($rootScope.name);
}));
@@ -3142,7 +3151,7 @@ describe('$compile', function() {
link: function($scope, $element) {
log($element.attr('scope-tester') + '=' + ($scope.$root === $scope ? 'non-isolate' : 'isolate'));
}
}
};
});
});
@@ -3156,7 +3165,7 @@ describe('$compile', function() {
expect(log).toEqual('inside=isolate; ' +
'outside replaced=non-isolate; ' + // outside
'outside replaced=isolate; ' + // replaced
'sibling=non-isolate')
'sibling=non-isolate');
});
});
@@ -3338,7 +3347,7 @@ describe('$compile', function() {
controller: asyncCtrlSpy,
compile: function() {
return function() {
}
};
}
}));
});
@@ -3398,7 +3407,7 @@ describe('$compile', function() {
element = $compile('<div parent-directive><div child-directive></div>childContentText;</div>')($rootScope);
$rootScope.$apply();
expect(log).toEqual('parentController; childController');
expect(element.text()).toBe('childTemplateText;childContentText;')
expect(element.text()).toBe('childTemplateText;childContentText;');
});
});
@@ -3502,7 +3511,7 @@ describe('$compile', function() {
'</div>')($rootScope);
$rootScope.$apply();
expect(log).toEqual('parentController; childController; babyController');
expect(element.text()).toBe('childContentText;babyTemplateText;')
expect(element.text()).toBe('childContentText;babyTemplateText;');
});
});
@@ -3605,7 +3614,7 @@ describe('$compile', function() {
replace: true,
scope: true,
template: '<ul><li>W:{{$parent.$id}}-{{$id}};</li><li ng-transclude></li></ul>'
}
};
});
});
inject(function(log, $rootScope, $compile) {
@@ -3637,7 +3646,7 @@ describe('$compile', function() {
$httpBackend.
expect('GET', 'chapter.html').
respond('<div>chapter-<div section>[<div ng-transclude></div>]</div></div>');
}
};
});
inject(function(log, $rootScope, $compile, $httpBackend) {
element = $compile('<div><div book>paragraph</div></div>')($rootScope);
@@ -3755,9 +3764,9 @@ describe('$compile', function() {
$compile('<div><div ng-transclude></div></div>')($rootScope);
} catch(e) {
expect(e.message).toMatch(new RegExp(
'^\\\[ngTransclude:orphan\\\] ' +
'^\\[ngTransclude:orphan\\] ' +
'Illegal use of ngTransclude directive in the template! ' +
'No parent directive that requires a transclusion found\. ' +
'No parent directive that requires a transclusion found\\. ' +
'Element: <div ng-transclude.+'));
}
});
@@ -4257,11 +4266,11 @@ describe('$compile', function() {
return function(scope, element, attrs, ctrl) {
log('link');
var cursor = element;
template(scope.$new(), function(clone) {cursor.after(cursor = clone)});
ctrl.$transclude(function(clone) {cursor.after(clone)});
template(scope.$new(), function(clone) { cursor.after(cursor = clone); });
ctrl.$transclude(function(clone) { cursor.after(clone); });
};
}
}
};
});
});
inject(function(log, $rootScope, $compile) {
@@ -4434,7 +4443,7 @@ describe('$compile', function() {
});
inject(function($compile) {
element = $compile('<div transclude></div>')($rootScope);
expect(_$transclude).toBeDefined()
expect(_$transclude).toBeDefined();
});
});
@@ -4559,7 +4568,8 @@ describe('$compile', function() {
expect(log.toArray()).toEqual([
"outer:#comment:outer:",
"innerAgain:#comment:innerAgain:",
"inner:#comment:innerAgain:"]);
"inner:#comment:innerAgain:"
]);
expect(child.length).toBe(1);
expect(child.contents().length).toBe(2);
expect(lowercase(nodeName_(child.contents().eq(0)))).toBe('#comment');
@@ -4644,6 +4654,7 @@ describe('$compile', function() {
}));
it('should not sanitize attributes other than src', inject(function($compile, $rootScope) {
/* jshint scripturl:true */
element = $compile('<img title="{{testUrl}}"></img>')($rootScope);
$rootScope.testUrl = "javascript:doEvilStuff()";
$rootScope.$apply();
@@ -4688,6 +4699,7 @@ describe('$compile', function() {
describe('a[href] sanitization', function() {
it('should not sanitize href on elements other than anchor', inject(function($compile, $rootScope) {
/* jshint scripturl:true */
element = $compile('<div href="{{testUrl}}"></div>')($rootScope);
$rootScope.testUrl = "javascript:doEvilStuff()";
$rootScope.$apply();
@@ -4696,6 +4708,7 @@ describe('$compile', function() {
}));
it('should not sanitize attributes other than href', inject(function($compile, $rootScope) {
/* jshint scripturl:true */
element = $compile('<a title="{{testUrl}}"></a>')($rootScope);
$rootScope.testUrl = "javascript:doEvilStuff()";
$rootScope.$apply();
@@ -4759,6 +4772,7 @@ describe('$compile', function() {
}));
it('should pass through arbitrary values on onXYZ event attributes that contain a hyphen', inject(function($compile, $rootScope) {
/* jshint scripturl:true */
element = $compile('<button on-click="{{onClickJs}}"></script>')($rootScope);
$rootScope.onClickJs = 'javascript:doSomething()';
$rootScope.$apply();
@@ -4789,22 +4803,24 @@ describe('$compile', function() {
it('should clear out src attributes for a different domain', inject(function($compile, $rootScope, $sce) {
element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
$rootScope.testUrl = "http://a.different.domain.example.com";
expect(function() { $rootScope.$apply() }).toThrowMinErr(
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: " +
"http://a.different.domain.example.com");
}));
it('should clear out JS src attributes', inject(function($compile, $rootScope, $sce) {
/* jshint scripturl:true */
element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
$rootScope.testUrl = "javascript:alert(1);";
expect(function() { $rootScope.$apply() }).toThrowMinErr(
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: " +
"javascript:alert(1);");
}));
it('should clear out non-resource_url src attributes', inject(function($compile, $rootScope, $sce) {
/* jshint scripturl:true */
element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()");
expect($rootScope.$apply).toThrowMinErr(
@@ -4813,6 +4829,7 @@ describe('$compile', function() {
}));
it('should pass through $sce.trustAs() values in src attributes', inject(function($compile, $rootScope, $sce) {
/* jshint scripturl:true */
element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
$rootScope.testUrl = $sce.trustAsResourceUrl("javascript:doTrustedStuff()");
$rootScope.$apply();
@@ -4832,22 +4849,24 @@ describe('$compile', function() {
it('should clear out action attribute for a different domain', inject(function($compile, $rootScope, $sce) {
element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
$rootScope.testUrl = "http://a.different.domain.example.com";
expect(function() { $rootScope.$apply() }).toThrowMinErr(
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: " +
"http://a.different.domain.example.com");
}));
it('should clear out JS action attribute', inject(function($compile, $rootScope, $sce) {
/* jshint scripturl:true */
element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
$rootScope.testUrl = "javascript:alert(1);";
expect(function() { $rootScope.$apply() }).toThrowMinErr(
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: " +
"javascript:alert(1);");
}));
it('should clear out non-resource_url action attribute', inject(function($compile, $rootScope, $sce) {
/* jshint scripturl:true */
element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()");
expect($rootScope.$apply).toThrowMinErr(
@@ -4856,6 +4875,7 @@ describe('$compile', function() {
}));
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);
$rootScope.testUrl = $sce.trustAsResourceUrl("javascript:doTrustedStuff()");
$rootScope.$apply();
+4 -4
View File
@@ -16,7 +16,7 @@ describe('$controller', function() {
describe('provider', function() {
it('should allow registration of controllers', function() {
var FooCtrl = function($scope) { $scope.foo = 'bar' },
var FooCtrl = function($scope) { $scope.foo = 'bar'; },
scope = {},
ctrl;
@@ -29,8 +29,8 @@ describe('$controller', function() {
it('should allow registration of map of controllers', function() {
var FooCtrl = function($scope) { $scope.foo = 'foo' },
BarCtrl = function($scope) { $scope.bar = 'bar' },
var FooCtrl = function($scope) { $scope.foo = 'foo'; },
BarCtrl = function($scope) { $scope.bar = 'bar'; },
scope = {},
ctrl;
@@ -47,7 +47,7 @@ describe('$controller', function() {
it('should allow registration of controllers annotated with arrays', function() {
var FooCtrl = function($scope) { $scope.foo = 'bar' },
var FooCtrl = function($scope) { $scope.foo = 'bar'; },
scope = {},
ctrl;
+11 -11
View File
@@ -10,7 +10,7 @@ describe('boolean attr directives', function() {
it('should properly evaluate 0 as false', inject(function($rootScope, $compile) {
// jQuery does not treat 0 as false, when setting attr()
element = $compile('<button ng-disabled="isDisabled">Button</button>')($rootScope)
element = $compile('<button ng-disabled="isDisabled">Button</button>')($rootScope);
$rootScope.isDisabled = 0;
$rootScope.$digest();
expect(element.attr('disabled')).toBeFalsy();
@@ -21,7 +21,7 @@ describe('boolean attr directives', function() {
it('should bind disabled', inject(function($rootScope, $compile) {
element = $compile('<button ng-disabled="isDisabled">Button</button>')($rootScope)
element = $compile('<button ng-disabled="isDisabled">Button</button>')($rootScope);
$rootScope.isDisabled = false;
$rootScope.$digest();
expect(element.attr('disabled')).toBeFalsy();
@@ -32,7 +32,7 @@ describe('boolean attr directives', function() {
it('should bind checked', inject(function($rootScope, $compile) {
element = $compile('<input type="checkbox" ng-checked="isChecked" />')($rootScope)
element = $compile('<input type="checkbox" ng-checked="isChecked" />')($rootScope);
$rootScope.isChecked = false;
$rootScope.$digest();
expect(element.attr('checked')).toBeFalsy();
@@ -43,8 +43,8 @@ describe('boolean attr directives', function() {
it('should bind selected', inject(function($rootScope, $compile) {
element = $compile('<select><option value=""></option><option ng-selected="isSelected">Greetings!</option></select>')($rootScope)
jqLite(document.body).append(element)
element = $compile('<select><option value=""></option><option ng-selected="isSelected">Greetings!</option></select>')($rootScope);
jqLite(document.body).append(element);
$rootScope.isSelected=false;
$rootScope.$digest();
expect(element.children()[1].selected).toBeFalsy();
@@ -55,7 +55,7 @@ describe('boolean attr directives', function() {
it('should bind readonly', inject(function($rootScope, $compile) {
element = $compile('<input type="text" ng-readonly="isReadonly" />')($rootScope)
element = $compile('<input type="text" ng-readonly="isReadonly" />')($rootScope);
$rootScope.isReadonly=false;
$rootScope.$digest();
expect(element.attr('readOnly')).toBeFalsy();
@@ -66,7 +66,7 @@ describe('boolean attr directives', function() {
it('should bind open', inject(function($rootScope, $compile) {
element = $compile('<details ng-open="isOpen"></details>')($rootScope)
element = $compile('<details ng-open="isOpen"></details>')($rootScope);
$rootScope.isOpen=false;
$rootScope.$digest();
expect(element.attr('open')).toBeFalsy();
@@ -78,7 +78,7 @@ describe('boolean attr directives', function() {
describe('multiple', function() {
it('should NOT bind to multiple via ngMultiple', inject(function($rootScope, $compile) {
element = $compile('<select ng-multiple="isMultiple"></select>')($rootScope)
element = $compile('<select ng-multiple="isMultiple"></select>')($rootScope);
$rootScope.isMultiple=false;
$rootScope.$digest();
expect(element.attr('multiple')).toBeFalsy();
@@ -92,7 +92,7 @@ describe('boolean attr directives', function() {
if (msie < 9) return; //IE8 doesn't support biding to boolean attributes
expect(function() {
$compile('<select multiple="{{isMultiple}}"></select>')
$compile('<select multiple="{{isMultiple}}"></select>');
}).toThrowMinErr('$compile', 'selmulti', 'Binding to the \'multiple\' attribute is not supported. ' +
'Element: <select multiple="{{isMultiple}}">');
@@ -225,7 +225,7 @@ describe('ngHref', function() {
it('should interpolate the expression and bind to href', inject(function($compile, $rootScope) {
element = $compile('<div ng-href="some/{{id}}"></div>')($rootScope)
element = $compile('<div ng-href="some/{{id}}"></div>')($rootScope);
$rootScope.$digest();
expect(element.attr('href')).toEqual('some/');
@@ -247,7 +247,7 @@ describe('ngHref', function() {
it('should bind href even if no interpolation', inject(function($rootScope, $compile) {
element = $compile('<a ng-href="http://server"></a>')($rootScope)
element = $compile('<a ng-href="http://server"></a>')($rootScope);
$rootScope.$digest();
expect(element.attr('href')).toEqual('http://server');
}));
+8 -7
View File
@@ -1,3 +1,4 @@
/* global FormController: false */
'use strict';
describe('form', function() {
@@ -148,9 +149,9 @@ describe('form', function() {
'<input name="hasOwnProperty" ng-model="some" />'+
'<input name="other" ng-model="someOther" />'+
'</form>');
expect(function() {
$compile(doc)(scope);
}).toThrowMinErr('ng', 'badname');
expect(function() {
$compile(doc)(scope);
}).toThrowMinErr('ng', 'badname');
});
@@ -177,7 +178,7 @@ describe('form', function() {
scope.submitMe = function() {
submitted = true;
}
};
if (msie!=8) addEventListenerFn(doc[0], 'submit', assertPreventDefaultListener);
@@ -218,11 +219,11 @@ describe('form', function() {
// $location change) that will cause some directive to destroy the dom (e.g. ngView+$route)
doc.empty();
destroyed = true;
}
};
scope.submitMe = function() {
submitted = true;
}
};
var assertPreventDefaultListener = function(e) {
reloadPrevented = e.defaultPrevented || (e.returnValue === false);
@@ -434,7 +435,7 @@ describe('form', function() {
expect(parent.$error.myRule).toBe(false);
expect(child.$error.myRule).toBe(false);
});
})
});
describe('validation', function() {
+30 -27
View File
@@ -1,6 +1,7 @@
'use strict';
describe('NgModelController', function() {
/* global NgModelController: false */
var ctrl, scope, ngModelAccessor, element, parentFormCtrl;
beforeEach(inject(function($rootScope, $controller) {
@@ -9,7 +10,7 @@ describe('NgModelController', function() {
parentFormCtrl = {
$setValidity: jasmine.createSpy('$setValidity'),
$setDirty: jasmine.createSpy('$setDirty')
}
};
element = jqLite('<form><input></form>');
element.data('$formController', parentFormCtrl);
@@ -17,7 +18,9 @@ describe('NgModelController', function() {
scope = $rootScope;
ngModelAccessor = jasmine.createSpy('ngModel accessor');
ctrl = $controller(NgModelController, {
$scope: scope, $element: element.find('input'), $attrs: attrs
$scope: scope,
$element: element.find('input'),
$attrs: attrs
});
}));
@@ -387,24 +390,20 @@ describe('ngModel', function() {
it('should keep previously defined watches consistent when changes in validity are made',
inject(function($compile, $rootScope) {
var isFormValid;
$rootScope.$watch('myForm.$valid', function(value) { isFormValid = value; });
var element = $compile('<form name="myForm">' +
'<input name="myControl" ng-model="value" required >' +
'</form>')($rootScope);
$rootScope.$apply();
expect(isFormValid).toBe(false);
expect($rootScope.myForm.$valid).toBe(false);
$rootScope.value='value';
$rootScope.$apply();
expect(isFormValid).toBe(true);
expect($rootScope.myForm.$valid).toBe(true);
dealoc(element);
}));
var isFormValid;
$rootScope.$watch('myForm.$valid', function(value) { isFormValid = value; });
var element = $compile('<form name="myForm">' +
'<input name="myControl" ng-model="value" required >' +
'</form>')($rootScope);
$rootScope.$apply();
expect(isFormValid).toBe(false);
expect($rootScope.myForm.$valid).toBe(false);
$rootScope.value='value';
$rootScope.$apply();
expect(isFormValid).toBe(true);
expect($rootScope.myForm.$valid).toBe(true);
dealoc(element);
}));
});
@@ -472,7 +471,7 @@ describe('input', function() {
this.message = function() {
return "Attribute '" + attributeName + "' expected to be off but was '" + actualValue +
"' in: " + angular.mock.dump(this.actual);
}
};
return !actualValue || actualValue == 'false';
}
@@ -495,7 +494,7 @@ describe('input', function() {
expect(scope.name).toEqual('adam');
});
if (!(msie < 9)) {
if (!msie || msie >= 9) {
describe('compositionevents', function() {
it('should not update the model between "compositionstart" and "compositionend" on non android', inject(function($sniffer) {
$sniffer.android = false;
@@ -529,7 +528,7 @@ describe('input', function() {
it('should update the model on "compositionend"', function() {
compileInput('<input type="text" ng-model="name" name="alias" />');
if (!(msie < 9)) {
if (!msie || msie >= 9) {
browserTrigger(inputElm, 'compositionstart');
changeInputValueTo('caitp');
expect(scope.name).toBeUndefined();
@@ -976,7 +975,7 @@ describe('input', function() {
});
expect(inputElm).toBeValid();
expect(inputElm.val()).toBe('0')
expect(inputElm.val()).toBe('0');
expect(scope.form.alias.$error.required).toBeFalsy();
});
@@ -1013,12 +1012,16 @@ describe('input', function() {
describe('EMAIL_REGEXP', function() {
/* global EMAIL_REGEXP: false */
it('should validate email', function() {
expect(EMAIL_REGEXP.test('a@b.com')).toBe(true);
expect(EMAIL_REGEXP.test('a@b.museum')).toBe(true);
expect(EMAIL_REGEXP.test('a@B.c')).toBe(true);
expect(EMAIL_REGEXP.test('a@.b.c')).toBe(false);
expect(EMAIL_REGEXP.test('a@-b.c')).toBe(false);
expect(EMAIL_REGEXP.test('a@b-.c')).toBe(false);
expect(EMAIL_REGEXP.test('a@3b.c')).toBe(true);
expect(EMAIL_REGEXP.test('a@b')).toBe(true);
});
});
});
@@ -1043,7 +1046,7 @@ describe('input', function() {
describe('URL_REGEXP', function() {
/* global URL_REGEXP: false */
it('should validate url', function() {
expect(URL_REGEXP.test('http://server:123/path')).toBe(true);
expect(URL_REGEXP.test('a@B.c')).toBe(false);
@@ -1558,7 +1561,7 @@ describe('NgModel animations', function() {
}
}
return animations;
};
}
function assertValidAnimation(animation, event, className) {
expect(animation.event).toBe(event);
+11 -10
View File
@@ -72,7 +72,8 @@ describe('ngClass', function() {
$rootScope.$digest();
expect(element.hasClass('A')).toBeFalsy();
expect(element.hasClass('B')).toBeTruthy();
}));
})
);
it('should support adding multiple classes via a space delimited string', inject(function($rootScope, $compile) {
@@ -195,16 +196,16 @@ describe('ngClass', function() {
it("should allow ngClassOdd/Even on the same element with overlapping classes", inject(function($rootScope, $compile, $animate) {
var className;
var className;
element = $compile('<ul><li ng-repeat="i in [0,1,2]" ng-class-odd="\'same odd\'" ng-class-even="\'same even\'"></li><ul>')($rootScope);
$rootScope.$digest();
var e1 = jqLite(element[0].childNodes[1]);
var e2 = jqLite(element[0].childNodes[5]);
expect(e1.hasClass('same')).toBeTruthy();
expect(e1.hasClass('odd')).toBeTruthy();
expect(e2.hasClass('same')).toBeTruthy();
expect(e2.hasClass('odd')).toBeTruthy();
element = $compile('<ul><li ng-repeat="i in [0,1,2]" ng-class-odd="\'same odd\'" ng-class-even="\'same even\'"></li><ul>')($rootScope);
$rootScope.$digest();
var e1 = jqLite(element[0].childNodes[1]);
var e2 = jqLite(element[0].childNodes[5]);
expect(e1.hasClass('same')).toBeTruthy();
expect(e1.hasClass('odd')).toBeTruthy();
expect(e2.hasClass('same')).toBeTruthy();
expect(e2.hasClass('odd')).toBeTruthy();
}));
it('should allow ngClass with overlapping classes', inject(function($rootScope, $compile, $animate) {
+1 -1
View File
@@ -35,7 +35,7 @@ describe('ngController', function() {
$window.Public = function() {
this.mark = 'works';
}
};
}));
afterEach(function() {
+6 -4
View File
@@ -226,8 +226,8 @@ describe('ngIf and transcludes', function() {
describe('ngIf animations', function () {
var body, element, $rootElement;
function html(html) {
$rootElement.html(html);
function html(content) {
$rootElement.html(content);
element = $rootElement.children().eq(0);
return element;
}
@@ -272,7 +272,8 @@ describe('ngIf animations', function () {
expect(item.element.text()).toBe('Hi');
expect(element.children().length).toBe(1);
}));
})
);
it('should fire off the leave animation',
inject(function ($compile, $rootScope, $animate) {
@@ -297,7 +298,8 @@ describe('ngIf animations', function () {
expect(item.element.text()).toBe('Hi');
expect(element.children().length).toBe(0);
}));
})
);
it('should destroy the previous leave animation if a new one takes place', function() {
module(function($provide) {
+21 -16
View File
@@ -112,7 +112,7 @@ describe('ngInclude', function() {
it('should fire $includeContentRequested event on scope after making the xhr call', inject(
function ($rootScope, $compile, $httpBackend) {
var contentRequestedSpy = jasmine.createSpy('content requested').andCallFake(function (event) {
expect(event.targetScope).toBe($rootScope);
expect(event.targetScope).toBe($rootScope);
});
$httpBackend.whenGET('url').respond('my partial');
@@ -233,7 +233,8 @@ describe('ngInclude', function() {
var called = 0;
// we want to assert only during first watch
$rootScope.$watch(function() {
if (!called++) expect(element.text()).toBe('');
if (!called) expect(element.text()).toBe('');
called++;
});
$rootScope.$digest();
@@ -249,7 +250,7 @@ describe('ngInclude', function() {
$rootScope.templateUrl = 'myUrl1';
$rootScope.logger = function(msg) {
log[msg] = true;
}
};
$compile(element)($rootScope);
expect(log).toEqual({});
@@ -451,16 +452,17 @@ describe('ngInclude', function() {
}));
it('should only call $anchorScroll after the "enter" animation completes', inject(
compileAndLink('<div><ng:include src="tpl" autoscroll></ng:include></div>'),
function($rootScope, $animate, $timeout) {
expect(autoScrollSpy).not.toHaveBeenCalled();
compileAndLink('<div><ng:include src="tpl" autoscroll></ng:include></div>'),
function($rootScope, $animate, $timeout) {
expect(autoScrollSpy).not.toHaveBeenCalled();
$rootScope.$apply("tpl = 'template.html'");
expect($animate.queue.shift().event).toBe('enter');
$animate.triggerCallbacks();
$rootScope.$apply("tpl = 'template.html'");
expect($animate.queue.shift().event).toBe('enter');
$animate.triggerCallbacks();
expect(autoScrollSpy).toHaveBeenCalledOnce();
}));
expect(autoScrollSpy).toHaveBeenCalledOnce();
}
));
});
});
@@ -569,8 +571,8 @@ describe('ngInclude and transcludes', function() {
describe('ngInclude animations', function() {
var body, element, $rootElement;
function html(html) {
$rootElement.html(html);
function html(content) {
$rootElement.html(content);
element = $rootElement.children().eq(0);
return element;
}
@@ -611,7 +613,8 @@ describe('ngInclude animations', function() {
var animation = $animate.queue.pop();
expect(animation.event).toBe('enter');
expect(animation.element.text()).toBe('data');
}));
})
);
it('should fire off the leave animation',
inject(function($compile, $rootScope, $templateCache, $animate) {
@@ -635,7 +638,8 @@ describe('ngInclude animations', function() {
animation = $animate.queue.shift();
expect(animation.event).toBe('leave');
expect(animation.element.text()).toBe('data');
}));
})
);
it('should animate two separate ngInclude elements',
inject(function($compile, $rootScope, $templateCache, $animate) {
@@ -661,7 +665,8 @@ describe('ngInclude animations', function() {
expect(itemA.attr('ng-include')).toBe('tpl');
expect(itemB.attr('ng-include')).toBe('tpl');
expect(itemA).not.toEqual(itemB);
}));
}
));
it('should destroy the previous leave animation if a new one takes place', function() {
module(function($provide) {
+1 -1
View File
@@ -240,6 +240,6 @@ describe('ngPluralize', function() {
expect(element.text()).toBe('Igor and 2 other people are viewing.');
expect(elementAlt.text()).toBe('Igor and 2 other people are viewing.');
});
})
});
});
});
+10 -8
View File
@@ -79,6 +79,7 @@ describe('ngRepeat', function() {
});
it('should iterate over an array-like class', function() {
/* jshint -W009 */
function Collection() {}
Collection.prototype = new Array();
Collection.prototype.length = 0;
@@ -395,10 +396,10 @@ describe('ngRepeat', function() {
it("should throw error when left-hand-side of ngRepeat can't be parsed", function() {
element = jqLite('<ul><li ng-repeat="i dont parse in foo"></li></ul>');
$compile(element)(scope);
element = jqLite('<ul><li ng-repeat="i dont parse in foo"></li></ul>');
$compile(element)(scope);
expect($exceptionHandler.errors.shift()[0].message).
toMatch(/^\[ngRepeat:iidexp\] '_item_' in '_item_ in _collection_' should be an identifier or '\(_key_, _value_\)' expression, but got 'i dont parse'\./);
toMatch(/^\[ngRepeat:iidexp\] '_item_' in '_item_ in _collection_' should be an identifier or '\(_key_, _value_\)' expression, but got 'i dont parse'\./);
});
@@ -818,7 +819,7 @@ describe('ngRepeat', function() {
expect(children[1].nextSibling.nodeValue).toBe(' end ngRepeat: val in values ');
expect(children[2].nextSibling.nodeType).toBe(8);
expect(children[2].nextSibling.nodeValue).toBe(' end ngRepeat: val in values ');
}
};
$rootScope.values = [1, 2, 3];
@@ -1045,7 +1046,7 @@ describe('ngRepeat', function() {
inject(function($compile, $rootScope) {
element = $compile('<div><div ng-repeat="i in [1,2]" elm-trans>{{i}}</div></div>')($rootScope);
$rootScope.$digest();
expect(element.text()).toBe('[[1]][[2]]')
expect(element.text()).toBe('[[1]][[2]]');
});
});
@@ -1143,8 +1144,8 @@ describe('ngRepeat and transcludes', function() {
describe('ngRepeat animations', function() {
var body, element, $rootElement;
function html(html) {
$rootElement.html(html);
function html(content) {
$rootElement.html(content);
element = $rootElement.children().eq(0);
return element;
}
@@ -1268,6 +1269,7 @@ describe('ngRepeat animations', function() {
item = $animate.queue.shift();
expect(item.event).toBe('move');
expect(item.element.text()).toBe('3');
}));
})
);
});
+2 -2
View File
@@ -55,9 +55,9 @@ describe('ngShow / ngHide', function() {
describe('ngShow / ngHide animations', function() {
var body, element, $rootElement;
function html(html) {
function html(content) {
body.append($rootElement);
$rootElement.html(html);
$rootElement.html(content);
element = $rootElement.children().eq(0);
return element;
}
+5 -2
View File
@@ -26,22 +26,24 @@ describe('ngSrc', function() {
it('should error on src attributes for a different domain', inject(function($compile, $rootScope) {
element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
$rootScope.testUrl = "http://a.different.domain.example.com";
expect(function() { $rootScope.$apply() }).toThrowMinErr(
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: " +
"http://a.different.domain.example.com");
}));
it('should error on JS src attributes', inject(function($compile, $rootScope) {
/* jshint scripturl:true */
element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
$rootScope.testUrl = "javascript:alert(1);";
expect(function() { $rootScope.$apply() }).toThrowMinErr(
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: " +
"javascript:alert(1);");
}));
it('should error on non-resource_url src attributes', inject(function($compile, $rootScope, $sce) {
/* jshint scripturl:true */
element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
$rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()");
expect($rootScope.$apply).toThrowMinErr(
@@ -51,6 +53,7 @@ describe('ngSrc', function() {
}));
it('should pass through $sce.trustAs() values in src attributes', inject(function($compile, $rootScope, $sce) {
/* jshint scripturl:true */
element = $compile('<iframe ng-src="{{testUrl}}"></iframe>')($rootScope);
$rootScope.testUrl = $sce.trustAsResourceUrl("javascript:doTrustedStuff()");
$rootScope.$apply();
+6 -4
View File
@@ -240,8 +240,8 @@ describe('ngSwitch', function() {
describe('ngSwitch animations', function() {
var body, element, $rootElement;
function html(html) {
$rootElement.html(html);
function html(content) {
$rootElement.html(content);
element = $rootElement.children().eq(0);
return element;
}
@@ -281,7 +281,8 @@ describe('ngSwitch animations', function() {
item = $animate.queue.shift();
expect(item.event).toBe('enter');
expect(item.element.text()).toBe('one');
}));
})
);
it('should fire off the leave animation',
@@ -314,7 +315,8 @@ describe('ngSwitch animations', function() {
item = $animate.queue.shift();
expect(item.event).toBe('enter');
expect(item.element.text()).toBe('three');
}));
})
);
it('should destroy the previous leave animation if a new one takes place', function() {
module(function($provide) {
+4 -4
View File
@@ -218,7 +218,7 @@ describe('select', function() {
it('should not break if both the select and repeater models change at once', function() {
scope.robots = ['c3p0', 'r2d2'];
scope.robot = 'c3p0'
scope.robot = 'c3p0';
compile('<select ng-model="robot">' +
'<option value="">--select--</option>' +
'<option ng-repeat="r in robots">{{r}}</option>' +
@@ -1206,7 +1206,7 @@ describe('select', function() {
it('should deselect all options when model is emptied', function() {
createMultiSelect();
scope.$apply(function() {
scope.$apply(function() {
scope.values = [{name: 'A'}, {name: 'B'}];
scope.selected = [scope.values[0]];
});
@@ -1217,7 +1217,7 @@ describe('select', function() {
});
expect(element.find('option')[0].selected).toEqual(false);
})
});
});
@@ -1325,7 +1325,7 @@ describe('select', function() {
});
it('should set value even if self closing HTML', function() {
scope.x = 'hello'
scope.x = 'hello';
compile('<select ng-model="x"><option>hello</select>');
expect(element).toEqualSelect(['hello']);
});
+17 -16
View File
@@ -1,24 +1,25 @@
'use strict';
describe('$exceptionHandler', function() {
it('should log errors with single argument', function() {
module(function($provide){
$provide.provider('$exceptionHandler', $ExceptionHandlerProvider);
});
inject(function($log, $exceptionHandler) {
$exceptionHandler('myError');
expect($log.error.logs.shift()).toEqual(['myError']);
});
/* global $ExceptionHandlerProvider:false */
it('should log errors with single argument', function() {
module(function($provide){
$provide.provider('$exceptionHandler', $ExceptionHandlerProvider);
});
inject(function($log, $exceptionHandler) {
$exceptionHandler('myError');
expect($log.error.logs.shift()).toEqual(['myError']);
});
});
it('should log errors with multiple arguments', function() {
module(function($provide){
$provide.provider('$exceptionHandler', $ExceptionHandlerProvider);
});
inject(function($log, $exceptionHandler) {
$exceptionHandler('myError', 'comment');
expect($log.error.logs.shift()).toEqual(['myError', 'comment']);
});
it('should log errors with multiple arguments', function() {
module(function($provide){
$provide.provider('$exceptionHandler', $ExceptionHandlerProvider);
});
inject(function($log, $exceptionHandler) {
$exceptionHandler('myError', 'comment');
expect($log.error.logs.shift()).toEqual(['myError', 'comment']);
});
});
});
+10 -9
View File
@@ -77,7 +77,8 @@ describe('Filter: filter', function() {
{person: {name: 'Joan'}}];
expect(filter(items, {person: {name: 'Jo'}}).length).toBe(2);
expect(filter(items, {person: {name: 'Jo'}})).toEqual([
{person: {name: 'John'}}, {person: {name: 'Joan'}}]);
{person: {name: 'John'}}, {person: {name: 'Joan'}}
]);
});
@@ -94,8 +95,8 @@ describe('Filter: filter', function() {
it('should support boolean properties', function() {
var items = [{name: 'tom', current: true},
{name: 'demi', current: false},
{name: 'sofia'}];
{name: 'demi', current: false},
{name: 'sofia'}];
expect(filter(items, {current:true}).length).toBe(1);
expect(filter(items, {current:true})[0].name).toBe('tom');
@@ -118,26 +119,26 @@ describe('Filter: filter', function() {
expect(filter(items, expr, true)).toEqual([items[1]]);
expect(filter(items, expr, false)).toEqual([items[1], items[2]]);
var items = [
items = [
{key: 'value1', nonkey: 1},
{key: 'value2', nonkey: 2},
{key: 'value12', nonkey: 3},
{key: 'value1', nonkey:4},
{key: 'Value1', nonkey:5}
];
var expr = {key: 'value1'};
expr = {key: 'value1'};
expect(filter(items, expr, true)).toEqual([items[0], items[3]]);
var items = [
items = [
{key: 1, nonkey: 1},
{key: 2, nonkey: 2},
{key: 12, nonkey: 3},
{key: 1, nonkey:4}
];
var expr = { key: 1 };
expr = { key: 1 };
expect(filter(items, expr, true)).toEqual([items[0], items[3]]);
var expr = 12;
expr = 12;
expect(filter(items, expr, true)).toEqual([items[2]]);
});
@@ -151,7 +152,7 @@ describe('Filter: filter', function() {
var expr = {key: 10};
var comparator = function (obj,value) {
return obj > value;
}
};
expect(filter(items, expr, comparator)).toEqual([items[2]]);
expr = 10;
+11 -9
View File
@@ -19,6 +19,7 @@ describe('filters', function() {
});
describe('formatNumber', function() {
/* global formatNumber: false */
var pattern;
beforeEach(function() {
@@ -68,18 +69,18 @@ describe('filters', function() {
expect(num).toBe('123.100');
num = formatNumber(123.12, pattern, ',', '.');
expect(num).toBe('123.12');
var num = formatNumber(123.1116, pattern, ',', '.');
num = formatNumber(123.1116, pattern, ',', '.');
expect(num).toBe('123.112');
});
it('should format the same with string as well as numeric fractionSize', function(){
var num = formatNumber(123.1, pattern, ',', '.', "0");
expect(num).toBe('123');
var num = formatNumber(123.1, pattern, ',', '.', 0);
num = formatNumber(123.1, pattern, ',', '.', 0);
expect(num).toBe('123');
var num = formatNumber(123.1, pattern, ',', '.', "3");
num = formatNumber(123.1, pattern, ',', '.', "3");
expect(num).toBe('123.100');
var num = formatNumber(123.1, pattern, ',', '.', 3);
num = formatNumber(123.1, pattern, ',', '.', 3);
expect(num).toBe('123.100');
});
});
@@ -121,6 +122,7 @@ describe('filters', function() {
it('should do basic filter', function() {
/* jshint -W008 */
expect(number(0, 0)).toEqual('0');
expect(number(-999)).toEqual('-999');
expect(number(123)).toEqual('123');
@@ -276,19 +278,19 @@ describe('filters', function() {
var westOfUTCPartial = new angular.mock.TzDate(+5.5, '2010-09-03T12:05:08.000Z');
expect(date(utc, "yyyy-MM-ddTHH:mm:ssZ")).
toEqual('2010-09-03T12:05:08+0000')
toEqual('2010-09-03T12:05:08+0000');
expect(date(eastOfUTC, "yyyy-MM-ddTHH:mm:ssZ")).
toEqual('2010-09-03T17:05:08+0500')
toEqual('2010-09-03T17:05:08+0500');
expect(date(westOfUTC, "yyyy-MM-ddTHH:mm:ssZ")).
toEqual('2010-09-03T07:05:08-0500')
toEqual('2010-09-03T07:05:08-0500');
expect(date(eastOfUTCPartial, "yyyy-MM-ddTHH:mm:ssZ")).
toEqual('2010-09-03T17:35:08+0530')
toEqual('2010-09-03T17:35:08+0530');
expect(date(westOfUTCPartial, "yyyy-MM-ddTHH:mm:ssZ")).
toEqual('2010-09-03T06:35:08-0530')
toEqual('2010-09-03T06:35:08-0530');
});
it('should treat single quoted strings as string literals', function() {
+2 -2
View File
@@ -2,7 +2,7 @@
describe('Filter: limitTo', function() {
var items;
var str
var str;
var limitTo;
beforeEach(inject(function($filter) {
@@ -67,7 +67,7 @@ describe('Filter: limitTo', function() {
expect(limitTo(str, '9')).toEqual(str);
expect(limitTo(str, -9)).toEqual(str);
expect(limitTo(str, '-9')).toEqual(str);
})
});
it('should return entire input array when limited by Infinity', function() {
expect(limitTo(items, Infinity)).toEqual(items);
+3 -1
View File
@@ -32,13 +32,15 @@ describe('Filter: orderBy', function() {
});
it('should support string predicates with names containing non-identifier characters', function() {
/* jshint -W008 */
expect(orderBy([{"Tip %": .25}, {"Tip %": .15}, {"Tip %": .40}], '"Tip %"'))
.toEqualData([{"Tip %": .15}, {"Tip %": .25}, {"Tip %": .40}]);
expect(orderBy([{"원": 76000}, {"원": 31000}, {"원": 156000}], '"원"'))
.toEqualData([{"원": 31000}, {"원": 76000}, {"원": 156000}])
.toEqualData([{"원": 31000}, {"원": 76000}, {"원": 156000}]);
});
it('should throw if quoted string predicate is quoted incorrectly', function() {
/* jshint -W008 */
expect(function() {
return orderBy([{"Tip %": .15}, {"Tip %": .25}, {"Tip %": .40}], '"Tip %\'');
}).toThrow();
+13 -7
View File
@@ -1,3 +1,6 @@
/* global createHttpBackend: false, createMockXhr: false, MockXhr: false */
'use strict';
describe('$httpBackend', function() {
var $backend, $browser, callbacks,
@@ -42,12 +45,14 @@ describe('$httpBackend', function() {
// msie8 depends on modifying readyState for testing. This property is readonly,
// so it requires a fake object. For other browsers, we do need to make use of
// event listener registration/deregistration, so these stubs are needed.
if (msie <= 8) return {
attachEvent: noop,
detachEvent: noop,
addEventListener: noop,
removeEventListener: noop
};
if (msie <= 8) {
return {
attachEvent: noop,
detachEvent: noop,
addEventListener: noop,
removeEventListener: noop
};
}
// Return a proper script element...
return document.createElement(arguments[0]);
}),
@@ -307,7 +312,7 @@ describe('$httpBackend', function() {
expect(response).toBe('response');
});
$backend = createHttpBackend($browser, function() { return new SyncXhr() });
$backend = createHttpBackend($browser, function() { return new SyncXhr(); });
$backend('GET', '/url', null, callback);
expect(callback).toHaveBeenCalledOnce();
});
@@ -518,6 +523,7 @@ describe('$httpBackend', function() {
});
it('should convert 0 to 404 if no content - relative url', function() {
/* global urlParsingNode: true */
var originalUrlParsingNode = urlParsingNode;
//temporarily overriding the DOM element to pretend that the test runs origin with file:// protocol
+57 -21
View File
@@ -9,12 +9,12 @@ describe('$http', function() {
});
beforeEach(module(function($exceptionHandlerProvider) {
$exceptionHandlerProvider.mode('log');
$exceptionHandlerProvider.mode('log');
}));
afterEach(inject(function($exceptionHandler, $httpBackend, $rootScope) {
forEach($exceptionHandler.errors, function(e) {
dump('Unhandled exception: ', e)
dump('Unhandled exception: ', e);
});
if ($exceptionHandler.errors.length) {
@@ -28,7 +28,7 @@ describe('$http', function() {
describe('$httpProvider', function() {
describe('interceptors', function() {
it('should accept injected rejected response interceptor', function() {
it('should accept injected rejected response interceptor', function() {
var wasCalled = false;
module(function($httpProvider, $provide) {
$httpProvider.responseInterceptors.push('injectedInterceptor');
@@ -83,7 +83,7 @@ describe('$http', function() {
return {
response: function(response) {
response.data += ':1';
savedResponse = response
savedResponse = response;
return $q.reject(':2');
}
};
@@ -194,7 +194,7 @@ describe('$http', function() {
response.data += '!';
return response;
});
}
};
});
// return a new resolved promise representing modified response object
@@ -221,7 +221,7 @@ describe('$http', function() {
response.data = uppercase(response.data);
return response;
});
}
};
});
$httpProvider.responseInterceptors.push('myInterceptor');
});
@@ -344,7 +344,7 @@ describe('$http', function() {
$rootScope.$apply();
expect(config.method).toEqual('get');
expect(config.url).toEqual('/url');
expect(config.headers.foo).toEqual('bar')
expect(config.headers.foo).toEqual('bar');
});
});
@@ -442,8 +442,8 @@ describe('$http', function() {
it('should expand arrays in params map', inject(function($httpBackend, $http) {
$httpBackend.expect('GET', '/url?a=1&a=2&a=3').respond('');
$http({url: '/url', params: {a: [1,2,3]}, method: 'GET'});
$httpBackend.expect('GET', '/url?a=1&a=2&a=3').respond('');
$http({url: '/url', params: {a: [1,2,3]}, method: 'GET'});
}));
@@ -460,7 +460,7 @@ describe('$http', function() {
it('should not add question mark when params is empty', function() {
$httpBackend.expect('GET', '/url').respond('');
$http({url: '/url', params: {}, method: 'GET'});
})
});
});
@@ -591,7 +591,7 @@ describe('$http', function() {
expect(r.headers('nothing')).toBe(null);
});
$http({url: '/url', method: 'GET'}).then(callback)
$http({url: '/url', method: 'GET'}).then(callback);
$httpBackend.flush();
expect(callback).toHaveBeenCalledOnce();
@@ -629,6 +629,7 @@ describe('$http', function() {
describe('response headers parser', function() {
/* global parseHeaders: false */
it('should parse basic', function() {
var parsed = parseHeaders(
@@ -771,6 +772,18 @@ describe('$http', function() {
$httpBackend.flush();
});
it('should delete default headers if custom header function returns null', function () {
$httpBackend.expect('POST', '/url', 'messageBody', function(headers) {
return !('Accept' in headers);
}).respond('');
$http({url: '/url', method: 'POST', data: 'messageBody', headers: {
'Accept': function() { return null; }
}});
$httpBackend.flush();
});
it('should override default headers with custom in a case insensitive manner', function() {
$httpBackend.expect('POST', '/url', 'messageBody', function(headers) {
return headers['accept'] == 'Rewritten' &&
@@ -812,6 +825,22 @@ describe('$http', function() {
$httpBackend.flush();
});
it('should NOT delete Content-Type header if request data/body is set by request transform', function() {
$httpBackend.expect('POST', '/url', {'one' : 'two'}, function(headers) {
return headers['Content-Type'] == 'application/json;charset=utf-8';
}).respond('');
$http({
url: '/url',
method: 'POST',
transformRequest : function(data) {
data = {'one' : 'two'};
return data;
}
});
$httpBackend.flush();
});
it('should set the XSRF cookie into a XSRF header', inject(function($browser) {
function checkXSRF(secret, header) {
@@ -833,8 +862,8 @@ describe('$http', function() {
$http({url: '/url', method: 'POST', headers: {'S-ome': 'Header'}});
$http({url: '/url', method: 'PUT', headers: {'Another': 'Header'}});
$http({url: '/url', method: 'DELETE', headers: {}});
$http({url: '/url', method: 'GET', xsrfHeaderName: 'aHeader'})
$http({url: '/url', method: 'GET', xsrfCookieName: 'aCookie'})
$http({url: '/url', method: 'GET', xsrfHeaderName: 'aHeader'});
$http({url: '/url', method: 'GET', xsrfCookieName: 'aCookie'});
$httpBackend.flush();
}));
@@ -1057,8 +1086,8 @@ describe('$http', function() {
it('should pipeline more functions', function() {
function first(d, h) {return d + '-first' + ':' + h('h1')}
function second(d) {return uppercase(d)}
function first(d, h) {return d + '-first' + ':' + h('h1');}
function second(d) {return uppercase(d);}
$httpBackend.expect('POST', '/url', 'REQ-FIRST:V1').respond(200);
$http.post('/url', 'req', {
@@ -1142,8 +1171,8 @@ describe('$http', function() {
it('should pipeline more functions', function() {
function first(d, h) {return d + '-first' + ':' + h('h1')}
function second(d) {return uppercase(d)}
function first(d, h) {return d + '-first' + ':' + h('h1');}
function second(d) {return uppercase(d);}
$httpBackend.expect('POST', '/url').respond(200, 'resp', {h1: 'v1'});
$http.post('/url', '', {transformResponse: [first, second]}).success(callback);
@@ -1352,7 +1381,7 @@ describe('$http', function() {
describe('$http.defaults.cache', function () {
it('should be undefined by default', function() {
expect($http.defaults.cache).toBeUndefined()
expect($http.defaults.cache).toBeUndefined();
});
it('should cache requests when no cache given in request config', function() {
@@ -1530,7 +1559,7 @@ describe('$http', function() {
expect($http.defaults.headers.post).not.toBe($http.defaults.headers.put);
expect($http.defaults.headers.post).not.toBe($http.defaults.headers.patch);
expect($http.defaults.headers.put).not.toBe($http.defaults.headers.patch);
})
});
});
});
@@ -1550,7 +1579,11 @@ describe('$http', function() {
inject(function($http, $rootScope) {
$http({
method: 'GET', url: 'some.html', timeout: 12345, withCredentials: true, responseType: 'json'
method: 'GET',
url: 'some.html',
timeout: 12345,
withCredentials: true,
responseType: 'json'
});
$rootScope.$digest();
expect($httpBackend).toHaveBeenCalledOnce();
@@ -1574,7 +1607,10 @@ describe('$http', function() {
inject(function($http, $rootScope) {
$http.defaults.withCredentials = true;
$http({
method: 'GET', url: 'some.html', timeout: 12345, responseType: 'json'
method: 'GET',
url: 'some.html',
timeout: 12345,
responseType: 'json'
});
$rootScope.$digest();
expect($httpBackend).toHaveBeenCalledOnce();
+4 -4
View File
@@ -62,7 +62,7 @@ describe('$interpolate', function() {
it('should ignore undefined return value', inject(function($interpolate, $rootScope) {
$rootScope.foo = function() {return undefined};
$rootScope.foo = function() {return undefined;};
expect($interpolate("Hello {{'World' + foo()}}")($rootScope)).toEqual('Hello World');
}));
@@ -70,7 +70,7 @@ describe('$interpolate', function() {
describe('interpolating in a trusted context', function() {
var sce;
beforeEach(function() {
function log() {};
function log() {}
var fakeLog = {log: log, warn: log, info: log, error: log};
module(function($provide, $sceProvider) {
$provide.value('$log', fakeLog);
@@ -106,8 +106,8 @@ describe('$interpolate', function() {
var foo = sce.trustAsCss("foo");
var bar = sce.trustAsCss("bar");
expect(function() {
return $interpolate('{{foo}}{{bar}}', true, sce.CSS)(
{foo: foo, bar: bar}); }).toThrowMinErr(
return $interpolate('{{foo}}{{bar}}', true, sce.CSS)({foo: foo, bar: bar});
}).toThrowMinErr(
"$interpolate", "noconcat", "Error while interpolating: {{foo}}{{bar}}\n" +
"Strict Contextual Escaping disallows interpolations that concatenate multiple " +
"expressions when a trusted value is required. See " +
+5 -4
View File
@@ -1,7 +1,7 @@
'use strict';
describe('$interval', function() {
/* global $IntervalProvider: false */
beforeEach(module(function($provide){
var repeatFns = [],
nextRepeatId = 0,
@@ -58,7 +58,7 @@ describe('$interval', function() {
expect(counter).toBe(0);
$window.flush(1000)
$window.flush(1000);
expect(counter).toBe(1);
$window.flush(1000);
@@ -113,7 +113,7 @@ describe('$interval', function() {
it('should allow you to specify a number of iterations', inject(function($interval, $window) {
var counter = 0;
$interval(function() {counter++}, 1000, 2);
$interval(function() {counter++;}, 1000, 2);
$window.flush(1000);
expect(counter).toBe(1);
@@ -157,7 +157,8 @@ describe('$interval', function() {
$window.flush(1000);
expect(log).toEqual([
'tick', 'promise update: 0', 'tick', 'promise update: 1', 'promise success: 2']);
'tick', 'promise update: 0', 'tick', 'promise update: 1', 'promise success: 2'
]);
}));
+1 -1
View File
@@ -1,7 +1,7 @@
'use strict';
describe('$locale', function() {
/* global $LocaleProvider: false */
var $locale = new $LocaleProvider().$get();
it('should have locale id set to en-us', function() {
+32 -20
View File
@@ -1,6 +1,6 @@
/* global LocationHashbangUrl: false, LocationHtml5Url: false */
'use strict';
describe('$location', function() {
var url;
@@ -14,6 +14,7 @@ describe('$location', function() {
describe('File Protocol', function () {
/* global urlParsingNode: true */
var urlParsingNodePlaceholder;
beforeEach(inject(function ($sniffer) {
@@ -117,6 +118,15 @@ describe('$location', function() {
});
it('search() should remove multiple parameters', function() {
url.search({one: 1, two: true});
expect(url.search()).toEqual({one: 1, two: true});
url.search({one: null, two: null});
expect(url.search()).toEqual({});
expect(url.absUrl()).toBe('http://www.domain.com:9877/path/b#hash');
});
it('search() should handle multiple value', function() {
url.search('a&b');
expect(url.search()).toEqual({a: true, b: true});
@@ -221,7 +231,7 @@ describe('$location', function() {
it('should set path to forward-slash when empty', function() {
url = new LocationHtml5Url('http://server/');
url.$$parse('http://server/')
url.$$parse('http://server/');
expect(url.path()).toBe('/');
expect(url.absUrl()).toBe('http://server/');
});
@@ -437,28 +447,28 @@ describe('$location', function() {
it('should return decoded characters for search specified with setter', function() {
var locationUrl = new LocationHtml5Url('http://host.com/');
locationUrl.$$parse('http://host.com/')
locationUrl.$$parse('http://host.com/');
locationUrl.search('q', '1/2 3');
expect(locationUrl.search()).toEqual({'q': '1/2 3'});
});
it('should return an array for duplicate params', function() {
var locationUrl = new LocationHtml5Url('http://host.com');
locationUrl.$$parse('http://host.com')
locationUrl.$$parse('http://host.com');
locationUrl.search('q', ['1/2 3','4/5 6']);
expect(locationUrl.search()).toEqual({'q': ['1/2 3','4/5 6']});
});
it('should encode an array correctly from search and add to url', function() {
var locationUrl = new LocationHtml5Url('http://host.com');
locationUrl.$$parse('http://host.com')
locationUrl.$$parse('http://host.com');
locationUrl.search({'q': ['1/2 3','4/5 6']});
expect(locationUrl.absUrl()).toEqual('http://host.com?q=1%2F2%203&q=4%2F5%206');
});
it('should rewrite params when specifing a single param in search', function() {
var locationUrl = new LocationHtml5Url('http://host.com');
locationUrl.$$parse('http://host.com')
locationUrl.$$parse('http://host.com');
locationUrl.search({'q': '1/2 3'});
expect(locationUrl.absUrl()).toEqual('http://host.com?q=1%2F2%203');
locationUrl.search({'q': '4/5 6'});
@@ -747,7 +757,7 @@ describe('$location', function() {
});
describe('PATH_MATCH', function() {
/* global PATH_MATCH: false */
it('should parse just path', function() {
var match = PATH_MATCH.exec('/path');
expect(match[1]).toBe('/path');
@@ -1120,7 +1130,7 @@ describe('$location', function() {
// don't run next tests on IE<9, as browserTrigger does not simulate pressed keys
if (!(msie < 9)) {
if (!msie || msie >= 9) {
it('should not rewrite when clicked with ctrl pressed', function() {
configureService('/a?b=c', true, true);
@@ -1154,10 +1164,10 @@ describe('$location', function() {
module(function() {
return function($browser) {
window.location.hash = 'someHash';
base = window.location.href
base = window.location.href;
$browser.url(base);
base = base.split('#')[0];
}
};
});
inject(function($rootScope, $compile, $browser, $rootElement, $document, $location) {
// we need to do this otherwise we can't simulate events
@@ -1189,7 +1199,7 @@ describe('$location', function() {
$browser.url(base = window.location.href);
base = base.split('#')[0];
$locationProvider.hashPrefix('!');
}
};
});
inject(function($rootScope, $compile, $browser, $rootElement, $document, $location) {
// we need to do this otherwise we can't simulate events
@@ -1222,7 +1232,7 @@ describe('$location', function() {
});
return function($browser) {
$browser.url(base = 'http://server/');
}
};
});
inject(function($location) {
// make IE happy
@@ -1252,7 +1262,7 @@ describe('$location', function() {
});
return function($browser) {
$browser.url(base = 'http://server/');
}
};
});
inject(function($rootScope, $compile, $browser, $rootElement, $document, $location) {
// make IE happy
@@ -1293,7 +1303,7 @@ describe('$location', function() {
$browser.url(base = window.location.href);
base = base.split('#')[0];
$locationProvider.hashPrefix('!');
}
};
});
inject(function($rootScope, $compile, $browser, $rootElement, $document, $location) {
// we need to do this otherwise we can't simulate events
@@ -1348,7 +1358,7 @@ describe('$location', function() {
event.preventDefault();
});
$rootScope.$on('$locationChangeSuccess', function(event, newUrl, oldUrl) {
throw Error('location should have been canceled');
throw new Error('location should have been canceled');
});
expect($location.url()).toEqual('');
@@ -1398,7 +1408,7 @@ describe('$location', function() {
$rootElement.html('<a href="http://server/#/somePath">link</a>');
$compile($rootElement)($rootScope);
jqLite(document.body).append($rootElement);
}
};
});
inject(function($location, $rootScope, $browser, $rootElement) {
@@ -1431,7 +1441,7 @@ describe('$location', function() {
$rootElement.html('<a href="http://server/somePath">link</a>');
$compile($rootElement)($rootScope);
jqLite(document.body).append($rootElement);
}
};
});
inject(function($location, $rootScope, $browser, $rootElement) {
@@ -1507,6 +1517,7 @@ describe('$location', function() {
var location;
it('should rewrite URL', function() {
/* jshint scripturl: true */
location = new LocationHashbangUrl('http://server/pre/', '#');
expect(location.$$rewrite('http://other')).toEqual(undefined);
@@ -1518,7 +1529,7 @@ describe('$location', function() {
it("should not set hash if one was not originally specified", function() {
location = new LocationHashbangUrl('http://server/pre/index.html', '#');
location.$$parse('http://server/pre/index.html')
location.$$parse('http://server/pre/index.html');
expect(location.url()).toBe('');
expect(location.absUrl()).toBe('http://server/pre/index.html');
});
@@ -1526,7 +1537,7 @@ describe('$location', function() {
it("should parse hash if one was specified", function() {
location = new LocationHashbangUrl('http://server/pre/index.html', '#');
location.$$parse('http://server/pre/index.html#/foo/bar')
location.$$parse('http://server/pre/index.html#/foo/bar');
expect(location.url()).toBe('/foo/bar');
expect(location.absUrl()).toBe('http://server/pre/index.html#/foo/bar');
});
@@ -1535,7 +1546,7 @@ describe('$location', function() {
it("should prefix hash url with / if one was originally missing", function() {
location = new LocationHashbangUrl('http://server/pre/index.html', '#');
location.$$parse('http://server/pre/index.html#not-starting-with-slash')
location.$$parse('http://server/pre/index.html#not-starting-with-slash');
expect(location.url()).toBe('/not-starting-with-slash');
expect(location.absUrl()).toBe('http://server/pre/index.html#/not-starting-with-slash');
});
@@ -1553,6 +1564,7 @@ describe('$location', function() {
describe('LocationHashbangInHtml5Url', function() {
/* global LocationHashbangInHtml5Url: false */
var location, locationIndex;
beforeEach(function() {
+18 -17
View File
@@ -1,3 +1,4 @@
/* global $LogProvider: false */
'use strict';
function initService(debugEnabled) {
@@ -118,24 +119,24 @@ describe('$log', function() {
describe("$log.debug", function () {
beforeEach(initService(false));
beforeEach(initService(false));
it("should skip debugging output if disabled", inject(
function(){
$window.console = {log: log,
warn: warn,
info: info,
error: error,
debug: debug};
},
function($log) {
$log.log();
$log.warn();
$log.info();
$log.error();
$log.debug();
expect(logger).toEqual('log;warn;info;error;');
}
it("should skip debugging output if disabled", inject(
function(){
$window.console = {log: log,
warn: warn,
info: info,
error: error,
debug: debug};
},
function($log) {
$log.log();
$log.warn();
$log.info();
$log.error();
$log.debug();
expect(logger).toEqual('log;warn;info;error;');
}
));
});
+11 -6
View File
@@ -3,6 +3,7 @@
describe('parser', function() {
beforeEach(function() {
/* global getterFnCache: true, promiseWarningCache: true */
// clear caches
getterFnCache = {};
promiseWarningCache = {};
@@ -13,6 +14,7 @@ describe('parser', function() {
var lex;
beforeEach(function () {
/* global Lexer: false */
lex = function () {
var lexer = new Lexer({csp: false, unwrapPromises: false});
return lexer.lex.apply(lexer, arguments);
@@ -225,6 +227,7 @@ describe('parser', function() {
}));
it('should parse expressions', function() {
/*jshint -W006, -W007 */
expect(scope.$eval("-1")).toEqual(-1);
expect(scope.$eval("1 + 2.5")).toEqual(3.5);
expect(scope.$eval("1 + -2.5")).toEqual(-1.5);
@@ -235,6 +238,7 @@ describe('parser', function() {
});
it('should parse comparison', function() {
/* jshint -W041 */
expect(scope.$eval("false")).toBeFalsy();
expect(scope.$eval("!true")).toBeFalsy();
expect(scope.$eval("1==1")).toBeTruthy();
@@ -367,11 +371,11 @@ describe('parser', function() {
// Assign to x1 and build path 'x1.x2.x3. ... .x[n]' to access the final value.
scope.x1 = obj;
var path = 'x1';
for (var i = 2; i <= pathLength; i++) {
for (i = 2; i <= pathLength; i++) {
path += '.x' + i;
}
expect(scope.$eval(path)).toBe(42);
locals['x' + pathLength] = 'not 42'
locals['x' + pathLength] = 'not 42';
expect(scope.$eval(path, locals)).toBe(42);
});
});
@@ -444,7 +448,7 @@ describe('parser', function() {
it('should evaluate function call from a return value', function() {
scope.val = 33;
scope.getter = function() { return function() { return this.val; }};
scope.getter = function() { return function() { return this.val; }; };
expect(scope.$eval("getter()()")).toBe(33);
});
@@ -580,6 +584,7 @@ describe('parser', function() {
});
it('should evaluate negation', function() {
/* jshint -W018 */
expect(scope.$eval("!false || true")).toEqual(!false || true);
expect(scope.$eval("!11 == 10")).toEqual(!11 == 10);
expect(scope.$eval("12/6/2")).toEqual(12/6/2);
@@ -709,7 +714,7 @@ describe('parser', function() {
'Expression: $eval.call()');
expect(function() {
scope.$eval('fn()')
scope.$eval('fn()');
}).toThrowMinErr(
'$parse', 'isecff', 'Referencing call, apply or bind in Angular expressions is disallowed! ' +
'Expression: fn()');
@@ -976,9 +981,9 @@ describe('parser', function() {
'null,' +
'"alert(1)"' +
')()' +
'')
'');
}).toThrow();
})
});
});
it('should call the function from the received instance and not from a new one', function() {
+31 -29
View File
@@ -72,7 +72,7 @@ describe('q', function() {
name = 'success' + (name || '');
return function() {
return _logInvocation(name, arguments, (returnValDefined ? returnVal : arguments[0]), throwReturnVal);
}
};
}
/**
@@ -88,7 +88,7 @@ describe('q', function() {
name = 'finally' + (name || '');
return function() {
return _logInvocation(name, arguments, (returnValDefined ? returnVal : arguments[0]), throwReturnVal);
}
};
}
/**
@@ -104,7 +104,7 @@ describe('q', function() {
name = 'progress' + (name || '');
return function() {
return _logInvocation(name, arguments, (returnValDefined ? returnVal : arguments[0]), throwReturnVal);
}
};
}
/**
@@ -125,7 +125,7 @@ describe('q', function() {
} else {
return _logInvocation(name, arguments, returnVal, throwReturnVal);
}
}
};
}
/** helper for synchronous resolution of deferred */
@@ -177,13 +177,14 @@ describe('q', function() {
});
}
}
}
};
beforeEach(function() {
/* global qFactory: false */
q = qFactory(mockNextTick.nextTick, noop),
defer = q.defer;
deferred = defer()
deferred = defer();
promise = deferred.promise;
log = [];
mockNextTick.queue = [];
@@ -343,7 +344,7 @@ describe('q', function() {
expect(mockNextTick.queue.length).toBe(0);
expect(logStr()).toBe('');
promise.then(success(2), error(2))
promise.then(success(2), error(2));
expect(logStr()).toBe('');
mockNextTick.flush();
expect(logStr()).toBe('success2(foo)->foo');
@@ -364,7 +365,7 @@ describe('q', function() {
expect(mockNextTick.queue.length).toBe(0);
expect(logStr()).toBe('');
promise.then(success(2), error(2))
promise.then(success(2), error(2));
expect(logStr()).toBe('');
mockNextTick.flush();
expect(logStr()).toBe('error2(foo)->reject(foo)');
@@ -442,7 +443,7 @@ describe('q', function() {
log = [];
deferred.reject('bar');
deferred.resolve('baz');
deferred.notify('qux')
deferred.notify('qux');
expect(mockNextTick.queue.length).toBe(0);
expect(logStr()).toBe('');
@@ -769,7 +770,7 @@ describe('q', function() {
it('should not take an argument',
function() {
promise['finally'](fin(1))
promise['finally'](fin(1));
syncResolve(deferred, 'foo');
expect(logStr()).toBe('finally1()');
});
@@ -778,7 +779,7 @@ describe('q', function() {
it('should call the callback',
function() {
promise.then(success(1))['finally'](fin(1))
promise.then(success(1))['finally'](fin(1));
syncResolve(deferred, 'foo');
expect(logStr()).toBe('success1(foo)->foo; finally1()');
});
@@ -800,7 +801,7 @@ describe('q', function() {
then(success('BB', 'bb'), error('BB'));
promise.then(success('C', 'c'), error('C'))['finally'](fin('CC', 'IGNORED'))
.then(success('CCC', 'cc'), error('CCC'))
.then(success('CCCC', 'ccc'), error('CCCC'))
.then(success('CCCC', 'ccc'), error('CCCC'));
syncResolve(deferred, 'RESOLVED_VAL');
expect(log).toEqual(['successA(RESOLVED_VAL)->a',
@@ -822,7 +823,7 @@ describe('q', function() {
returnedDef.resolve('bar');
promise['finally'](fin(1, returnedDef.promise))
.then(success(2))
.then(success(2));
syncResolve(deferred, 'foo');
@@ -833,10 +834,10 @@ describe('q', function() {
describe("that is rejected", function() {
it("should reject with this new rejection reason",
function () {
var returnedDef = defer()
var returnedDef = defer();
returnedDef.reject('bar');
promise['finally'](fin(1, returnedDef.promise))
.then(success(2), error(1))
.then(success(2), error(1));
syncResolve(deferred, 'foo');
expect(logStr()).toBe('finally1()->{}; error1(bar)->reject(bar)');
});
@@ -847,7 +848,7 @@ describe('q', function() {
describe("when the callback throws an exception", function() {
it("should reject with this new exception", function() {
promise['finally'](fin(1, "exception", true))
.then(success(1), error(2))
.then(success(1), error(2));
syncResolve(deferred, 'foo');
expect(logStr()).toBe('finally1()->throw(exception); error2(exception)->reject(exception)');
});
@@ -860,14 +861,14 @@ describe('q', function() {
it("should call the callback", function () {
promise['finally'](fin(1))
.then(success(2), error(1))
.then(success(2), error(1));
syncReject(deferred, 'foo');
expect(logStr()).toBe('finally1(); error1(foo)->reject(foo)');
});
it('should reject with the original reason', function() {
promise['finally'](fin(1), "hello")
.then(success(2), error(2))
.then(success(2), error(2));
syncReject(deferred, 'original');
expect(logStr()).toBe('finally1(); error2(original)->reject(original)');
});
@@ -877,10 +878,10 @@ describe('q', function() {
describe("that is fulfilled", function() {
it("should reject with the original reason after that promise resolves", function () {
var returnedDef = defer()
var returnedDef = defer();
returnedDef.resolve('bar');
promise['finally'](fin(1, returnedDef.promise))
.then(success(2), error(2))
.then(success(2), error(2));
syncReject(deferred, 'original');
expect(logStr()).toBe('finally1()->{}; error2(original)->reject(original)');
});
@@ -890,10 +891,10 @@ describe('q', function() {
describe("that is rejected", function () {
it("should reject with the new reason", function() {
var returnedDef = defer()
var returnedDef = defer();
returnedDef.reject('bar');
promise['finally'](fin(1, returnedDef.promise))
.then(success(2), error(1))
.then(success(2), error(1));
syncResolve(deferred, 'foo');
expect(logStr()).toBe('finally1()->{}; error1(bar)->reject(bar)');
});
@@ -906,7 +907,7 @@ describe('q', function() {
it("should reject with this new exception", function() {
promise['finally'](fin(1, "exception", true))
.then(success(1), error(2))
.then(success(1), error(2));
syncResolve(deferred, 'foo');
expect(logStr()).toBe('finally1()->throw(exception); error2(exception)->reject(exception)');
});
@@ -918,7 +919,7 @@ describe('q', function() {
describe('catch', function() {
it('should be a shorthand for defining promise error handlers', function() {
promise['catch'](error(1)).then(null, error(2))
promise['catch'](error(1)).then(null, error(2));
syncReject(deferred, 'foo');
expect(logStr()).toBe('error1(foo)->reject(foo); error2(foo)->reject(foo)');
});
@@ -937,7 +938,7 @@ describe('q', function() {
it('should package an exception into a rejected promise', function() {
var rejectedPromise = q.reject(Error('not gonna happen'));
var rejectedPromise = q.reject(new Error('not gonna happen'));
promise.then(success(), error());
syncResolve(deferred, rejectedPromise);
expect(log).toEqual(['error(Error: not gonna happen)->reject(Error: not gonna happen)']);
@@ -955,7 +956,7 @@ describe('q', function() {
it('should catch exceptions thrown in errback and forward them to derived promises', function() {
var rejectedPromise = q.reject('rejected');
rejectedPromise.then(null, error('Broken', 'catch me!', true)).
then(null, error('Affected'))
then(null, error('Affected'));
mockNextTick.flush();
expect(log).toEqual(['errorBroken(rejected)->throw(catch me!)', 'errorAffected(catch me!)->reject(catch me!)']);
});
@@ -1355,13 +1356,13 @@ describe('q', function() {
logger: function(e) {
mockExceptionLogger.log.push(e);
}
}
};
beforeEach(function() {
q = qFactory(mockNextTick.nextTick, mockExceptionLogger.logger),
defer = q.defer;
deferred = defer()
deferred = defer();
promise = deferred.promise;
log = [];
mockExceptionLogger.log = [];
@@ -1413,7 +1414,8 @@ describe('q', function() {
log = [];
syncResolve(deferred, 'ok');
expect(logStr()).toBe('success(ok)->ok');
});
}
);
});
+1 -1
View File
@@ -27,7 +27,7 @@ describe('$$rAF', function() {
try {
$$rAF.flush();
} catch(e) {};
} catch(e) {}
expect(present).toBe(true);
}));
+26 -22
View File
@@ -13,6 +13,7 @@ describe('Scope', function() {
it('should expose the constructor', inject(function($rootScope) {
/* jshint -W103 */
if (msie) return;
expect($rootScope.__proto__).toBe($rootScope.constructor.prototype);
}));
@@ -251,7 +252,7 @@ describe('Scope', function() {
try {
$rootScope.$digest();
throw Error('Should have thrown exception');
throw new Error('Should have thrown exception');
} catch(e) {
expect(e.message.match(/"fn: (watcherA|function)/g).length).toBe(10);
}
@@ -260,27 +261,27 @@ describe('Scope', function() {
it('should prevent infinite loop when creating and resolving a promise in a watched expression', function() {
module(function($rootScopeProvider) {
$rootScopeProvider.digestTtl(10);
$rootScopeProvider.digestTtl(10);
});
inject(function($rootScope, $q) {
var d = $q.defer();
var d = $q.defer();
d.resolve('Hello, world.');
$rootScope.$watch(function () {
var $d2 = $q.defer();
$d2.resolve('Goodbye.');
$d2.promise.then(function () { });
return d.promise;
}, function () { return 0; });
d.resolve('Hello, world.');
$rootScope.$watch(function () {
var $d2 = $q.defer();
$d2.resolve('Goodbye.');
$d2.promise.then(function () { });
return d.promise;
}, function () { return 0; });
expect(function() {
$rootScope.$digest();
}).toThrowMinErr('$rootScope', 'infdig', '10 $digest() iterations reached. Aborting!\n'+
'Watchers fired in the last 5 iterations: []');
expect(function() {
$rootScope.$digest();
}).toThrowMinErr('$rootScope', 'infdig', '10 $digest() iterations reached. Aborting!\n'+
'Watchers fired in the last 5 iterations: []');
expect($rootScope.$$phase).toBeNull();
});
expect($rootScope.$$phase).toBeNull();
});
});
it('should not fire upon $watch registration on initial $digest', inject(function($rootScope) {
@@ -748,7 +749,7 @@ describe('Scope', function() {
$rootScope.$watch(log.fn('w4'), function() {
log('w4action');
$rootScope.$evalAsync(function() {
log('evalAsync')
log('evalAsync');
});
});
$rootScope.$digest();
@@ -1067,7 +1068,8 @@ describe('Scope', function() {
expect($rootScope.$$asyncQueue).toEqual([
{scope: $rootScope, expression: 'rootExpression'},
{scope: childScope, expression: 'childExpression'},
{scope: isolateScope, expression: 'isolateExpression'}]);
{scope: isolateScope, expression: 'isolateExpression'}
]);
}));
@@ -1247,9 +1249,11 @@ describe('Scope', function() {
});
});
expect(function() { childScope2.$apply(function() {
childScope2.x = 'something';
}); }).toThrowMinErr('$rootScope', 'inprog', '$digest already in progress');
expect(function() {
childScope2.$apply(function() {
childScope2.x = 'something';
});
}).toThrowMinErr('$rootScope', 'inprog', '$digest already in progress');
}));
});
});
@@ -1668,7 +1672,7 @@ describe('Scope', function() {
expect(scope.greeting).toEqual(undefined);
scope.$watch('name', function() {
scope.greeting = scope.salutation + ' ' + scope.name + '!';
scope.greeting = scope.salutation + ' ' + scope.name + '!';
}); // initialize the watch
expect(scope.greeting).toEqual(undefined);
+11 -3
View File
@@ -12,7 +12,7 @@ describe('sanitizeUri', function() {
};
sanitizeImg = function(uri) {
return $$sanitizeUri(uri, true);
}
};
});
});
@@ -25,6 +25,7 @@ describe('sanitizeUri', function() {
describe('img[src] sanitization', function() {
it('should sanitize javascript: urls', function() {
/* jshint scripturl:true */
testUrl = "javascript:doEvilStuff()";
expect(sanitizeImg(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
});
@@ -50,6 +51,7 @@ describe('sanitizeUri', function() {
});
it('should sanitize obfuscated javascript: urls', function() {
/* jshint scripturl:true */
// case-sensitive
testUrl = "JaVaScRiPt:doEvilStuff()";
expect(sanitizeImg(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
@@ -79,6 +81,7 @@ describe('sanitizeUri', function() {
});
it('should sanitize ng-src bindings as well', function() {
/* jshint scripturl:true */
testUrl = "javascript:doEvilStuff()";
expect(sanitizeImg(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
});
@@ -115,6 +118,7 @@ describe('sanitizeUri', function() {
it('should allow reconfiguration of the src whitelist', function() {
/* jshint scripturl:true */
var returnVal;
expect(sanitizeUriProvider.imgSrcSanitizationWhitelist() instanceof RegExp).toBe(true);
returnVal = sanitizeUriProvider.imgSrcSanitizationWhitelist(/javascript:/);
@@ -133,6 +137,7 @@ describe('sanitizeUri', function() {
describe('a[href] sanitization', function() {
it('should sanitize javascript: urls', inject(function() {
/* jshint scripturl:true */
testUrl = "javascript:doEvilStuff()";
expect(sanitizeHref(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
}));
@@ -145,6 +150,7 @@ describe('sanitizeUri', function() {
it('should sanitize obfuscated javascript: urls', inject(function() {
/* jshint scripturl:true */
// case-sensitive
testUrl = "JaVaScRiPt:doEvilStuff()";
expect(sanitizeHref(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
@@ -175,6 +181,7 @@ describe('sanitizeUri', function() {
it('should sanitize ngHref bindings as well', inject(function() {
/* jshint scripturl:true */
testUrl = "javascript:doEvilStuff()";
expect(sanitizeHref(testUrl)).toBe('unsafe:javascript:doEvilStuff()');
}));
@@ -213,16 +220,17 @@ describe('sanitizeUri', function() {
}));
it('should allow reconfiguration of the href whitelist', function() {
/* jshint scripturl:true */
var returnVal;
expect(sanitizeUriProvider.aHrefSanitizationWhitelist() instanceof RegExp).toBe(true);
returnVal = sanitizeUriProvider.aHrefSanitizationWhitelist(/javascript:/);
expect(returnVal).toBe(sanitizeUriProvider);
testUrl = "javascript:doEvilStuff()";
expect(sanitizeHref(testUrl)).toBe('javascript:doEvilStuff()');
expect(sanitizeHref(testUrl)).toBe('javascript:doEvilStuff()');
testUrl = "http://recon/figured";
expect(sanitizeHref(testUrl)).toBe('unsafe:http://recon/figured');
expect(sanitizeHref(testUrl)).toBe('unsafe:http://recon/figured');
});
});
+33 -20
View File
@@ -38,6 +38,7 @@ describe('SCE', function() {
inject(function($window, $injector) {
function constructSce() {
/* global $SceProvider: false */
var sceProvider = new $SceProvider();
sceProvider.enabled(enabled);
return $injector.invoke(sceProvider.$get, sceProvider);
@@ -162,7 +163,7 @@ describe('SCE', function() {
};
}
var wrappedValue = new TrustedValueHolder("originalValue");
expect(function() { return $sce.getTrusted($sce.HTML, wrappedValue) }).toThrowMinErr(
expect(function() { return $sce.getTrusted($sce.HTML, wrappedValue); }).toThrowMinErr(
'$sce', 'unsafe', 'Attempting to use an unsafe value in a safe context.');
}));
@@ -179,9 +180,9 @@ describe('SCE', function() {
it('should override the default $sce.trustAs/valueOf/etc.', function() {
module(function($provide) {
$provide.value('$sceDelegate', {
trustAs: function(type, value) { return "wrapped:" + value; },
getTrusted: function(type, value) { return "unwrapped:" + value; },
valueOf: function(value) { return "valueOf:" + value; }
trustAs: function(type, value) { return "wrapped:" + value; },
getTrusted: function(type, value) { return "unwrapped:" + value; },
valueOf: function(value) { return "valueOf:" + value; }
});
});
@@ -196,7 +197,7 @@ describe('SCE', function() {
describe('$sce.parseAs', function($sce) {
it('should parse constant literals as trusted', inject(function($sce) {
it('should parse constant literals as trusted', inject(function($sce) {
expect($sce.parseAsJs('1')()).toBe(1);
expect($sce.parseAsJs('1', $sce.ANY)()).toBe(1);
expect($sce.parseAsJs('1', $sce.HTML)()).toBe(1);
@@ -218,7 +219,7 @@ describe('SCE', function() {
it('should NOT return untrusted values from expression function', inject(function($sce) {
var exprFn = $sce.parseAs($sce.HTML, 'foo');
expect(function() {
return exprFn({}, {'foo': true})
return exprFn({}, {'foo': true});
}).toThrowMinErr(
'$sce', 'unsafe', 'Attempting to use an unsafe value in a safe context.');
}));
@@ -226,7 +227,7 @@ describe('SCE', function() {
it('should NOT return trusted values of the wrong type from expression function', inject(function($sce) {
var exprFn = $sce.parseAs($sce.HTML, 'foo');
expect(function() {
return exprFn({}, {'foo': $sce.trustAs($sce.JS, '123')})
return exprFn({}, {'foo': $sce.trustAs($sce.JS, '123')});
}).toThrowMinErr(
'$sce', 'unsafe', 'Attempting to use an unsafe value in a safe context.');
}));
@@ -262,11 +263,11 @@ describe('SCE', function() {
}
});
inject(testFn);
}
};
}
it('should default to "self" which allows relative urls', runTest({}, function($sce, $document) {
expect($sce.getTrustedResourceUrl('foo/bar')).toEqual('foo/bar');
expect($sce.getTrustedResourceUrl('foo/bar')).toEqual('foo/bar');
}));
it('should reject everything when whitelist is empty', runTest(
@@ -276,7 +277,8 @@ describe('SCE', function() {
}, function($sce) {
expect(function() { $sce.getTrustedResourceUrl('#'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: #');
}));
}
));
it('should match against normalized urls', runTest(
{
@@ -285,7 +287,8 @@ describe('SCE', function() {
}, function($sce) {
expect(function() { $sce.getTrustedResourceUrl('foo'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: foo');
}));
}
));
it('should not accept unknown matcher type', function() {
expect(function() {
@@ -296,6 +299,7 @@ describe('SCE', function() {
});
describe('adjustMatcher', function() {
/* global adjustMatcher: false */
it('should rewrite regex into regex and add ^ & $ on either end', function() {
expect(adjustMatcher(/a.*b/).exec('a.b')).not.toBeNull();
expect(adjustMatcher(/a.*b/).exec('-a.b-')).toBeNull();
@@ -318,7 +322,8 @@ describe('SCE', function() {
// https doesn't match (mismatched protocol.)
expect(function() { $sce.getTrustedResourceUrl('https://example.com/foo'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: https://example.com/foo');
}));
}
));
it('should match entire regex', runTest(
{
@@ -335,7 +340,8 @@ describe('SCE', function() {
// Prefix not allowed even though original regex does not contain a leading ^.
expect(function() { $sce.getTrustedResourceUrl('xhttp://example.com/foo'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: xhttp://example.com/foo');
}));
}
));
});
describe('string matchers', function() {
@@ -354,7 +360,8 @@ describe('SCE', function() {
// You can match a suffix.
expect(function() { $sce.getTrustedResourceUrl('xhttp://example.com/foo'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: xhttp://example.com/foo');
}));
}
));
it('should support the * wildcard', runTest(
{
@@ -382,7 +389,8 @@ describe('SCE', function() {
// The * wildcard does not match ';'
expect(function() { $sce.getTrustedResourceUrl('http://example-com/foo;bar'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example-com/foo;bar');
}));
}
));
it('should support the ** wildcard', runTest(
{
@@ -394,7 +402,8 @@ describe('SCE', function() {
expect($sce.getTrustedResourceUrl('http://example.com/foo-bar')).toEqual('http://example.com/foo-bar');
// The ** wildcard accepts the ':/.?&' characters.
expect($sce.getTrustedResourceUrl('http://example.com/foo:1/2.3?4&5-6')).toEqual('http://example.com/foo:1/2.3?4&5-6');
}));
}
));
it('should not accept *** in the string', function() {
expect(function() {
@@ -412,7 +421,8 @@ describe('SCE', function() {
blackList: []
}, function($sce) {
expect($sce.getTrustedResourceUrl('foo')).toEqual('foo');
}));
}
));
it('should support the special string "self" in blacklist', runTest(
{
@@ -421,7 +431,8 @@ describe('SCE', function() {
}, function($sce) {
expect(function() { $sce.getTrustedResourceUrl('foo'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: foo');
}));
}
));
});
it('should have blacklist override the whitelist', runTest(
@@ -431,7 +442,8 @@ describe('SCE', function() {
}, function($sce) {
expect(function() { $sce.getTrustedResourceUrl('foo'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: foo');
}));
}
));
it('should support multiple items in both lists', runTest(
{
@@ -445,7 +457,8 @@ describe('SCE', function() {
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example.com/3');
expect(function() { $sce.getTrustedResourceUrl('open_redirect'); }).toThrowMinErr(
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: open_redirect');
}));
}
));
});
describe('sanitizing html', function() {
+1
View File
@@ -3,6 +3,7 @@
describe('$sniffer', function() {
function sniffer($window, $document) {
/* global $SnifferProvider: false */
$window.navigator = {};
$document = jqLite($document || {});
if (!$document[0].body) {

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