Compare commits

...

35 Commits

Author SHA1 Message Date
Jeff Cross 3468ad1b61 chore(release): cut 1.2.5 singularity-expansion release 2013-12-13 10:52:13 -08:00
Jeff Cross e9c79cad43 docs(CHANGELOG): add v1.2.5 changes 2013-12-13 10:44:40 -08:00
Igor Minar e455e7d878 docs(TRIAGING): add info about "needs: public api" 2013-12-13 08:53:33 -08:00
Michał Gołębiowski 3410f65e79 perf(jqLite): implement and use the empty method in place of html(‘’)
jQuery's elem.html('') is way slower than elem.empty(). As clearing
element contents happens quite often in certain scenarios, switching
to using .empty() provides a significant performance boost when using
Angular with jQuery.

Closes #4457
2013-12-13 02:07:11 -08:00
Karl Seamon f3de5b6eac perf(a): do not link when href or name exists in template
Change the a directive to link and hookup a click event only when
there is no href or name in the template element.
In a large Google app, this results in about 800 fewer registrations,
saving a small but measurable amount of time and memory.

Closes #5362
2013-12-13 00:31:25 -08:00
Karl Seamon fcd2a8131a perf($resource): use shallow copy instead of angular.copy
Replace calls to angular.copy with calls to a new function, shallowClearAndCopy.
Add calls to copy for cache access in $http in order to prevent modification of cached data.
Results in a measurable improvement to the startup time of complex apps within Google.

Closes #5300
2013-12-13 00:24:37 -08:00
Karl Seamon 62dbe85798 perf: use call and === instead of apply and == in type check functions
Updates isDate et al to use call instead of apply and === instead of ==.
The change to call brings minor performance improvement and === is just
better practice than ==.
http://jsperf.com/call-vs-apply-tostring

Closes #5295
2013-12-13 00:22:47 -08:00
Brian Atkinson 1d5e18b062 fix(closure): add missing FormController extern definitions
Closes #5303
2013-12-13 00:14:31 -08:00
Igor Minar a0ed371389 style($injector): remove ws 2013-12-12 23:51:45 -08:00
Ben Wiklund 05e4fd3488 perf($injector): remove invoke optimization that doesn't work
Closes #5388
2013-12-12 23:49:03 -08:00
Tobias Bosch 30a8b7d0b5 fix(ngInclude): Add template to DOM before linking other directives
The template needs to be added to the DOM before
other directives at the same element as `ngInclude` are linked.

Fixes #5247.
2013-12-12 17:18:44 -08:00
Tobias Bosch f8944efe70 fix(ngView): Add template to DOM before linking other directives
The template needs to be added to the DOM before
other directives at the same element as `ngView` are linked.

Related to #5247.
2013-12-12 17:18:44 -08:00
Tobias Bosch 43072e3812 fix($compile): Allow literals in isolate scope references
When a component uses an isolate scope reference
and the the component is used with an object literal
a new object is created on every evaluation.
Therefore the compiler needs to compare
the values of the parent and the isolate scope
using object equality and not object reference
equality.

Fixes #5296.
2013-12-12 16:30:31 -08:00
Pete Bacon Darwin 9396d55414 docs(ngSwitch): clarify that ngSwitch matches against string literals
Closes #5285
2013-12-12 11:42:49 +00:00
mbrookes 82e97cf53e docs(guide/expression): remove misplaced comma
Closes #5280
2013-12-12 11:25:41 +00:00
Jürgen Walter cf2a7614a4 docs(tutorial/step-07): update path to pages in e2e scenarios
The url paths in the tutorial are not in line with the actual tutorial code

Closes #5264
2013-12-12 11:22:31 +00:00
Vlad GURDIGA 9e538e7c31 docs(ng.$rootScope.Scope): fix API links
Also added a note to the Writing AngularJS Documentation:
https://github.com/angular/angular.js/wiki/Writing-AngularJS-Documentation/d0c715ef89

