Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed6e91b318 | |||
| 7b7b082125 | |||
| 3831e45a7d | |||
| 018991f8c8 | |||
| c77f5d1a29 | |||
| 030101a43a | |||
| 2a0254e181 | |||
| ce20dd06fe | |||
| d7a78e420a | |||
| 4b4098bfca | |||
| c3b3b90bc9 | |||
| 43b1a3739a | |||
| b4db713cde | |||
| df3d739654 | |||
| 99ec8d66c5 | |||
| d1ccf17635 | |||
| c3fcbbd750 | |||
| 29d727210d | |||
| 875f8f6557 | |||
| f34c1ff53f | |||
| 54ddca537e | |||
| 2cd5b4ec44 | |||
| 4bf254c155 | |||
| d0226ebbbf | |||
| 3df9de2e31 | |||
| 4d12812bb4 | |||
| 42f7c80bb6 | |||
| 7574dd25d9 | |||
| 3b3d9218e8 | |||
| e780eeee27 | |||
| 4cccf0f2a8 | |||
| a54b25d779 | |||
| 36666f6fad | |||
| d3b1f502e3 | |||
| 94f5a285bf | |||
| 7f65f97919 | |||
| 922162853b | |||
| 655fccce3a | |||
| 40bbc98178 | |||
| 9ad6c77568 | |||
| cfe7b0e9ef | |||
| 031d4cd2a9 | |||
| acbd302efb | |||
| 37790e920d | |||
| 531a8de72c | |||
| d488a89466 | |||
| 3635721ce4 | |||
| e9c5be58ab | |||
| 5d7763ebf9 | |||
| 0a380b4264 | |||
| 52ceec2229 | |||
| 38d12de661 | |||
| 89c57a8761 | |||
| 2240c113f5 | |||
| fc56c9b3cc | |||
| 22b817ec11 | |||
| 762713e660 | |||
| d97b427656 | |||
| 303610c743 | |||
| 1025f6ebf4 | |||
| a7f886e6c8 | |||
| b8f3ad4b21 | |||
| 483ce91da2 | |||
| 31ec9f14ef | |||
| 8b921617e9 | |||
| e4ce0ddda5 | |||
| e1c0a8e642 | |||
| ba9d0738cd | |||
| 998c61cbe0 | |||
| 35e2a068ad | |||
| 146440c5b2 | |||
| bf9e7bfb5a | |||
| ed3f799b5c | |||
| b64b9ea02c | |||
| 7fa66348cb | |||
| e5c53b393b | |||
| 24d00cce4f | |||
| accb22d644 | |||
| 1785251eab | |||
| fe58238e35 | |||
| 1bd473eb45 | |||
| 9078a6ae37 | |||
| e9dcec0c5d | |||
| d5457bb83b | |||
| 036871df5e | |||
| c06e12276b | |||
| 4aaf47534e | |||
| 502bb648ff | |||
| 6cba9c5e7c | |||
| 6e5e76e4b1 | |||
| 45252c3a54 | |||
| c2edef86c5 | |||
| 5b982998c3 | |||
| d7f84e2d7f | |||
| fddf4bd5fe | |||
| c2fb4b6986 | |||
| 8b2f1a47b5 | |||
| fb1b202f38 | |||
| 47e15aa2b4 | |||
| 22da294cbb | |||
| 22407a9296 | |||
| fc70a98be4 | |||
| 49d03a5b2e | |||
| ed85ec4d70 | |||
| 6502ab0977 | |||
| 02aa4f4b85 | |||
| 69bf2f02d0 | |||
| fd375c5d46 | |||
| b8b63df664 | |||
| 28661d1a8c | |||
| 7f4d24c6fa |
@@ -10,9 +10,6 @@ end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[src/ngLocale/**]
|
||||
insert_final_newline = false
|
||||
|
||||
[dropdown-toggle.js]
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
|
||||
@@ -1,6 +1,33 @@
|
||||
{
|
||||
"excludeFiles": ["src/ngLocale/**"],
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleLineStrings": true,
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
"disallowSpaceAfterObjectKeys": true,
|
||||
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
|
||||
"disallowSpaceBeforeBinaryOperators": [","],
|
||||
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
|
||||
"disallowSpacesInAnonymousFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInFunctionDeclaration": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInNamedFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"disallowTrailingComma": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"requireRightStickedOperators": ["!"],
|
||||
"requireLeftStickedOperators": [","]
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
"requireLineFeedAtFileEnd": true,
|
||||
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"requireSpacesInFunction": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"validateLineBreaks": "LF",
|
||||
"validateParameterSeparator": ", "
|
||||
}
|
||||
|
||||
@@ -5,13 +5,11 @@
|
||||
|
||||
{
|
||||
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
|
||||
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
|
||||
"disallowLeftStickedOperators": ["?", "+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
"disallowRightStickedOperators": ["?", "+", "/", "*", ":", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
"requireSpaceAfterBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
|
||||
"requireSpaceBeforeBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
|
||||
"disallowImplicitTypeConversion": ["string"],
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
"requireLineFeedAtFileEnd": true,
|
||||
"validateJSDoc": {
|
||||
"checkParamNames": true,
|
||||
"requireParamTypes": true
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
- **currencyFilter:** add fractionSize as optional parameter
|
||||
([20685ffe](https://github.com/angular/angular.js/commit/20685ffe11036d4d604d13f0d792ca46497af4a1),
|
||||
[#3642](https://github.com/angular/angular.js/issues/3642), [#3461](https://github.com/angular/angular.js/issues/3461), [#3642](https://github.com/angular/angular.js/issues/3642), [#7922](https://github.com/angular/angular.js/issues/7922))
|
||||
- **jqLite:** add private jqDocumentComplete function
|
||||
- **jqLite:** add private jqLiteDocumentLoaded function
|
||||
([0dd316ef](https://github.com/angular/angular.js/commit/0dd316efea209e5e5de3e456b4e6562f011a1294))
|
||||
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
|
||||
* **Do not use namespaces**: Instead, wrap the entire angular code base in an anonymous closure and
|
||||
export our API explicitly rather than implicitly.
|
||||
* Wrap all code at **100 characters**.
|
||||
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypical
|
||||
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypal
|
||||
inheritance only when absolutely necessary.
|
||||
* We **love functions and closures** and, whenever possible, prefer them over objects.
|
||||
* To write concise code that can be better minified, we **use aliases internally** that map to the
|
||||
|
||||
@@ -4,6 +4,7 @@ var files = require('./angularFiles').files;
|
||||
var util = require('./lib/grunt/utils.js');
|
||||
var versionInfo = require('./lib/versions/version-info');
|
||||
var path = require('path');
|
||||
var e2e = require('./test/e2e/tools');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
//grunt plugins
|
||||
@@ -46,12 +47,14 @@ module.exports = function(grunt) {
|
||||
base: '.',
|
||||
keepalive: true,
|
||||
middleware: function(connect, options){
|
||||
var base = Array.isArray(options.base) ? options.base[options.base.length - 1] : options.base;
|
||||
return [
|
||||
util.conditionalCsp(),
|
||||
util.rewrite(),
|
||||
e2e.middleware(),
|
||||
connect.favicon('images/favicon.ico'),
|
||||
connect.static(options.base),
|
||||
connect.directory(options.base)
|
||||
connect.static(base),
|
||||
connect.directory(base)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -64,6 +67,7 @@ module.exports = function(grunt) {
|
||||
port: 8000,
|
||||
hostname: '0.0.0.0',
|
||||
middleware: function(connect, options){
|
||||
var base = Array.isArray(options.base) ? options.base[options.base.length - 1] : options.base;
|
||||
return [
|
||||
function(req, resp, next) {
|
||||
// cache get requests to speed up tests on travis
|
||||
@@ -74,8 +78,9 @@ module.exports = function(grunt) {
|
||||
next();
|
||||
},
|
||||
util.conditionalCsp(),
|
||||
e2e.middleware(),
|
||||
connect.favicon('images/favicon.ico'),
|
||||
connect.static(options.base)
|
||||
connect.static(base)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -287,14 +292,14 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
|
||||
shell:{
|
||||
"promises-aplus-tests":{
|
||||
options:{
|
||||
//stdout:true,
|
||||
stderr:true,
|
||||
failOnError:true
|
||||
shell: {
|
||||
"promises-aplus-tests": {
|
||||
options: {
|
||||
stdout: false,
|
||||
stderr: true,
|
||||
failOnError: true
|
||||
},
|
||||
command:path.normalize('./node_modules/.bin/promises-aplus-tests tmp/promises-aplus-adapter++.js')
|
||||
command: path.normalize('./node_modules/.bin/promises-aplus-tests tmp/promises-aplus-adapter++.js')
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ found at: https://github.com/angular/benchpress/blob/master/README.md.
|
||||
|
||||
In this project, there is a configured grunt task for building the benchmarks,
|
||||
`grunt bp_build`, which places the runnable benchmarks in "/build/benchmarks/".
|
||||
The existing `grunt webserver` task can be used to serve the built benchmarks at `localhost:8000/build/benchmarks/<benchmark-name>`
|
||||
The existing `grunt webserver` task can be used to serve the built benchmarks at `localhost:8000/build/benchmarks/<benchmark-name>`
|
||||
|
||||
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 209 KiB |
|
Before Width: | Height: | Size: 205 KiB |
@@ -5,15 +5,15 @@ describe("doc.angularjs.org", function() {
|
||||
describe("API pages", function() {
|
||||
|
||||
it("should display links to code on GitHub", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$http');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.improve-docs')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/edit\/.+\/src\/ng\/http\.js/);
|
||||
|
||||
browser.get('index-debug.html#!/api/ng/service/$http');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
|
||||
});
|
||||
|
||||
it('should change the page content when clicking a link to a service', function () {
|
||||
browser.get('');
|
||||
browser.get('build/docs/index.html');
|
||||
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
@@ -24,7 +24,7 @@ describe("doc.angularjs.org", function() {
|
||||
|
||||
|
||||
it('should show the functioning input directive example', function () {
|
||||
browser.get('index-debug.html#!/api/ng/directive/input');
|
||||
browser.get('build/docs/index.html#!/api/ng/directive/input');
|
||||
|
||||
// Ensure that the page is loaded before trying to switch frames.
|
||||
browser.waitForAngular();
|
||||
@@ -39,7 +39,7 @@ describe("doc.angularjs.org", function() {
|
||||
});
|
||||
|
||||
it("should trim indentation from code blocks", function() {
|
||||
browser.get('index-debug.html#!/api/ng/type/$rootScope.Scope');
|
||||
browser.get('build/docs/index.html#!/api/ng/type/$rootScope.Scope');
|
||||
|
||||
var codeBlocks = element.all(by.css('pre > code.lang-js'));
|
||||
codeBlocks.each(function(codeBlock) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
describe("provider pages", function() {
|
||||
|
||||
it("should show the related service", function() {
|
||||
browser.get('index-debug.html#!/api/ng/provider/$compileProvider');
|
||||
browser.get('build/docs/index.html#!/api/ng/provider/$compileProvider');
|
||||
var serviceLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(serviceLink.getText()).toEqual('- $compile');
|
||||
expect(serviceLink.getAttribute('href')).toMatch(/api\/ng\/service\/\$compile/);
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
describe("service pages", function() {
|
||||
|
||||
it("should show the related provider if there is one", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$compile');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$compile');
|
||||
var providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(providerLink.getText()).toEqual('- $compileProvider');
|
||||
expect(providerLink.getAttribute('href')).toMatch(/api\/ng\/provider\/\$compileProvider/);
|
||||
|
||||
browser.get('index-debug.html#!/api/ng/service/$q');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$q');
|
||||
providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(providerLink.getText()).not.toEqual('- $qProvider');
|
||||
expect(providerLink.getAttribute('href')).not.toMatch(/api\/ng\/provider\/\$compileProvider/);
|
||||
});
|
||||
|
||||
it("should show parameter defaults", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$timeout');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$timeout');
|
||||
expect(element.all(by.css('.input-arguments p em')).first().getText()).toContain('(default: 0)');
|
||||
});
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('docs.angularjs.org', function () {
|
||||
|
||||
|
||||
it('should change the page content when clicking a link to a service', function () {
|
||||
browser.get('');
|
||||
browser.get('build/docs/index.html');
|
||||
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
@@ -51,33 +51,33 @@ describe('docs.angularjs.org', function () {
|
||||
|
||||
|
||||
it('should be resilient to trailing slashes', function() {
|
||||
browser.get('index-debug.html#!/api/ng/function/angular.noop/');
|
||||
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing "index"', function() {
|
||||
browser.get('index-debug.html#!/api/ng/function/angular.noop/index');
|
||||
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/index');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing "index/"', function() {
|
||||
browser.get('index-debug.html#!/api/ng/function/angular.noop/index/');
|
||||
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/index/');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should display formatted error messages on error doc pages', function() {
|
||||
browser.get('index-debug.html#!error/ng/areq?p0=Missing&p1=not%20a%20function,%20got%20undefined');
|
||||
browser.get('build/docs/index.html#!error/ng/areq?p0=Missing&p1=not%20a%20function,%20got%20undefined');
|
||||
expect(element(by.css('.minerr-errmsg')).getText()).toEqual("Argument 'Missing' is not a function, got undefined");
|
||||
});
|
||||
|
||||
it("should display an error if the page does not exist", function() {
|
||||
browser.get('index-debug.html#!/api/does/not/exist');
|
||||
browser.get('build/docs/index.html#!/api/does/not/exist');
|
||||
expect(element(by.css('h1')).getText()).toBe('Oops!');
|
||||
});
|
||||
|
||||
|
||||
@@ -41,10 +41,14 @@ angular.module('search', [])
|
||||
|
||||
$scope.submit = function() {
|
||||
var result;
|
||||
for(var i in $scope.results) {
|
||||
result = $scope.results[i][0];
|
||||
if(result) {
|
||||
break;
|
||||
if ($scope.results.api) {
|
||||
result = $scope.results.api[0];
|
||||
} else {
|
||||
for(var i in $scope.results) {
|
||||
result = $scope.results[i][0];
|
||||
if(result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(result) {
|
||||
|
||||
@@ -5,8 +5,8 @@ var packagePath = __dirname;
|
||||
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
// Create and export a new Dgeni package called dgeni-example. This package depends upon
|
||||
// the jsdoc and nunjucks packages defined in the dgeni-packages npm module.
|
||||
// Create and export a new Dgeni package called angularjs. This package depends upon
|
||||
// the ngdoc,nunjucks and examples packages defined in the dgeni-packages npm module.
|
||||
module.exports = new Package('angularjs', [
|
||||
require('dgeni-packages/ngdoc'),
|
||||
require('dgeni-packages/nunjucks'),
|
||||
@@ -157,6 +157,8 @@ module.exports = new Package('angularjs', [
|
||||
jqueryDeployment
|
||||
];
|
||||
|
||||
generateProtractorTestsProcessor.basePath = 'build/docs/';
|
||||
|
||||
generateExamplesProcessor.deployments = [
|
||||
debugDeployment,
|
||||
defaultDeployment,
|
||||
|
||||
@@ -6,6 +6,22 @@
|
||||
This error occurs when a module fails to load due to some exception. The error
|
||||
message above should provide additional context.
|
||||
|
||||
### Using `ngRoute`
|
||||
|
||||
In AngularJS `1.2.0` and later, `ngRoute` has been moved to its own module.
|
||||
If you are getting this error after upgrading to `1.2.x` or later, be sure that you've
|
||||
installed {@link ngRoute `ngRoute`}.
|
||||
|
||||
### Monkey-patching Angular's `ng` module
|
||||
|
||||
This error can also occur if you have tried to add your own components to the `ng` module.
|
||||
This has never been supported and from `1.3.0` it will actually trigger this error.
|
||||
For instance the following code could trigger this error.
|
||||
|
||||
```js
|
||||
angular.module('ng').filter('tel', function (){});
|
||||
```
|
||||
|
||||
Instead create your own module and add it as a dependency to your application's top-level module.
|
||||
See [#9692](https://github.com/angular/angular.js/issues/9692) and
|
||||
[#7709](https://github.com/angular/angular.js/issues/7709) for more information
|
||||
@@ -15,7 +15,7 @@ For example the issue can be triggered by this *invalid* code:
|
||||
|
||||
To resolve this error either ensure that the items in the collection have unique identity or use the `track by` syntax to specify how to track the association between models and DOM.
|
||||
|
||||
To resolve the example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
|
||||
The example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
|
||||
|
||||
```
|
||||
<div ng-repeat="value in [4, 4] track by $index"></div>
|
||||
|
||||
@@ -332,7 +332,7 @@ reload to the original link.
|
||||
Be sure to check all relative links, images, scripts etc. Angular requires you to specify the url
|
||||
base in the head of your main html file (`<base href="/my-base">`) unless `html5Mode.requireBase` is
|
||||
set to `false` in the html5Mode definition object passed to `$locationProvider.html5Mode()`. With
|
||||
that, relative urls will always be resolved to this base url, event if the initial url of the
|
||||
that, relative urls will always be resolved to this base url, even if the initial url of the
|
||||
document was different.
|
||||
|
||||
There is one exception: Links that only contain a hash fragment (e.g. `<a href="#target">`)
|
||||
|
||||
@@ -20,7 +20,7 @@ initialization.
|
||||
<html xmlns:ng="http://angularjs.org" ng-app>
|
||||
<body>
|
||||
...
|
||||
<script src="angular.js">
|
||||
<script src="angular.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
@@ -73,6 +73,23 @@ If the {@link ng.directive:ngApp `ng-app`} directive is found then Angular will:
|
||||
</html>
|
||||
```
|
||||
|
||||
As a best practice, consider adding an `ng-strict-di` directive on the same element as
|
||||
`ng-app`:
|
||||
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html ng-app="optionalModuleName" ng-strict-di>
|
||||
<body>
|
||||
I can add: {{ 1+2 }}.
|
||||
<script src="angular.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
This will ensure that all services in your application are properly annotated.
|
||||
See the {@link guide/di#using-strict-dependency-injection dependancy injection strict mode} docs
|
||||
for more.
|
||||
|
||||
|
||||
## Manual Initialization
|
||||
@@ -128,8 +145,8 @@ This is the sequence that your code should follow:
|
||||
|
||||
## Deferred Bootstrap
|
||||
|
||||
This feature enables tools like Batarang and test runners to
|
||||
hook into angular's bootstrap process and sneak in more modules
|
||||
This feature enables tools like [Batarang](github.com/angular/angularjs-batarang) and test runners
|
||||
to hook into angular's bootstrap process and sneak in more modules
|
||||
into the DI registry which can replace or augment DI services for
|
||||
the purpose of instrumentation or mocking out heavy dependencies.
|
||||
|
||||
|
||||
@@ -11,13 +11,227 @@ their dependencies.
|
||||
The Angular injector subsystem is in charge of creating components, resolving their dependencies,
|
||||
and providing them to other components as requested.
|
||||
|
||||
|
||||
## Using Dependency Injection
|
||||
|
||||
DI is pervasive throughout Angular. You can use it when defining components or when providing `run`
|
||||
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" and "value"
|
||||
components as dependencies.
|
||||
|
||||
- Controllers are defined by a constructor function, which can be injected with any of the "service"
|
||||
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.
|
||||
|
||||
- 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.
|
||||
|
||||
See {@link module#module-loading-dependencies Modules} for more details about `run` and `config`
|
||||
blocks.
|
||||
|
||||
|
||||
### Factory Methods
|
||||
|
||||
The way you define a directive, service, or filter is with a factory function.
|
||||
The factory methods are registered with modules. The recommended way of declaring factories is:
|
||||
|
||||
```js
|
||||
angular.module('myModule', [])
|
||||
.factory('serviceId', ['depService', function(depService) {
|
||||
// ...
|
||||
}])
|
||||
.directive('directiveName', ['depService', function(depService) {
|
||||
// ...
|
||||
}])
|
||||
.filter('filterName', ['depService', function(depService) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
### Module Methods
|
||||
|
||||
We can specify functions to run at configuration and run time for a module by calling the `config`
|
||||
and `run` methods. These functions are injectable with dependencies just like the factory functions
|
||||
above.
|
||||
|
||||
```js
|
||||
angular.module('myModule', [])
|
||||
.config(['depProvider', function(depProvider) {
|
||||
// ...
|
||||
}])
|
||||
.run(['depService', function(depService) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
### Controllers
|
||||
|
||||
Controllers are "classes" or "constructor functions" that are responsible for providing the
|
||||
application behavior that supports the declarative markup in the template. The recommended way of
|
||||
declaring Controllers is using the array notation:
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
|
||||
...
|
||||
$scope.aMethod = function() {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
Unlike services, there can be many instances of the same type of controller in an application.
|
||||
|
||||
Moreover, additional dependencies are made available to Controllers:
|
||||
|
||||
* {@link scope `$scope`}: Controllers are associated with an element in the DOM and so are
|
||||
provided with access to the {@link scope scope}. Other components (like services) only have
|
||||
access to the {@link $rootScope `$rootScope`} service.
|
||||
* {@link ngRoute.$routeProvider#when resolves}: If a controller is instantiated as part of a route,
|
||||
then any values that are resolved as part of the route are made available for injection into the
|
||||
controller.
|
||||
|
||||
|
||||
## Dependency Annotation
|
||||
|
||||
Angular invokes certain functions (like service factories and controllers) via the injector.
|
||||
You need to annotate these functions so that the injector knows what services to inject into
|
||||
the function. There are three ways of annotating your code with service name information:
|
||||
|
||||
- Using the inline array annotation (preferred)
|
||||
- Using the `$inject` property annotation
|
||||
- Implicitly from the function parameter names (has caveats)
|
||||
|
||||
### Inline Array Annotation
|
||||
|
||||
This is the preferred way to annotate application components. This is how the examples in the
|
||||
documentation are written.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
Here we pass an array whose elements consist of a list of strings (the names of the dependencies)
|
||||
followed by the function itself.
|
||||
|
||||
When using this type of annotation, take care to keep the annotation array in sync with the
|
||||
parameters in the function declaration.
|
||||
|
||||
### `$inject` Property Annotation
|
||||
|
||||
To allow the minifiers to rename the function parameters and still be able to inject the right services,
|
||||
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
|
||||
of service names to inject.
|
||||
|
||||
```js
|
||||
var MyController = function($scope, greeter) {
|
||||
// ...
|
||||
}
|
||||
MyController.$inject = ['$scope', 'greeter'];
|
||||
someModule.controller('MyController', MyController);
|
||||
```
|
||||
|
||||
In this scenario the ordering of the values in the `$inject` array must match the ordering of the
|
||||
parameters in `MyController`.
|
||||
|
||||
Just like with the array annotation, you'll need to take care to keep the `$inject` in sync with
|
||||
the parameters in the function declaration.
|
||||
|
||||
### Implicit Annotation
|
||||
|
||||
<div class="alert alert-danger">
|
||||
**Careful:** If you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming))
|
||||
your code, your service names will get renamed and break your app.
|
||||
</div>
|
||||
|
||||
The simplest way to get hold of the dependencies is to assume that the function parameter names
|
||||
are the names of the dependencies.
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', function($scope, greeter) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Given a function the injector can infer the names of the services to inject by examining the
|
||||
function declaration and extracting the parameter names. In the above example `$scope`, and
|
||||
`greeter` are two services which need to be injected into the function.
|
||||
|
||||
One advantage of this approach is that there's no array of names to keep in sync with the
|
||||
function parameters. You can also freely reorder dependencies.
|
||||
|
||||
However this method will not work with JavaScript minifiers/obfuscators because of how they
|
||||
rename parameters.
|
||||
|
||||
Tools like [ng-annotate](https://github.com/olov/ng-annotate) let you use implicit dependency
|
||||
annotations in your app and automatically add inline array annotations prior to minifying.
|
||||
If you decide to take this approach, you probably want to use `ng-strict-di`.
|
||||
|
||||
Because of these caveats, we recommend avoiding this style of annotation.
|
||||
|
||||
|
||||
## Using Strict Dependency Injection
|
||||
|
||||
You can add an `ng-strict-di` directive on the same element as `ng-app` to opt into strict DI mode:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html ng-app="myApp" ng-strict-di>
|
||||
<body>
|
||||
I can add: {{ 1 + 2 }}.
|
||||
<script src="angular.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Strict mode throws an error whenever a service tries to use implicit annotations.
|
||||
|
||||
Consider this module, which includes a `willBreak` service that uses implicit DI:
|
||||
|
||||
```js
|
||||
angular.module('myApp', [])
|
||||
.factory('willBreak', function($rootScope) {
|
||||
// $rootScope is implicitly injected
|
||||
})
|
||||
.run(['willBreak', function(willBreak) {
|
||||
// Angular will throw when this runs
|
||||
}]);
|
||||
```
|
||||
|
||||
When the `willBreak` service is instantiated, Angular will throw an error because of strict mode.
|
||||
This is useful when using a tool like [ng-annotate](https://github.com/olov/ng-annotate) to
|
||||
ensure that all of your application components have annotations.
|
||||
|
||||
If you're using manual bootstrapping, you can also use strict DI by providing `strictDi: true` in
|
||||
the optional config argument:
|
||||
|
||||
```js
|
||||
angular.bootstrap(document, ['myApp'], {
|
||||
strictDi: true
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Why Dependency Injection?
|
||||
|
||||
This section motivates and explains Angular's use of DI. For how to use DI, see above.
|
||||
|
||||
For in-depth discussion about DI, see
|
||||
[Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection) at Wikipedia,
|
||||
[Inversion of Control](http://martinfowler.com/articles/injection.html) by Martin Fowler,
|
||||
or read about DI in your favorite software design pattern book.
|
||||
|
||||
## DI in a Nutshell
|
||||
|
||||
There are only three ways a component (object or function) can get a hold of its dependencies:
|
||||
|
||||
1. The component can create the dependency, typically using the `new` operator.
|
||||
@@ -117,186 +331,7 @@ controller ever knowing about the injector.
|
||||
This is the best outcome. The application code simply declares the dependencies it needs, without
|
||||
having to deal with the injector. This setup does not break the Law of Demeter.
|
||||
|
||||
|
||||
## Dependency Annotation
|
||||
|
||||
**How does the injector know what components need to be injected?**
|
||||
|
||||
The application developer needs to provide annotation information that the injector uses in order
|
||||
to resolve the dependencies. Throughout Angular, certain API functions are invoked using the
|
||||
injector, as per the API documentation. The injector needs to know what services to inject into
|
||||
the function. There are three equivalent ways of annotating your code with service name
|
||||
information:
|
||||
|
||||
- Implicitly from the function parameter names
|
||||
- Using the `$inject` property annotation
|
||||
- Using the inline array annotation
|
||||
|
||||
These can be used interchangeably as you see fit and are equivalent.
|
||||
|
||||
### Implicit Dependencies
|
||||
|
||||
The simplest way to get hold of the dependencies is to assume that the function parameter names
|
||||
are the names of the dependencies.
|
||||
|
||||
```js
|
||||
function MyController($scope, greeter) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Given a function the injector can infer the names of the services to inject by examining the
|
||||
function declaration and extracting the parameter names. In the above example `$scope`, and
|
||||
`greeter` are two services which need to be injected into the function.
|
||||
|
||||
While straightforward, this method will not work with JavaScript minifiers/obfuscators as they
|
||||
rename the method parameter names. This makes this way of annotating only useful for
|
||||
[pretotyping](http://www.pretotyping.org/), and demo applications.
|
||||
|
||||
### `$inject` Property Annotation
|
||||
|
||||
To allow the minifiers to rename the function parameters and still be able to inject the right services,
|
||||
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
|
||||
of service names to inject.
|
||||
|
||||
```js
|
||||
var MyController = function(renamed$scope, renamedGreeter) {
|
||||
...
|
||||
}
|
||||
MyController['$inject'] = ['$scope', 'greeter'];
|
||||
```
|
||||
|
||||
In this scenario the ordering of the values in the `$inject` array must match the ordering of the
|
||||
arguments to inject. Using the above code snippet as an example, `$scope` will be injected into
|
||||
`renamed$scope` and `greeter` into `renamedGreeter`. Care must be taken that the `$inject`
|
||||
annotation is kept in sync with the actual arguments in the function declaration.
|
||||
|
||||
This method of annotation is useful for controller declarations since it assigns the annotation
|
||||
information with the function.
|
||||
|
||||
### Inline Array Annotation
|
||||
|
||||
Sometimes using the `$inject` annotation style is not convenient such as when annotating
|
||||
directives or services defined inline by a factory function.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
someModule.factory('greeter', function($window) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Results in code bloat due to needing a temporary variable:
|
||||
|
||||
```js
|
||||
var greeterFactory = function(renamed$window) {
|
||||
// ...
|
||||
};
|
||||
|
||||
greeterFactory.$inject = ['$window'];
|
||||
|
||||
someModule.factory('greeter', greeterFactory);
|
||||
```
|
||||
|
||||
For this reason the third annotation style is provided as well.
|
||||
|
||||
```js
|
||||
someModule.factory('greeter', ['$window', function(renamed$window) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
Here, instead of simply providing the factory function, we pass an array whose elements consist of
|
||||
a list of strings (the names of the dependencies) followed by the function itself.
|
||||
|
||||
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
|
||||
where injection is supported.
|
||||
|
||||
## Where Can I Use DI?
|
||||
|
||||
DI is pervasive throughout Angular. You can use it when defining components or when providing `run`
|
||||
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" 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"
|
||||
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
|
||||
|
||||
Factory methods are responsible for creating most objects in Angular. Examples are directives,
|
||||
services, and filters. The factory methods are registered with the module, and the recommended way
|
||||
of declaring factories is:
|
||||
|
||||
```js
|
||||
angular.module('myModule', [])
|
||||
.factory('serviceId', ['depService', function(depService) {
|
||||
...
|
||||
}])
|
||||
.directive('directiveName', ['depService', function(depService) {
|
||||
...
|
||||
}])
|
||||
.filter('filterName', ['depService', function(depService) {
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
### Module Methods
|
||||
|
||||
We can specify functions to run at configuration and run time for a module by calling the `run` and
|
||||
`config` methods. These functions are injectable with dependencies just like the factory functions
|
||||
above.
|
||||
|
||||
```js
|
||||
angular.module('myModule', [])
|
||||
.config(['depProvider', function(depProvider){
|
||||
...
|
||||
}])
|
||||
.run(['depService', function(depService) {
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
### Controllers
|
||||
|
||||
Controllers are "classes" or "constructor functions" that are responsible for providing the
|
||||
application behavior that supports the declarative markup in the template. The recommended way of
|
||||
declaring Controllers is using the array notation:
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
|
||||
...
|
||||
$scope.aMethod = function() {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
This avoids the creation of global functions for controllers and also protects against minification.
|
||||
|
||||
Controllers are special in that, unlike services, there can be many instances of them in the
|
||||
application. For example, there would be one instance for every `ng-controller` directive in the template.
|
||||
|
||||
Moreover, additional dependencies are made available to Controllers:
|
||||
|
||||
* {@link scope `$scope`}: Controllers are always associated with a point in the DOM and so are provided with
|
||||
access to the {@link scope scope} at that point. Other components, such as services only have access to the
|
||||
singleton {@link $rootScope} service.
|
||||
* {@link $route} resolves: If a controller is instantiated as part of a route, then any values that
|
||||
are resolved as part of the route are made available for injection into the controller.
|
||||
<div class="alert alert-info">
|
||||
**Note:** Angular uses
|
||||
[**constructor injection**](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/).
|
||||
</div>
|
||||
|
||||
@@ -66,15 +66,9 @@ The **normalization** process is as follows:
|
||||
1. Strip `x-` and `data-` from the front of the element/attributes.
|
||||
2. Convert the `:`, `-`, or `_`-delimited name to `camelCase`.
|
||||
|
||||
Here are some equivalent examples of elements that match `ngBind`:
|
||||
For example, the following forms are all equivalent and match the {@link ngBind} directive:
|
||||
|
||||
<example module="docsBindExample">
|
||||
<file name="script.js">
|
||||
angular.module('docsBindExample', [])
|
||||
.controller('Controller', ['$scope', function($scope) {
|
||||
$scope.name = 'Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)';
|
||||
}]);
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
Hello <input ng-model='name'> <hr/>
|
||||
@@ -85,6 +79,12 @@ Here are some equivalent examples of elements that match `ngBind`:
|
||||
<span x-ng-bind="name"></span> <br/>
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('docsBindExample', [])
|
||||
.controller('Controller', ['$scope', function($scope) {
|
||||
$scope.name = 'Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)';
|
||||
}]);
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should show off bindings', function() {
|
||||
expect(element(by.css('div[ng-controller="Controller"] span[ng-bind]')).getText())
|
||||
@@ -282,7 +282,7 @@ using `templateUrl` instead:
|
||||
</file>
|
||||
</example>
|
||||
|
||||
`templateUrl` can also be a function which returns the URL of an HMTL template to be loaded and
|
||||
`templateUrl` can also be a function which returns the URL of an HTML template to be loaded and
|
||||
used for the directive. Angular will call the `templateUrl` function with two parameters: the
|
||||
element that the directive was called on, and an `attr` object associated with that element.
|
||||
|
||||
|
||||
@@ -278,9 +278,9 @@ digest cycle as long as that value is not undefined. If the value of the express
|
||||
within the digest loop and later, within the same digest loop, it is set to undefined,
|
||||
then the expression is not fulfilled and will remain watched.
|
||||
|
||||
1. Given an expression that starts with `::` when a digest loop is entered and expression
|
||||
is dirty-checked store the value as V
|
||||
2. If V is not undefined mark the result of the expression as stable and schedule a task
|
||||
1. Given an expression that starts with `::`, when a digest loop is entered and expression
|
||||
is dirty-checked, store the value as V
|
||||
2. If V is not undefined, mark the result of the expression as stable and schedule a task
|
||||
to deregister the watch for this expression when we exit the digest loop
|
||||
3. Process the digest loop as normal
|
||||
4. When digest loop is done and all the values have settled process the queue of watch
|
||||
|
||||
@@ -7,15 +7,17 @@ Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
|
||||
A Form is a collection of controls for the purpose of grouping related controls together.
|
||||
|
||||
Form and controls provide validation services, so that the user can be notified of invalid input.
|
||||
This provides a better user experience, because the user gets instant feedback on how to correct the error.
|
||||
Keep in mind that while client-side validation plays an important role in providing good user experience, it can easily be circumvented and thus can not be trusted.
|
||||
This provides a better user experience, because the user gets instant feedback on how to
|
||||
correct the error. Keep in mind that while client-side validation plays an important role
|
||||
in providing good user experience, it can easily be circumvented and thus can not be trusted.
|
||||
Server-side validation is still necessary for a secure application.
|
||||
|
||||
|
||||
# Simple form
|
||||
The key directive in understanding two-way data-binding is {@link ng.directive:ngModel ngModel}.
|
||||
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.
|
||||
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 module="formExample">
|
||||
<file name="index.html">
|
||||
@@ -60,16 +62,20 @@ Note that `novalidate` is used to disable browser's native form validation.
|
||||
|
||||
To allow styling of form as well as controls, `ngModel` adds these CSS classes:
|
||||
|
||||
- `ng-valid`
|
||||
- `ng-invalid`
|
||||
- `ng-pristine`
|
||||
- `ng-dirty`
|
||||
- `ng-touched`
|
||||
- `ng-untouched`
|
||||
- `ng-valid`: the model is valid
|
||||
- `ng-invalid`: the model is invalid
|
||||
- `ng-valid-[key]`: for each valid key added by `$setValidity`
|
||||
- `ng-invalid-[key]`: for each invalid key added by `$setValidity`
|
||||
- `ng-pristine`: the control hasn't been interacted with yet
|
||||
- `ng-dirty`: the control has been interacted with
|
||||
- `ng-touched`: the control has been blurred
|
||||
- `ng-untouched`: the control hasn't been blurred
|
||||
- `ng-pending`: any `$asyncValidators` are unfulfilled
|
||||
|
||||
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.
|
||||
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 module="formExample">
|
||||
<file name="index.html">
|
||||
@@ -122,9 +128,9 @@ A form is an instance of {@link form.FormController FormController}.
|
||||
The form instance can optionally be published into the scope using the `name` attribute.
|
||||
|
||||
Similarly, an input control that has the {@link ng.directive:ngModel ngModel} directive holds an
|
||||
instance of {@link 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.
|
||||
instance of {@link 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.
|
||||
@@ -187,7 +193,7 @@ This allows us to extend the above example with these features:
|
||||
|
||||
|
||||
|
||||
# Custom triggers
|
||||
# Custom model update triggers
|
||||
|
||||
By default, any change to the content will trigger a model update and form validation. You can
|
||||
override this behavior using the {@link ng.directive:ngModelOptions ngModelOptions} directive to
|
||||
@@ -195,13 +201,15 @@ bind only to specified list of events. I.e. `ng-model-options="{ updateOn: 'blur
|
||||
and validate only after the control loses focus. You can set several events using a space delimited
|
||||
list. I.e. `ng-model-options="{ updateOn: 'mousedown blur' }"`
|
||||
|
||||
<img alt="animation showing debounced input" src="img/guide/forms-update-on-blur.gif">
|
||||
|
||||
If you want to keep the default behavior and just add new events that may trigger the model update
|
||||
and validation, add "default" as one of the specified events.
|
||||
|
||||
I.e. `ng-model-options="{ updateOn: 'default blur' }"`
|
||||
|
||||
The following example shows how to override immediate updates. Changes on the inputs within the form will update the model
|
||||
only when the control loses focus (blur event).
|
||||
The following example shows how to override immediate updates. Changes on the inputs within the form
|
||||
will update the model only when the control loses focus (blur event).
|
||||
|
||||
<example module="customTriggerExample">
|
||||
<file name="index.html">
|
||||
@@ -232,6 +240,8 @@ You can delay the model update/validation by using the `debounce` key with the
|
||||
{@link ng.directive:ngModelOptions ngModelOptions} directive. This delay will also apply to
|
||||
parsers, validators and model flags like `$dirty` or `$pristine`.
|
||||
|
||||
<img alt="animation showing debounced input" src="img/guide/forms-debounce.gif">
|
||||
|
||||
I.e. `ng-model-options="{ debounce: 500 }"` will wait for half a second since
|
||||
the last content change before triggering the model update and form validation.
|
||||
|
||||
@@ -241,10 +251,11 @@ in `debounce`. This can be useful to force immediate updates on some specific ci
|
||||
|
||||
I.e. `ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"`
|
||||
|
||||
If those attributes are added to an element, they will be applied to all the child elements and controls that inherit from it unless they are
|
||||
overridden.
|
||||
If those attributes are added to an element, they will be applied to all the child elements and
|
||||
controls that inherit from it unless they are overridden.
|
||||
|
||||
This example shows how to debounce model changes. Model will be updated only 250 milliseconds after last change.
|
||||
This example shows how to debounce model changes. Model will be updated only 250 milliseconds
|
||||
after last change.
|
||||
|
||||
<example module="debounceExample">
|
||||
<file name="index.html">
|
||||
@@ -264,35 +275,40 @@ This example shows how to debounce model changes. Model will be updated only 250
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
|
||||
# Custom Validation
|
||||
|
||||
Angular provides basic implementation for most common html5 {@link ng.directive:input input}
|
||||
types: ({@link input[text] text}, {@link input[number] number}, {@link input[url] url}, {@link input[email] email}, {@link input[radio] radio}, {@link input[checkbox] checkbox}), as well as some directives for validation (`required`, `pattern`, `minlength`, `maxlength`, `min`, `max`).
|
||||
Angular provides basic implementation for most common HTML5 {@link ng.directive:input input}
|
||||
types: ({@link input[text] text}, {@link input[number] number}, {@link input[url] url},
|
||||
{@link input[email] email}, {@link input[radio] radio}, {@link input[checkbox] checkbox}),
|
||||
as well as some directives for validation (`required`, `pattern`, `minlength`, `maxlength`,
|
||||
`min`, `max`).
|
||||
|
||||
Defining your own validator can be done by defining your own directive which adds a custom validation function to the `ngModel` {@link ngModel.NgModelController controller}.
|
||||
To get a hold of the controller the directive specifies a dependency as shown in the example below.
|
||||
The validation can occur in two places:
|
||||
With a custom directive, you can add your own validation functions to the `$validators` object on
|
||||
the {@link ngModel.NgModelController `ngModelController`}. To get a hold of the controller,
|
||||
you require it in the directive as shown in the example below.
|
||||
|
||||
* **Model to View update** -
|
||||
Whenever the bound model changes, all functions in {@link ngModel.NgModelController#$formatters NgModelController#$formatters} array are pipe-lined, so that each of these functions has an opportunity to format the value and change validity state of the form control through {@link ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
|
||||
Each function in the `$validators` object receives the `modelValue` and the `viewValue`
|
||||
as parameters. Angular will then call `$setValidity` internally with the function's return value
|
||||
(`true`: valid, `false`: invalid). The validation functions are executed every time an input
|
||||
is changed (`$setViewValue` is called) or whenever the bound `model` changes.
|
||||
Validation happens after successfully running `$parsers` and `$formatters`, respectively.
|
||||
Failed validators are stored by key in
|
||||
{@link ngModel.NgModelController#$error `ngModelController.$error`}.
|
||||
|
||||
* **View to Model update** -
|
||||
In a similar way, whenever a user interacts with a control it calls {@link ngModel.NgModelController#$setViewValue NgModelController#$setViewValue}.
|
||||
This in turn pipelines all functions in the {@link ngModel.NgModelController#$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
|
||||
Additionally, there is the `$asyncValidators` object which handles asynchronous validation,
|
||||
such as making an `$http` request to the backend. Functions added to the object must return
|
||||
a promise that must be `resolved` when valid or `rejected` when invalid.
|
||||
In-progress async validations are stored by key in
|
||||
{@link ngModel.NgModelController#$pending `ngModelController.$pending`}.
|
||||
|
||||
In the following example we create two directives.
|
||||
|
||||
* The first one is `integer` and it validates whether the input is a valid integer.
|
||||
For example `1.23` is an invalid value, since it contains a fraction.
|
||||
Note that we unshift the array instead of pushing.
|
||||
This is because we want it to be the first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
|
||||
|
||||
* The second directive is a `smart-float`.
|
||||
It parses both `1.2` and `1,2` into a valid float number `1.2`.
|
||||
Note that we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
|
||||
In the following example we create two directives:
|
||||
* An `integer` directive that validates whether the input is a valid integer. For example,
|
||||
`1.23` is an invalid value, since it contains a fraction. Note that we validate the viewValue
|
||||
(the string value of the control), and not the modelValue. This is because input[number] converts
|
||||
the viewValue to a number when running the `$parsers`.
|
||||
|
||||
* A `username` directive that asynchronously checks if a user-entered value is already taken.
|
||||
We mock the server request with a `$q` deferred.
|
||||
|
||||
<example module="form-example1">
|
||||
<file name="index.html">
|
||||
@@ -301,18 +317,18 @@ In the following example we create two directives.
|
||||
Size (integer 0 - 10):
|
||||
<input type="number" ng-model="size" name="size"
|
||||
min="0" max="10" integer />{{size}}<br />
|
||||
<span ng-show="form.size.$error.integer">This is not valid integer!</span>
|
||||
<span ng-show="form.size.$error.integer">The value is not a valid integer!</span>
|
||||
<span ng-show="form.size.$error.min || form.size.$error.max">
|
||||
The value must be in range 0 to 10!</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Length (float):
|
||||
<input type="text" ng-model="length" name="length" smart-float />
|
||||
{{length}}<br />
|
||||
<span ng-show="form.length.$error.float">
|
||||
This is not a valid float number!</span>
|
||||
Username:
|
||||
<input type="text" ng-model="name" name="name" username />{{name}}<br />
|
||||
<span ng-show="form.name.$pending.username">Checking if this name is available ...</span>
|
||||
<span ng-show="form.name.$error.username">This username is already taken!</span>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</file>
|
||||
|
||||
@@ -324,35 +340,96 @@ In the following example we create two directives.
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
ctrl.$parsers.unshift(function(viewValue) {
|
||||
ctrl.$validators.integer = function(modelValue, viewValue) {
|
||||
if (ctrl.$isEmpty(modelValue)) {
|
||||
// consider empty models to be valid
|
||||
return true;
|
||||
}
|
||||
|
||||
if (INTEGER_REGEXP.test(viewValue)) {
|
||||
// it is valid
|
||||
ctrl.$setValidity('integer', true);
|
||||
return viewValue;
|
||||
} else {
|
||||
// it is invalid, return undefined (no model update)
|
||||
ctrl.$setValidity('integer', false);
|
||||
return undefined;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// it is invalid
|
||||
return false;
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var FLOAT_REGEXP = /^\-?\d+((\.|\,)\d+)?$/;
|
||||
app.directive('smartFloat', function() {
|
||||
app.directive('username', function($q, $timeout) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
ctrl.$parsers.unshift(function(viewValue) {
|
||||
if (FLOAT_REGEXP.test(viewValue)) {
|
||||
ctrl.$setValidity('float', true);
|
||||
return parseFloat(viewValue.replace(',', '.'));
|
||||
} else {
|
||||
ctrl.$setValidity('float', false);
|
||||
return undefined;
|
||||
var usernames = ['Jim', 'John', 'Jill', 'Jackie'];
|
||||
|
||||
ctrl.$asyncValidators.username = function(modelValue, viewValue) {
|
||||
|
||||
if (ctrl.$isEmpty(modelValue)) {
|
||||
// consider empty model valid
|
||||
return $q.when();
|
||||
}
|
||||
});
|
||||
|
||||
var def = $q.defer();
|
||||
|
||||
$timeout(function() {
|
||||
// Mock a delayed response
|
||||
if (usernames.indexOf(modelValue) === -1) {
|
||||
// The username is available
|
||||
def.resolve();
|
||||
} else {
|
||||
def.reject();
|
||||
}
|
||||
|
||||
}, 2000);
|
||||
|
||||
return def.promise;
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
|
||||
# Modifying built-in validators
|
||||
|
||||
Since Angular itself uses `$validators`, you can easily replace or remove built-in validators,
|
||||
should you find it necessary. The following example shows you how to overwrite the email validator
|
||||
in `input[email]` from a custom directive so that it requires a specific top-level domain,
|
||||
`example.com` to be present.
|
||||
Note that you can alternatively use `ng-pattern` to further restrict the validation.
|
||||
|
||||
<example module="form-example-modify-validators">
|
||||
<file name="index.html">
|
||||
<form name="form" class="css-form" novalidate>
|
||||
<div>
|
||||
Overwritten Email:
|
||||
<input type="email" ng-model="myEmail" overwrite-email name="overwrittenEmail" />
|
||||
<span ng-show="form.overwrittenEmail.$error.email">This email format is invalid!</span><br>
|
||||
Model: {{myEmail}}
|
||||
</div>
|
||||
</form>
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
var app = angular.module('form-example-modify-validators', []);
|
||||
|
||||
app.directive('overwriteEmail', function() {
|
||||
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example\.com$/i;
|
||||
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: '',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
// only apply the validator if ngModel is present and Angular has added the email validator
|
||||
if (ctrl && ctrl.$validators.email) {
|
||||
|
||||
// this will overwrite the default Angular email validator
|
||||
ctrl.$validators.email = function(modelValue) {
|
||||
return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue);
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -361,15 +438,19 @@ In the following example we create two directives.
|
||||
|
||||
|
||||
# Implementing custom form controls (using `ngModel`)
|
||||
Angular implements all of the basic HTML form controls ({@link ng.directive:input input}, {@link ng.directive:select select}, {@link ng.directive:textarea textarea}), which should be sufficient for most cases.
|
||||
However, if you need more flexibility, you can write your own form control as a directive.
|
||||
Angular implements all of the basic HTML form controls ({@link ng.directive:input input},
|
||||
{@link ng.directive:select select}, {@link ng.directive:textarea textarea}),
|
||||
which should be sufficient for most cases. However, if you need more flexibility,
|
||||
you can write your own form control as a directive.
|
||||
|
||||
In order for custom control to work with `ngModel` and to achieve two-way data-binding it needs to:
|
||||
|
||||
- implement `$render` method, which is responsible for rendering the data after it passed the {@link ngModel.NgModelController#$formatters NgModelController#$formatters},
|
||||
- call `$setViewValue` method, whenever the user interacts with the control and model needs to be updated. This is usually done inside a DOM Event listener.
|
||||
- implement `$render` method, which is responsible for rendering the data after it passed the
|
||||
{@link ngModel.NgModelController#$formatters `NgModelController.$formatters`},
|
||||
- call `$setViewValue` method, whenever the user interacts with the control and model
|
||||
needs to be updated. This is usually done inside a DOM Event listener.
|
||||
|
||||
See {@link guide/directive $compileProvider.directive} for more info.
|
||||
See {@link guide/directive `$compileProvider.directive`} for more info.
|
||||
|
||||
The following example shows how to add two-way data-binding to contentEditable elements.
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
* **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)
|
||||
* **Meteor: **[angular-meteor package](https://github.com/Urigo/angular-meteor)
|
||||
|
||||
## Learning Resources
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ browser new syntax through a construct we call directives. Examples include:
|
||||
* Data binding, as in `{{}}`.
|
||||
* DOM control structures for repeating/hiding DOM fragments.
|
||||
* Support for forms and form validation.
|
||||
* Attaching code-behind to DOM elements.
|
||||
* Attaching new behavior to DOM elements, such as DOM event handling.
|
||||
* Grouping of HTML into reusable components.
|
||||
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ linking} phase the {@link ng.$compileProvider#directive directives} set up
|
||||
render the updated value to the DOM.
|
||||
|
||||
Both controllers and directives have reference to the scope, but not to each other. This
|
||||
arrangement isolates the controller from the directive as well as from DOM. This is an important
|
||||
arrangement isolates the controller from the directive as well as from the DOM. This is an important
|
||||
point since it makes the controllers view agnostic, which greatly improves the testing story of
|
||||
the applications.
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Angular offers several useful services (like {@link ng.$http `$http`}), but for
|
||||
you'll also want to {@link services#creating-services create your own}.
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Note:** Like other core Angular identifiers built-in services always start with `$`
|
||||
**Note:** Like other core Angular identifiers, built-in services always start with `$`
|
||||
(e.g. `$http`).
|
||||
</div>
|
||||
|
||||
@@ -68,79 +68,6 @@ subsystem takes care of the rest.
|
||||
</file>
|
||||
</example>
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Note:** Angular uses
|
||||
[**constructor injection**](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/).
|
||||
</div>
|
||||
|
||||
### Explicit Dependency Injection
|
||||
|
||||
A component should explicitly define its dependencies using one of the {@link di injection
|
||||
annotation} methods:
|
||||
|
||||
1. Inline array injection annotation (preferred):
|
||||
```js
|
||||
myModule.controller('MyController', ['$location', function($location) { ... }]);
|
||||
```
|
||||
|
||||
2. `$inject` property:
|
||||
```js
|
||||
var MyController = function($location) { ... };
|
||||
MyController.$inject = ['$location'];
|
||||
myModule.controller('MyController', MyController);
|
||||
```
|
||||
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** Use the array annotation shown above.
|
||||
</div>
|
||||
|
||||
### Implicit Dependency Injection
|
||||
|
||||
Even if you don't annotate your dependencies, Angular's DI can determine the dependency from the
|
||||
name of the parameter. Let's rewrite the above example to show the use of this implicit dependency
|
||||
injection of `$window`, `$scope`, and our `notify` service:
|
||||
|
||||
<example module="myServiceModuleDI">
|
||||
<file name="index.html">
|
||||
<div id="implicit" ng-controller="MyController">
|
||||
<p>Let's try the notify service, that is implicitly injected into the controller...</p>
|
||||
<input ng-init="message='test'" ng-model="message">
|
||||
<button ng-click="callNotify(message);">NOTIFY</button>
|
||||
<p>(you have to click 3 times to see an alert)</p>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('myServiceModuleDI', []).
|
||||
factory('notify', function($window) {
|
||||
var msgs = [];
|
||||
return function(msg) {
|
||||
msgs.push(msg);
|
||||
if (msgs.length == 3) {
|
||||
$window.alert(msgs.join("\n"));
|
||||
msgs = [];
|
||||
}
|
||||
};
|
||||
}).
|
||||
controller('MyController', function($scope, notify) {
|
||||
$scope.callNotify = function(msg) {
|
||||
notify(msg);
|
||||
};
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
|
||||
<div class="alert alert-danger">
|
||||
**Careful:** If you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming)) your
|
||||
code, your variable names will get renamed unless you use one of the annotation techniques above.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
If you use a tool like [ng-annotate](https://github.com/olov/ng-annotate) in your workflow you can
|
||||
use implicit dependency notation within your codebase and let **ng-annotate** automatically convert such
|
||||
injectable functions to the array notation prior to minifying.
|
||||
</div>
|
||||
|
||||
|
||||
## Creating Services
|
||||
|
||||
@@ -157,11 +84,11 @@ on the service.
|
||||
Services are registered to modules via the {@link angular.Module Module API}.
|
||||
Typically you use the {@link angular.module Module#factory} API to register a service:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
var myModule = angular.module('myModule', []);
|
||||
myModule.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
// factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
```
|
||||
@@ -174,6 +101,8 @@ will create this instance when called.
|
||||
Services can have their own dependencies. Just like declaring dependencies in a controller, you
|
||||
declare dependencies by specifying them in the service's factory function signature.
|
||||
|
||||
For more on dependencies, see the {@link guide/di dependency injection} docs.
|
||||
|
||||
The example module below has two services, each with various dependencies:
|
||||
|
||||
```js
|
||||
@@ -231,14 +160,14 @@ In the example, note that:
|
||||
You can also register services via the {@link auto.$provide `$provide`} service inside of a
|
||||
module's `config` function:
|
||||
|
||||
```javascript
|
||||
angular.module('myModule', []).config(function($provide) {
|
||||
```js
|
||||
angular.module('myModule', []).config(['$provide', function($provide) {
|
||||
$provide.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
// factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
});
|
||||
}]);
|
||||
```
|
||||
|
||||
This technique is often used in unit tests to mock out a service's dependencies.
|
||||
|
||||
@@ -31,7 +31,7 @@ development web server, run tests, and generate distributable files. Depending o
|
||||
pre-packaged bundle.
|
||||
|
||||
* [Java](http://www.java.com): We minify JavaScript using our
|
||||
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 6 or higher) installed
|
||||
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 7 or higher) installed
|
||||
and included in your [PATH](http://docs.oracle.com/javase/tutorial/essential/environment/paths.html) variable.
|
||||
|
||||
* [Grunt](http://gruntjs.com): We use Grunt as our build system. Install the grunt command-line tool globally with:
|
||||
|
||||
@@ -50,7 +50,7 @@ Yes. See instructions in {@link downloading}.
|
||||
|
||||
### What browsers does Angular work with?
|
||||
|
||||
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
|
||||
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera 15,
|
||||
IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). See {@link guide/ie Internet
|
||||
Explorer Compatibility} for more details in supporting legacy IE browsers.
|
||||
|
||||
|
||||
@@ -110,8 +110,9 @@ suggested solution is to also install the `nodejs-legacy` apt package, which ren
|
||||
`nodejs`.
|
||||
|
||||
```
|
||||
apt-get install nodejs-legacy
|
||||
apt-get install nodejs-legacy npm
|
||||
nodejs --version
|
||||
npm --version
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ __`app/index.html`:__
|
||||
|
||||
<ul>
|
||||
<li ng-repeat="phone in phones">
|
||||
{{phone.name}}
|
||||
<span>{{phone.name}}</span>
|
||||
<p>{{phone.snippet}}</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -150,7 +150,7 @@ __`test/e2e/scenarios.js`:__
|
||||
...
|
||||
it('should be possible to control phone order via the drop down select box', function() {
|
||||
|
||||
var phoneNameColumn = element.all(by.repeater('phone in phones').column('{{phone.name}}'));
|
||||
var phoneNameColumn = element.all(by.repeater('phone in phones').column('phone.name'));
|
||||
var query = element(by.model('query'));
|
||||
|
||||
function getNames() {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
In this step, you will learn how to create a layout template and how to build an app that has
|
||||
multiple views by adding routing, using an Angular module called 'ngRoute'.
|
||||
|
||||
* When you now navigate to `app/index.html`, you are redirected to `app/index.html#/phones`
|
||||
* When you now navigate to `app/index.html`, you are redirected to `app/index.html/#/phones`
|
||||
and the phone list appears in the browser.
|
||||
* When you click on a phone link the url changes to one specific to that phone and the stub of a
|
||||
phone detail page is displayed.
|
||||
|
||||
@@ -171,7 +171,7 @@ we require, so in these cases, we can add a callback to process the server respo
|
||||
|
||||
## Test
|
||||
|
||||
Because we're now using the {@link ngResource ngResource} module, it's necessary to also need to
|
||||
Because we're now using the {@link ngResource ngResource} module, it's necessary to
|
||||
update the Karma config file with angular-resource so the new tests will pass.
|
||||
|
||||
__`test/karma.conf.js`:__
|
||||
@@ -276,7 +276,7 @@ describe('PhoneCat controllers', function() {
|
||||
|
||||
You should now see the following output in the Karma tab:
|
||||
|
||||
<pre>Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)</pre>
|
||||
<pre>Chrome 22.0: Executed 5 of 5 SUCCESS (0.038 secs / 0.01 secs)</pre>
|
||||
|
||||
|
||||
# Summary
|
||||
|
||||
@@ -63,8 +63,8 @@ gulp.task('build-app', function() {
|
||||
gulp.task('assets', ['bower'], function() {
|
||||
var JS_EXT = /\.js$/;
|
||||
return merge(
|
||||
gulp.src([assets])
|
||||
.pipe(gulp.dest(outputFolder)),
|
||||
gulp.src(['img/**/*']).pipe(gulp.dest(outputFolder + '/img')),
|
||||
gulp.src([assets]).pipe(gulp.dest(outputFolder)),
|
||||
gulp.src([assets])
|
||||
.pipe(foreach(function(stream, file) {
|
||||
if (JS_EXT.test(file.relative)) {
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]>
|
||||
<svg version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
|
||||
x="0" y="0" width="687px" height="176px" viewBox="0 0 687 176" overflow="visible" enable-background="new 0 0 687 176"
|
||||
xml:space="preserve">
|
||||
<defs>
|
||||
</defs>
|
||||
<path fill="#FFFFFF" d="M179.011,125.328V54.527h9.158l43.322,57.035V54.527h8.666v70.801h-9.158l-43.326-57.536v57.536H179.011z
|
||||
M179.011,125.328"/>
|
||||
<path fill="#FFFFFF" d="M310.46,122.554c-5.708,2.182-11.864,3.269-18.467,3.269c-25.644,0-38.469-12.294-38.469-36.887
|
||||
c0-23.27,12.378-34.908,37.134-34.908c7.096,0,13.7,0.994,19.802,2.976v7.921c-6.103-2.311-12.378-3.468-18.813-3.468
|
||||
c-19.306,0-28.96,9.162-28.96,27.479c0,19.639,9.504,29.463,28.517,29.463c3.034,0,6.404-0.396,10.103-1.193V93.145h9.154V122.554z
|
||||
M310.46,122.554"/>
|
||||
<path fill="#FFFFFF" d="M325.067,97.996V54.523h9.154v43.473c0,13.598,6.768,20.4,20.303,20.4c13.531,0,20.301-6.803,20.301-20.4
|
||||
V54.523h9.158v43.473c0,18.556-9.82,27.825-29.459,27.825C334.886,125.821,325.067,116.552,325.067,97.996L325.067,97.996z
|
||||
M325.067,97.996"/>
|
||||
<path fill="#FFFFFF" d="M409.48,54.523v63.376h37.037v7.425h-46.191V54.523H409.48z M409.48,54.523"/>
|
||||
<path fill="#FFFFFF" d="M459.736,125.327h-9.504l35.201-80.146l35.199,80.146h-10.15l-9.158-22.282h-23.418l2.527-7.424h17.82
|
||||
l-13.217-32.088L459.736,125.327z M459.736,125.327"/>
|
||||
<path fill="#FFFFFF" d="M530.289,125.328V54.527h30.203c13.469,0,20.197,5.659,20.197,16.982c0,9.207-6.578,16.028-19.75,20.445
|
||||
l24.309,33.374h-12.086l-22.521-31.835v-5.992c13.531-2.151,20.301-7.344,20.301-15.598c0-6.533-3.766-9.801-11.293-9.801h-20.201
|
||||
v63.226H530.289z M530.289,125.328"/>
|
||||
<path fill="#B52E31" d="M619.561,54.523v50.405c0,13.603-8.006,20.396-24.016,20.396V117.9c9.902,0,14.857-4.329,14.857-12.973
|
||||
V54.523H619.561z M619.561,54.523"/>
|
||||
<path fill="#B52E31" d="M635.896,122.849v-8.418c7.428,2.639,15.447,3.965,24.064,3.965c12.178,0,18.271-4.457,18.271-13.372
|
||||
c0-7.584-4.492-11.385-13.469-11.385h-9.113c-14.818,0-22.234-6.435-22.234-19.31c0-13.531,9.492-20.303,28.479-20.303
|
||||
c8.25,0,15.922,0.998,23.021,2.976v8.418c-7.1-2.644-14.771-3.965-23.021-3.965c-12.875,0-19.311,4.293-19.311,12.875
|
||||
c0,7.588,4.352,11.385,13.066,11.385h9.113c15.08,0,22.627,6.439,22.627,19.31c0,13.864-9.141,20.796-27.43,20.796
|
||||
C651.344,125.819,643.324,124.826,635.896,122.849L635.896,122.849z M635.896,122.849"/>
|
||||
<path fill="#B2B2B2" d="M82.688,0L0,29.1l13.066,108.335l69.71,38.314l70.069-38.834l13.062-108.331L82.688,0z M82.688,0"/>
|
||||
<path fill="#B52E31" d="M157.66,34.846L82.496,9.214v157.381l62.991-34.861L157.66,34.846z M157.66,34.846"/>
|
||||
<path fill="#E23237" d="M9.279,35.308l11.196,96.889l62.019,34.398V9.211L9.279,35.308z M9.279,35.308"/>
|
||||
<path fill="#F2F2F2" d="M99.918,87.493L82.632,51.396L67.415,87.493H99.918z M106.508,102.672h-45.82l-10.251,25.64l-19.067,0.352
|
||||
L82.496,14.929l52.908,113.734h-17.673L106.508,102.672z M106.508,102.672"/>
|
||||
<path fill="#B2B2B2" d="M82.496,14.929l0.136,36.467l17.268,36.125H82.534l-0.039,15.127l24.012,0.023l11.223,25.996l18.245,0.339
|
||||
L82.496,14.929z M82.496,14.929"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
@@ -267,7 +267,7 @@ goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
|
||||
* 18: two decimals precision (2), currency sign last (16), no space (0)
|
||||
* 50: two decimals precision (2), currency sign last (16), space (32)
|
||||
*
|
||||
* @type {!Object.<!Array>}
|
||||
* @type {!Object.<!Array.<?>>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfo = {
|
||||
'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
|
||||
@@ -334,7 +334,7 @@ goog.i18n.currency.CurrencyInfo = {
|
||||
|
||||
/**
|
||||
* Tier 2 currency information.
|
||||
* @type {!Object.<!Array>}
|
||||
* @type {!Object.<!Array.<?>>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'AFN': [48, 'Af.', 'AFN'],
|
||||
|
||||
@@ -56,7 +56,7 @@ function newTestLocaleInfo() {
|
||||
}
|
||||
|
||||
|
||||
describe("findLocaleId", function () {
|
||||
describe("findLocaleId", function() {
|
||||
it("should find the id from numbers", function() {
|
||||
expect(findLocaleId("NumberFormatSymbols_en_GB", "num")).toEqual("en_GB");
|
||||
});
|
||||
@@ -74,7 +74,7 @@ describe("findLocaleId", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractNumberSymbols", function () {
|
||||
describe("extractNumberSymbols", function() {
|
||||
it("should extract number data", function() {
|
||||
var CONTENT = [
|
||||
"goog.provide('goog.i18n.NumberFormatSymbols_en_GB');",
|
||||
@@ -117,7 +117,7 @@ describe("extractNumberSymbols", function () {
|
||||
})
|
||||
});
|
||||
|
||||
describe("extractCurrencySymbols", function () {
|
||||
describe("extractCurrencySymbols", function() {
|
||||
it("should extract currency data", function() {
|
||||
var CONTENT = [
|
||||
"goog.i18n.currency.CurrencyInfo = {",
|
||||
@@ -137,7 +137,7 @@ describe("extractCurrencySymbols", function () {
|
||||
});
|
||||
|
||||
|
||||
describe("extractDateTimeSymbols", function () {
|
||||
describe("extractDateTimeSymbols", function() {
|
||||
it("should extract date time data", function() {
|
||||
var CONTENT = [
|
||||
"goog.i18n.DateTimeSymbols_fr_CA = {",
|
||||
|
||||
@@ -87,6 +87,7 @@ function pluralExtractor(content, localeInfo) {
|
||||
continue;
|
||||
}
|
||||
var temp = goog.i18n.pluralRules.select.toString().
|
||||
replace(/function\s+\(/g, 'function(').
|
||||
replace(/goog\.i18n\.pluralRules\.Keyword/g, 'PLURAL_CATEGORY').
|
||||
replace(/goog\.i18n\.pluralRules\.get_vf_/g, 'getVF').
|
||||
replace(/goog\.i18n\.pluralRules\.get_wt_/g, 'getWT').
|
||||
@@ -223,7 +224,7 @@ function outputLocale(localeInfo, localeID) {
|
||||
getDecimals + getVF + getWT +
|
||||
'$provide.value("$locale", ';
|
||||
|
||||
var suffix = ');\n}]);';
|
||||
var suffix = ');\n}]);\n';
|
||||
|
||||
return prefix + content + suffix;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ function writeLocaleFiles() {
|
||||
var filename = NG_LOCALE_DIR + 'angular-locale_' + correctedLocaleId + '.js'
|
||||
console.log('Writing ' + filename);
|
||||
return qfs.write(filename, content)
|
||||
.then(function () {
|
||||
.then(function() {
|
||||
console.log('Wrote ' + filename);
|
||||
++num_files;
|
||||
});
|
||||
|
||||
@@ -303,7 +303,7 @@ module.exports = {
|
||||
rewrite: function(){
|
||||
return function(req, res, next){
|
||||
var REWRITE = /\/(guide|api|cookbook|misc|tutorial|error).*$/,
|
||||
IGNORED = /(\.(css|js|png|jpg)$|partials\/.*\.html$)/,
|
||||
IGNORED = /(\.(css|js|png|jpg|gif)$|partials\/.*\.html$)/,
|
||||
match;
|
||||
|
||||
if (!IGNORED.test(req.url) && (match = req.url.match(REWRITE))) {
|
||||
|
||||
@@ -12,7 +12,7 @@ set -e
|
||||
# before_script:
|
||||
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
|
||||
|
||||
CONNECT_URL="https://d2nkw87yt5k0to.cloudfront.net/downloads/sc-4.3-linux.tar.gz"
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3-linux.tar.gz"
|
||||
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
|
||||
CONNECT_DOWNLOAD="sc-4.3-linux.tar.gz"
|
||||
|
||||
|
||||
@@ -9,24 +9,24 @@
|
||||
"angular-benchpress": "0.x.x",
|
||||
"benchmark": "1.x.x",
|
||||
"bower": "~1.3.9",
|
||||
"browserstacktunnel-wrapper": "~1.1.1",
|
||||
"browserstacktunnel-wrapper": "~1.3.1",
|
||||
"canonical-path": "0.0.2",
|
||||
"dgeni": "^0.4.0",
|
||||
"dgeni-packages": "^0.10.0",
|
||||
"event-stream": "~3.1.0",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-bump": "~0.0.13",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-connect": "~0.5.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"grunt-contrib-clean": "~0.6.0",
|
||||
"grunt-contrib-compress": "~0.12.0",
|
||||
"grunt-contrib-connect": "~0.8.0",
|
||||
"grunt-contrib-copy": "~0.6.0",
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-ddescribe-iit": "~0.0.1",
|
||||
"grunt-jasmine-node": "git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code",
|
||||
"grunt-jscs-checker": "~0.4.0",
|
||||
"grunt-jscs": "~0.7.1",
|
||||
"grunt-merge-conflict": "~0.0.1",
|
||||
"grunt-parallel": "~0.3.1",
|
||||
"grunt-shell": "~0.4.0",
|
||||
"grunt-shell": "~1.1.1",
|
||||
"gulp": "~3.8.0",
|
||||
"gulp-concat": "^2.4.1",
|
||||
"gulp-foreach": "0.0.1",
|
||||
@@ -35,32 +35,33 @@
|
||||
"gulp-sourcemaps": "^1.2.2",
|
||||
"gulp-uglify": "^1.0.1",
|
||||
"gulp-util": "^3.0.1",
|
||||
"jasmine-node": "~1.11.0",
|
||||
"jasmine-reporters": "~0.2.1",
|
||||
"jshint-stylish": "~0.1.5",
|
||||
"jasmine-node": "~1.14.5",
|
||||
"jasmine-reporters": "~1.0.1",
|
||||
"jshint-stylish": "~1.0.0",
|
||||
"karma": "^0.12.0",
|
||||
"karma-browserstack-launcher": "0.0.7",
|
||||
"karma-chrome-launcher": "0.1.2",
|
||||
"karma-browserstack-launcher": "0.1.1",
|
||||
"karma-chrome-launcher": "0.1.5",
|
||||
"karma-firefox-launcher": "0.1.3",
|
||||
"karma-jasmine": "0.1.5",
|
||||
"karma-junit-reporter": "0.2.1",
|
||||
"karma-junit-reporter": "0.2.2",
|
||||
"karma-ng-scenario": "0.1.0",
|
||||
"karma-sauce-launcher": "0.2.0",
|
||||
"karma-sauce-launcher": "0.2.10",
|
||||
"karma-script-launcher": "0.1.0",
|
||||
"load-grunt-tasks": "~0.3.0",
|
||||
"lodash": "~2.1.0",
|
||||
"load-grunt-tasks": "~0.6.0",
|
||||
"lodash": "~2.4.1",
|
||||
"marked": "~0.3.0",
|
||||
"node-html-encoder": "0.0.2",
|
||||
"promises-aplus-tests": "~2.0.4",
|
||||
"promises-aplus-tests": "~2.1.0",
|
||||
"protractor": "1.3.1",
|
||||
"q": "~1.0.0",
|
||||
"q-io": "^1.10.9",
|
||||
"qq": "^0.3.5",
|
||||
"rewire": "1.1.3",
|
||||
"semver": "~2.1.0",
|
||||
"shelljs": "~0.2.6",
|
||||
"rewire": "~2.1.0",
|
||||
"semver": "~4.0.3",
|
||||
"shelljs": "~0.3.0",
|
||||
"sorted-object": "^1.0.0",
|
||||
"stringmap": "^0.2.2"
|
||||
"stringmap": "^0.2.2",
|
||||
"cheerio": "^0.17.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
var config = require('./protractor-shared-conf').config;
|
||||
|
||||
config.specs = [
|
||||
'test/e2e/tests/**/*.js',
|
||||
'build/docs/ptore2e/**/*.js',
|
||||
'docs/app/e2e/**/*.scenario.js'
|
||||
];
|
||||
|
||||
@@ -4,6 +4,7 @@ exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
|
||||
specs: [
|
||||
'test/e2e/tests/**/*.js',
|
||||
'build/docs/ptore2e/**/*.js',
|
||||
'docs/app/e2e/*.scenario.js'
|
||||
],
|
||||
@@ -12,7 +13,7 @@ exports.config = {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
|
||||
baseUrl: 'http://localhost:8000/build/docs/',
|
||||
baseUrl: 'http://localhost:8000/',
|
||||
|
||||
framework: 'jasmine',
|
||||
|
||||
@@ -30,7 +31,7 @@ exports.config = {
|
||||
|
||||
require('jasmine-reporters');
|
||||
jasmine.getEnv().addReporter(
|
||||
new jasmine.JUnitXmlReporter('test_out/e2e-' + exports.config.capabilities.browserName + '-', true, true));
|
||||
new jasmine.JUnitXmlReporter('test_out/docs-e2e-' + exports.config.capabilities.browserName + '-', true, true));
|
||||
},
|
||||
|
||||
jasmineNodeOpts: {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
|
||||
baseUrl: 'http://localhost:8000/build/docs/',
|
||||
baseUrl: 'http://localhost:8000/',
|
||||
|
||||
framework: 'jasmine',
|
||||
|
||||
|
||||
@@ -5,16 +5,22 @@ set -e
|
||||
export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
|
||||
if [ $JOB = "unit" ]; then
|
||||
grunt ci-checks
|
||||
grunt test:promises-aplus
|
||||
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
|
||||
grunt ci-checks
|
||||
grunt tests:docs --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
|
||||
grunt test:travis-protractor --specs "docs/app/e2e/**/*.scenario.js"
|
||||
elif [ $JOB = "e2e" ]; then
|
||||
if [ $TEST_TARGET = "jquery" ]; then
|
||||
export USE_JQUERY=1
|
||||
fi
|
||||
|
||||
export TARGET_SPECS="build/docs/ptore2e/**/default_test.js"
|
||||
if [ $TEST_TARGET = "jquery" ]; then
|
||||
TARGET_SPECS="build/docs/ptore2e/**/jquery_test.js"
|
||||
fi
|
||||
|
||||
export TARGET_SPECS="test/e2e/tests/**/*.js,$TARGET_SPECS"
|
||||
grunt test:travis-protractor --specs "$TARGET_SPECS"
|
||||
else
|
||||
echo "Unknown job type. Please set JOB=unit or JOB=e2e-*."
|
||||
|
||||
@@ -54,12 +54,11 @@
|
||||
"isBoolean": false,
|
||||
"isPromiseLike": false,
|
||||
"trim": false,
|
||||
"escapeForRegexp": false,
|
||||
"isElement": false,
|
||||
"makeMap": false,
|
||||
"size": false,
|
||||
"includes": false,
|
||||
"arrayRemove": false,
|
||||
"isLeafNode": false,
|
||||
"copy": false,
|
||||
"shallowCopy": false,
|
||||
"equals": false,
|
||||
@@ -99,6 +98,8 @@
|
||||
"NODE_TYPE_DOCUMENT": false,
|
||||
"NODE_TYPE_DOCUMENT_FRAGMENT": false,
|
||||
|
||||
"defaultHttpResponseTransform": false,
|
||||
|
||||
/* filters.js */
|
||||
"getFirstThursdayOfYear": false,
|
||||
|
||||
|
||||
@@ -49,12 +49,11 @@
|
||||
isBoolean: true,
|
||||
isPromiseLike: true,
|
||||
trim: true,
|
||||
escapeForRegexp: true,
|
||||
isElement: true,
|
||||
makeMap: true,
|
||||
size: true,
|
||||
includes: true,
|
||||
arrayRemove: true,
|
||||
isLeafNode: true,
|
||||
copy: true,
|
||||
shallowCopy: true,
|
||||
equals: true,
|
||||
@@ -124,7 +123,7 @@ var VALIDITY_STATE_PROPERTY = 'validity';
|
||||
* @param {string} string String to be converted to lowercase.
|
||||
* @returns {string} Lowercased string.
|
||||
*/
|
||||
var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
|
||||
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
@@ -137,7 +136,7 @@ var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
* @param {string} string String to be converted to uppercase.
|
||||
* @returns {string} Uppercased string.
|
||||
*/
|
||||
var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
|
||||
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
|
||||
|
||||
|
||||
var manualLowercase = function(s) {
|
||||
@@ -220,6 +219,11 @@ function isArrayLike(obj) {
|
||||
*
|
||||
* It is worth noting that `.forEach` does not iterate over inherited properties because it filters
|
||||
* using the `hasOwnProperty` method.
|
||||
*
|
||||
* Unlike ES262's
|
||||
* [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
|
||||
* Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
|
||||
* return the value provided.
|
||||
*
|
||||
```js
|
||||
var values = {name: 'misko', gender: 'male'};
|
||||
@@ -268,18 +272,12 @@ function forEach(obj, iterator, context) {
|
||||
}
|
||||
|
||||
function sortedKeys(obj) {
|
||||
var keys = [];
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
return keys.sort();
|
||||
return Object.keys(obj).sort();
|
||||
}
|
||||
|
||||
function forEachSorted(obj, iterator, context) {
|
||||
var keys = sortedKeys(obj);
|
||||
for ( var i = 0; i < keys.length; i++) {
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
iterator.call(context, obj[keys[i]], keys[i]);
|
||||
}
|
||||
return keys;
|
||||
@@ -334,6 +332,7 @@ function setHashKey(obj, h) {
|
||||
* Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
|
||||
* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
|
||||
* by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
|
||||
* Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy).
|
||||
*
|
||||
* @param {Object} dst Destination object.
|
||||
* @param {...Object} src Source object(s).
|
||||
@@ -420,7 +419,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';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -435,7 +434,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';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -451,7 +450,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){
|
||||
function isObject(value) {
|
||||
// http://jsperf.com/isobject4
|
||||
return value !== null && typeof value === 'object';
|
||||
}
|
||||
@@ -469,7 +468,7 @@ function isObject(value){
|
||||
* @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';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -484,7 +483,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';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -530,7 +529,7 @@ var isArray = Array.isArray;
|
||||
* @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';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -586,6 +585,14 @@ var trim = function(value) {
|
||||
return isString(value) ? value.trim() : value;
|
||||
};
|
||||
|
||||
// Copied from:
|
||||
// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
|
||||
// Prereq: s is a string.
|
||||
var escapeForRegexp = function(s) {
|
||||
return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
|
||||
replace(/\x08/g, '\\x08');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
@@ -611,7 +618,7 @@ function isElement(node) {
|
||||
*/
|
||||
function makeMap(str) {
|
||||
var obj = {}, items = str.split(","), i;
|
||||
for ( i = 0; i < items.length; i++ )
|
||||
for (i = 0; i < items.length; i++)
|
||||
obj[ items[i] ] = true;
|
||||
return obj;
|
||||
}
|
||||
@@ -621,34 +628,6 @@ function nodeName_(element) {
|
||||
return lowercase(element.nodeName || element[0].nodeName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Determines the number of elements in an array, the number of properties an object has, or
|
||||
* the length of a string.
|
||||
*
|
||||
* Note: This function is used to augment the Object type in Angular expressions. See
|
||||
* {@link angular.Object} for more information about Angular arrays.
|
||||
*
|
||||
* @param {Object|Array|string} obj Object, array, or string to inspect.
|
||||
* @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
|
||||
* @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
|
||||
*/
|
||||
function size(obj, ownPropsOnly) {
|
||||
var count = 0, key;
|
||||
|
||||
if (isArray(obj) || isString(obj)) {
|
||||
return obj.length;
|
||||
} else if (isObject(obj)) {
|
||||
for (key in obj)
|
||||
if (!ownPropsOnly || obj.hasOwnProperty(key))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
function includes(array, obj) {
|
||||
return Array.prototype.indexOf.call(array, obj) != -1;
|
||||
}
|
||||
@@ -660,18 +639,6 @@ function arrayRemove(array, value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
function isLeafNode (node) {
|
||||
if (node) {
|
||||
switch (nodeName_(node)) {
|
||||
case "option":
|
||||
case "pre":
|
||||
case "title":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.copy
|
||||
@@ -769,7 +736,7 @@ function copy(source, destination, stackSource, stackDest) {
|
||||
var result;
|
||||
if (isArray(source)) {
|
||||
destination.length = 0;
|
||||
for ( var i = 0; i < source.length; i++) {
|
||||
for (var i = 0; i < source.length; i++) {
|
||||
result = copy(source[i], null, stackSource, stackDest);
|
||||
if (isObject(source[i])) {
|
||||
stackSource.push(source[i]);
|
||||
@@ -786,8 +753,8 @@ function copy(source, destination, stackSource, stackDest) {
|
||||
delete destination[key];
|
||||
});
|
||||
}
|
||||
for ( var key in source) {
|
||||
if(source.hasOwnProperty(key)) {
|
||||
for (var key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
result = copy(source[key], null, stackSource, stackDest);
|
||||
if (isObject(source[key])) {
|
||||
stackSource.push(source[key]);
|
||||
@@ -868,7 +835,7 @@ function equals(o1, o2) {
|
||||
if (isArray(o1)) {
|
||||
if (!isArray(o2)) return false;
|
||||
if ((length = o1.length) == o2.length) {
|
||||
for(key=0; key<length; key++) {
|
||||
for (key=0; key<length; key++) {
|
||||
if (!equals(o1[key], o2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -881,12 +848,12 @@ function equals(o1, o2) {
|
||||
} else {
|
||||
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
|
||||
keySet = {};
|
||||
for(key in o1) {
|
||||
for (key in o1) {
|
||||
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
||||
if (!equals(o1[key], o2[key])) return false;
|
||||
keySet[key] = true;
|
||||
}
|
||||
for(key in o2) {
|
||||
for (key in o2) {
|
||||
if (!keySet.hasOwnProperty(key) &&
|
||||
key.charAt(0) !== '$' &&
|
||||
o2[key] !== undefined &&
|
||||
@@ -1034,14 +1001,14 @@ function startingTag(element) {
|
||||
// turns out IE does not let you set .html() on elements which
|
||||
// are not allowed to have children. So we just ignore it.
|
||||
element.empty();
|
||||
} catch(e) {}
|
||||
} catch (e) {}
|
||||
var elemHtml = jqLite('<div>').append(element).html();
|
||||
try {
|
||||
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
|
||||
elemHtml.
|
||||
match(/^(<[^>]+>)/)[1].
|
||||
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
return lowercase(elemHtml);
|
||||
}
|
||||
|
||||
@@ -1061,7 +1028,7 @@ function startingTag(element) {
|
||||
function tryDecodeURIComponent(value) {
|
||||
try {
|
||||
return decodeURIComponent(value);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// Ignore any invalid uri component
|
||||
}
|
||||
}
|
||||
@@ -1074,14 +1041,14 @@ function tryDecodeURIComponent(value) {
|
||||
function parseKeyValue(/**string*/keyValue) {
|
||||
var obj = {}, key_value, key;
|
||||
forEach((keyValue || "").split('&'), function(keyValue) {
|
||||
if ( keyValue ) {
|
||||
if (keyValue) {
|
||||
key_value = keyValue.replace(/\+/g,'%20').split('=');
|
||||
key = tryDecodeURIComponent(key_value[0]);
|
||||
if ( isDefined(key) ) {
|
||||
if (isDefined(key)) {
|
||||
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
|
||||
if (!hasOwnProperty.call(obj, key)) {
|
||||
obj[key] = val;
|
||||
} else if(isArray(obj[key])) {
|
||||
} else if (isArray(obj[key])) {
|
||||
obj[key].push(val);
|
||||
} else {
|
||||
obj[key] = [obj[key],val];
|
||||
|
||||
@@ -110,7 +110,7 @@ var version = {
|
||||
};
|
||||
|
||||
|
||||
function publishExternalAPI(angular){
|
||||
function publishExternalAPI(angular) {
|
||||
extend(angular, {
|
||||
'bootstrap': bootstrap,
|
||||
'copy': copy,
|
||||
@@ -236,7 +236,7 @@ function publishExternalAPI(angular){
|
||||
$timeout: $TimeoutProvider,
|
||||
$window: $WindowProvider,
|
||||
$$rAF: $$RAFProvider,
|
||||
$$asyncCallback : $$AsyncCallbackProvider
|
||||
$$asyncCallback: $$AsyncCallbackProvider
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -705,7 +705,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
////////////////////////////////////
|
||||
// Module Loading
|
||||
////////////////////////////////////
|
||||
function loadModules(modulesToLoad){
|
||||
function loadModules(modulesToLoad) {
|
||||
var runBlocks = [], moduleFn;
|
||||
forEach(modulesToLoad, function(module) {
|
||||
if (loadedModules.get(module)) return;
|
||||
@@ -713,7 +713,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
|
||||
function runInvokeQueue(queue) {
|
||||
var i, ii;
|
||||
for(i = 0, ii = queue.length; i < ii; i++) {
|
||||
for (i = 0, ii = queue.length; i < ii; i++) {
|
||||
var invokeArgs = queue[i],
|
||||
provider = providerInjector.get(invokeArgs[0]);
|
||||
|
||||
@@ -793,7 +793,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
length, i,
|
||||
key;
|
||||
|
||||
for(i = 0, length = $inject.length; i < length; i++) {
|
||||
for (i = 0, length = $inject.length; i < length; i++) {
|
||||
key = $inject[i];
|
||||
if (typeof key !== 'string') {
|
||||
throw $injectorMinErr('itkn',
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
|
||||
* - [`clone()`](http://api.jquery.com/clone/)
|
||||
* - [`contents()`](http://api.jquery.com/contents/)
|
||||
* - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyles()`
|
||||
* - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`
|
||||
* - [`data()`](http://api.jquery.com/data/)
|
||||
* - [`detach()`](http://api.jquery.com/detach/)
|
||||
* - [`empty()`](http://api.jquery.com/empty/)
|
||||
@@ -122,7 +122,7 @@ function jqNextId() { return ++jqId; }
|
||||
|
||||
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
|
||||
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
|
||||
var MOUSE_EVENT_MAP= { mouseleave : "mouseout", mouseenter : "mouseover"};
|
||||
var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
|
||||
var jqLiteMinErr = minErr('jqLite');
|
||||
|
||||
/**
|
||||
@@ -251,7 +251,7 @@ function jqLiteClone(element) {
|
||||
return element.cloneNode(true);
|
||||
}
|
||||
|
||||
function jqLiteDealoc(element, onlyDescendants){
|
||||
function jqLiteDealoc(element, onlyDescendants) {
|
||||
if (!onlyDescendants) jqLiteRemoveData(element);
|
||||
|
||||
if (element.querySelectorAll) {
|
||||
@@ -358,7 +358,7 @@ function jqLiteData(element, key, value) {
|
||||
function jqLiteHasClass(element, selector) {
|
||||
if (!element.getAttribute) return false;
|
||||
return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
|
||||
indexOf( " " + selector + " " ) > -1);
|
||||
indexOf(" " + selector + " ") > -1);
|
||||
}
|
||||
|
||||
function jqLiteRemoveClass(element, cssClasses) {
|
||||
@@ -417,13 +417,13 @@ function jqLiteAddNodes(root, elements) {
|
||||
|
||||
|
||||
function jqLiteController(element, name) {
|
||||
return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
|
||||
return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
|
||||
}
|
||||
|
||||
function jqLiteInheritedData(element, name, value) {
|
||||
// if element is the document object work with the html element instead
|
||||
// this makes $(document).scope() possible
|
||||
if(element.nodeType == NODE_TYPE_DOCUMENT) {
|
||||
if (element.nodeType == NODE_TYPE_DOCUMENT) {
|
||||
element = element.documentElement;
|
||||
}
|
||||
var names = isArray(name) ? name : [name];
|
||||
@@ -481,7 +481,7 @@ var JQLitePrototype = JQLite.prototype = {
|
||||
}
|
||||
|
||||
// check if document is already loaded
|
||||
if (document.readyState === 'complete'){
|
||||
if (document.readyState === 'complete') {
|
||||
setTimeout(trigger);
|
||||
} else {
|
||||
this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
|
||||
@@ -489,12 +489,11 @@ var JQLitePrototype = JQLite.prototype = {
|
||||
// jshint -W064
|
||||
JQLite(window).on('load', trigger); // fallback to window.onload for others
|
||||
// jshint +W064
|
||||
this.on('DOMContentLoaded', trigger);
|
||||
}
|
||||
},
|
||||
toString: function() {
|
||||
var value = [];
|
||||
forEach(this, function(e){ value.push('' + e);});
|
||||
forEach(this, function(e) { value.push('' + e);});
|
||||
return '[' + value.join(', ') + ']';
|
||||
},
|
||||
|
||||
@@ -522,11 +521,11 @@ forEach('input,select,option,textarea,button,form,details'.split(','), function(
|
||||
BOOLEAN_ELEMENTS[value] = true;
|
||||
});
|
||||
var ALIASED_ATTR = {
|
||||
'ngMinlength' : 'minlength',
|
||||
'ngMaxlength' : 'maxlength',
|
||||
'ngMin' : 'min',
|
||||
'ngMax' : 'max',
|
||||
'ngPattern' : 'pattern'
|
||||
'ngMinlength': 'minlength',
|
||||
'ngMaxlength': 'maxlength',
|
||||
'ngMin': 'min',
|
||||
'ngMax': 'max',
|
||||
'ngPattern': 'pattern'
|
||||
};
|
||||
|
||||
function getBooleanAttrName(element, name) {
|
||||
@@ -585,7 +584,7 @@ forEach({
|
||||
}
|
||||
},
|
||||
|
||||
attr: function(element, name, value){
|
||||
attr: function(element, name, value) {
|
||||
var lowercasedName = lowercase(name);
|
||||
if (BOOLEAN_ATTR[lowercasedName]) {
|
||||
if (isDefined(value)) {
|
||||
@@ -638,7 +637,7 @@ forEach({
|
||||
if (isUndefined(value)) {
|
||||
if (element.multiple && nodeName_(element) === 'select') {
|
||||
var result = [];
|
||||
forEach(element.options, function (option) {
|
||||
forEach(element.options, function(option) {
|
||||
if (option.selected) {
|
||||
result.push(option.value || option.text);
|
||||
}
|
||||
@@ -659,7 +658,7 @@ forEach({
|
||||
},
|
||||
|
||||
empty: jqLiteEmpty
|
||||
}, function(fn, name){
|
||||
}, function(fn, name) {
|
||||
/**
|
||||
* Properties: writes return selection, reads return first value
|
||||
*/
|
||||
@@ -711,7 +710,7 @@ forEach({
|
||||
});
|
||||
|
||||
function createEventHandler(element, events) {
|
||||
var eventHandler = function (event, type) {
|
||||
var eventHandler = function(event, type) {
|
||||
// jQuery specific api
|
||||
event.isDefaultPrevented = function() {
|
||||
return event.defaultPrevented;
|
||||
@@ -767,7 +766,7 @@ function createEventHandler(element, events) {
|
||||
forEach({
|
||||
removeData: jqLiteRemoveData,
|
||||
|
||||
on: function jqLiteOn(element, type, fn, unsupported){
|
||||
on: function jqLiteOn(element, type, fn, unsupported) {
|
||||
if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
|
||||
|
||||
// Do not add event handlers to non-elements because they will not be cleaned up.
|
||||
@@ -803,7 +802,7 @@ forEach({
|
||||
var target = this, related = event.relatedTarget;
|
||||
// For mousenter/leave call the handler if related is outside the target.
|
||||
// NB: No relatedTarget if the mouse left/entered the browser window
|
||||
if ( !related || (related !== target && !target.contains(related)) ){
|
||||
if (!related || (related !== target && !target.contains(related))) {
|
||||
handle(event, type);
|
||||
}
|
||||
});
|
||||
@@ -837,7 +836,7 @@ forEach({
|
||||
replaceWith: function(element, replaceNode) {
|
||||
var index, parent = element.parentNode;
|
||||
jqLiteDealoc(element);
|
||||
forEach(new JQLite(replaceNode), function(node){
|
||||
forEach(new JQLite(replaceNode), function(node) {
|
||||
if (index) {
|
||||
parent.insertBefore(node, index.nextSibling);
|
||||
} else {
|
||||
@@ -849,7 +848,7 @@ forEach({
|
||||
|
||||
children: function(element) {
|
||||
var children = [];
|
||||
forEach(element.childNodes, function(element){
|
||||
forEach(element.childNodes, function(element) {
|
||||
if (element.nodeType === NODE_TYPE_ELEMENT)
|
||||
children.push(element);
|
||||
});
|
||||
@@ -875,7 +874,7 @@ forEach({
|
||||
prepend: function(element, node) {
|
||||
if (element.nodeType === NODE_TYPE_ELEMENT) {
|
||||
var index = element.firstChild;
|
||||
forEach(new JQLite(node), function(child){
|
||||
forEach(new JQLite(node), function(child) {
|
||||
element.insertBefore(child, index);
|
||||
});
|
||||
}
|
||||
@@ -912,7 +911,7 @@ forEach({
|
||||
|
||||
toggleClass: function(element, selector, condition) {
|
||||
if (selector) {
|
||||
forEach(selector.split(' '), function(className){
|
||||
forEach(selector.split(' '), function(className) {
|
||||
var classCondition = condition;
|
||||
if (isUndefined(classCondition)) {
|
||||
classCondition = !jqLiteHasClass(element, className);
|
||||
@@ -977,14 +976,14 @@ forEach({
|
||||
});
|
||||
}
|
||||
}
|
||||
}, function(fn, name){
|
||||
}, function(fn, name) {
|
||||
/**
|
||||
* chaining functions
|
||||
*/
|
||||
JQLite.prototype[name] = function(arg1, arg2, arg3) {
|
||||
var value;
|
||||
|
||||
for(var i = 0, ii = this.length; i < ii; i++) {
|
||||
for (var i = 0, ii = this.length; i < ii; i++) {
|
||||
if (isUndefined(value)) {
|
||||
value = fn(this[i], arg1, arg2, arg3);
|
||||
if (isDefined(value)) {
|
||||
|
||||
@@ -296,7 +296,7 @@ function setupModuleLoader(window) {
|
||||
config(configFn);
|
||||
}
|
||||
|
||||
return moduleInstance;
|
||||
return moduleInstance;
|
||||
|
||||
/**
|
||||
* @param {string} provider
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
|
||||
function minErr(module, ErrorConstructor) {
|
||||
ErrorConstructor = ErrorConstructor || Error;
|
||||
return function () {
|
||||
return function() {
|
||||
var code = arguments[0],
|
||||
prefix = '[' + (module ? module + ':' : '') + code + '] ',
|
||||
template = arguments[1],
|
||||
templateArgs = arguments,
|
||||
stringify = function (obj) {
|
||||
stringify = function(obj) {
|
||||
if (typeof obj === 'function') {
|
||||
return obj.toString().replace(/ \{[\s\S]*$/, '');
|
||||
} else if (typeof obj === 'undefined') {
|
||||
@@ -49,7 +49,7 @@ function minErr(module, ErrorConstructor) {
|
||||
},
|
||||
message, i;
|
||||
|
||||
message = prefix + template.replace(/\{\d+\}/g, function (match) {
|
||||
message = prefix + template.replace(/\{\d+\}/g, function(match) {
|
||||
var index = +match.slice(1, -1), arg;
|
||||
|
||||
if (index + 2 < templateArgs.length) {
|
||||
|
||||
@@ -168,7 +168,6 @@ function $AnchorScrollProvider() {
|
||||
*/
|
||||
this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
|
||||
var document = $window.document;
|
||||
var scrollScheduled = false;
|
||||
|
||||
// Helper function to get first anchor from a NodeList
|
||||
// (using `Array#some()` instead of `angular#forEach()` since it's more performant
|
||||
|
||||
@@ -75,7 +75,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @return {RegExp} The current CSS className expression value. If null then there is no expression value
|
||||
*/
|
||||
this.classNameFilter = function(expression) {
|
||||
if(arguments.length === 1) {
|
||||
if (arguments.length === 1) {
|
||||
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
|
||||
}
|
||||
return this.$$classNameFilter;
|
||||
@@ -170,7 +170,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* page}.
|
||||
*/
|
||||
return {
|
||||
animate : function(element, from, to) {
|
||||
animate: function(element, from, to) {
|
||||
applyStyles(element, { from: from, to: to });
|
||||
return asyncPromise();
|
||||
},
|
||||
@@ -191,7 +191,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @param {object=} options an optional collection of styles that will be applied to the element.
|
||||
* @return {Promise} the animation callback promise
|
||||
*/
|
||||
enter : function(element, parent, after, options) {
|
||||
enter: function(element, parent, after, options) {
|
||||
applyStyles(element, options);
|
||||
after ? after.after(element)
|
||||
: parent.prepend(element);
|
||||
@@ -209,7 +209,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @param {object=} options an optional collection of options that will be applied to the element.
|
||||
* @return {Promise} the animation callback promise
|
||||
*/
|
||||
leave : function(element, options) {
|
||||
leave: function(element, options) {
|
||||
element.remove();
|
||||
return asyncPromise();
|
||||
},
|
||||
@@ -232,7 +232,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @param {object=} options an optional collection of options that will be applied to the element.
|
||||
* @return {Promise} the animation callback promise
|
||||
*/
|
||||
move : function(element, parent, after, options) {
|
||||
move: function(element, parent, after, options) {
|
||||
// Do not remove element before insert. Removing will cause data associated with the
|
||||
// element to be dropped. Insert will implicitly do the remove.
|
||||
return this.enter(element, parent, after, options);
|
||||
@@ -251,16 +251,16 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @param {object=} options an optional collection of options that will be applied to the element.
|
||||
* @return {Promise} the animation callback promise
|
||||
*/
|
||||
addClass : function(element, className, options) {
|
||||
addClass: function(element, className, options) {
|
||||
return this.setClass(element, className, [], options);
|
||||
},
|
||||
|
||||
$$addClassImmediately : function(element, className, options) {
|
||||
$$addClassImmediately: function(element, className, options) {
|
||||
element = jqLite(element);
|
||||
className = !isString(className)
|
||||
? (isArray(className) ? className.join(' ') : '')
|
||||
: className;
|
||||
forEach(element, function (element) {
|
||||
forEach(element, function(element) {
|
||||
jqLiteAddClass(element, className);
|
||||
});
|
||||
applyStyles(element, options);
|
||||
@@ -280,16 +280,16 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @param {object=} options an optional collection of options that will be applied to the element.
|
||||
* @return {Promise} the animation callback promise
|
||||
*/
|
||||
removeClass : function(element, className, options) {
|
||||
removeClass: function(element, className, options) {
|
||||
return this.setClass(element, [], className, options);
|
||||
},
|
||||
|
||||
$$removeClassImmediately : function(element, className, options) {
|
||||
$$removeClassImmediately: function(element, className, options) {
|
||||
element = jqLite(element);
|
||||
className = !isString(className)
|
||||
? (isArray(className) ? className.join(' ') : '')
|
||||
: className;
|
||||
forEach(element, function (element) {
|
||||
forEach(element, function(element) {
|
||||
jqLiteRemoveClass(element, className);
|
||||
});
|
||||
applyStyles(element, options);
|
||||
@@ -310,7 +310,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @param {object=} options an optional collection of options that will be applied to the element.
|
||||
* @return {Promise} the animation callback promise
|
||||
*/
|
||||
setClass : function(element, add, remove, options) {
|
||||
setClass: function(element, add, remove, options) {
|
||||
var self = this;
|
||||
var STORAGE_KEY = '$$animateClasses';
|
||||
var createdCache = false;
|
||||
@@ -320,7 +320,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
if (!cache) {
|
||||
cache = {
|
||||
classes: {},
|
||||
options : options
|
||||
options: options
|
||||
};
|
||||
createdCache = true;
|
||||
} else if (options && cache.options) {
|
||||
@@ -357,15 +357,15 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
return cache.promise;
|
||||
},
|
||||
|
||||
$$setClassImmediately : function(element, add, remove, options) {
|
||||
$$setClassImmediately: function(element, add, remove, options) {
|
||||
add && this.$$addClassImmediately(element, add);
|
||||
remove && this.$$removeClassImmediately(element, remove);
|
||||
applyStyles(element, options);
|
||||
return asyncPromise();
|
||||
},
|
||||
|
||||
enabled : noop,
|
||||
cancel : noop
|
||||
enabled: noop,
|
||||
cancel: noop
|
||||
};
|
||||
}];
|
||||
}];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
function $$AsyncCallbackProvider(){
|
||||
function $$AsyncCallbackProvider() {
|
||||
this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
|
||||
return $$rAF.supported
|
||||
? function(fn) { return $$rAF(fn); }
|
||||
|
||||
@@ -51,7 +51,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
} finally {
|
||||
outstandingRequestCount--;
|
||||
if (outstandingRequestCount === 0) {
|
||||
while(outstandingRequestCallbacks.length) {
|
||||
while (outstandingRequestCallbacks.length) {
|
||||
try {
|
||||
outstandingRequestCallbacks.pop()();
|
||||
} catch (e) {
|
||||
@@ -72,7 +72,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
// force browser to execute all pollFns - this is needed so that cookies and other pollers fire
|
||||
// at some deterministic time in respect to the test runner's actions. Leaving things up to the
|
||||
// regular poller would result in flaky tests.
|
||||
forEach(pollFns, function(pollFn){ pollFn(); });
|
||||
forEach(pollFns, function(pollFn) { pollFn(); });
|
||||
|
||||
if (outstandingRequestCount === 0) {
|
||||
callback();
|
||||
@@ -114,7 +114,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
*/
|
||||
function startPoller(interval, setTimeout) {
|
||||
(function check() {
|
||||
forEach(pollFns, function(pollFn){ pollFn(); });
|
||||
forEach(pollFns, function(pollFn) { pollFn(); });
|
||||
pollTimeout = setTimeout(check, interval);
|
||||
})();
|
||||
}
|
||||
@@ -449,9 +449,9 @@ function Browser(window, document, $log, $sniffer) {
|
||||
|
||||
}
|
||||
|
||||
function $BrowserProvider(){
|
||||
function $BrowserProvider() {
|
||||
this.$get = ['$window', '$log', '$sniffer', '$document',
|
||||
function( $window, $log, $sniffer, $document){
|
||||
function($window, $log, $sniffer, $document) {
|
||||
return new Browser($window, $document, $log, $sniffer);
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -369,7 +369,8 @@ function $CacheFactoryProvider() {
|
||||
* ```
|
||||
*
|
||||
* **Note:** the `script` tag containing the template does not need to be included in the `head` of
|
||||
* the document, but it must be below the `ng-app` definition.
|
||||
* the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
|
||||
* element with ng-app attribute), otherwise the template will be ignored.
|
||||
*
|
||||
* Adding via the $templateCache service:
|
||||
*
|
||||
|
||||
@@ -164,7 +164,9 @@
|
||||
* value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
|
||||
* in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
|
||||
* scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
|
||||
* can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
|
||||
* can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
|
||||
* you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
|
||||
* `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
|
||||
*
|
||||
* * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
|
||||
* If no `attr` name is specified then the attribute name is assumed to be the same as the
|
||||
@@ -680,8 +682,8 @@ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
|
||||
function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var hasDirectives = {},
|
||||
Suffix = 'Directive',
|
||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/,
|
||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
|
||||
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
|
||||
REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
|
||||
|
||||
@@ -691,7 +693,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
|
||||
|
||||
function parseIsolateBindings(scope, directiveName) {
|
||||
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
|
||||
var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
|
||||
|
||||
var bindings = {};
|
||||
|
||||
@@ -706,9 +708,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
bindings[scopeName] = {
|
||||
attrName: match[3] || scopeName,
|
||||
mode: match[1],
|
||||
optional: match[2] === '?'
|
||||
mode: match[1][0],
|
||||
collection: match[2] === '*',
|
||||
optional: match[3] === '?',
|
||||
attrName: match[4] || scopeName
|
||||
};
|
||||
});
|
||||
|
||||
@@ -854,7 +857,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
*/
|
||||
var debugInfoEnabled = true;
|
||||
this.debugInfoEnabled = function(enabled) {
|
||||
if(isDefined(enabled)) {
|
||||
if (isDefined(enabled)) {
|
||||
debugInfoEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
@@ -898,8 +901,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
*
|
||||
* @param {string} classVal The className value that will be added to the element
|
||||
*/
|
||||
$addClass : function(classVal) {
|
||||
if(classVal && classVal.length > 0) {
|
||||
$addClass: function(classVal) {
|
||||
if (classVal && classVal.length > 0) {
|
||||
$animate.addClass(this.$$element, classVal);
|
||||
}
|
||||
},
|
||||
@@ -915,8 +918,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
*
|
||||
* @param {string} classVal The className value that will be removed from the element
|
||||
*/
|
||||
$removeClass : function(classVal) {
|
||||
if(classVal && classVal.length > 0) {
|
||||
$removeClass: function(classVal) {
|
||||
if (classVal && classVal.length > 0) {
|
||||
$animate.removeClass(this.$$element, classVal);
|
||||
}
|
||||
},
|
||||
@@ -933,7 +936,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
* @param {string} newClasses The current CSS className value
|
||||
* @param {string} oldClasses The former CSS className value
|
||||
*/
|
||||
$updateClass : function(newClasses, oldClasses) {
|
||||
$updateClass: function(newClasses, oldClasses) {
|
||||
var toAdd = tokenDifference(newClasses, oldClasses);
|
||||
if (toAdd && toAdd.length) {
|
||||
$animate.addClass(this.$$element, toAdd);
|
||||
@@ -963,13 +966,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
booleanKey = getBooleanAttrName(node, key),
|
||||
aliasedKey = getAliasedAttrName(node, key),
|
||||
observer = key,
|
||||
normalizedVal,
|
||||
nodeName;
|
||||
|
||||
if (booleanKey) {
|
||||
this.$$element.prop(key, value);
|
||||
attrName = booleanKey;
|
||||
} else if(aliasedKey) {
|
||||
} else if (aliasedKey) {
|
||||
this[aliasedKey] = value;
|
||||
observer = aliasedKey;
|
||||
}
|
||||
@@ -1010,9 +1012,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
for (var i=0; i<nbrUrisWith2parts; i++) {
|
||||
var innerIdx = i*2;
|
||||
// sanitize the uri
|
||||
result += $$sanitizeUri(trim( rawUris[innerIdx]), true);
|
||||
result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
|
||||
// add the descriptor
|
||||
result += ( " " + trim(rawUris[innerIdx+1]));
|
||||
result += (" " + trim(rawUris[innerIdx+1]));
|
||||
}
|
||||
|
||||
// split the last item into uri and descriptor
|
||||
@@ -1022,7 +1024,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
result += $$sanitizeUri(trim(lastTuple[0]), true);
|
||||
|
||||
// and add the last descriptor if any
|
||||
if( lastTuple.length === 2) {
|
||||
if (lastTuple.length === 2) {
|
||||
result += (" " + trim(lastTuple[1]));
|
||||
}
|
||||
this[key] = value = result;
|
||||
@@ -1073,7 +1075,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
listeners.push(fn);
|
||||
$rootScope.$evalAsync(function() {
|
||||
if (!listeners.$$inter) {
|
||||
if (!listeners.$$inter && attrs.hasOwnProperty(key)) {
|
||||
// no one registered attribute interpolation function, so lets call it manually
|
||||
fn(attrs[key]);
|
||||
}
|
||||
@@ -1089,7 +1091,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
function safeAddClass($element, className) {
|
||||
try {
|
||||
$element.addClass(className);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// ignore, since it means that we are trying to set class on
|
||||
// SVG element, where class name is read-only.
|
||||
}
|
||||
@@ -1143,7 +1145,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
// We can not compile top level text elements since text nodes can be merged and we will
|
||||
// not be able to attach scope data to them, so we will wrap them in <span>
|
||||
forEach($compileNodes, function(node, index){
|
||||
forEach($compileNodes, function(node, index) {
|
||||
if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
|
||||
$compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
|
||||
}
|
||||
@@ -1153,7 +1155,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
maxPriority, ignoreDirective, previousCompileContext);
|
||||
compile.$$addScopeClass($compileNodes);
|
||||
var namespace = null;
|
||||
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn, futureParentElement){
|
||||
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn, futureParentElement) {
|
||||
assertArg(scope, 'scope');
|
||||
if (!namespace) {
|
||||
namespace = detectNamespaceForChildElements(futureParentElement);
|
||||
@@ -1278,7 +1280,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
stableNodeList = nodeList;
|
||||
}
|
||||
|
||||
for(i = 0, ii = linkFns.length; i < ii;) {
|
||||
for (i = 0, ii = linkFns.length; i < ii;) {
|
||||
node = stableNodeList[linkFns[i++]];
|
||||
nodeLinkFn = linkFns[i++];
|
||||
childLinkFn = linkFns[i++];
|
||||
@@ -1291,7 +1293,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
childScope = scope;
|
||||
}
|
||||
|
||||
if ( nodeLinkFn.transcludeOnThisElement ) {
|
||||
if (nodeLinkFn.transcludeOnThisElement) {
|
||||
childBoundTranscludeFn = createBoundTranscludeFn(
|
||||
scope, nodeLinkFn.transclude, parentBoundTranscludeFn,
|
||||
nodeLinkFn.elementTranscludeOnThisElement);
|
||||
@@ -1346,7 +1348,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
match,
|
||||
className;
|
||||
|
||||
switch(nodeType) {
|
||||
switch (nodeType) {
|
||||
case NODE_TYPE_ELEMENT: /* Element */
|
||||
// use the node name: <directive>
|
||||
addDirective(directives,
|
||||
@@ -1438,7 +1440,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var nodes = [];
|
||||
var depth = 0;
|
||||
if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
|
||||
var startNode = node;
|
||||
do {
|
||||
if (!node) {
|
||||
throw $compileMinErr('uterdir',
|
||||
@@ -1522,7 +1523,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
directiveValue;
|
||||
|
||||
// executes all directives on the current element
|
||||
for(var i = 0, ii = directives.length; i < ii; i++) {
|
||||
for (var i = 0, ii = directives.length; i < ii; i++) {
|
||||
directive = directives[i];
|
||||
var attrStart = directive.$$start;
|
||||
var attrEnd = directive.$$end;
|
||||
@@ -1766,7 +1767,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
"Controller '{0}', required by directive '{1}', can't be found!",
|
||||
require, directiveName);
|
||||
}
|
||||
return value;
|
||||
return value || null;
|
||||
} else if (isArray(require)) {
|
||||
value = [];
|
||||
forEach(require, function(require) {
|
||||
@@ -1828,8 +1829,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
if (newIsolateScopeDirective) {
|
||||
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
|
||||
|
||||
compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
|
||||
templateDirective === newIsolateScopeDirective.$$originalDirective)));
|
||||
compile.$$addScopeClass($element, true);
|
||||
@@ -1855,7 +1854,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
isolateBindingContext[scopeName] = value;
|
||||
});
|
||||
attrs.$$observers[attrName].$$scope = scope;
|
||||
if( attrs[attrName] ) {
|
||||
if (attrs[attrName]) {
|
||||
// If the attribute has been provided then we trigger an interpolation to ensure
|
||||
// the value is there for use in the link fn
|
||||
isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
|
||||
@@ -1870,7 +1869,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (parentGet.literal) {
|
||||
compare = equals;
|
||||
} else {
|
||||
compare = function(a,b) { return a === b || (a !== a && b !== b); };
|
||||
compare = function(a, b) { return a === b || (a !== a && b !== b); };
|
||||
}
|
||||
parentSet = parentGet.assign || function() {
|
||||
// reset the change, or we will throw this exception on every $digest
|
||||
@@ -1894,7 +1893,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
return lastValue = parentValue;
|
||||
};
|
||||
parentValueWatch.$stateful = true;
|
||||
var unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
|
||||
var unwatch;
|
||||
if (definition.collection) {
|
||||
unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
|
||||
} else {
|
||||
unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
|
||||
}
|
||||
isolateScope.$on('$destroy', unwatch);
|
||||
break;
|
||||
|
||||
@@ -1915,7 +1919,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
// PRELINKING
|
||||
for(i = 0, ii = preLinkFns.length; i < ii; i++) {
|
||||
for (i = 0, ii = preLinkFns.length; i < ii; i++) {
|
||||
linkFn = preLinkFns[i];
|
||||
invokeLinkFn(linkFn,
|
||||
linkFn.isolateScope ? isolateScope : scope,
|
||||
@@ -1936,7 +1940,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
|
||||
|
||||
// POSTLINKING
|
||||
for(i = postLinkFns.length - 1; i >= 0; i--) {
|
||||
for (i = postLinkFns.length - 1; i >= 0; i--) {
|
||||
linkFn = postLinkFns[i];
|
||||
invokeLinkFn(linkFn,
|
||||
linkFn.isolateScope ? isolateScope : scope,
|
||||
@@ -1996,11 +2000,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (name === ignoreDirective) return null;
|
||||
var match = null;
|
||||
if (hasDirectives.hasOwnProperty(name)) {
|
||||
for(var directive, directives = $injector.get(name + Suffix),
|
||||
for (var directive, directives = $injector.get(name + Suffix),
|
||||
i = 0, ii = directives.length; i<ii; i++) {
|
||||
try {
|
||||
directive = directives[i];
|
||||
if ( (maxPriority === undefined || maxPriority > directive.priority) &&
|
||||
if ((maxPriority === undefined || maxPriority > directive.priority) &&
|
||||
directive.restrict.indexOf(location) != -1) {
|
||||
if (startAttrName) {
|
||||
directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
|
||||
@@ -2008,7 +2012,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
tDirectives.push(directive);
|
||||
match = directive;
|
||||
}
|
||||
} catch(e) { $exceptionHandler(e); }
|
||||
} catch (e) { $exceptionHandler(e); }
|
||||
}
|
||||
}
|
||||
return match;
|
||||
@@ -2025,7 +2029,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
*/
|
||||
function directiveIsMultiElement(name) {
|
||||
if (hasDirectives.hasOwnProperty(name)) {
|
||||
for(var directive, directives = $injector.get(name + Suffix),
|
||||
for (var directive, directives = $injector.get(name + Suffix),
|
||||
i = 0, ii = directives.length; i<ii; i++) {
|
||||
directive = directives[i];
|
||||
if (directive.multiElement) {
|
||||
@@ -2142,7 +2146,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
});
|
||||
afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
|
||||
|
||||
while(linkQueue.length) {
|
||||
while (linkQueue.length) {
|
||||
var scope = linkQueue.shift(),
|
||||
beforeTemplateLinkNode = linkQueue.shift(),
|
||||
linkRootElement = linkQueue.shift(),
|
||||
@@ -2241,7 +2245,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
function wrapTemplate(type, template) {
|
||||
type = lowercase(type || 'html');
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case 'svg':
|
||||
case 'math':
|
||||
var wrapper = document.createElement('div');
|
||||
@@ -2322,7 +2326,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
//skip animations when the first digest occurs (when
|
||||
//both the new and the old values are the same) since
|
||||
//the CSS classes are the non-interpolated values
|
||||
if(name === 'class' && newValue != oldValue) {
|
||||
if (name === 'class' && newValue != oldValue) {
|
||||
attr.$updateClass(newValue, oldValue);
|
||||
} else {
|
||||
attr.$set(name, newValue);
|
||||
@@ -2352,7 +2356,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
i, ii;
|
||||
|
||||
if ($rootElement) {
|
||||
for(i = 0, ii = $rootElement.length; i < ii; i++) {
|
||||
for (i = 0, ii = $rootElement.length; i < ii; i++) {
|
||||
if ($rootElement[i] == firstElementToRemove) {
|
||||
$rootElement[i++] = newNode;
|
||||
for (var j = i, j2 = j + removeCount - 1,
|
||||
@@ -2427,14 +2431,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
|
||||
try {
|
||||
linkFn(scope, $element, attrs, controllers, transcludeFn);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
$exceptionHandler(e, startingTag($element));
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
|
||||
var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
|
||||
/**
|
||||
* Converts all accepted directives format into proper directive name.
|
||||
* All of these will become 'myDirective':
|
||||
@@ -2500,7 +2504,7 @@ function nodesetLinkingFn(
|
||||
/* NodeList */ nodeList,
|
||||
/* Element */ rootElement,
|
||||
/* function(Function) */ boundTranscludeFn
|
||||
){}
|
||||
) {}
|
||||
|
||||
function directiveLinkingFn(
|
||||
/* nodesetLinkingFn */ nodesetLinkingFn,
|
||||
@@ -2508,7 +2512,7 @@ function directiveLinkingFn(
|
||||
/* Node */ node,
|
||||
/* Element */ rootElement,
|
||||
/* function(Function) */ boundTranscludeFn
|
||||
){}
|
||||
) {}
|
||||
|
||||
function tokenDifference(str1, str2) {
|
||||
var values = '',
|
||||
@@ -2516,10 +2520,10 @@ function tokenDifference(str1, str2) {
|
||||
tokens2 = str2.split(/\s+/);
|
||||
|
||||
outer:
|
||||
for(var i = 0; i < tokens1.length; i++) {
|
||||
for (var i = 0; i < tokens1.length; i++) {
|
||||
var token = tokens1[i];
|
||||
for(var j = 0; j < tokens2.length; j++) {
|
||||
if(token == tokens2[j]) continue outer;
|
||||
for (var j = 0; j < tokens2.length; j++) {
|
||||
if (token == tokens2[j]) continue outer;
|
||||
}
|
||||
values += (values.length > 0 ? ' ' : '') + token;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ function $ControllerProvider() {
|
||||
identifier = ident;
|
||||
}
|
||||
|
||||
if(isString(expression)) {
|
||||
if (isString(expression)) {
|
||||
match = expression.match(CNTRL_REG),
|
||||
constructor = match[1],
|
||||
identifier = identifier || match[3];
|
||||
|
||||
@@ -21,7 +21,7 @@ var htmlAnchorDirective = valueFn({
|
||||
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
||||
var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
||||
'xlink:href' : 'href';
|
||||
element.on('click', function(event){
|
||||
element.on('click', function(event) {
|
||||
// if we have no href url, then don't navigate anywhere.
|
||||
if (!element.attr(href)) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -44,6 +44,11 @@ function nullFormRenameControl(control, name) {
|
||||
* - `pattern`
|
||||
* - `required`
|
||||
* - `url`
|
||||
* - `date`
|
||||
* - `datetimelocal`
|
||||
* - `time`
|
||||
* - `week`
|
||||
* - `month`
|
||||
*
|
||||
* @description
|
||||
* `FormController` keeps track of all its controls and nested forms as well as the state of them,
|
||||
@@ -232,7 +237,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
* Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
|
||||
* saving or resetting it.
|
||||
*/
|
||||
form.$setPristine = function () {
|
||||
form.$setPristine = function() {
|
||||
$animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
|
||||
form.$dirty = false;
|
||||
form.$pristine = true;
|
||||
@@ -255,7 +260,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
* Setting a form controls back to their untouched state is often useful when setting the form
|
||||
* back to its pristine state.
|
||||
*/
|
||||
form.$setUntouched = function () {
|
||||
form.$setUntouched = function() {
|
||||
forEach(controls, function(control) {
|
||||
control.$setUntouched();
|
||||
});
|
||||
@@ -268,7 +273,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
* @description
|
||||
* Sets the form to its submitted state.
|
||||
*/
|
||||
form.$setSubmitted = function () {
|
||||
form.$setSubmitted = function() {
|
||||
$animate.addClass(element, SUBMITTED_CLASS);
|
||||
form.$submitted = true;
|
||||
parentForm.$setSubmitted();
|
||||
|
||||