Closes #5261
2013-12-12 11:19:16 +00:00
Mattias Holmlund 4ac21ac039 docs(error/transclude/orphan): fix spelling mistakes
Closes #5259
2013-12-12 11:15:31 +00:00
Karl Seamon f69dc16241 fix(angular-mocks): use copy of mock data in $httpBackend
Copy mock data returned from the mock $httpBackend.
This prevents modifications to the response from affecting future responses.
Previously, this misbehavior was being mitigated by the deep copy in $resource, but that no longer exists.
2013-12-11 15:18:45 -08:00
Brian Ford f1a8d419d5 chore(scripts): fix bower script to pull from master before updating 2013-12-11 14:35:23 -08:00
Vojta Jina 8864e54f1f chore(scripts): refactor travis scripts
Refactoring so that it's easier to use both SL/BS just depending on a global switch.
2013-12-11 10:12:18 -08:00
Vojta Jina dc4df93177 chore(travis): run two jobs
Instead of parallelization on a single Travis VM, we use two VMs.
- output is nicer (we don't have to buffer e2e tests and then show it at the end)
- you can easily see faster the result of unit tests (as it's basically a separate build)

We should also make sure we only do the necesary stuff (for install we don't need to do `grunt
package` for unit tests, we only need to generate the docs for e2e tests.
2013-12-11 10:02:14 -08:00
Tobias Bosch 043190f397 docs(TRIAGING): Add Type:Perf label 2013-12-09 17:54:08 -08:00
Tobias Bosch f4d850e168 docs(TRIAGING): Labels cla yes/no are automatically set
The labels are set by a script and
should not be set manually any more.
2013-12-09 17:30:43 -08:00
Andy Ferra 8ec2743ca1 docs(design): guide index formatting
Just my first pass at a more readable format of the guide index.

Note: the styles apply to all content in the docs, not just the guide
index. This is intentional and I feel that the result is positive.
2013-12-09 16:32:10 -08:00
Vojta Jina ecbee8147b style($route): make jshint happy
Fix the broken build and earn a late (french spelling).
2013-12-09 14:57:49 -08:00
miknsh5 f8c6ee3df5 docs(input): remove redundant closing span tag
Closes #5257
2013-12-09 20:52:00 +00:00
hambyiii fe84f7bef8 docs($route): clarify examples of route parameters
Putting route parameter examples in braces was misleading newcomers.

Closes #5243
2013-12-09 20:48:50 +00:00
Robin Böhm d653607162 docs($q): correct typo in the 'Differences Q/$q' section
Closes #5230
2013-12-09 20:46:21 +00:00
gdi2290 082fe180ec docs(contribute) add platform agnostic git install link
Closes #5216
2013-12-09 20:27:08 +00:00
Shane M. Pelletier d3491083a5 docs(tutorial): enlarge clickable area of tutorial nav buttons
Change position of <a> and <li> tags in tutorial nav buttons
partial. This allows the full area of the button to be clicked
rather than just the text.

Closes #5074
Closes #5209
2013-12-09 20:24:54 +00:00
Wesley Cho c3d6ca97e1 docs(guide/forms): clarify how NgModelController can be added to scope
Closes #5200
2013-12-09 20:14:45 +00:00
Matias Niemelä a14266e464 chore(CHANGELOG): introduce perf() section for performance-related commits
Instead of using fix() or chore() when labelling a commit which improves
speed or performance use perf(). Perf commits will be listed in the
CHANGELOG under "Performance Improvements".

For example:
perf($animate): cache all getComputedStyle operations to reduce additional reflows
2013-12-09 11:52:28 -05:00
Joscha Feth b4d44e1298 docs($injector): add example on how to use the element.injector
Closes #5188
2013-12-09 16:32:09 +00:00
Matias Niemelä ca116c35a6 chore(release): start 1.2.5 singularity-expansion iteration 2013-12-06 14:51:45 -05:00
54 changed files with 634 additions and 244 deletions
+7 -5
View File
@@ -3,13 +3,16 @@ node_js:
- 0.10
env:
matrix:
- JOB=unit
- JOB=e2e
global:
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
- BROWSER_STACK_USERNAME=VojtaJina
- BROWSER_STACK_ACCESS_KEY=HAfHZaypxAc3PEUrUU9a
- LOGS_DIR=/tmp/angular-build/logs
- BROWSER_PROVIDER_READY_FILE=/tmp/sauce-connect-ready
before_script:
- mkdir -p $LOGS_DIR
@@ -18,11 +21,10 @@ before_script:
- grunt bower
- grunt bower
- grunt package-without-bower
- ./lib/sauce/sauce_connect_block.sh
- ./scripts/travis/wait_for_browser_provider.sh
script:
- grunt ci-checks
- ./travis_build.sh
- ./scripts/travis/build.sh
after_script:
- ./travis_print_logs.sh
- ./scripts/travis/print_logs.sh
+43
View File
@@ -1,3 +1,46 @@
<a name="1.2.5"></a>
# 1.2.5 singularity-expansion (2013-12-13)
## Bug Fixes
- **$compile:** allow literals in isolate scope references
([43072e38](https://github.com/angular/angular.js/commit/43072e3812e32b89b97ad03144577cba50d4b776),
[#5296](https://github.com/angular/angular.js/issues/5296))
- **angular-mocks:** use copy of mock data in $httpBackend
([f69dc162](https://github.com/angular/angular.js/commit/f69dc16241c8b631123ad0b09674f0a5e0ff32fe))
- **closure:** add missing FormController extern definitions
([1d5e18b0](https://github.com/angular/angular.js/commit/1d5e18b062c3e33b2a8d96aa58d905ed2cd48649),
[#5303](https://github.com/angular/angular.js/issues/5303))
- **ngInclude:** add template to DOM before linking other directives
([30a8b7d0](https://github.com/angular/angular.js/commit/30a8b7d0b5d4882c2bf3b20eb696a02f5b667726),
[#5247](https://github.com/angular/angular.js/issues/5247))
- **ngView:** add template to DOM before linking other directives
([f8944efe](https://github.com/angular/angular.js/commit/f8944efe70b81e02704df9b53ea2546c80c73d3b))
## Performance Improvements
- **$injector:** remove invoke optimization that doesn't work
([05e4fd34](https://github.com/angular/angular.js/commit/05e4fd3488b89e670c36869f18defe26deac2efa),
[#5388](https://github.com/angular/angular.js/issues/5388))
- **$resource:** use shallow copy instead of angular.copy
([fcd2a813](https://github.com/angular/angular.js/commit/fcd2a8131a3cb3e59a616bf31e61510b5c3a97d3),
[#5300](https://github.com/angular/angular.js/issues/5300))
- **a:** do not link when href or name exists in template
([f3de5b6e](https://github.com/angular/angular.js/commit/f3de5b6eac90baf649506072162f36dbc6d2f028),
[#5362](https://github.com/angular/angular.js/issues/5362))
- **jqLite:** implement and use the `empty` method in place of `html(‘’)`
([3410f65e](https://github.com/angular/angular.js/commit/3410f65e790a81d457b4f4601a1e760a6f8ede5e),
[#4457](https://github.com/angular/angular.js/issues/4457))
## Breaking Changes
- **angular-mocks:** due to [f69dc162](https://github.com/angular/angular.js/commit/f69dc16241c8b631123ad0b09674f0a5e0ff32fe),
some tests that rely on identity comparison rather than equality comparison in checking mock http responses will be broken,
since now each mock response is a copy of the original response. This is usually fixable by changing a `.toBe()` comparison
to `toEqual()` inside of tests.
<a name="1.2.4"></a>
# 1.2.4 wormhole-blaster (2013-12-06)
+1
View File
@@ -198,6 +198,7 @@ Must be one of the following:
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug or adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
+9 -3
View File
@@ -10,6 +10,13 @@ The labels are used later on for planning releases.
* these tags can be used for labeling a closed issue/PR with a reason why it was closed. (we can add reasons as we need them, right there are only a few rejection reasons. it doesn't make sense to label issues that were fixed or prs that were merged)
## Automatic processing ##
We have automatic tools (e.g. Mary Poppins) that automatically add comments / labels to issues and PRs.
The following is done automatically and should not be done manually:
* Label "cla: yes" or "cla: no" for pull requests
## Process ##
1. Open list of [non triaged issues](https://github.com/angular/angular.js/issues?direction=desc&milestone=none&page=1&sort=created&state=open)
@@ -29,8 +36,9 @@ The labels are used later on for planning releases.
* Reproducible on master? - http://code.angularjs.org/snapshot/
1. Non bugs:
* Label "Type: Feature" or "Type: Chore"
* Label "Type: Feature" or "Type: Chore" or "Type: Perf"
* Label "needs: breaking change" - if needed
* Label "needs: public api" - if a new public api is needed
* Understandable? - verify if the description of the request is clear. if not ask for clarification
* Goals of angular core? - Often new features should be implemented as a third-party module rather than an addition to the core.
@@ -46,8 +54,6 @@ The labels are used later on for planning releases.
* large - changes to many components in angular or any changes to $compile, ngRepeat or other "fun" components
1. Label "PRs welcome" for "GH: issue"
* if complexity is small or medium and the problem as well as solution are well captured in the issue
1. Label "cla: yes" for "GH: PR":
* otherwise prompt the contributor to sign the CLA
1. Label "origin: google" for issues from Google
1. Label "high priority" for security issues, major performance regressions or memory leaks
+3 -1
View File
@@ -142,6 +142,7 @@ var writeChangelog = function(stream, commits, version) {
var sections = {
fix: {},
feat: {},
perf: {},
breaks: {}
};
@@ -169,6 +170,7 @@ var writeChangelog = function(stream, commits, version) {
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
printSection(stream, 'Bug Fixes', sections.fix);
printSection(stream, 'Features', sections.feat);
printSection(stream, 'Performance Improvements', sections.perf);
printSection(stream, 'Breaking Changes', sections.breaks, false);
}
@@ -186,7 +188,7 @@ var getPreviousTag = function() {
var generate = function(version, file) {
getPreviousTag().then(function(tag) {
console.log('Reading git log since', tag);
readGitLog('^fix|^feat|BREAKING', tag).then(function(commits) {
readGitLog('^fix|^feat|^perf|BREAKING', tag).then(function(commits) {
console.log('Parsed', commits.length, 'commits');
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
+33
View File
@@ -1441,6 +1441,11 @@ angular.NgModelController.prototype.$viewValue;
*/
angular.FormController = function() {};
/**
* @param {*} control
*/
angular.FormController.prototype.$addControl = function(control) {};
/**
* @type {boolean}
*/
@@ -1456,11 +1461,39 @@ angular.FormController.prototype.$error;
*/
angular.FormController.prototype.$invalid;
/**
* @type {string}
*/
angular.FormController.prototype.$name;
/**
* @type {boolean}
*/
angular.FormController.prototype.$pristine;
/**
* @param {*} control
*/
angular.FormController.prototype.$removeControl = function(control) {};
/**
* @type {function()}
*/
angular.FormController.prototype.$setDirty = function() {};
/**
* @type {function()}
*/
angular.FormController.prototype.$setPristine = function() {};
/**
* @param {string} validationToken
* @param {boolean} isValid
* @param {*} control
*/
angular.FormController.prototype.$setValidity = function(
validationToken, isValid, control) {};
/**
* @type {boolean}
*/
+1 -1
View File
@@ -5,7 +5,7 @@ describe('Docs Annotations', function() {
var body;
beforeEach(function() {
body = angular.element(document.body);
body.html('');
body.empty();
});
var normalizeHtml = function(html) {
+1 -1
View File
@@ -28,7 +28,7 @@ function escape(text) {
function setHtmlIe8SafeWay(element, html) {
var newElement = angular.element('<pre>' + html + '</pre>');
element.html('');
element.empty();
element.append(newElement.contents());
return element;
}
+2 -2
View File
@@ -3,9 +3,9 @@
@fullName Orphan ngTransclude Directive
@description
Occurs when an `ngTransclude` occurs without a transcluded ancesstor element.
Occurs when an `ngTransclude` occurs without a transcluded ancestor element.
This error often occurs when you have forgotten to set `transclude: true` in some directive definition, and then used `ngTranslude` in the driective's template.
This error often occurs when you have forgotten to set `transclude: true` in some directive definition, and then used `ngTransclude` in the directive's template.
To resolve, either remove the offending `ngTransclude` or check that `transclude: true` is included in the intended directive definition.
@@ -222,7 +222,7 @@ var pc = new PasswordCtrl();
input.val('abc');
pc.grade();
expect(span.text()).toEqual('weak');
$('body').html('');
$('body').empty();
</pre>
In angular the controllers are strictly separated from the DOM manipulation logic and this results in
+1 -1
View File
@@ -18,7 +18,7 @@ It might be tempting to think of Angular view expressions as JavaScript expressi
not entirely correct, since Angular does not use a JavaScript `eval()` to evaluate expressions.
You can think of Angular expressions as JavaScript expressions with following differences:
* **Attribute Evaluation:** evaluation of all properties are against the scope, doing the
* **Attribute Evaluation:** evaluation of all properties are against the scope doing the
evaluation, unlike in JavaScript where the expressions are evaluated against the global
`window`.
+8 -3
View File
@@ -115,9 +115,14 @@ This ensures that the user is not distracted with an error until after interacti
A form is an instance of {@link api/ng.directive:form.FormController FormController}.
The form instance can optionally be published into the scope using the `name` attribute.
Similarly, control is an instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
The control instance can similarly be published into the form instance using the `name` attribute.
This implies that the internal state of both the form and the control is available for binding in the view using the standard binding primitives.
Similarly, an input control that has the {@link api.ng.directive:ng-model} directive holds an
instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
Such a control instance can be published as a property of the form instance using the `name` attribute
on the input control. The name attribute specifies the name of the property on the form instance.
This implies that the internal state of both the form and the control is available for binding in
the view using the standard binding primitives.
This allows us to extend the above example with these features:
+6 -46
View File
@@ -7,19 +7,14 @@
Everything you need to know about AngularJS
* {@link guide/introduction What is AngularJS?}
* {@link guide/concepts Conceptual Overview}
## Tutorials
* {@link tutorial/index Official AngularJS Tutorial}
* [10 Reasons Why You Should Use AngularJS](http://www.sitepoint.com/10-reasons-use-angularjs/)
* [Design Principles of AngularJS (video)](https://www.youtube.com/watch?v=HCR7i5F5L8c)
* [Fundamentals in 60 Minutes (video)](http://www.youtube.com/watch?v=i9MHigUZKEM)
* [For folks with jQuery background](http://stackoverflow.com/questions/14994391/how-do-i-think-in-angularjs-if-i-have-a-jquery-background)
## Core Concepts
@@ -29,63 +24,44 @@ Everything you need to know about AngularJS
In Angular applications, you move the job of filling page templates with data from the server to the client. The result is a system better structured for dynamic page updates. Below are the core features you'll use.
* {@link guide/databinding Data binding}
* {@link guide/expression Expressions}
* {@link guide/directive Directives}
* {@link api/ngRoute.$route Views and routes (see the example)}
* {@link guide/filter Filters}
* {@link guide/forms Forms} and [Concepts of AngularJS Forms](http://mrbool.com/the-concepts-of-angularjs-forms/29117)
### Application Structure
* **Blog post: **[When to use directives, controllers or services](http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/)
* **App wiring:** {@link guide/di Dependency injection}
* **Exposing model to templates:** {@link guide/scope Scopes}
* **Communicating with servers:** {@link api/ng.$http $http}, {@link api/ngResource.$resource $resource}
### Other AngularJS Features
* **Animation:** {@link guide/animations Core concepts}, {@link api/ngAnimate ngAnimate API}, and [Animation in AngularJS 1.2](http://www.yearofmoo.com/2013/08/remastered-animation-in-angularjs-1-2.html)
* **Security:** {@link api/ng.$sce Strict Contextual Escaping}, {@link api/ng.directive:ngCsp Content Security Policy}, {@link api/ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
* **Internationalization and Localization:** {@link guide/i18n Angular Guide to i18n and l10n}, {@link api/ng.filter:date date filter}, {@link api/ng.filter:currency currency filter}, [Creating multilingual support](http://www.novanet.no/blog/hallstein-brotan/dates/2013/10/creating-multilingual-support-using-angularjs/)
* **Mobile:** {@link api/ngTouch Touch events}
### Testing
* **Unit testing:** [Using Karma (video)](http://www.youtube.com/watch?v=YG5DEzaQBIc), {@link guide/dev_guide.unit-testing Unit testing}, {@link guide/dev_guide.services.testing_services Testing services}, [Karma in Webstorm](http://blog.jetbrains.com/webstorm/2013/10/running-javascript-tests-with-karma-in-webstorm-7/)
* **Scenario testing:** [Protractor](https://github.com/angular/protractor)
## Specific Topics
* **Login: **[Google example](https://developers.google.com/+/photohunt/python), [Facebook example](http://blog.brunoscopelliti.com/facebook-authentication-in-your-angularjs-web-app), [authentication strategy](http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app), [unix-style authorization](http://frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/)
* **Mobile:** [Angular on Mobile Guide](http://www.ng-newsletter.com/posts/angular-on-mobile.html), [PhoneGap](http://devgirl.org/2013/06/10/quick-start-guide-phonegap-and-angularjs/)
* **Other Languages:** [CoffeeScript](http://www.coffeescriptlove.com/2013/08/angularjs-and-coffeescript-tutorials.html), [Dart](https://github.com/angular/angular.dart.tutorial/wiki)
* **Realtime: **[Socket.io](http://www.creativebloq.com/javascript/angularjs-collaboration-board-socketio-2132885), [OmniBinder](https://github.com/jeffbcross/omnibinder)
* **Visualization:** [SVG](http://gaslight.co/blog/angular-backed-svgs), [D3.js](http://www.ng-newsletter.com/posts/d3-on-angular.html)
## Tools
* **Debugging:** [Batarang](https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en)
* **Testing:** [Karma](http://karma-runner.github.io), [Protractor](https://github.com/angular/protractor)
* **Editor support:** [Webstorm](http://plugins.jetbrains.com/plugin/6971) (and [video](http://www.youtube.com/watch?v=LJOyrSh1kDU)), [Sublime Text](https://github.com/angular-ui/AngularJS-sublime-package), [Visual Studio](http://madskristensen.net/post/angularjs-intellisense-in-visual-studio-2012)
* **Workflow:** [Yeoman.io](https://github.com/yeoman/generator-angular) and [Angular Yeoman Tutorial](http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower/)
## Complementary Libraries
@@ -93,37 +69,26 @@ In Angular applications, you move the job of filling page templates with data fr
This is a short list of libraries with specific support and documentation for working with Angular. You can find a full list of all known Angular external libraries at [ngmodules.org](http://ngmodules.org/).
* **Internationalization:** [angular-translate](http://pascalprecht.github.io/angular-translate/), [angular-gettext](http://angular-gettext.rocketeer.be/)
* **RESTful services:** [Restangular](https://github.com/mgonto/restangular)
* **SQL and NoSQL backends:** [BreezeJS](http://www.breezejs.com/), [AngularFire](http://angularfire.com/)
* **UI Widgets: **[KendoUI](http://kendo-labs.github.io/angular-kendo/#/), [UI Bootstrap](http://angular-ui.github.io/bootstrap/), [Wijmo](http://wijmo.com/tag/angularjs-2/)
## Deployment
### General
### General
* **Javascript minification: **[Background](http://thegreenpizza.github.io/2013/05/25/building-minification-safe-angular.js-applications/), [ngmin automation tool](http://www.thinkster.io/pick/XlWneEZCqY/angularjs-ngmin)
* **Tracking:** [Angularyitcs (Google Analytics)](http://ngmodules.org/modules/angularytics), [Logging Client-Side Errors](http://www.bennadel.com/blog/2542-Logging-Client-Side-Errors-With-AngularJS-And-Stacktrace-js.htm)
* **SEO:** [By hand](http://www.yearofmoo.com/2012/11/angularjs-and-seo.html), [prerender.io](http://prerender.io/), [Brombone](http://www.brombone.com/), [SEO.js](http://getseojs.com/), [SEO4Ajax](http://www.seo4ajax.com/)
### Server-Specific
* **Django:** [Tutorial](http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework), [Integrating AngularJS with Django](http://django-angular.readthedocs.org/en/latest/integration.html)
* **FireBase:** [AngularFire](http://angularfire.com/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
* **Google Cloud Platform: **[with Cloud Endpoints](https://cloud.google.com/resources/articles/angularjs-cloud-endpoints-recipe-for-building-modern-web-applications), [with Go](https://github.com/GoogleCloudPlatform/appengine-angular-gotodos)
* **Hood.ie:** [60 Minutes to Awesome](http://www.roberthorvick.com/2013/06/30/todomvc-angularjs-hood-ie-60-minutes-to-awesome/)
* **MEAN Stack: **[Blog post](http://blog.mongodb.org/post/49262866911/the-mean-stack-mongodb-expressjs-angularjs-and), [Setup](http://thecodebarbarian.wordpress.com/2013/07/22/introduction-to-the-mean-stack-part-one-setting-up-your-tools/), [GDL Video](https://developers.google.com/live/shows/913996610)
* **Rails: **[Tutorial](http://coderberry.me/blog/2013/04/22/angularjs-on-rails-4-part-1/), [AngularJS with Rails4](https://shellycloud.com/blog/2013/10/how-to-integrate-angularjs-with-rails-4), [angularjs-rails](https://github.com/hiravgandhi/angularjs-rails)
* **PHP: **[Building a RESTful web service](http://blog.brunoscopelliti.com/building-a-restful-web-service-with-angularjs-and-php-more-power-with-resource), [End to End with Laravel 4 (video)](http://www.youtube.com/watch?v=hqAyiqUs93c)
## Learning Resources
@@ -137,18 +102,18 @@ This is a short list of libraries with specific support and documentation for wo
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
###Videos:
* [egghead.io](http://egghead.io/),
* [egghead.io](http://egghead.io/)
* [Angular on YouTube](http://youtube.com/angularjs)
###Courses
* **Free on-line:**
### Courses
* **Free online:**
[thinkster.io](http://thinkster.io),
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1)
* **Paid on-line:**
* **Paid online:**
[Pluralsite (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=angularjs),
[Tuts+](https://tutsplus.com/course/easier-js-apps-with-angular/),
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html)
* **Paid on-site:**
* **Paid onsite:**
[angularbootcamp.com](http://angularbootcamp.com/)
## Getting Help
@@ -156,19 +121,14 @@ This is a short list of libraries with specific support and documentation for wo
The recipe for getting help on your unique issue is to create an example that could work (even if it doesn't) in a shareable example on [Plunker](http://plnkr.co/), [JSFiddle](http://jsfiddle.net/), or similar site and then post to one of the following:
* [Stackoverflow.com](http://stackoverflow.com/search?q=angularjs)
* [AngularJS mailing list](https://groups.google.com/forum/#!forum/angular)
* [AngularJS IRC channel](http://webchat.freenode.net/?channels=angularjs&uio=d4)
## Social Channels
* **Daily updates:** [Google+](https://plus.google.com/u/0/+AngularJS) or [Twitter](https://twitter.com/angularjs)
* **Weekly newsletter:** [ng-newsletter](http://www.ng-newsletter.com/)
* **Meetups: **[meetup.com](http://www.meetup.com/find/?keywords=angularJS&radius=Infinity&userFreeform=San+Francisco%2C+CA&mcId=z94108&mcName=San+Francisco%2C+CA&sort=member_count&eventFilter=mysugg)
* **Official news and releases: **[AngularJS Blog](http://blog.angularjs.org/)
## Contributing to AngularJS
+1 -1
View File
@@ -23,7 +23,7 @@ for how to contribute your own code to AngularJS.
Before you can build AngularJS, you must install and configure the following dependencies on your
machine:
* {@link http://git-scm.com/ Git}: The {@link http://help.github.com/mac-git-installation Github Guide to
* {@link http://git-scm.com/ Git}: The {@link https://help.github.com/articles/set-up-git Github Guide to
Installing Git} is a good source of information.
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation, run a
+2 -2
View File
@@ -258,7 +258,7 @@ to various URLs and verify that the correct view was rendered.
<pre>
...
it('should redirect index.html to index.html#/phones', function() {
browser().navigateTo('../../app/index.html');
browser().navigateTo('app/index.html');
expect(browser().location().url()).toBe('/phones');
});
...
@@ -266,7 +266,7 @@ to various URLs and verify that the correct view was rendered.
describe('Phone detail view', function() {
beforeEach(function() {
browser().navigateTo('../../app/index.html#/phones/nexus-s');
browser().navigateTo('app/index.html#/phones/nexus-s');
});
+21
View File
@@ -144,6 +144,27 @@
.content h4,
.content h5 {
margin-top: 1em;
letter-spacing: -0.06em;
}
.content h2 {
font-size: 36px;
margin-bottom: .5em;
}
.content h3 {
font-size: 24px;
border-top: 1px solid #eee;
padding-top: .5em;
}
.content h4 {
font-size: 16px;
margin-top: 1.5em;
}
.content ul {
margin-top: .5em;
}
ul.parameters > li > p,
+4 -4
View File
@@ -273,10 +273,10 @@ docsApp.directive.docTutorialNav = function(templateMerge) {
element.addClass('btn-group');
element.addClass('tutorial-nav');
element.append(templateMerge(
'<li class="btn btn-primary"><a href="tutorial/{{prev}}"><i class="icon-step-backward"></i> Previous</a></li>\n' +
'<li class="btn btn-primary"><a href="http://angular.github.com/angular-phonecat/step-{{seq}}/app"><i class="icon-play"></i> Live Demo</a></li>\n' +
'<li class="btn btn-primary"><a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><i class="icon-search"></i> Code Diff</a></li>\n' +
'<li class="btn btn-primary"><a href="tutorial/{{next}}">Next <i class="icon-step-forward"></i></a></li>', props));
'<a href="tutorial/{{prev}}"><li class="btn btn-primary"><i class="icon-step-backward"></i> Previous</li></a>\n' +
'<a href="http://angular.github.com/angular-phonecat/step-{{seq}}/app"><li class="btn btn-primary"><i class="icon-play"></i> Live Demo</li></a>\n' +
'<a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><li class="btn btn-primary"><i class="icon-search"></i> Code Diff</li></a>\n' +
'<a href="tutorial/{{next}}"><li class="btn btn-primary">Next <i class="icon-step-forward"></i></li></a>', props));
}
};
};
+2 -2
View File
@@ -36,8 +36,8 @@ ARGS=""
if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then
ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_NUMBER"
fi
if [ ! -z "$SAUCE_CONNECT_READY_FILE" ]; then
ARGS="$ARGS --readyfile $SAUCE_CONNECT_READY_FILE"
if [ ! -z "$BROWSER_PROVIDER_READY_FILE" ]; then
ARGS="$ARGS --readyfile $BROWSER_PROVIDER_READY_FILE"
fi
+3 -3
View File
@@ -1,8 +1,8 @@
{
"name": "angularjs",
"version": "1.2.4",
"cdnVersion": "1.2.3",
"codename": "wormhole-baster",
"version": "1.2.5",
"cdnVersion": "1.2.4",
"codename": "singularity-expansion",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
+7 -4
View File
@@ -33,8 +33,10 @@ REPOS=(
# download and unzip the file
#
#wget $ZIP_FILE_URL
unzip $ZIP_FILE
if [ ! -f $ZIP_FILE ]; then
wget $ZIP_FILE_URL
unzip $ZIP_FILE
fi
#
@@ -46,8 +48,10 @@ do
if [ -f $ZIP_DIR/$repo.js ] # ignore i18l
then
cd bower-$repo
git checkout master
git reset --hard HEAD
git checkout master
git fetch --all
git reset --hard origin/master
cd ..
mv $ZIP_DIR/$repo.* bower-$repo/
fi
@@ -76,7 +80,6 @@ echo $NEW_VERSION
for repo in "${REPOS[@]}"
do
cd bower-$repo
pwd
sed -i '' -e "s/$OLD_VERSION/$NEW_VERSION/g" bower.json
git add -A
git commit -m "v$NEW_VERSION"
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
set -e
export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
if [ $JOB = "unit" ]; then
grunt ci-checks
grunt test:docgen
grunt test:promises-aplus
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
elif [ $JOB = "e2e" ]; then
grunt test:e2e --browsers SL_Chrome --reporters dots
else
echo "Unknown job type. Please set JOB=unit or JOB=e2e."
fi
@@ -2,6 +2,6 @@
# Wait for Connect to be ready before exiting
while [ ! -f $SAUCE_CONNECT_READY_FILE ]; do
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
sleep .5
done
+13 -13
View File
@@ -393,7 +393,7 @@ function valueFn(value) {return function() {return value;};}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is undefined.
*/
function isUndefined(value){return typeof value == 'undefined';}
function isUndefined(value){return typeof value === 'undefined';}
/**
@@ -407,7 +407,7 @@ function isUndefined(value){return typeof value == 'undefined';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is defined.
*/
function isDefined(value){return typeof value != 'undefined';}
function isDefined(value){return typeof value !== 'undefined';}
/**
@@ -422,7 +422,7 @@ function isDefined(value){return typeof value != 'undefined';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Object` but not `null`.
*/
function isObject(value){return value != null && typeof value == 'object';}
function isObject(value){return value != null && typeof value === 'object';}
/**
@@ -436,7 +436,7 @@ function isObject(value){return value != null && typeof value == 'object';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `String`.
*/
function isString(value){return typeof value == 'string';}
function isString(value){return typeof value === 'string';}
/**
@@ -450,7 +450,7 @@ function isString(value){return typeof value == 'string';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Number`.
*/
function isNumber(value){return typeof value == 'number';}
function isNumber(value){return typeof value === 'number';}
/**
@@ -465,7 +465,7 @@ function isNumber(value){return typeof value == 'number';}
* @returns {boolean} True if `value` is a `Date`.
*/
function isDate(value){
return toString.apply(value) == '[object Date]';
return toString.call(value) === '[object Date]';
}
@@ -481,7 +481,7 @@ function isDate(value){
* @returns {boolean} True if `value` is an `Array`.
*/
function isArray(value) {
return toString.apply(value) == '[object Array]';
return toString.call(value) === '[object Array]';
}
@@ -496,7 +496,7 @@ function isArray(value) {
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Function`.
*/
function isFunction(value){return typeof value == 'function';}
function isFunction(value){return typeof value === 'function';}
/**
@@ -507,7 +507,7 @@ function isFunction(value){return typeof value == 'function';}
* @returns {boolean} True if `value` is a `RegExp`.
*/
function isRegExp(value) {
return toString.apply(value) == '[object RegExp]';
return toString.call(value) === '[object RegExp]';
}
@@ -529,12 +529,12 @@ function isScope(obj) {
function isFile(obj) {
return toString.apply(obj) === '[object File]';
return toString.call(obj) === '[object File]';
}
function isBoolean(value) {
return typeof value == 'boolean';
return typeof value === 'boolean';
}
@@ -638,7 +638,7 @@ function includes(array, obj) {
function indexOf(array, obj) {
if (array.indexOf) return array.indexOf(obj);
for ( var i = 0; i < array.length; i++) {
for (var i = 0; i < array.length; i++) {
if (obj === array[i]) return i;
}
return -1;
@@ -974,7 +974,7 @@ function startingTag(element) {
try {
// turns out IE does not let you set .html() on elements which
// are not allowed to have children. So we just ignore it.
element.html('');
element.empty();
} catch(e) {}
// As Per DOM Standards
var TEXT_NODE = 3;
+4
View File
@@ -28,6 +28,7 @@
ngHideDirective,
ngIfDirective,
ngIncludeDirective,
ngIncludeFillContentDirective,
ngInitDirective,
ngNonBindableDirective,
ngPluralizeDirective,
@@ -181,6 +182,9 @@ function publishExternalAPI(angular){
ngRequired: requiredDirective,
ngValue: ngValueDirective
}).
directive({
ngInclude: ngIncludeFillContentDirective
}).
directive(ngAttributeAliasDirectives).
directive(ngEventDirectives);
$provide.provider({
+25 -18
View File
@@ -27,6 +27,28 @@
* $rootScope.$digest();
* });
* </pre>
*
* Sometimes you want to get access to the injector of a currently running Angular app
* from outside Angular. Perhaps, you want to inject and compile some markup after the
* application has been bootstrapped. You can do this using extra `injector()` added
* to JQuery/jqLite elements. See {@link angular.element}.
*
* *This is fairly rare but could be the case if a third party library is injecting the
* markup.*
*
* In the following example a new block of HTML containing a `ng-controller`
* directive is added to the end of the document body by JQuery. We then compile and link
* it into the current AngularJS scope.
*
* <pre>
* var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
* $(document.body).append($div);
*
* angular.element(document).injector().invoke(function($compile) {
* var scope = angular.element($div).scope();
* $compile($div)(scope);
* });
* </pre>
*/
@@ -747,24 +769,9 @@ function createInjector(modulesToLoad) {
fn = fn[length];
}
// Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
switch (self ? -1 : args.length) {
case 0: return fn();
case 1: return fn(args[0]);
case 2: return fn(args[0], args[1]);
case 3: return fn(args[0], args[1], args[2]);
case 4: return fn(args[0], args[1], args[2], args[3]);
case 5: return fn(args[0], args[1], args[2], args[3], args[4]);
case 6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
case 7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case 8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
case 9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
args[8]);
case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
args[8], args[9]);
default: return fn.apply(self, args);
}
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
}
function instantiate(Type, locals) {
+18 -4
View File
@@ -46,6 +46,7 @@
* - [`contents()`](http://api.jquery.com/contents/)
* - [`css()`](http://api.jquery.com/css/)
* - [`data()`](http://api.jquery.com/data/)
* - [`empty()`](http://api.jquery.com/empty/)
* - [`eq()`](http://api.jquery.com/eq/)
* - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
* - [`hasClass()`](http://api.jquery.com/hasClass/)
@@ -358,6 +359,15 @@ function jqLiteInheritedData(element, name, value) {
}
}
function jqLiteEmpty(element) {
for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
jqLiteDealoc(childNodes[i]);
}
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
@@ -552,7 +562,9 @@ forEach({
jqLiteDealoc(childNodes[i]);
}
element.innerHTML = value;
}
},
empty: jqLiteEmpty
}, function(fn, name){
/**
* Properties: writes return selection, reads return first value
@@ -562,11 +574,13 @@ forEach({
// jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
// in a way that survives minification.
if (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined) {
// jqLiteEmpty takes no arguments but is a setter.
if (fn !== jqLiteEmpty &&
(((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
if (isObject(arg1)) {
// we are a write, but the object properties are the key/values
for(i=0; i < this.length; i++) {
for (i = 0; i < this.length; i++) {
if (fn === jqLiteData) {
// data() takes the whole object in jQuery
fn(this[i], arg1);
@@ -591,7 +605,7 @@ forEach({
}
} else {
// we are a write, so apply to all children
for(i=0; i < this.length; i++) {
for (i = 0; i < this.length; i++) {
fn(this[i], arg1, arg2);
}
// return self for chaining
+11 -7
View File
@@ -1219,7 +1219,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
});
} else {
$template = jqLite(jqLiteClone(compileNode)).contents();
$compileNode.html(''); // clear contents
$compileNode.empty(); // clear contents
childTranscludeFn = compile($template, transcludeFn);
}
}
@@ -1400,7 +1400,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
optional = (match[2] == '?'),
mode = match[1], // @, =, or &
lastValue,
parentGet, parentSet;
parentGet, parentSet, compare;
isolateScope.$$isolateBindings[scopeName] = mode + attrName;
@@ -1423,6 +1423,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return;
}
parentGet = $parse(attrs[attrName]);
if (parentGet.literal) {
compare = equals;
} else {
compare = function(a,b) { return a === b; };
}
parentSet = parentGet.assign || function() {
// reset the change, or we will throw this exception on every $digest
lastValue = isolateScope[scopeName] = parentGet(scope);
@@ -1433,10 +1438,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
lastValue = isolateScope[scopeName] = parentGet(scope);
isolateScope.$watch(function parentValueWatch() {
var parentValue = parentGet(scope);
if (parentValue !== isolateScope[scopeName]) {
if (!compare(parentValue, isolateScope[scopeName])) {
// we are out of sync and need to copy
if (parentValue !== lastValue) {
if (!compare(parentValue, lastValue)) {
// parent changed and it has precedence
isolateScope[scopeName] = parentValue;
} else {
@@ -1445,7 +1449,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
return lastValue = parentValue;
});
}, null, parentGet.literal);
break;
case '&':
@@ -1647,7 +1651,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
? origAsyncDirective.templateUrl($compileNode, tAttrs)
: origAsyncDirective.templateUrl;
$compileNode.html('');
$compileNode.empty();
$http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
success(function(content) {
+10 -8
View File
@@ -32,13 +32,15 @@ var htmlAnchorDirective = valueFn({
element.append(document.createComment('IE fix'));
}
return function(scope, element) {
element.on('click', function(event){
// if we have no href url, then don't navigate anywhere.
if (!element.attr('href')) {
event.preventDefault();
}
});
};
if (!attr.href && !attr.name) {
return function(scope, element) {
element.on('click', function(event){
// if we have no href url, then don't navigate anywhere.
if (!element.attr('href')) {
event.preventDefault();
}
});
};
}
}
});
-1
View File
@@ -1432,7 +1432,6 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
id="{{name}}"
name="favorite">
</label>
</span>
<div>You chose {{my.favorite}}</div>
</form>
</doc:source>
+27 -7
View File
@@ -147,13 +147,14 @@
* @description
* Emitted every time the ngInclude content is reloaded.
*/
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animate', '$sce',
function($http, $templateCache, $anchorScroll, $compile, $animate, $sce) {
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
function($http, $templateCache, $anchorScroll, $animate, $sce) {
return {
restrict: 'ECA',
priority: 400,
terminal: true,
transclude: 'element',
controller: angular.noop,
compile: function(element, attr) {
var srcExp = attr.ngInclude || attr.src,
onloadExp = attr.onload || '',
@@ -187,6 +188,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
$http.get(src, {cache: $templateCache}).success(function(response) {
if (thisChangeId !== changeCounter) return;
var newScope = scope.$new();
ctrl.template = response;
// Note: This will also link all children of ng-include that were contained in the original
// html. If that content contains controllers, ... they could pollute/change the scope.
@@ -194,15 +196,14 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
// Note: We can't remove them in the cloneAttchFn of $transclude as that
// function is called before linking the content, which would apply child
// directives to non existing elements.
var clone = $transclude(newScope, noop);
cleanupLastIncludeContent();
var clone = $transclude(newScope, function(clone) {
cleanupLastIncludeContent();
$animate.enter(clone, null, $element, afterAnimation);
});
currentScope = newScope;
currentElement = clone;
currentElement.html(response);
$animate.enter(currentElement, null, $element, afterAnimation);
$compile(currentElement.contents())(currentScope);
currentScope.$emit('$includeContentLoaded');
scope.$eval(onloadExp);
}).error(function() {
@@ -211,9 +212,28 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
scope.$emit('$includeContentRequested');
} else {
cleanupLastIncludeContent();
ctrl.template = null;
}
});
};
}
};
}];
// This directive is called during the $transclude call of the first `ngInclude` directive.
// It will replace and compile the content of the element with the loaded template.
// We need this directive so that the element content is already filled when
// the link function of another directive on the same element as ngInclude
// is called.
var ngIncludeFillContentDirective = ['$compile',
function($compile) {
return {
restrict: 'ECA',
priority: -400,
require: 'ngInclude',
link: function(scope, $element, $attr, ctrl) {
$element.html(ctrl.template);
$compile($element.contents())(scope);
}
};
}];
+13 -5
View File
@@ -6,19 +6,26 @@
* @restrict EA
*
* @description
* The ngSwitch directive is used to conditionally swap DOM structure on your template based on a scope expression.
* Elements within ngSwitch but without ngSwitchWhen or ngSwitchDefault directives will be preserved at the location
* The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
* Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
* as specified in the template.
*
* The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
* from the template cache), ngSwitch simply choses one of the nested elements and makes it visible based on which element
* from the template cache), `ngSwitch` simply choses one of the nested elements and makes it visible based on which element
* matches the value obtained from the evaluated expression. In other words, you define a container element
* (where you place the directive), place an expression on the **on="..." attribute**
* (or the **ng-switch="..." attribute**), define any inner elements inside of the directive and place
* (where you place the directive), place an expression on the **`on="..."` attribute**
* (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
* a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
* expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
* attribute is displayed.
*
* <div class="alert alert-info">
* Be aware that the attribute values to match against cannot be expressions. They are interpreted
* as literal string values to match against.
* For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
* value of the expression `$scope.someVal`.
* </div>
* @animations
* enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
* leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
@@ -30,6 +37,7 @@
* <ANY ng-switch-default>...</ANY>
* </ANY>
*
*
* @scope
* @priority 800
* @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
+1 -1
View File
@@ -69,7 +69,7 @@ var ngTranscludeDirective = ngDirective({
link: function($scope, $element, $attrs, controller) {
controller.$transclude(function(clone) {
$element.html('');
$element.empty();
$element.append(clone);
});
}
+2 -2
View File
@@ -333,13 +333,13 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
// becomes the compilation root
nullOption.removeClass('ng-scope');
// we need to remove it before calling selectElement.html('') because otherwise IE will
// we need to remove it before calling selectElement.empty() because otherwise IE will
// remove the label from the element. wtf?
nullOption.remove();
}
// clear contents, we'll add what's needed based on the model
selectElement.html('');
selectElement.empty();
selectElement.on('change', function() {
scope.$apply(function() {
+1 -1
View File
@@ -136,7 +136,7 @@
*
* # Differences between Kris Kowal's Q and $q
*
* There are three main differences:
* There are two main differences:
*
* - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
* mechanism in angular, which means faster propagation of resolution or rejection into your
+32 -32
View File
@@ -156,11 +156,11 @@ function $RootScopeProvider(){
* @description
* Creates a new child {@link ng.$rootScope.Scope scope}.
*
* The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
* {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
* scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
* The parent scope will propagate the {@link ng.$rootScope.Scope#methods_$digest $digest()} and
* {@link ng.$rootScope.Scope#methods_$digest $digest()} events. The scope can be removed from the
* scope hierarchy using {@link ng.$rootScope.Scope#methods_$destroy $destroy()}.
*
* {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
* {@link ng.$rootScope.Scope#methods_$destroy $destroy()} must be called on a scope when it is
* desired for the scope and its child scopes to be permanently detached from the parent and
* thus stop participating in model change detection and listener notification by invoking.
*
@@ -213,11 +213,11 @@ function $RootScopeProvider(){
* @description
* Registers a `listener` callback to be executed whenever the `watchExpression` changes.
*
* - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
* - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#methods_$digest
* $digest()} and should return the value that will be watched. (Since
* {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
* {@link ng.$rootScope.Scope#methods_$digest $digest()} reruns when it detects changes the
* `watchExpression` can execute multiple times per
* {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
* {@link ng.$rootScope.Scope#methods_$digest $digest()} and should be idempotent.)
* - The `listener` is called only when the value from the current `watchExpression` and the
* previous call to `watchExpression` are not equal (with the exception of the initial run,
* see below). The inequality is determined according to
@@ -229,13 +229,13 @@ function $RootScopeProvider(){
* iteration limit is 10 to prevent an infinite loop deadlock.
*
*
* If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
* If you want to be notified whenever {@link ng.$rootScope.Scope#methods_$digest $digest} is called,
* you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
* can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
* can execute multiple times per {@link ng.$rootScope.Scope#methods_$digest $digest} cycle when a
* change is detected, be prepared for multiple calls to your listener.)
*
* After a watcher is registered with the scope, the `listener` fn is called asynchronously
* (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
* (via {@link ng.$rootScope.Scope#methods_$evalAsync $evalAsync}) to initialize the
* watcher. In rare cases, this is undesirable because the listener is called when the result
* of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
* can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
@@ -299,7 +299,7 @@ function $RootScopeProvider(){
*
*
* @param {(function()|string)} watchExpression Expression that is evaluated on each
* {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
* {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. A change in the return value triggers
* a call to the `listener`.
*
* - `string`: Evaluated as {@link guide/expression expression}
@@ -397,7 +397,7 @@ function $RootScopeProvider(){
*
* @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The
* expression value should evaluate to an object or an array which is observed on each
* {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
* {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. Any shallow change within the
* collection will trigger a call to the `listener`.
*
* @param {function(newCollection, oldCollection, scope)} listener a callback function that is
@@ -502,9 +502,9 @@ function $RootScopeProvider(){
* @function
*
* @description
* Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
* its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
* the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
* Processes all of the {@link ng.$rootScope.Scope#methods_$watch watchers} of the current scope and
* its children. Because a {@link ng.$rootScope.Scope#methods_$watch watcher}'s listener can change
* the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#methods_$watch watchers}
* until no more listeners are firing. This means that it is possible to get into an infinite
* loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
* iterations exceeds 10.
@@ -512,12 +512,12 @@ function $RootScopeProvider(){
* Usually, you don't call `$digest()` directly in
* {@link ng.directive:ngController controllers} or in
* {@link ng.$compileProvider#methods_directive directives}.
* Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
* Instead, you should call {@link ng.$rootScope.Scope#methods_$apply $apply()} (typically from within
* a {@link ng.$compileProvider#methods_directive directives}), which will force a `$digest()`.
*
* If you want to be notified whenever `$digest()` is called,
* you can register a `watchExpression` function with
* {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
* {@link ng.$rootScope.Scope#methods_$watch $watch()} with no `listener`.
*
* In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
*
@@ -672,7 +672,7 @@ function $RootScopeProvider(){
*
* @description
* Removes the current scope (and all of its children) from the parent scope. Removal implies
* that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
* that calls to {@link ng.$rootScope.Scope#methods_$digest $digest()} will no longer
* propagate to the current scope and its children. Removal also implies that the current
* scope is eligible for garbage collection.
*
@@ -754,7 +754,7 @@ function $RootScopeProvider(){
*
* - it will execute after the function that scheduled the evaluation (preferably before DOM
* rendering).
* - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
* - at least one {@link ng.$rootScope.Scope#methods_$digest $digest cycle} will be performed after
* `expression` execution.
*
* Any exceptions from the execution of the expression are forwarded to the
@@ -799,7 +799,7 @@ function $RootScopeProvider(){
* framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
* Because we are calling into the angular framework we need to perform proper scope life
* cycle of {@link ng.$exceptionHandler exception handling},
* {@link ng.$rootScope.Scope#$digest executing watches}.
* {@link ng.$rootScope.Scope#methods_$digest executing watches}.
*
* ## Life cycle
*
@@ -820,11 +820,11 @@ function $RootScopeProvider(){
* Scope's `$apply()` method transitions through the following stages:
*
* 1. The {@link guide/expression expression} is executed using the
* {@link ng.$rootScope.Scope#$eval $eval()} method.
* {@link ng.$rootScope.Scope#methods_$eval $eval()} method.
* 2. Any exceptions from the execution of the expression are forwarded to the
* {@link ng.$exceptionHandler $exceptionHandler} service.
* 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
* expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
* 3. The {@link ng.$rootScope.Scope#methods_$watch watch} listeners are fired immediately after the
* expression was executed using the {@link ng.$rootScope.Scope#methods_$digest $digest()} method.
*
*
* @param {(string|function())=} exp An angular expression to be executed.
@@ -858,7 +858,7 @@ function $RootScopeProvider(){
* @function
*
* @description
* Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
* Listens on events of a given type. See {@link ng.$rootScope.Scope#methods_$emit $emit} for
* discussion of event life cycle.
*
* The event listener function format is: `function(event, args...)`. The `event` object
@@ -899,20 +899,20 @@ function $RootScopeProvider(){
*
* @description
* Dispatches an event `name` upwards through the scope hierarchy notifying the
* registered {@link ng.$rootScope.Scope#$on} listeners.
* registered {@link ng.$rootScope.Scope#methods_$on} listeners.
*
* The event life cycle starts at the scope on which `$emit` was called. All
* {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
* {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
* notified. Afterwards, the event traverses upwards toward the root scope and calls all
* registered listeners along the way. The event will stop propagating if one of the listeners
* cancels it.
*
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
* Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
*
* @param {string} name Event name to emit.
* @param {...*} args Optional set of arguments which will be passed onto the event listeners.
* @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
* @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}).
*/
$emit: function(name, args) {
var empty = [],
@@ -968,19 +968,19 @@ function $RootScopeProvider(){
*
* @description
* Dispatches an event `name` downwards to all child scopes (and their children) notifying the
* registered {@link ng.$rootScope.Scope#$on} listeners.
* registered {@link ng.$rootScope.Scope#methods_$on} listeners.
*
* The event life cycle starts at the scope on which `$broadcast` was called. All
* {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
* {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
* notified. Afterwards, the event propagates to all direct and indirect scopes of the current
* scope and calls all registered listeners along the way. The event cannot be canceled.
*
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
* Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
*
* @param {string} name Event name to broadcast.
* @param {...*} args Optional set of arguments which will be passed onto the event listeners.
* @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
* @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on}
*/
$broadcast: function(name, args) {
var target = this,
+1 -1
View File
@@ -1237,7 +1237,7 @@ angular.module('ngAnimate', ['ng'])
//make the element super hidden and override any CSS style values
clone.attr('style','position:absolute; top:-9999px; left:-9999px');
clone.removeAttr('id');
clone.html('');
clone.empty();
forEach(oldClasses.split(' '), function(klass) {
clone.removeClass(klass);
+3 -2
View File
@@ -1087,7 +1087,8 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
var definitions = [],
expectations = [],
responses = [],
responsesPush = angular.bind(responses, responses.push);
responsesPush = angular.bind(responses, responses.push),
copy = angular.copy;
function createResponse(status, data, headers) {
if (angular.isFunction(status)) return status;
@@ -1119,7 +1120,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
function handleResponse() {
var response = wrapped.response(method, url, data, headers);
xhr.$$respHeaders = response[2];
callback(response[0], response[1], xhr.getAllResponseHeaders());
callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders());
}
function handleTimeout() {
+22 -3
View File
@@ -24,6 +24,25 @@ function lookupDottedPath(obj, path) {
return obj;
}
/**
* Create a shallow copy of an object and clear other fields from the destination
*/
function shallowClearAndCopy(src, dst) {
dst = dst || {};
angular.forEach(dst, function(value, key){
delete dst[key];
});
for (var key in src) {
if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
dst[key] = src[key];
}
}
return dst;
}
/**
* @ngdoc overview
* @name ngResource
@@ -393,7 +412,7 @@ angular.module('ngResource', ['ng']).
}
function Resource(value){
copy(value || {}, this);
shallowClearAndCopy(value || {}, this);
}
forEach(actions, function(action, name) {
@@ -465,7 +484,7 @@ angular.module('ngResource', ['ng']).
if (data) {
// Need to convert action.isArray to boolean in case it is undefined
// jshint -W018
if ( angular.isArray(data) !== (!!action.isArray) ) {
if (angular.isArray(data) !== (!!action.isArray)) {
throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' +
'response to contain an {0} but got an {1}',
action.isArray?'array':'object', angular.isArray(data)?'array':'object');
@@ -477,7 +496,7 @@ angular.module('ngResource', ['ng']).
value.push(new Resource(item));
});
} else {
copy(data, value);
shallowClearAndCopy(data, value);
value.$promise = promise;
}
}
+47 -27
View File
@@ -1,6 +1,8 @@
'use strict';
ngRouteModule.directive('ngView', ngViewFactory);
ngRouteModule.directive('ngView', ngViewFillContentFactory);
/**
* @ngdoc directive
@@ -166,8 +168,8 @@ ngRouteModule.directive('ngView', ngViewFactory);
* @description
* Emitted every time the ngView content is reloaded.
*/
ngViewFactory.$inject = ['$route', '$anchorScroll', '$compile', '$controller', '$animate'];
function ngViewFactory( $route, $anchorScroll, $compile, $controller, $animate) {
ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
function ngViewFactory( $route, $anchorScroll, $animate) {
return {
restrict: 'ECA',
terminal: true,
@@ -199,6 +201,7 @@ function ngViewFactory( $route, $anchorScroll, $compile, $controller,
if (template) {
var newScope = scope.$new();
var current = $route.current;
// Note: This will also link all children of ng-view that were contained in the original
// html. If that content contains controllers, ... they could pollute/change the scope.
@@ -206,34 +209,18 @@ function ngViewFactory( $route, $anchorScroll, $compile, $controller,
// Note: We can't remove them in the cloneAttchFn of $transclude as that
// function is called before linking the content, which would apply child
// directives to non existing elements.
var clone = $transclude(newScope, angular.noop);
clone.html(template);
$animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
if (angular.isDefined(autoScrollExp)
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
$anchorScroll();
}
var clone = $transclude(newScope, function(clone) {
$animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
if (angular.isDefined(autoScrollExp)
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
$anchorScroll();
}
});
cleanupLastView();
});
cleanupLastView();
var link = $compile(clone.contents()),
current = $route.current;
currentScope = current.scope = newScope;
currentElement = clone;
if (current.controller) {
locals.$scope = currentScope;
var controller = $controller(current.controller, locals);
if (current.controllerAs) {
currentScope[current.controllerAs] = controller;
}
clone.data('$ngControllerController', controller);
clone.children().data('$ngControllerController', controller);
}
link(currentScope);
currentScope = current.scope = newScope;
currentScope.$emit('$viewContentLoaded');
currentScope.$eval(onloadExp);
} else {
@@ -243,3 +230,36 @@ function ngViewFactory( $route, $anchorScroll, $compile, $controller,
}
};
}
// This directive is called during the $transclude call of the first `ngView` directive.
// It will replace and compile the content of the element with the loaded template.
// We need this directive so that the element content is already filled when
// the link function of another directive on the same element as ngView
// is called.
ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
function ngViewFillContentFactory($compile, $controller, $route) {
return {
restrict: 'ECA',
priority: -400,
link: function(scope, $element) {
var current = $route.current,
locals = current.locals;
$element.html(locals.$template);
var link = $compile($element.contents());
if (current.controller) {
locals.$scope = scope;
var controller = $controller(current.controller, locals);
if (current.controllerAs) {
scope[current.controllerAs] = controller;
}
$element.data('$ngControllerController', controller);
$element.children().data('$ngControllerController', controller);
}
link(scope);
}
};
}
+4 -4
View File
@@ -52,13 +52,13 @@ function $RouteProvider(){
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
* route definition.
*
* * `path` can contain named groups starting with a colon (`:name`). All characters up
* * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
* to the next slash are matched and stored in `$routeParams` under the given `name`
* when the route matches.
* * `path` can contain named groups starting with a colon and ending with a star (`:name*`).
* All characters are eagerly stored in `$routeParams` under the given `name`
* * `path` can contain named groups starting with a colon and ending with a star:
* e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
* when the route matches.
* * `path` can contain optional named groups with a question mark (`:name?`).
* * `path` can contain optional named groups with a question mark: e.g.`:name?`.
*
* For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
* `/color/brown/largecode/code/with/slashs/edit` and extract:
+1 -2
View File
@@ -29,8 +29,7 @@ beforeEach(function() {
bindJQuery();
}
angular.element(document.body).html('').removeData();
angular.element(document.body).empty().removeData();
});
afterEach(function() {
+23 -2
View File
@@ -322,7 +322,7 @@ describe('jqLite', function() {
});
it('should emit $destroy event if an element is removed via html()', inject(function(log) {
it('should emit $destroy event if an element is removed via html(\'\')', inject(function(log) {
var element = jqLite('<div><span>x</span></div>');
element.find('span').on('$destroy', log.fn('destroyed'));
@@ -333,6 +333,17 @@ describe('jqLite', function() {
}));
it('should emit $destroy event if an element is removed via empty()', inject(function(log) {
var element = jqLite('<div><span>x</span></div>');
element.find('span').on('$destroy', log.fn('destroyed'));
element.empty();
expect(element.html()).toBe('');
expect(log).toEqual('destroyed');
}));
it('should retrieve all data if called without params', function() {
var element = jqLite(a);
expect(element.data()).toEqual({});
@@ -786,7 +797,7 @@ describe('jqLite', function() {
});
it('should read/write value', function() {
it('should read/write a value', function() {
var element = jqLite('<div>abc</div>');
expect(element.length).toEqual(1);
expect(element[0].innerHTML).toEqual('abc');
@@ -797,6 +808,16 @@ describe('jqLite', function() {
});
describe('empty', function() {
it('should write a value', function() {
var element = jqLite('<div>abc</div>');
expect(element.length).toEqual(1);
expect(element.empty() == element).toBeTruthy();
expect(element.html()).toEqual('');
});
});
describe('on', function() {
it('should bind to window on hashchange', function() {
if (jqLite.fn) return; // don't run in jQuery
+60 -4
View File
@@ -170,26 +170,26 @@ describe('$compile', function() {
// First with only elements at the top level
element = jqLite('<div><div></div></div>');
$compile(element.contents())($rootScope);
element.html('');
element.empty();
expect(calcCacheSize()).toEqual(0);
// Next with non-empty text nodes at the top level
// (in this case the compiler will wrap them in a <span>)
element = jqLite('<div>xxx</div>');
$compile(element.contents())($rootScope);
element.html('');
element.empty();
expect(calcCacheSize()).toEqual(0);
// Next with comment nodes at the top level
element = jqLite('<div><!-- comment --></div>');
$compile(element.contents())($rootScope);
element.html('');
element.empty();
expect(calcCacheSize()).toEqual(0);
// Finally with empty text nodes at the top level
element = jqLite('<div> \n<div></div> </div>');
$compile(element.contents())($rootScope);
element.html('');
element.empty();
expect(calcCacheSize()).toEqual(0);
});
@@ -2492,6 +2492,62 @@ describe('$compile', function() {
expect(lastRefValueInParent).toBe('new');
}));
describe('literal objects', function() {
it('should copy parent changes', inject(function() {
compile('<div><span my-component reference="{name: name}">');
$rootScope.name = 'a';
$rootScope.$apply();
expect(componentScope.reference).toEqual({name: 'a'});
$rootScope.name = 'b';
$rootScope.$apply();
expect(componentScope.reference).toEqual({name: 'b'});
}));
it('should not change the component when parent does not change', inject(function() {
compile('<div><span my-component reference="{name: name}">');
$rootScope.name = 'a';
$rootScope.$apply();
var lastComponentValue = componentScope.reference;
$rootScope.$apply();
expect(componentScope.reference).toBe(lastComponentValue);
}));
it('should complain when the component changes', inject(function() {
compile('<div><span my-component reference="{name: name}">');
$rootScope.name = 'a';
$rootScope.$apply();
componentScope.reference = {name: 'b'};
expect(function() {
$rootScope.$apply();
}).toThrowMinErr("$compile", "nonassign", "Expression '{name: name}' used with directive 'myComponent' is non-assignable!");
}));
it('should work for primitive literals', inject(function() {
test('1', 1);
test('null', null);
test('undefined', undefined);
test("'someString'", 'someString');
function test(literalString, literalValue) {
compile('<div><span my-component reference="'+literalString+'">');
$rootScope.$apply();
expect(componentScope.reference).toBe(literalValue);
dealoc(element);
}
}));
});
});
+26
View File
@@ -58,4 +58,30 @@ describe('a', function() {
expect(element.text()).toBe('hello@you');
});
it('should not link and hookup an event if href is present at compile', function() {
var jq = jQuery || jqLite;
element = jq('<a href="//a.com">hello@you</a>');
var linker = $compile(element);
spyOn(jq.prototype, 'on');
linker($rootScope);
expect(jq.prototype.on).not.toHaveBeenCalled();
});
it('should not link and hookup an event if name is present at compile', function() {
var jq = jQuery || jqLite;
element = jq('<a name="bobby">hello@you</a>');
var linker = $compile(element);
spyOn(jq.prototype, 'on');
linker($rootScope);
expect(jq.prototype.on).not.toHaveBeenCalled();
});
});
+1 -1
View File
@@ -216,7 +216,7 @@ describe('form', function() {
// yes, I know, scope methods should not do direct DOM manipulation, but I wanted to keep
// this test small. Imagine that the destroy action will cause a model change (e.g.
// $location change) that will cause some directive to destroy the dom (e.g. ngView+$route)
doc.html('');
doc.empty();
destroyed = true;
}
+44 -4
View File
@@ -47,7 +47,7 @@ describe('ngInclude', function() {
$rootScope.url = 'myUrl';
$rootScope.$digest();
expect(body.text()).toEqual('misko');
body.html('');
body.empty();
}));
@@ -60,7 +60,7 @@ describe('ngInclude', function() {
$rootScope.url = 'myUrl';
$rootScope.$digest();
expect(element.text()).toEqual('Alibaba');
jqLite(document.body).html('');
jqLite(document.body).empty();
}));
@@ -74,7 +74,7 @@ describe('ngInclude', function() {
expect(function() { $rootScope.$digest(); }).toThrowMinErr(
'$sce', 'insecurl',
/Blocked loading resource from url not allowed by \$sceDelegate policy. URL: http:\/\/example.com\/myUrl.*/);
jqLite(document.body).html('');
jqLite(document.body).empty();
}));
@@ -88,7 +88,7 @@ describe('ngInclude', function() {
expect(function() { $rootScope.$digest(); }).toThrowMinErr(
'$sce', 'insecurl',
/Blocked loading resource from url not allowed by \$sceDelegate policy. URL: http:\/\/example.com\/myUrl.*/);
jqLite(document.body).html('');
jqLite(document.body).empty();
}));
@@ -524,6 +524,46 @@ describe('ngInclude and transcludes', function() {
});
});
it('should link directives on the same element after the content has been loaded', function() {
var contentOnLink;
module(function() {
directive('test', function() {
return {
link: function(scope, element) {
contentOnLink = element.text();
}
};
});
});
inject(function($compile, $rootScope, $httpBackend) {
$httpBackend.expectGET('include.html').respond('someContent');
element = $compile('<div><div ng-include="\'include.html\'" test></div>')($rootScope);
$rootScope.$apply();
$httpBackend.flush();
expect(contentOnLink).toBe('someContent');
});
});
it('should add the content to the element before compiling it', function() {
var root;
module(function() {
directive('test', function() {
return {
link: function(scope, element) {
root = element.parent().parent();
}
};
});
});
inject(function($compile, $rootScope, $httpBackend) {
$httpBackend.expectGET('include.html').respond('<span test></span>');
element = $compile('<div><div ng-include="\'include.html\'"></div>')($rootScope);
$rootScope.$apply();
$httpBackend.flush();
expect(root[0]).toBe(element[0]);
});
});
});
describe('ngInclude animations', function() {
+1 -1
View File
@@ -301,7 +301,7 @@ describe("ngAnimate", function() {
inject(function($animate, $compile, $rootScope, $timeout, $sniffer) {
$rootScope.$digest();
element.html('');
element.empty();
var child1 = $compile('<div>1</div>')($rootScope);
var child2 = $compile('<div>2</div>')($rootScope);
+28 -2
View File
@@ -766,7 +766,7 @@ describe('ngMock', function() {
describe('object literal format', function() {
var mock = { log: 'module' };
beforeEach(function() {
module({
'service': mock,
@@ -782,7 +782,7 @@ describe('ngMock', function() {
expect(service).toEqual(mock);
});
});
it('should support multiple key value pairs', function() {
inject(function(service, other) {
expect(other.some).toEqual('replacement');
@@ -891,6 +891,32 @@ describe('ngMock', function() {
});
it('should respond with a copy of the mock data', function() {
var mockObject = {a: 'b'};
hb.when('GET', '/url1').respond(200, mockObject, {});
callback.andCallFake(function(status, response) {
expect(status).toBe(200);
expect(response).toEqual({a: 'b'});
expect(response).not.toBe(mockObject);
response.a = 'c';
});
hb('GET', '/url1', null, callback);
hb.flush();
expect(callback).toHaveBeenCalledOnce();
// Fire it again and verify that the returned mock data has not been
// modified.
callback.reset();
hb('GET', '/url1', null, callback);
hb.flush();
expect(callback).toHaveBeenCalledOnce();
expect(mockObject).toEqual({a: 'b'});
});
it('should throw error when unexpected request', function() {
hb.when('GET', '/url1').respond(200, 'content');
expect(function() {
+40
View File
@@ -582,6 +582,46 @@ describe('ngView and transcludes', function() {
});
});
it('should link directives on the same element after the content has been loaded', function() {
var contentOnLink;
module(function($compileProvider, $routeProvider) {
$routeProvider.when('/view', {template: 'someContent'});
$compileProvider.directive('test', function() {
return {
link: function(scope, element) {
contentOnLink = element.text();
}
};
});
});
inject(function($compile, $rootScope, $location) {
element = $compile('<div><div ng-view test></div>')($rootScope);
$location.url('/view');
$rootScope.$apply();
expect(contentOnLink).toBe('someContent');
});
});
it('should add the content to the element before compiling it', function() {
var root;
module(function($compileProvider, $routeProvider) {
$routeProvider.when('/view', {template: '<span test></span>'});
$compileProvider.directive('test', function() {
return {
link: function(scope, element) {
root = element.parent().parent();
}
};
});
});
inject(function($compile, $rootScope, $location) {
element = $compile('<div><div ng-view></div>')($rootScope);
$location.url('/view');
$rootScope.$apply();
expect(root[0]).toBe(element[0]);
});
});
});
describe('ngView animations', function() {
+1 -1
View File
@@ -53,7 +53,7 @@ describe("angular.scenario.dsl", function() {
// Just use the real one since it delegates to this.addFuture
$root.addFutureAction = angular.scenario.
SpecRunner.prototype.addFutureAction;
jqLite($window.document).html('');
jqLite($window.document).empty();
}));
afterEach(function(){
+1 -1
View File
@@ -152,7 +152,7 @@ describe('ngClick (touch)', function() {
}));
afterEach(inject(function($document) {
$document.find('body').html('');
$document.find('body').empty();
}));
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
set -e
export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
grunt parallel:travis --reporters dots \
--browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 \
--e2e-browsers SL_Chrome
+1
View File
@@ -21,6 +21,7 @@ var TYPES = {
docs: true,
style: true,
refactor: true,
perf: true,
test: true,
chore: true,
revert: true