Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a9b5a1087d | |||
| 87b18b9fbe | |||
| ad128e09ff | |||
| 187b4adbd2 | |||
| 375c47d0c0 | |||
| 8fd47a1cd5 | |||
| e48c28fe92 | |||
| 10d3e1e447 | |||
| 93d1c95c61 | |||
| 01a34f513b | |||
| 916e53ce14 | |||
| b91b3119a4 | |||
| 0d60f8d367 | |||
| ca69dc6f17 | |||
| 5b7f1bcc00 | |||
| 9ab594a66c | |||
| 6c82a497c6 | |||
| df804406fb | |||
| dadce485a7 | |||
| 344cdce136 | |||
| f0347d5efa | |||
| 1c27e5fc37 | |||
| 5fb298b90f | |||
| 483325a7b5 | |||
| a86cb7d794 | |||
| c7e60153a5 | |||
| c0416866f5 | |||
| 8ba452544e | |||
| 8f7f0d26ed | |||
| 98d825e10d | |||
| 57b0d91fd8 | |||
| 9226b36572 | |||
| 39635fd0d7 | |||
| cad307fa1f | |||
| 78bc84c497 | |||
| 1f2750136e | |||
| 5b93e5fcfc | |||
| 770fd5a917 | |||
| 4b29186696 | |||
| 7b5be9ee29 | |||
| eeb261bcd5 | |||
| ef88a8a020 | |||
| 86ab885fd9 | |||
| de07ddeac6 | |||
| dc149de936 | |||
| 320f6d1214 | |||
| 1517d6d2f2 | |||
| 6bb17af2e3 | |||
| 505ead7e58 | |||
| 1da4e89385 | |||
| 83f37d78ba | |||
| d4ac25496a | |||
| e84da2283c | |||
| 3dd9572754 | |||
| 922cb7e42f | |||
| 103cb513d9 | |||
| c24e4e4ed5 | |||
| 1b46a7dcdf | |||
| 8d28d65b36 | |||
| fbb125a3af | |||
| ca7336391a | |||
| 771bccc35c | |||
| c794b96bdc | |||
| f108a2a994 | |||
| 7cbf61cabb | |||
| dfdb72559f | |||
| d69793d93c | |||
| b068c8b605 | |||
| ec16352579 | |||
| aa4ba23350 | |||
| 25e639b474 | |||
| ee8e4a946e | |||
| a41a2a1d2c | |||
| eadd8d08d3 | |||
| 602a1142e8 | |||
| 0b7fef3d94 | |||
| 809d47ec77 | |||
| f3444d495d | |||
| 612c882b83 | |||
| f2a6be3129 | |||
| 465663ed77 | |||
| 1102ffaaf8 | |||
| 98f6a82390 | |||
| a43c6e1828 | |||
| 0db301f863 | |||
| 8e6d3875c6 | |||
| b9d77d46ff | |||
| 96f94d4347 | |||
| 63831f118f | |||
| ebe280eede | |||
| 95d6cdc7c7 | |||
| 9223215add | |||
| 309cfd109f | |||
| cfc6175aab | |||
| dc39f368c3 | |||
| c0f3400573 | |||
| 822d7e5ae9 | |||
| 5874db84ab | |||
| e9e8d49216 | |||
| 550fc21ce5 | |||
| a8aba8957b | |||
| ca0ac64997 | |||
| 7678501bc9 | |||
| dec5eb6e83 | |||
| 2eff326781 | |||
| 50ce5746a7 | |||
| 1537f80267 | |||
| 021d3aa21a | |||
| e8c8c5459e | |||
| 1c20aed318 | |||
| 4c4d24a338 | |||
| 8c7b9b8de4 | |||
| f39ac571c4 | |||
| 84f36701bc | |||
| 6d4ce240de | |||
| 229a155aef | |||
| 73250089cd | |||
| a72bc4e69f | |||
| 0812061274 | |||
| d07101dec0 | |||
| 2206b99359 | |||
| 989f6f2056 | |||
| 4cb5113546 | |||
| 66c14ce84a | |||
| d224f03ef4 | |||
| fde61423cf | |||
| c29d21f4cd | |||
| 7a19a80af2 | |||
| c7e42223a2 | |||
| 220e7bf2d4 | |||
| 8d6eed21d2 | |||
| 7c34e1f1a7 | |||
| bf82c8a708 | |||
| d5f2084883 | |||
| 9bffccd935 | |||
| 6b18a564dd | |||
| 27b7fa3914 | |||
| d7ecab775c | |||
| e89139dc9d | |||
| 26169075c8 | |||
| bf01ab2a13 | |||
| 3248233f5e | |||
| 3a8bbb721d |
+2
-1
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowTrailingWhitespace": true,
|
||||
"requireRightStickedOperators": ["!"]
|
||||
"requireRightStickedOperators": ["!"],
|
||||
"requireLeftStickedOperators": [","]
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
|
||||
"disallowLeftStickedOperators": ["?", "+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
"disallowRightStickedOperators": ["?", "+", "/", "*", ":", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
"requireLeftStickedOperators": [","],
|
||||
"disallowImplicitTypeConversion": ["string"],
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
|
||||
+68
-15
@@ -1,3 +1,56 @@
|
||||
<a name="v1.2.15"></a>
|
||||
# v1.2.15 beer-underestimating (2014-03-21)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$$RAFProvider:** check for webkitCancelRequestAnimationFrame
|
||||
([e84da228](https://github.com/angular/angular.js/commit/e84da2283c4e195be557f7b06c8783fe502acbbb),
|
||||
[#6526](https://github.com/angular/angular.js/issues/6526))
|
||||
- **$$rAF:** always fallback to a $timeout incase native rAF isn't supported
|
||||
([ee8e4a94](https://github.com/angular/angular.js/commit/ee8e4a946ed8f943e00846b88d8d51c0b2cd1fab),
|
||||
[#6654](https://github.com/angular/angular.js/issues/6654))
|
||||
- **$compile:** support templates with thead and tfoot root elements
|
||||
([ca0ac649](https://github.com/angular/angular.js/commit/ca0ac649971ae4fb50419b38f92a98d2226eb696),
|
||||
[#6289](https://github.com/angular/angular.js/issues/6289))
|
||||
- **$http:**
|
||||
- allow sending Blob data using $http
|
||||
([fbb125a3](https://github.com/angular/angular.js/commit/fbb125a3af164e52af2f8119175b04cbbed2f331),
|
||||
[#5012](https://github.com/angular/angular.js/issues/5012))
|
||||
- don't covert 0 status codes to 404 for non-file protocols
|
||||
([f108a2a9](https://github.com/angular/angular.js/commit/f108a2a994149ecc011e29f327bcb8e11adf72d9),
|
||||
[#6074](https://github.com/angular/angular.js/issues/6074), [#6155](https://github.com/angular/angular.js/issues/6155))
|
||||
- **$rootScope:**
|
||||
- ng-repeat can't handle NaN values. #4605
|
||||
([e48c28fe](https://github.com/angular/angular.js/commit/e48c28fe9292efe7af6205b2be116d2350990c73),
|
||||
[#4605](https://github.com/angular/angular.js/issues/4605))
|
||||
- $watchCollection should call listener with oldValue
|
||||
([3dd95727](https://github.com/angular/angular.js/commit/3dd9572754c7bafec30dd625f5c611346959c969),
|
||||
[#2621](https://github.com/angular/angular.js/issues/2621), [#5661](https://github.com/angular/angular.js/issues/5661), [#5688](https://github.com/angular/angular.js/issues/5688), [#6736](https://github.com/angular/angular.js/issues/6736))
|
||||
- **angular.bootstrap:** only allow angular to load once
|
||||
([0d60f8d3](https://github.com/angular/angular.js/commit/0d60f8d367e38224696749b0f7de04bd60649815),
|
||||
[#5863](https://github.com/angular/angular.js/issues/5863), [#5587](https://github.com/angular/angular.js/issues/5587))
|
||||
- **jqLite:** traverse `host` property for DocumentFragment in inheritedData()
|
||||
([98d825e1](https://github.com/angular/angular.js/commit/98d825e10d3bf76f47e69abba857a8933c8cb7d9),
|
||||
[#6637](https://github.com/angular/angular.js/issues/6637))
|
||||
- **ngAnimate:** setting classNameFilter disables animation inside ng-if
|
||||
([a41a2a1d](https://github.com/angular/angular.js/commit/a41a2a1d2ce20f86ac2709592e4ada527160e580),
|
||||
[#6539](https://github.com/angular/angular.js/issues/6539))
|
||||
- **ngCookie:** convert non-string values to string
|
||||
([93d1c95c](https://github.com/angular/angular.js/commit/93d1c95c61dbfa565333bb64527a103242175af7),
|
||||
[#6151](https://github.com/angular/angular.js/issues/6151), [#6220](https://github.com/angular/angular.js/issues/6220))
|
||||
- **ngTouch:** update workaround for desktop Webkit quirk
|
||||
([01a34f51](https://github.com/angular/angular.js/commit/01a34f513bb567ed6d4c81d00d7c2a777c0dae01),
|
||||
[#6302](https://github.com/angular/angular.js/issues/6302))
|
||||
- **orderBy:** support string predicates containing non-ident characters
|
||||
([10d3e1e4](https://github.com/angular/angular.js/commit/10d3e1e4472ab9f5cf4418b6438ec2e0f2b0b288),
|
||||
[#6143](https://github.com/angular/angular.js/issues/6143), [#6144](https://github.com/angular/angular.js/issues/6144))
|
||||
- **select:** avoid checking option element selected properties in render
|
||||
([dc149de9](https://github.com/angular/angular.js/commit/dc149de9364c66b988f169f67cad39577ba43434),
|
||||
[#2448](https://github.com/angular/angular.js/issues/2448), [#5994](https://github.com/angular/angular.js/issues/5994), [#6769](https://github.com/angular/angular.js/issues/6769))
|
||||
|
||||
|
||||
|
||||
<a name="1.2.14"></a>
|
||||
# 1.2.14 feisty-cryokinesis (2014-03-01)
|
||||
|
||||
@@ -275,26 +328,26 @@ The animation mock module has been renamed from `mock.animate` to `ngAnimateMock
|
||||
## Breaking Changes
|
||||
|
||||
- **$http:** due to [e1cfb195](https://github.com/angular/angular.js/commit/e1cfb1957feaf89408bccf48fae6f529e57a82fe),
|
||||
it is now necessary to separately specify default HTTP headers for PUT, POST and PATCH requests, as these no longer share a single object.
|
||||
it is now necessary to separately specify default HTTP headers for PUT, POST and PATCH requests, as these no longer share a single object.
|
||||
|
||||
To migrate your code, follow the example below:
|
||||
To migrate your code, follow the example below:
|
||||
|
||||
Before:
|
||||
Before:
|
||||
|
||||
// Will apply to POST, PUT and PATCH methods
|
||||
$httpProvider.defaults.headers.post = {
|
||||
"X-MY-CSRF-HEADER": "..."
|
||||
};
|
||||
// Will apply to POST, PUT and PATCH methods
|
||||
$httpProvider.defaults.headers.post = {
|
||||
"X-MY-CSRF-HEADER": "..."
|
||||
};
|
||||
|
||||
After:
|
||||
After:
|
||||
|
||||
// POST, PUT and PATCH default headers must be specified separately,
|
||||
// as they do not share data.
|
||||
$httpProvider.defaults.headers.post =
|
||||
$httpProvider.defaults.headers.put =
|
||||
$httpProviders.defaults.headers.patch = {
|
||||
"X-MY-CSRF-HEADER": "..."
|
||||
};
|
||||
// POST, PUT and PATCH default headers must be specified separately,
|
||||
// as they do not share data.
|
||||
$httpProvider.defaults.headers.post =
|
||||
$httpProvider.defaults.headers.put =
|
||||
$httpProviders.defaults.headers.patch = {
|
||||
"X-MY-CSRF-HEADER": "..."
|
||||
};
|
||||
|
||||
<a name="1.2.8"></a>
|
||||
# 1.2.8 interdimensional-cartography (2014-01-10)
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
var files = require('./angularFiles').files;
|
||||
var util = require('./lib/grunt/utils.js');
|
||||
var versionInfo = require('./lib/versions/version-info');
|
||||
var path = require('path');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
@@ -8,10 +9,10 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.loadTasks('lib/grunt');
|
||||
|
||||
var NG_VERSION = util.getVersion();
|
||||
var NG_VERSION = versionInfo.currentVersion;
|
||||
NG_VERSION.cdn = versionInfo.currentPackage.cdnVersion;
|
||||
var dist = 'angular-'+ NG_VERSION.full;
|
||||
|
||||
|
||||
//global beforeEach
|
||||
util.init();
|
||||
|
||||
|
||||
+3
-3
@@ -61,9 +61,9 @@ This process based on the idea of minimizing user pain
|
||||
1. Label `origin: google` for issues from Google
|
||||
|
||||
1. Assign a milestone:
|
||||
* Current 1.x.y milestone - regressions and urgent bugs only
|
||||
* Backlog - fixes; changes that should go into a patch release
|
||||
* Ice Box - new features; changes that belong inß a major/minor release
|
||||
* Backlog - triaged fixes and features, should be the default choice
|
||||
* Current 1.x.y milestone (e.g. 1.3.0-beta-2) - regressions and urgent bugs only
|
||||
|
||||
|
||||
1. Unassign yourself from the issue
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<h1>Oops!</h1>
|
||||
|
||||
<p>The page you requested does not exist. Perhaps you were looking for something else...</p>
|
||||
|
||||
<div ng-controller="Error404SearchCtrl">
|
||||
|
||||
<dl ng-repeat="(key, value) in results" ng-show="value.length" style="float: left; margin-right:20px">
|
||||
<dt>{{ key }}</dt>
|
||||
<dd ng-repeat="item in value"><a ng-href="{{ item.path }}">{{ item.name }}</a></dd>
|
||||
</dl>
|
||||
</div>
|
||||
@@ -184,10 +184,12 @@ h1,h2,h3,h4,h5,h6 {
|
||||
}
|
||||
|
||||
pre {
|
||||
padding:15px;
|
||||
border:1px solid #ddd;
|
||||
display:block;
|
||||
border-radius:5px;
|
||||
padding: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
display: block;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.aside-nav a,
|
||||
@@ -464,6 +466,10 @@ iframe.example {
|
||||
background:rgb(189, 63, 66);
|
||||
}
|
||||
|
||||
.type-hint-regexp {
|
||||
background: rgb(90, 84, 189);
|
||||
}
|
||||
|
||||
.runnable-example-frame {
|
||||
width:100%;
|
||||
height:300px;
|
||||
@@ -501,10 +507,6 @@ h4 {
|
||||
padding-top:20px;
|
||||
}
|
||||
|
||||
.improve-docs {
|
||||
float:right;
|
||||
}
|
||||
|
||||
.btn {
|
||||
color:#428bca;
|
||||
position: relative;
|
||||
@@ -538,10 +540,17 @@ h4 {
|
||||
background:white!important;
|
||||
}
|
||||
|
||||
.view-source, .improve-docs {
|
||||
position:relative;
|
||||
z-index:100;
|
||||
}
|
||||
|
||||
.view-source {
|
||||
margin-right:10px;
|
||||
padding-right:10px;
|
||||
border-right:1px solid #999;
|
||||
}
|
||||
|
||||
.improve-docs {
|
||||
float:right;
|
||||
}
|
||||
|
||||
.return-arguments,
|
||||
|
||||
@@ -10,9 +10,10 @@ angular.module('directives', [])
|
||||
*
|
||||
* @description Ensure that the browser scrolls when the anchor is clicked
|
||||
*/
|
||||
.directive('backToTop', ['$anchorScroll', function($anchorScroll) {
|
||||
.directive('backToTop', ['$anchorScroll', '$location', function($anchorScroll, $location) {
|
||||
return function link(scope, element) {
|
||||
element.on('click', function(event) {
|
||||
$location.hash('');
|
||||
scope.$apply($anchorScroll);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@ angular.module('DocsController', [])
|
||||
|
||||
.controller('DocsController', function($scope, $rootScope, $location, $window, $cookies, NG_PAGES, NG_NAVIGATION, NG_VERSION) {
|
||||
|
||||
$scope.docsVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.version;
|
||||
|
||||
$scope.fold = function(url) {
|
||||
if(url) {
|
||||
$scope.docs_fold = '/notes/' + url;
|
||||
@@ -87,7 +89,7 @@ angular.module('DocsController', [])
|
||||
breadcrumbPath += '/';
|
||||
});
|
||||
} else {
|
||||
$scope.currentArea = null;
|
||||
$scope.currentArea = NG_NAVIGATION['api'];
|
||||
$scope.breadcrumb = [];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,6 +45,10 @@ angular.module('search', [])
|
||||
};
|
||||
}])
|
||||
|
||||
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch', function($scope, $location, docsSearch) {
|
||||
$scope.results = docsSearch($location.path().split(/[\/\.:]/).pop());
|
||||
}])
|
||||
|
||||
.factory('lunrSearch', function() {
|
||||
return function(properties) {
|
||||
if (window.RUNNING_IN_NG_TEST_RUNNER) return null;
|
||||
|
||||
@@ -21,10 +21,10 @@ angular.module('tutorials', [])
|
||||
element.addClass('btn-group');
|
||||
element.addClass('tutorial-nav');
|
||||
element.append(templateMerge(
|
||||
'<a href="tutorial/{{prev}}"><li class="btn btn-primary"><i class="icon-step-backward"></i> Previous</li></a>\n' +
|
||||
'<a href="http://angular.github.com/angular-phonecat/step-{{seq}}/app"><li class="btn btn-primary"><i class="icon-play"></i> Live Demo</li></a>\n' +
|
||||
'<a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><li class="btn btn-primary"><i class="icon-search"></i> Code Diff</li></a>\n' +
|
||||
'<a href="tutorial/{{next}}"><li class="btn btn-primary">Next <i class="icon-step-forward"></i></li></a>', props));
|
||||
'<a href="tutorial/{{prev}}"><li class="btn btn-primary"><i class="glyphicon glyphicon-step-backward"></i> Previous</li></a>\n' +
|
||||
'<a href="http://angular.github.com/angular-phonecat/step-{{seq}}/app"><li class="btn btn-primary"><i class="glyphicon glyphicon-play"></i> Live Demo</li></a>\n' +
|
||||
'<a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><li class="btn btn-primary"><i class="glyphicon glyphicon-search"></i> Code Diff</li></a>\n' +
|
||||
'<a href="tutorial/{{next}}"><li class="btn btn-primary">Next <i class="glyphicon glyphicon-step-forward"></i></li></a>', props));
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
@@ -25,6 +25,10 @@ module.exports = function(config) {
|
||||
require('./tag-defs/tutorial-step')
|
||||
]);
|
||||
|
||||
config.append('processing.inlineTagDefinitions', [
|
||||
require('./inline-tag-defs/type')
|
||||
]);
|
||||
|
||||
config.set('processing.search.ignoreWordsFile', path.resolve(packagePath, 'ignore.words'));
|
||||
|
||||
config.prepend('rendering.templateFolders', [
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
var typeClassFilter = require('dgeni-packages/ngdoc/rendering/filters/type-class');
|
||||
var encoder = new require('node-html-encoder').Encoder();
|
||||
|
||||
module.exports = {
|
||||
name: 'type',
|
||||
description: 'Replace with markup that displays a nice type',
|
||||
handlerFactory: function() {
|
||||
return function(doc, tagName, tagDescription) {
|
||||
return '<a href="" class="' + typeClassFilter.process(tagDescription) + '">'+encoder.htmlEncode(tagDescription) + '</a>';
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -22,6 +22,12 @@ module.exports = {
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'error' ) {
|
||||
|
||||
// Parse out the error info from the id
|
||||
parts = doc.name.split(':');
|
||||
doc.namespace = parts[0];
|
||||
doc.name = parts[1];
|
||||
|
||||
|
||||
var namespaceDoc = errorNamespaces[doc.namespace];
|
||||
if ( !namespaceDoc ) {
|
||||
// First time we came across this namespace, so create a new one
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var gruntUtils = require('../../../lib/grunt/utils');
|
||||
var versionInfo = require('../../../lib/versions/version-info');
|
||||
|
||||
module.exports = {
|
||||
name: 'git-data',
|
||||
@@ -6,9 +7,9 @@ module.exports = {
|
||||
description: 'This processor adds information from the local git repository to the extraData injectable',
|
||||
init: function(config, injectables) {
|
||||
injectables.value('gitData', {
|
||||
version: gruntUtils.getVersion(),
|
||||
versions: gruntUtils.getPreviousVersions(),
|
||||
info: gruntUtils.getGitRepoInfo()
|
||||
version: versionInfo.currentVersion,
|
||||
versions: versionInfo.previousVersions,
|
||||
info: versionInfo.gitRepoInfo
|
||||
});
|
||||
},
|
||||
process: function(extraData, gitData) {
|
||||
|
||||
@@ -11,17 +11,17 @@ var AREA_NAMES = {
|
||||
};
|
||||
|
||||
function getNavGroup(pages, area, pageSorter, pageMapper) {
|
||||
|
||||
|
||||
var navItems = _(pages)
|
||||
// We don't want the child to include the index page as this is already catered for
|
||||
.omit(function(page) { return page.id === 'index'; })
|
||||
|
||||
|
||||
// Apply the supplied sorting function
|
||||
.sortBy(pageSorter)
|
||||
|
||||
|
||||
// Apply the supplied mapping function
|
||||
.map(pageMapper)
|
||||
|
||||
|
||||
.value();
|
||||
|
||||
return {
|
||||
@@ -145,6 +145,9 @@ module.exports = {
|
||||
_(docs)
|
||||
.filter(function(doc) { return doc.area === 'api'; })
|
||||
.filter(function(doc) { return doc.docType === 'module'; })
|
||||
.forEach(function(doc) { if ( !doc.path ) {
|
||||
log.warn('Missing path property for ', doc.id);
|
||||
}})
|
||||
.map(function(doc) { return _.pick(doc, ['id', 'module', 'docType', 'area']); })
|
||||
.tap(function(docs) {
|
||||
log.debug(docs);
|
||||
@@ -173,7 +176,7 @@ module.exports = {
|
||||
// - ngView
|
||||
// - section "service"
|
||||
// - $route
|
||||
//
|
||||
//
|
||||
var areas = {};
|
||||
_(navPages)
|
||||
.groupBy('area')
|
||||
@@ -188,12 +191,6 @@ module.exports = {
|
||||
area.navGroups = navGroupMapper(pages, area);
|
||||
});
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( !doc.path ) {
|
||||
log.warn('Missing path property for ', doc.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Extract a list of basic page information for mapping paths to paritals and for client side searching
|
||||
var pages = _(docs)
|
||||
.map(function(doc) {
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
<div class="container main-grid main-header-grid">
|
||||
<div class="grid-left">
|
||||
<div ng-controller="DocsVersionsCtrl" class="picker version-picker">
|
||||
<select ng-options="v as ('v' + v.full) group by (v.isStable?'Stable':'Unstable') for v in docs_versions"
|
||||
<select ng-options="v as ('v' + v.version + (v.isSnapshot ? ' (snapshot)' : '')) group by (v.isStable?'Stable':'Unstable') for v in docs_versions"
|
||||
ng-model="docs_version"
|
||||
ng-change="jumpToDocsVersion(docs_version)"
|
||||
class="docs-version-jump">
|
||||
@@ -219,14 +219,14 @@
|
||||
</div>
|
||||
<div class="grid-right">
|
||||
<div id="loading" ng-show="loading">Loading...</div>
|
||||
<div ng-hide="loading" ng-include="currentPage.outputPath" onload="afterPartialLoaded()" autoscroll></div>
|
||||
<div ng-hide="loading" ng-include="currentPage.outputPath || 'Error404.html'" onload="afterPartialLoaded()" autoscroll></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p class="pull-right"><a back-to-top href="#">Back to top</a></p>
|
||||
<p class="pull-right"><a back-to-top>Back to top</a></p>
|
||||
|
||||
<p>
|
||||
Super-powered by Google ©2010-2014
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{# Be aware that we need these extra new lines here or marked will not realise that the <div>
|
||||
is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
|
||||
<div>
|
||||
<a ng-href="http://plnkr.co/edit/ngdoc:{$ doc.example.id $}@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank">
|
||||
<i class="glyphicon glyphicon-edit"> </i>
|
||||
Edit in Plunker</a>
|
||||
<div class="runnable-example"
|
||||
path="{$ doc.example.outputFolder $}"
|
||||
{%- for attrName, attrValue in doc.example.attributes %}
|
||||
{$ attrName $}="{$ attrValue $}"{% endfor %}>
|
||||
|
||||
{% for fileName, file in doc.example.files %}
|
||||
<div class="runnable-example-file" {% for attrName, attrValue in file.attributes %}
|
||||
{$ attrName $}="{$ attrValue $}"{% endfor %}>
|
||||
{% code -%}
|
||||
{$ file.fileContents $}
|
||||
{%- endcode %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<iframe class="runnable-example-frame" src="{$ doc.example.outputFolder $}/index.html" name="{$ doc.example.id $}"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Be aware that we need these extra new lines here or marked will not realise that the <div>
|
||||
above is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
@@ -30,6 +30,9 @@ Following are invalid uses of this directive:
|
||||
|
||||
<!-- ERROR because `myFn()=localValue` is an invalid statement -->
|
||||
<my-directive bind="myFn()">
|
||||
|
||||
<!-- ERROR because attribute bind wasn't provided -->
|
||||
<my-directive>
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
@fullName App Already Bootstrapped with this Element
|
||||
@description
|
||||
|
||||
Occurs when calling angular.bootstrap on an element that has already been bootstrapped.
|
||||
Occurs when calling {@link angular.bootstrap} on an element that has already been bootstrapped.
|
||||
|
||||
This usually happens when you accidentally use both `ng-app` and `angular.bootstrap` to bootstrap an
|
||||
application.
|
||||
|
||||
This usually happens when you accidentally use both `ng-app` and `angular.bootstrap` to bootstrap an application.
|
||||
|
||||
```
|
||||
<html>
|
||||
@@ -18,7 +20,9 @@ This usually happens when you accidentally use both `ng-app` and `angular.bootst
|
||||
</html>
|
||||
```
|
||||
|
||||
Note that for bootrapping purposes, the `<html>` element is the same as `document`, so the following will also throw an error.
|
||||
Note that for bootrapping purposes, the `<html>` element is the same as `document`, so the following
|
||||
will also throw an error.
|
||||
|
||||
```
|
||||
<html>
|
||||
...
|
||||
@@ -27,3 +31,22 @@ Note that for bootrapping purposes, the `<html>` element is the same as `documen
|
||||
</script>
|
||||
</html>
|
||||
```
|
||||
|
||||
You can also get this error if you accidentally load AngularJS itself more than once.
|
||||
|
||||
```
|
||||
<html ng-app>
|
||||
<head>
|
||||
<script src="angular.js"></script>
|
||||
|
||||
...
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
...
|
||||
|
||||
<script src="angular.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Using $location
|
||||
@name Using $location
|
||||
@description
|
||||
|
||||
# What does it do?
|
||||
@@ -329,7 +329,7 @@ reload to the original link.
|
||||
Example: `<a href="http://angularjs.org/">link</a>`
|
||||
- Links starting with '/' that lead to a different base path when base is defined<br>
|
||||
Example: `<a href="/not-my-base/link">link</a>`
|
||||
|
||||
|
||||
When running Angular in the root of a domain, along side perhaps a normal application in the same
|
||||
directory, the "otherwise" route handler will try to handle all the URLs, including ones that map
|
||||
to static files.
|
||||
@@ -2,7 +2,7 @@
|
||||
@name Bootstrap
|
||||
@description
|
||||
|
||||
# Overview
|
||||
# Bootstrap
|
||||
|
||||
This page explains the Angular initialization process and how you can manually initialize Angular
|
||||
if necessary.
|
||||
@@ -23,7 +23,7 @@ initialization.
|
||||
</html>
|
||||
```
|
||||
|
||||
* Place the `script` tag at the bottom of the page. Placing script tags at the end of the page
|
||||
1. Place the `script` tag at the bottom of the page. Placing script tags at the end of the page
|
||||
improves app load time because the HTML loading is not blocked by loading of the `angular.js`
|
||||
script. You can get the latest bits from http://code.angularjs.org. Please don't link
|
||||
your production code to this URL, as it will expose a security hole on your site. For
|
||||
@@ -32,16 +32,16 @@ initialization.
|
||||
debugging.
|
||||
* Choose: `angular-[version].min.js` for a compressed and obfuscated file, suitable for use in
|
||||
production.
|
||||
* Place `ng-app` to the root of your application, typically on the `<html>` tag if you want
|
||||
2. Place `ng-app` to the root of your application, typically on the `<html>` tag if you want
|
||||
angular to auto-bootstrap your application.
|
||||
|
||||
<html ng-app>
|
||||
|
||||
* If IE7 support is required add `id="ng-app"`
|
||||
3. If you require IE7 support add `id="ng-app"`
|
||||
|
||||
<html ng-app id="ng-app">
|
||||
|
||||
* If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
|
||||
4. If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
|
||||
to make IE happy. (This is here for historical reasons, and we no longer recommend use of
|
||||
`ng:`.)
|
||||
|
||||
@@ -103,8 +103,8 @@ Here is an example of manually initializing Angular:
|
||||
```
|
||||
|
||||
Note that we have provided the name of our application module to be loaded into the injector as the second
|
||||
parameter of the {@link angular.bootstrap} function. Notice that `angular.bootstrap` will not create modules
|
||||
on the fly. You must create any custom {@link guide/module modules} before you pass them as a parameter.
|
||||
parameter of the {@link angular.bootstrap} function. Notice that `angular.bootstrap` will not create modules
|
||||
on the fly. You must create any custom {@link guide/module modules} before you pass them as a parameter.
|
||||
|
||||
This is the sequence that your code should follow:
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ This will not render properly, unless we do some scope magic.
|
||||
|
||||
The first issue we have to solve is that the dialog box template expects `title` to be defined.
|
||||
But we would like the template's scope property `title` to be the result of interpolating the
|
||||
`<dialog>` element's `title` attribute (i.e. `"Hello {{username}}"`. Furthermore, the buttons expect
|
||||
`<dialog>` element's `title` attribute (i.e. `"Hello {{username}}"`). Furthermore, the buttons expect
|
||||
the `onOk` and `onCancel` functions to be present in the scope. This limits the usefulness of the
|
||||
widget. To solve the mapping issue we use the `locals` to create local variables which the template
|
||||
expects as follows:
|
||||
|
||||
@@ -32,9 +32,9 @@ In the following example we will build a form to calculate the costs of an invoi
|
||||
Let's start with input fields for quantity and cost whose values are multiplied to produce the total of the invoice:
|
||||
|
||||
|
||||
<example>
|
||||
<example name="guide-concepts-1" ng-app-included="true">
|
||||
<file name="index.html">
|
||||
<div ng-init="qty=1;cost=2">
|
||||
<div ng-app ng-init="qty=1;cost=2">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" ng-model="qty" required >
|
||||
@@ -102,7 +102,7 @@ The concept behind this is <a name="databinding">"{@link databinding two-way dat
|
||||
Let's add some more logic to the example that allows us to enter and calculate the costs in
|
||||
different currencies and also pay the invoice.
|
||||
|
||||
<example module="invoice1">
|
||||
<example name="guide-concepts-2" ng-app-included="true" >
|
||||
<file name="invoice1.js">
|
||||
angular.module('invoice1', [])
|
||||
.controller('InvoiceController', function() {
|
||||
@@ -128,7 +128,7 @@ different currencies and also pay the invoice.
|
||||
});
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="InvoiceController as invoice">
|
||||
<div ng-app="invoice1" ng-controller="InvoiceController as invoice">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||
@@ -185,13 +185,13 @@ The following graphic shows how everything works together after we introduced th
|
||||
|
||||
Right now, the `InvoiceController` contains all logic of our example. When the application grows it
|
||||
is a good practice to move view independent logic from the controller into a so called
|
||||
<a name="service">"{@link dev_guide.services service}"</a>, so it can be reused by other parts
|
||||
<a name="service">"{@link services service}"</a>, so it can be reused by other parts
|
||||
of the application as well. Later on, we could also change that service to load the exchange rates
|
||||
from the web, e.g. by calling the Yahoo Finance API, without changing the controller.
|
||||
|
||||
Let's refactor our example and move the currency conversion into a service in another file:
|
||||
|
||||
<example module="invoice2">
|
||||
<example name="guide-concepts-2" ng-app-included="true">
|
||||
<file name="finance2.js">
|
||||
angular.module('finance2', [])
|
||||
.factory('currencyConverter', function() {
|
||||
@@ -228,7 +228,7 @@ Let's refactor our example and move the currency conversion into a service in an
|
||||
}]);
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="InvoiceController as invoice">
|
||||
<div ng-app="invoice2" ng-controller="InvoiceController as invoice">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||
@@ -278,7 +278,7 @@ The code snippet `angular.module('invoice2', ['finance2'])` specifies that the
|
||||
Now that Angular knows of all the parts of the application, it needs to create them.
|
||||
In the previous section we saw that controllers are created using a factory function.
|
||||
For services there are multiple ways to define their factory
|
||||
(see the {@link dev_guide.services service guide}).
|
||||
(see the {@link services service guide}).
|
||||
In the example above, we are using a function that returns the `currencyConverter` function as the factory
|
||||
for the service.
|
||||
|
||||
@@ -302,7 +302,7 @@ to something shorter like `a`.
|
||||
Let's finish our example by fetching the exchange rates from the Yahoo Finance API.
|
||||
The following example shows how this is done with Angular:
|
||||
|
||||
<example module="invoice3">
|
||||
<example name="guide-concepts-3" ng-app-included="true">
|
||||
<file name="invoice3.js">
|
||||
angular.module('invoice3', ['finance3'])
|
||||
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
|
||||
@@ -356,7 +356,7 @@ The following example shows how this is done with Angular:
|
||||
}]);
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="InvoiceController as invoice">
|
||||
<div ng-app="invoice3" ng-controller="InvoiceController as invoice">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||
|
||||
@@ -4,19 +4,31 @@
|
||||
|
||||
# Understanding Controllers
|
||||
|
||||
In Angular, a Controller is a JavaScript **constructor function** that is used to augment the
|
||||
In Angular, a Controller is a JavaScript **constructor function** that is used to augment the
|
||||
{@link scope Angular Scope}.
|
||||
|
||||
When a Controller is attached to the DOM via the {@link ng.directive:ngController ng-controller}
|
||||
directive, Angular will instantiate a new Controller object, using the specified Controller's
|
||||
**constructor function**. A new **child scope** will be available as an injectable parameter to the
|
||||
**constructor function**. A new **child scope** will be available as an injectable parameter to the
|
||||
Controller's constructor function as `$scope`.
|
||||
|
||||
Use Controllers to:
|
||||
Use controllers to:
|
||||
|
||||
- Set up the initial state of the `$scope` object.
|
||||
- Add behavior to the `$scope` object.
|
||||
|
||||
Do not use controllers to:
|
||||
|
||||
- Manipulate DOM — Controllers should contain only business logic.
|
||||
Putting any presentation logic into Controllers significantly affects its testability. Angular
|
||||
has {@link databinding databinding} for most cases and {@link guide/directive directives} to
|
||||
encapsulate manual DOM manipulation.
|
||||
- Format input — Use {@link forms angular form controls} instead.
|
||||
- Filter output — Use {@link guide/filter angular filters} instead.
|
||||
- Share code or state across controllers — Use {@link services angular
|
||||
services} instead.
|
||||
- Manage the life-cycle of other components (for example, to create service instances).
|
||||
|
||||
# Setting up the initial state of a `$scope` object
|
||||
|
||||
Typically, when you create an application you need to set up the initial state for the Angular
|
||||
@@ -25,22 +37,22 @@ The properties contain the **view model** (the model that will be presented by t
|
||||
`$scope` properties will be available to the template at the point in the DOM where the Controller
|
||||
is registered.
|
||||
|
||||
The following example shows a very simple constructor function for a Controller, `GreetingCtrl`,
|
||||
The following example shows a very simple constructor function for a Controller, `GreetingController`,
|
||||
which attaches a `greeting` property containing the string `'Hola!'` to the `$scope`:
|
||||
|
||||
```js
|
||||
function GreetingCtrl($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}
|
||||
function GreetingController($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}
|
||||
```
|
||||
|
||||
Once the Controller has been attached to the DOM, the `greeting` property can be data-bound to the
|
||||
template:
|
||||
|
||||
```js
|
||||
<div ng-controller="GreetingCtrl">
|
||||
{{ greeting }}
|
||||
</div>
|
||||
<div ng-controller="GreetingController">
|
||||
{{ greeting }}
|
||||
</div>
|
||||
```
|
||||
|
||||
**NOTE**: Although Angular allows you to create Controller functions in the global scope, this is
|
||||
@@ -48,15 +60,15 @@ not recommended. In a real application you should use the `.controller` method
|
||||
{@link module Angular Module} for your application as follows:
|
||||
|
||||
```js
|
||||
var myApp = angular.module('myApp',[]);
|
||||
var myApp = angular.module('myApp',[]);
|
||||
|
||||
myApp.controller('GreetingCtrl', ['$scope', function($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}]);
|
||||
myApp.controller('GreetingController', ['$scope', function($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}]);
|
||||
```
|
||||
|
||||
We have used an **inline injection annotation** to explicitly specify the dependency
|
||||
of the Controller on the `$scope` service provided by Angular. See the guide on
|
||||
of the Controller on the `$scope` service provided by Angular. See the guide on
|
||||
[Dependency Injection](http://docs.angularjs.org/guide/di) for more information.
|
||||
|
||||
|
||||
@@ -69,20 +81,20 @@ then available to be called from the template/view.
|
||||
The following example uses a Controller to add a method to the scope, which doubles a number:
|
||||
|
||||
```js
|
||||
var myApp = angular.module('myApp',[]);
|
||||
var myApp = angular.module('myApp',[]);
|
||||
|
||||
myApp.controller('DoubleCtrl', ['$scope', function($scope) {
|
||||
$scope.double = function(value) { return value * 2; };
|
||||
}]);
|
||||
myApp.controller('DoubleController', ['$scope', function($scope) {
|
||||
$scope.double = function(value) { return value * 2; };
|
||||
}]);
|
||||
```
|
||||
|
||||
Once the Controller has been attached to the DOM, the `double` method can be invoked in an Angular
|
||||
expression in the template:
|
||||
|
||||
```js
|
||||
<div ng-controller="DoubleCtrl">
|
||||
Two times <input ng-model="num"> equals {{ double(num) }}
|
||||
</div>
|
||||
<div ng-controller="DoubleController">
|
||||
Two times <input ng-model="num"> equals {{ double(num) }}
|
||||
</div>
|
||||
```
|
||||
|
||||
As discussed in the {@link concepts Concepts} section of this guide, any
|
||||
@@ -97,23 +109,9 @@ needed for a single view.
|
||||
|
||||
The most common way to keep Controllers slim is by encapsulating work that doesn't belong to
|
||||
controllers into services and then using these services in Controllers via dependency injection.
|
||||
This is discussed in the {@link di Dependency Injection} {@link dev_guide.services
|
||||
This is discussed in the {@link di Dependency Injection} {@link services
|
||||
Services} sections of this guide.
|
||||
|
||||
Do not use Controllers for:
|
||||
|
||||
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
|
||||
manipulation (the presentation logic of an application) is well known for being hard to test.
|
||||
Putting any presentation logic into Controllers significantly affects testability of the business
|
||||
logic. Angular offers {@link databinding databinding} for automatic DOM manipulation. If
|
||||
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
|
||||
{@link guide/directive directives}.
|
||||
- Input formatting — Use {@link forms angular form controls} instead.
|
||||
- Output filtering — Use {@link guide/filter angular filters} instead.
|
||||
- Sharing stateless or stateful code across Controllers — Use {@link dev_guide.services angular
|
||||
services} instead.
|
||||
- Managing the life-cycle of other components (for example, to create service instances).
|
||||
|
||||
|
||||
# Associating Controllers with Angular Scope Objects
|
||||
|
||||
@@ -147,11 +145,11 @@ string "very". Depending on which button is clicked, the `spice` model is set to
|
||||
|
||||
myApp.controller('SpicyCtrl', ['$scope', function($scope){
|
||||
$scope.spice = 'very';
|
||||
|
||||
|
||||
$scope.chiliSpicy = function() {
|
||||
$scope.spice = 'chili';
|
||||
};
|
||||
|
||||
|
||||
$scope.jalapenoSpicy = function() {
|
||||
$scope.spice = 'jalapeño';
|
||||
};
|
||||
@@ -190,7 +188,7 @@ previous example.
|
||||
myApp.controller('SpicyCtrl', ['$scope', function($scope){
|
||||
$scope.customSpice = "wasabi";
|
||||
$scope.spice = 'very';
|
||||
|
||||
|
||||
$scope.spicy = function(spice){
|
||||
$scope.spice = spice;
|
||||
};
|
||||
@@ -205,7 +203,7 @@ input box) in the second button.
|
||||
|
||||
## Scope Inheritance Example
|
||||
|
||||
It is common to attach Controllers at different levels of the DOM hierarchy. Since the
|
||||
It is common to attach Controllers at different levels of the DOM hierarchy. Since the
|
||||
{@link ng.directive:ngController ng-controller} directive creates a new child scope, we get a
|
||||
hierarchy of scopes that inherit from each other. The `$scope` that each Controller receives will
|
||||
have access to properties and methods defined by Controllers higher up the hierarchy.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
@ngdoc overview
|
||||
@name Templates: Working With CSS in Angular
|
||||
@name Working With CSS
|
||||
@description
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@name Data Binding
|
||||
@description
|
||||
|
||||
Data-binding in Angular web apps is the automatic synchronization of data between the model and view
|
||||
Data-binding in Angular apps is the automatic synchronization of data between the model and view
|
||||
components. The way that Angular implements data-binding lets you treat the model as the
|
||||
single-source-of-truth in your application. The view is a projection of the model at all times.
|
||||
When the model changes, the view reflects the change, and vice versa.
|
||||
@@ -11,7 +11,7 @@ When the model changes, the view reflects the change, and vice versa.
|
||||
|
||||
<img class="right" src="img/One_Way_Data_Binding.png"/>
|
||||
Most templating systems bind data in only one direction: they merge template and model components
|
||||
together into a view, as illustrated in the diagram. After the merge occurs, changes to the model
|
||||
together into a view. After the merge occurs, changes to the model
|
||||
or related sections of the view are NOT automatically reflected in the view. Worse, any changes
|
||||
that the user makes to the view are not reflected in the model. This means that the developer has
|
||||
to write code that constantly syncs the view with the model and the model with the view.
|
||||
@@ -19,12 +19,11 @@ to write code that constantly syncs the view with the model and the model with t
|
||||
## Data Binding in Angular Templates
|
||||
|
||||
<img class="right" src="img/Two_Way_Data_Binding.png"/>
|
||||
The way Angular templates works is different, as illustrated in the diagram. They are different
|
||||
because first the template (which is the uncompiled HTML along with any additional markup or
|
||||
directives) is compiled on the browser, and second, the compilation step produces a live view. We
|
||||
say live because any changes to the view are immediately reflected in the model, and any changes in
|
||||
the model are propagated to the view. This makes the model always the single-source-of-truth for
|
||||
the application state, greatly simplifying the programming model for the developer. You can think of
|
||||
Angular templates work differently. First the template (which is the uncompiled HTML along with
|
||||
any additional markup or directives) is compiled on the browser. The compilation step produces a
|
||||
live view. Any changes to the view are immediately reflected in the model, and any changes in
|
||||
the model are propagated to the view. The model is the single-source-of-truth for the application
|
||||
state, greatly simplifying the programming model for the developer. You can think of
|
||||
the view as simply an instant projection of your model.
|
||||
|
||||
Because the view is just a projection of the model, the controller is completely separated from the
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Creating Services
|
||||
@description
|
||||
|
||||
While Angular offers several useful services, for any nontrivial application you'll find it useful
|
||||
to write your own custom services. To do this you begin by registering a service factory function
|
||||
with a module either via the {@link angular.module Module#factory api} or directly
|
||||
via the {@link auto.$provide $provide} api inside of module config function.
|
||||
|
||||
All Angular services participate in {@link di dependency injection (DI)} by registering
|
||||
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
|
||||
dependencies which need to be provided for the factory function of the registered service. The
|
||||
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
||||
testable.
|
||||
|
||||
|
||||
# Registering Services
|
||||
|
||||
To register a service, you must have a module that this service will be part of. Afterwards, you
|
||||
can register the service with the module either via the {@link angular.Module Module api} or
|
||||
by using the {@link auto.$provide $provide} service in the module configuration
|
||||
function. The following pseudo-code shows both approaches:
|
||||
|
||||
Using the angular.Module api:
|
||||
|
||||
```js
|
||||
var myModule = angular.module('myModule', []);
|
||||
myModule.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
```
|
||||
|
||||
Using the $provide service:
|
||||
|
||||
```js
|
||||
angular.module('myModule', [], function($provide) {
|
||||
$provide.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Note that you are not registering a service instance, but rather a factory function that will
|
||||
create this instance when called.
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
Services can not only be depended upon, but can also have their own dependencies. These can be specified
|
||||
as arguments of the factory function. {@link di Read more} about dependency injection (DI)
|
||||
in Angular and the use of array notation and the $inject property to make DI annotation
|
||||
minification-proof.
|
||||
|
||||
Following is an example of a very simple service. This service depends on the `$window` service
|
||||
(which is passed as a parameter to the factory function) and is just a function. The service simply
|
||||
stores all notifications; after the third one, the service displays all of the notifications by
|
||||
window alert.
|
||||
|
||||
```js
|
||||
angular.module('myModule', [], function($provide) {
|
||||
$provide.factory('notify', ['$window', function(win) {
|
||||
var msgs = [];
|
||||
return function(msg) {
|
||||
msgs.push(msg);
|
||||
if (msgs.length == 3) {
|
||||
win.alert(msgs.join("\n"));
|
||||
msgs = [];
|
||||
}
|
||||
};
|
||||
}]);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
# Instantiating Angular Services
|
||||
|
||||
All services in Angular are instantiated lazily. This means that a service will be created
|
||||
only when it is needed for instantiation of a service or an application component that depends on it.
|
||||
In other words, Angular won't instantiate services unless they are requested directly or
|
||||
indirectly by the application.
|
||||
|
||||
|
||||
# Services as singletons
|
||||
|
||||
Lastly, it is important to realize that all Angular services are application singletons. This means
|
||||
that there is only one instance of a given service per injector. Since Angular is lethally allergic
|
||||
to global state, it is possible to create multiple injectors, each with its own instance of a
|
||||
given service, but that is rarely needed, except in tests where this property is crucially
|
||||
important.
|
||||
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ng Angular Service API}
|
||||
@@ -1,123 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Injecting Services Into Controllers
|
||||
@description
|
||||
|
||||
Using services as dependencies for controllers is very similar to using services as dependencies
|
||||
for another service.
|
||||
|
||||
Since JavaScript is a dynamic language, DI can't figure out which services to inject by static
|
||||
types (like in static typed languages). Therefore, you can specify the service name by using the
|
||||
`$inject` property, which is an array containing strings with names of services to be injected.
|
||||
The name must match the corresponding service ID registered with angular. The order of the service
|
||||
IDs matters: the order of the services in the array will be used when calling the factory function
|
||||
with injected parameters. The names of parameters in factory function don't matter, but by
|
||||
convention they match the service IDs, which has added benefits discussed below.
|
||||
|
||||
```js
|
||||
function myController($loc, $log) {
|
||||
this.firstMethod = function() {
|
||||
// use $location service
|
||||
$loc.setHash();
|
||||
};
|
||||
this.secondMethod = function() {
|
||||
// use $log service
|
||||
$log.info('...');
|
||||
};
|
||||
}
|
||||
// which services to inject ?
|
||||
myController.$inject = ['$location', '$log'];
|
||||
```
|
||||
|
||||
<example module="MyServiceModule">
|
||||
<file name="index.html">
|
||||
<div id="simple" ng-controller="myController">
|
||||
<p>Let's try this simple notify service, 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('MyServiceModule', []).
|
||||
factory('notify', ['$window', function(win) {
|
||||
var msgs = [];
|
||||
return function(msg) {
|
||||
msgs.push(msg);
|
||||
if (msgs.length == 3) {
|
||||
win.alert(msgs.join("\n"));
|
||||
msgs = [];
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
function myController(scope, notifyService) {
|
||||
scope.callNotify = function(msg) {
|
||||
notifyService(msg);
|
||||
};
|
||||
}
|
||||
|
||||
myController.$inject = ['$scope','notify'];
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should test service', function() {
|
||||
expect(element(by.id('simple')).element(by.model('message')).getAttribute('value'))
|
||||
.toEqual('test');
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
|
||||
## Implicit Dependency Injection
|
||||
|
||||
A new feature of Angular DI allows it to 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 = [];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function myController($scope, notify) {
|
||||
$scope.callNotify = function(msg) {
|
||||
notify(msg);
|
||||
};
|
||||
}
|
||||
</file>
|
||||
</example>
|
||||
|
||||
However, if you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming)) your
|
||||
code, your variable names will get renamed in which case you will still need to explicitly specify
|
||||
dependencies with the `$inject` property.
|
||||
|
||||
## Related Topics
|
||||
|
||||
{@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
{@link dev_guide.services.creating_services Creating Angular Services}
|
||||
{@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
{@link dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
## Related API
|
||||
|
||||
{@link ng Angular Service API}
|
||||
@@ -1,113 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Managing Service Dependencies
|
||||
@description
|
||||
|
||||
Angular allows services to declare other services as dependencies needed for construction of their
|
||||
instances.
|
||||
|
||||
To declare dependencies, you specify them in the factory function signature and annotate the
|
||||
function with the inject annotations either using by setting the `$inject` property, as an array of
|
||||
string identifiers or using the array notation. Optionally the `$inject` property declaration can be
|
||||
dropped (see "Inferring `$inject`" but note that that is currently an experimental feature).
|
||||
|
||||
Using the array notation:
|
||||
|
||||
```js
|
||||
function myModuleCfgFn($provide) {
|
||||
$provide.factory('myService', ['dep1', 'dep2', function(dep1, dep2) {}]);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Using the $inject property:
|
||||
|
||||
```js
|
||||
function myModuleCfgFn($provide) {
|
||||
var myServiceFactory = function(dep1, dep2) {};
|
||||
myServiceFactory.$inject = ['dep1', 'dep2'];
|
||||
$provide.factory('myService', myServiceFactory);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Using DI inference (incompatible with minifiers):
|
||||
|
||||
```js
|
||||
function myModuleCfgFn($provide) {
|
||||
$provide.factory('myService', function(dep1, dep2) {});
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Here is an example of two services, one of which depends on the other and both
|
||||
of which depend on other services that are provided by the Angular framework:
|
||||
|
||||
```js
|
||||
/**
|
||||
* batchLog service allows for messages to be queued in memory and flushed
|
||||
* to the console.log every 50 seconds.
|
||||
*
|
||||
* @param {*} message Message to be logged.
|
||||
*/
|
||||
function batchLogModule($provide){
|
||||
$provide.factory('batchLog', ['$interval', '$log', function($interval, $log) {
|
||||
var messageQueue = [];
|
||||
|
||||
function log() {
|
||||
if (messageQueue.length) {
|
||||
$log.log('batchLog messages: ', messageQueue);
|
||||
messageQueue = [];
|
||||
}
|
||||
}
|
||||
|
||||
// start periodic checking
|
||||
$interval(log, 50000);
|
||||
|
||||
return function(message) {
|
||||
messageQueue.push(message);
|
||||
}
|
||||
}]);
|
||||
|
||||
/**
|
||||
* routeTemplateMonitor monitors each $route change and logs the current
|
||||
* template via the batchLog service.
|
||||
*/
|
||||
$provide.factory('routeTemplateMonitor',
|
||||
['$route', 'batchLog', '$rootScope',
|
||||
function($route, batchLog, $rootScope) {
|
||||
$rootScope.$on('$routeChangeSuccess', function() {
|
||||
batchLog($route.current ? $route.current.template : null);
|
||||
});
|
||||
}]);
|
||||
}
|
||||
|
||||
// get the main service to kick off the application
|
||||
angular.injector([batchLogModule]).get('routeTemplateMonitor');
|
||||
```
|
||||
|
||||
Things to notice in this example:
|
||||
|
||||
* The `batchLog` service depends on the built-in {@link ng.$interval $interval} and
|
||||
{@link ng.$log $log} services, and allows messages to be logged into the
|
||||
`console.log` in batches.
|
||||
* The `routeTemplateMonitor` service depends on the built-in {@link ngRoute.$route
|
||||
$route} service as well as our custom `batchLog` service.
|
||||
* Both of our services use the factory function signature and array notation for inject annotations
|
||||
to declare their dependencies. It is important that the order of the string identifiers in the array
|
||||
is the same as the order of argument names in the signature of the factory function. Unless the
|
||||
dependencies are inferred from the function signature, it is this array with IDs and their order
|
||||
that the injector uses to determine which services and in which order to inject.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
* {@link angular.injector Angular Injector API}
|
||||
@@ -1,20 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services
|
||||
@description
|
||||
|
||||
Services are a feature that Angular brings to client-side web apps from the server side, where
|
||||
services have been commonly used for a long time. Services in Angular apps are substitutable
|
||||
objects that are wired together using {@link di dependency injection (DI)}.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
|
||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
@@ -1,62 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Testing Angular Services
|
||||
@description
|
||||
|
||||
The following is a unit test for the 'notify' service in the 'Dependencies' example in {@link
|
||||
dev_guide.services.creating_services Creating Angular Services}. The unit test example uses Jasmine
|
||||
spy (mock) instead of a real browser alert.
|
||||
|
||||
```js
|
||||
var mock, notify;
|
||||
|
||||
beforeEach(function() {
|
||||
mock = {alert: jasmine.createSpy()};
|
||||
|
||||
module(function($provide) {
|
||||
$provide.value('$window', mock);
|
||||
});
|
||||
|
||||
inject(function($injector) {
|
||||
notify = $injector.get('notify');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not alert first two notifications', function() {
|
||||
notify('one');
|
||||
notify('two');
|
||||
|
||||
expect(mock.alert).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should alert all after third notification', function() {
|
||||
notify('one');
|
||||
notify('two');
|
||||
notify('three');
|
||||
|
||||
expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree");
|
||||
});
|
||||
|
||||
it('should clear messages after alert', function() {
|
||||
notify('one');
|
||||
notify('two');
|
||||
notify('third');
|
||||
notify('more');
|
||||
notify('two');
|
||||
notify('third');
|
||||
|
||||
expect(mock.alert.callCount).toEqual(2);
|
||||
expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
@@ -1,60 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Understanding Angular Services
|
||||
@description
|
||||
|
||||
## What are Angular Services?
|
||||
|
||||
Angular services are singletons objects or functions that carry out specific tasks common to web apps.
|
||||
Angular has a number of built in services, such as the {@link ng.$http $http service}, which
|
||||
provides access to the browser's `XMLHttpRequest` object for making requests to a server. Like other core
|
||||
Angular variables and identifiers, the built-in services always start with `$` (such as `$http` mentioned
|
||||
above). You can also create your own custom services.
|
||||
|
||||
## Using a Service
|
||||
|
||||
To use an Angular service, you identify it as a dependency for the component (controller, service,
|
||||
filter or directive) that depends on the service. Angular's dependency injection subsystem takes
|
||||
care of the rest. The Angular injector subsystem is in charge of service instantiation, resolution
|
||||
of dependencies, and provision of dependencies to components as requested.
|
||||
|
||||
Angular injects dependencies using
|
||||
["constructor" injection](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/).
|
||||
The dependency is passed to the component's factory/constructor function. Because JavaScript is a dynamically
|
||||
typed language, Angular's dependency injection subsystem cannot use static types to identify service
|
||||
dependencies. For this reason a component must, explicitly, define its dependencies by using one of the
|
||||
{@link di injection annotation} methods. For example, by providing a `$inject` property:
|
||||
|
||||
var MyController = function($location) { ... };
|
||||
MyController.$inject = ['$location'];
|
||||
myModule.controller('MyController', MyController);
|
||||
|
||||
Or by providing an "inline" injection annotation:
|
||||
|
||||
var myService = function($http) { ... };
|
||||
myModule.factory('myService', ['$http', myService]);
|
||||
|
||||
## Defining a Service
|
||||
|
||||
Application developers are free to define their own services by registering their name, and **service
|
||||
factory function**, in Angular modules.
|
||||
|
||||
The purpose of the **service factory function** is to generate the single object, or function, that
|
||||
represents the service to the rest of the application. That object, or function, will then be
|
||||
injected into any component (controller, service, filter or directive) that specifies a dependency
|
||||
on the service.
|
||||
|
||||
Angular factory functions are executed lazily. That is, they are only executed when needed
|
||||
to satisfy a dependency, and are then executed exactly once for each service. Everything that is
|
||||
dependent on this service gets a reference to the single instance generated by the service factory.
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link guide/di About Angular Dependency Injection}
|
||||
* {@link guide/dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link guide/dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link guide/dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
* {@link angular.injector Injector API}
|
||||
+89
-87
@@ -7,6 +7,9 @@
|
||||
Dependency Injection (DI) is a software design pattern that deals with how code gets hold of its
|
||||
dependencies.
|
||||
|
||||
The Angular injector subsystem is in charge of service instantiation, resolution
|
||||
of dependencies, and provision of dependencies to components as requested.
|
||||
|
||||
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,
|
||||
@@ -17,9 +20,7 @@ or read about DI in your favorite software design pattern book.
|
||||
There are only three ways an object or a function can get a hold of its dependencies:
|
||||
|
||||
1. The dependency can be created, typically using the `new` operator.
|
||||
|
||||
2. The dependency can be looked up by referring to a global variable.
|
||||
|
||||
3. The dependency can be passed in to where it is needed.
|
||||
|
||||
|
||||
@@ -32,13 +33,13 @@ The third option is the most viable, since it removes the responsibility of loca
|
||||
dependency from the component. The dependency is simply handed to the component.
|
||||
|
||||
```js
|
||||
function SomeClass(greeter) {
|
||||
this.greeter = greeter;
|
||||
}
|
||||
|
||||
SomeClass.prototype.doSomething = function(name) {
|
||||
this.greeter.greet(name);
|
||||
}
|
||||
function SomeClass(greeter) {
|
||||
this.greeter = greeter;
|
||||
}
|
||||
|
||||
SomeClass.prototype.doSomething = function(name) {
|
||||
this.greeter.greet(name);
|
||||
}
|
||||
```
|
||||
|
||||
In the above example `SomeClass` is not concerned with locating the `greeter` dependency, it
|
||||
@@ -56,27 +57,27 @@ construction and lookup of dependencies.
|
||||
Here is an example of using the injector service:
|
||||
|
||||
```js
|
||||
// Provide the wiring information in a module
|
||||
angular.module('myModule', []).
|
||||
|
||||
// Teach the injector how to build a 'greeter'
|
||||
// Notice that greeter itself is dependent on '$window'
|
||||
factory('greeter', function($window) {
|
||||
// This is a factory function, and is responsible for
|
||||
// creating the 'greet' service.
|
||||
return {
|
||||
greet: function(text) {
|
||||
$window.alert(text);
|
||||
}
|
||||
};
|
||||
});
|
||||
// Provide the wiring information in a module
|
||||
angular.module('myModule', []).
|
||||
|
||||
// New injector is created from the module.
|
||||
// (This is usually done automatically by angular bootstrap)
|
||||
var injector = angular.injector(['myModule', 'ng']);
|
||||
|
||||
// Request any dependency from the injector
|
||||
var greeter = injector.get('greeter');
|
||||
// Teach the injector how to build a 'greeter'
|
||||
// Notice that greeter itself is dependent on '$window'
|
||||
factory('greeter', function($window) {
|
||||
// This is a factory function, and is responsible for
|
||||
// creating the 'greet' service.
|
||||
return {
|
||||
greet: function(text) {
|
||||
$window.alert(text);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// New injector is created from the module.
|
||||
// (This is usually done automatically by angular bootstrap)
|
||||
var injector = angular.injector(['myModule', 'ng']);
|
||||
|
||||
// Request any dependency from the injector
|
||||
var greeter = injector.get('greeter');
|
||||
```
|
||||
|
||||
Asking for dependencies solves the issue of hard coding, but it also means that the injector needs
|
||||
@@ -84,22 +85,22 @@ to be passed throughout the application. Passing the injector breaks the [Law of
|
||||
dependency lookup responsibility to the injector by declaring the dependencies as in this example:
|
||||
|
||||
```html
|
||||
<!-- Given this HTML -->
|
||||
<div ng-controller="MyController">
|
||||
<button ng-click="sayHello()">Hello</button>
|
||||
</div>
|
||||
<!-- Given this HTML -->
|
||||
<div ng-controller="MyController">
|
||||
<button ng-click="sayHello()">Hello</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
```js
|
||||
// And this controller definition
|
||||
function MyController($scope, greeter) {
|
||||
$scope.sayHello = function() {
|
||||
greeter.greet('Hello World');
|
||||
};
|
||||
}
|
||||
|
||||
// The 'ng-controller' directive does this behind the scenes
|
||||
injector.instantiate(MyController);
|
||||
// And this controller definition
|
||||
function MyController($scope, greeter) {
|
||||
$scope.sayHello = function() {
|
||||
greeter.greet('Hello World');
|
||||
};
|
||||
}
|
||||
|
||||
// The 'ng-controller' directive does this behind the scenes
|
||||
injector.instantiate(MyController);
|
||||
```
|
||||
|
||||
Notice that by having the `ng-controller` instantiate the class, it can satisfy all of the
|
||||
@@ -123,9 +124,9 @@ The simplest way to get hold of the dependencies, is to assume that the function
|
||||
are the names of the dependencies.
|
||||
|
||||
```js
|
||||
function MyController($scope, greeter) {
|
||||
...
|
||||
}
|
||||
function MyController($scope, greeter) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Given a function the injector can infer the names of the service to inject by examining the
|
||||
@@ -142,10 +143,10 @@ the function needs to be annotated with the `$inject` property. The `$inject` pr
|
||||
of service names to inject.
|
||||
|
||||
```js
|
||||
var MyController = function(renamed$scope, renamedGreeter) {
|
||||
...
|
||||
}
|
||||
MyController['$inject'] = ['$scope', 'greeter'];
|
||||
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.
|
||||
@@ -164,29 +165,29 @@ directives.
|
||||
For example:
|
||||
|
||||
```js
|
||||
someModule.factory('greeter', function($window) {
|
||||
...
|
||||
});
|
||||
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);
|
||||
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) {
|
||||
...
|
||||
}]);
|
||||
someModule.factory('greeter', ['$window', function(renamed$window) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
|
||||
@@ -194,21 +195,22 @@ where injection is supported.
|
||||
|
||||
## Where can I use DI?
|
||||
|
||||
DI is pervasive throughout Angular. It is typically used in controllers and factory methods.
|
||||
DI is pervasive throughout Angular. You can use it in controllers, services, directives, filters,
|
||||
animations, and `run` and `config` blocks.
|
||||
|
||||
### DI in controllers
|
||||
|
||||
Controllers are classes which are responsible for application behavior. The recommended way of
|
||||
Controllers are classes which are responsible for application behavior. The recommended way of
|
||||
declaring controllers is using the array notation:
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
|
||||
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
|
||||
...
|
||||
$scope.aMethod = function() {
|
||||
...
|
||||
$scope.aMethod = function() {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]);
|
||||
}
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
This avoids the creation of global functions for controllers and also protects against minification.
|
||||
@@ -221,20 +223,20 @@ services, and filters. The factory methods are registered with the module, and t
|
||||
of declaring factories is:
|
||||
|
||||
```js
|
||||
angular.module('myModule', []).
|
||||
config(['depProvider', function(depProvider){
|
||||
...
|
||||
}]).
|
||||
factory('serviceId', ['depService', function(depService) {
|
||||
...
|
||||
}]).
|
||||
directive('directiveName', ['depService', function(depService) {
|
||||
...
|
||||
}]).
|
||||
filter('filterName', ['depService', function(depService) {
|
||||
...
|
||||
}]).
|
||||
run(['depService', function(depService) {
|
||||
...
|
||||
}]);
|
||||
angular.module('myModule', []).
|
||||
config(['depProvider', function(depProvider){
|
||||
...
|
||||
}]).
|
||||
factory('serviceId', ['depService', function(depService) {
|
||||
...
|
||||
}]).
|
||||
directive('directiveName', ['depService', function(depService) {
|
||||
...
|
||||
}]).
|
||||
filter('filterName', ['depService', function(depService) {
|
||||
...
|
||||
}]).
|
||||
run(['depService', function(depService) {
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
@@ -293,9 +293,9 @@ The `restrict` option is typically set to:
|
||||
* `'E'` - only matches element name
|
||||
* `'C'` - only matches class name
|
||||
|
||||
These restictions can all be combined as needed:
|
||||
These restrictions can all be combined as needed:
|
||||
|
||||
* `'AEC'` - matches either attribure or element or class name
|
||||
* `'AEC'` - matches either attribute or element or class name
|
||||
|
||||
Let's change our directive to use `restrict: 'E'`:
|
||||
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ To solve this problem, we have built an Angular Scenario Runner which simulates
|
||||
that will help you verify the health of your Angular application.
|
||||
|
||||
# Overview
|
||||
You will write scenario tests in JavaScript, which describe how your application should behave,
|
||||
You write scenario tests in JavaScript. These tests describe how your application should behave
|
||||
given a certain interaction in a specific state. A scenario is comprised of one or more `it` blocks
|
||||
(you can think of these as the requirements of your application), which in turn are made of
|
||||
**commands** and **expectations**. Commands tell the Runner to do something with the application
|
||||
@@ -310,4 +310,4 @@ element('.btn-danger').click();
|
||||
|
||||
# Caveats
|
||||
|
||||
ngScenario does not work with apps that manually bootstrap using angular.bootstrap. You must use the ng-app directive.
|
||||
`ngScenario` does not work with apps that manually bootstrap using `angular.bootstrap`. You must use the `ng-app` directive.
|
||||
@@ -2,35 +2,36 @@
|
||||
@name Expressions
|
||||
@description
|
||||
|
||||
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
|
||||
expression }}`. Expressions are processed by the {@link ng.$parse $parse}
|
||||
service. Expressions are often post processed using {@link guide/filter filters} to create a more user-friendly format.
|
||||
Expressions are JavaScript-like code snippets that are usually placed in bindings such as
|
||||
`{{ expression }}`.
|
||||
|
||||
For example, these are all valid expressions in angular:
|
||||
For example, these are valid expressions in Angular:
|
||||
|
||||
* `1+2`
|
||||
* `a+b`
|
||||
* `user.name`
|
||||
* `items[index]`
|
||||
|
||||
|
||||
## Angular Expressions vs. JS Expressions
|
||||
## Angular Expressions vs. JavaScript Expressions
|
||||
|
||||
It might be tempting to think of Angular view expressions as JavaScript expressions, but that is
|
||||
not entirely correct, since Angular does not use a JavaScript `eval()` to evaluate expressions.
|
||||
You can think of Angular expressions as JavaScript expressions with following differences:
|
||||
Angular expressions are like JavaScript expressions with the following differences:
|
||||
|
||||
* **Attribute Evaluation:** evaluation of all properties are against the scope doing the
|
||||
evaluation, unlike in JavaScript where the expressions are evaluated against the global
|
||||
`window`.
|
||||
* **Context:** JavaScript expressions are evaluated against the global `window`.
|
||||
In Angular, expressions are evaluated against a {@link ng.$rootScope.Scope `scope`} object.
|
||||
|
||||
* **Forgiving:** expression evaluation is forgiving to `undefined` and `null`, unlike in JavaScript,
|
||||
where trying to evaluate undefined properties can generate `ReferenceError` or `TypeError`.
|
||||
* **Forgiving:** In JavaScript, trying to evaluate undefined properties generates `ReferenceError`
|
||||
or `TypeError`. In Angular, expression evaluation is forgiving to `undefined` and `null`.
|
||||
|
||||
* **No Control Flow Statements:** you cannot do any of the following in angular expression:
|
||||
conditionals, loops, or throw.
|
||||
* **No Control Flow Statements:** you cannot use the following in an Angular expression:
|
||||
conditionals, loops, or exceptions.
|
||||
|
||||
If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a
|
||||
controller method and call the method. If you want to `eval()` an angular expression from
|
||||
JavaScript, use the {@link ng.$rootScope.Scope#$eval `$eval()`} method.
|
||||
* **Filters:** You can use {@link guide/filter filters} within expressions to format data before
|
||||
displaying it.
|
||||
|
||||
If you want to run more complex JavaScript code, you should make it a controller method and call
|
||||
the method from your view. If you want to `eval()` an Angular expression yourself, use the
|
||||
{@link ng.$rootScope.Scope#$eval `$eval()`} method.
|
||||
|
||||
## Example
|
||||
<example>
|
||||
@@ -87,13 +88,15 @@ You can try evaluating different expressions here:
|
||||
</example>
|
||||
|
||||
|
||||
# Property Evaluation
|
||||
# Context
|
||||
|
||||
Evaluation of all properties takes place against a scope. Unlike JavaScript, where names default
|
||||
to global window properties, Angular expressions have to use {@link ng.$window
|
||||
`$window`} to refer to the global `window` object. For example, if you want to call `alert()`, which is
|
||||
defined on `window`, in an expression you must use `$window.alert()`. This is done intentionally to
|
||||
prevent accidental access to the global state (a common source of subtle bugs).
|
||||
Angular does not use JavaScript's `eval()` to evaluate expressions. Instead Angular's
|
||||
{@link ng.$parse $parse} service processes these expressions.
|
||||
|
||||
Unlike JavaScript, where names default to global `window` properties, Angular expressions must use
|
||||
{@link ng.$window `$window`} explicitly to refer to the global `window` object. For example, if you
|
||||
want to call `alert()` in an expression you must use `$window.alert()`. This restriction is
|
||||
intentional. It prevents accidental access to the global state – a common source of subtle bugs.
|
||||
|
||||
<example>
|
||||
<file name="index.html">
|
||||
@@ -142,12 +145,12 @@ It makes more sense to show nothing than to throw an exception if `a` is undefin
|
||||
waiting for the server response, and it will become defined soon). If expression evaluation wasn't
|
||||
forgiving we'd have to write bindings that clutter the code, for example: `{{((a||{}).b||{}).c}}`
|
||||
|
||||
Similarly, invoking a function `a.b.c()` on undefined or null simply returns undefined.
|
||||
Similarly, invoking a function `a.b.c()` on `undefined` or `null` simply returns `undefined`.
|
||||
|
||||
|
||||
## No Control Flow Statements
|
||||
|
||||
You cannot write a control flow statement in an expression. The reason behind this is core to the
|
||||
Angular philosophy that application logic should be in controllers, not in the view. If you need a
|
||||
Angular philosophy that application logic should be in controllers, not the views. If you need a
|
||||
conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ Note that `novalidate` is used to disable browser's native form validation.
|
||||
|
||||
# Using CSS classes
|
||||
|
||||
To allow styling of form as well as controls, `ngModel` add these CSS classes:
|
||||
To allow styling of form as well as controls, `ngModel` adds these CSS classes:
|
||||
|
||||
- `ng-valid`
|
||||
- `ng-invalid`
|
||||
@@ -211,26 +211,24 @@ In the following example we create two directives.
|
||||
|
||||
<example module="form-example1">
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<form name="form" class="css-form" novalidate>
|
||||
<div>
|
||||
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.min || form.size.$error.max">
|
||||
The value must be in range 0 to 10!</span>
|
||||
</div>
|
||||
<form name="form" class="css-form" novalidate>
|
||||
<div>
|
||||
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.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>
|
||||
</div>
|
||||
</form>
|
||||
</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>
|
||||
</div>
|
||||
</form>
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
|
||||
@@ -26,7 +26,7 @@ To make your Angular application work on IE please make sure that:
|
||||
1. You polyfill JSON.stringify for IE7 and below. You can use
|
||||
[JSON2](https://github.com/douglascrockford/JSON-js) or
|
||||
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
|
||||
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
@@ -42,7 +42,7 @@ To make your Angular application work on IE please make sure that:
|
||||
```
|
||||
|
||||
2. add `id="ng-app"` to the root element in conjunction with `ng-app` attribute
|
||||
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
|
||||
@@ -54,7 +54,7 @@ To make your Angular application work on IE please make sure that:
|
||||
`<div ng-view>` instead), or
|
||||
|
||||
4. if you **do use** custom element tags, then you must take these steps to make IE 8 and below happy:
|
||||
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
|
||||
@@ -64,7 +64,7 @@ To make your Angular application work on IE please make sure that:
|
||||
document.createElement('ng-include');
|
||||
document.createElement('ng-pluralize');
|
||||
document.createElement('ng-view');
|
||||
|
||||
|
||||
// Optionally these for CSS
|
||||
document.createElement('ng:include');
|
||||
document.createElement('ng:pluralize');
|
||||
@@ -79,7 +79,7 @@ To make your Angular application work on IE please make sure that:
|
||||
```
|
||||
5. Use `ng-style` tags instead of `style="{{ someCss }}"`. The later works in Chrome and Firefox
|
||||
but does not work in Internet Explorer <= 11 (the most recent version at time of writing).
|
||||
|
||||
|
||||
|
||||
The **important** parts are:
|
||||
|
||||
@@ -165,7 +165,7 @@ In IE, the behavior is that the `BODY` element has three children:
|
||||
|
||||
## CSS Styling of Custom Tag Names
|
||||
|
||||
To make CSS selectors work with custom elements, the custom element name must be pre-created with
|
||||
To make CSS selectors work with custom elements, the custom element name must be pre-created with
|
||||
`document.createElement('my-tag')` regardless of XML namespace.
|
||||
|
||||
```html
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
|
||||
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
|
||||
language and lets you extend HTML's syntax to express your application's components clearly and
|
||||
succinctly. Out of the box, it eliminates much of the code you currently write through data
|
||||
binding and dependency injection. And it all happens in JavaScript within the browser, making it
|
||||
succinctly. Angular's data binding and dependency injection eliminate much of the code you
|
||||
currently have to write. And it all happens within the browser, making it
|
||||
an ideal partner with any server technology.
|
||||
|
||||
Angular is what HTML would have been had it been designed for applications. HTML is a great
|
||||
declarative language for static documents. It does not contain much in the way of creating
|
||||
applications, and as a result building web applications is an exercise in *what do I have to do
|
||||
to trick the browser into doing what I want.*
|
||||
to trick the browser into doing what I want?*
|
||||
|
||||
The impedance mismatch between dynamic applications and static documents is often solved with:
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ AngularJS version 1.2 introduces several breaking changes that may require chang
|
||||
application's source code.
|
||||
|
||||
Although we try to avoid breaking changes, there are some cases where it is unavoidable.
|
||||
AngularJS 1.2 has undergone a thourough security review to make applications safer by default,
|
||||
AngularJS 1.2 has undergone a thorough security review to make applications safer by default,
|
||||
which has driven many of these changes. Several new features, especially animations, would not
|
||||
be possible without a few changes. Finally, some outstanding bugs were best fixed by changing
|
||||
an existing API.
|
||||
@@ -43,11 +43,12 @@ below should still apply, but you may want to consult the
|
||||
<li>{@link guide/migration#ngscenario ngScenario}</li>
|
||||
<li>{@link guide/migration#nginclude-and-ngview-replace-its-entire-element-on-update ngInclude and ngView replace its entire element on update}</li>
|
||||
<li>{@link guide/migration#urls-are-now-sanitized-against-a-whitelist URLs are now sanitized against a whitelist}</li>
|
||||
<li>{@link guide/migration#isolate-scope-only-exposed-to-directives-with-property Isolate scope only exposed to directives with <code>scope</code> property}</li>
|
||||
<li>{@link guide/migration#isolate-scope-only-exposed-to-directives-with-scope-property Isolate scope only exposed to directives with <code>scope</code> property}</li>
|
||||
<li>{@link guide/migration#change-to-interpolation-priority Change to interpolation priority}</li>
|
||||
<li>{@link guide/migration#underscore-prefixed/suffixed-properties-are-non-bindable Underscore-prefixed/suffixed properties are non-bindable}</li>
|
||||
<li>{@link guide/migration#you-cannot-bind-to-select[multiple] You cannot bind to select[multiple]}</li>
|
||||
<li>{@link guide/migration#uncommon-region-specific-local-files-were-removed-from-i18n Uncommon region-specific local files were removed from i18n}</li>
|
||||
<li>{@link guide/migration#services-can-now-return-functions Services can now return functions}</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -493,7 +494,7 @@ See [31f190d4](https://github.com/angular/angular.js/commit/31f190d4d53921d32253
|
||||
|
||||
the priority of ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView has changed. This could affect directives that explicitly specify their priority.
|
||||
|
||||
In order to make ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView work together in all common scenarios their directives are being adjusted to achieve the following precendence:
|
||||
In order to make ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView work together in all common scenarios their directives are being adjusted to achieve the following precedence:
|
||||
|
||||
|
||||
Directive | Old Priority | New Priority
|
||||
@@ -532,7 +533,7 @@ See [7d69d52a](https://github.com/angular/angular.js/commit/7d69d52acff8578e0f7d
|
||||
|
||||
A whitelist configured via `$compileProvider` can be used to configure what URLs are considered safe.
|
||||
By default all common protocol prefixes are whitelisted including `data:` URIs with mime types `image/*`.
|
||||
This change sholdn't impact apps that don't contain malicious image links.
|
||||
This change shouldn't impact apps that don't contain malicious image links.
|
||||
|
||||
See [1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d61286840177607edd552a9df97),
|
||||
[3e39ac7e](https://github.com/angular/angular.js/commit/3e39ac7e1b10d4812a44dad2f959a93361cd823b).
|
||||
@@ -613,7 +614,7 @@ controller.) That's easier said that done for two reasons:
|
||||
someone on the scope chain for JavaScript use, you also expose it to
|
||||
Angular expressions
|
||||
2. The new `controller as` syntax that's now in increased usage exposes the
|
||||
entire controller on the scope chain greatly increaing the exposed surface.
|
||||
entire controller on the scope chain greatly increasing the exposed surface.
|
||||
|
||||
Though Angular expressions are written and controlled by the developer, they:
|
||||
|
||||
@@ -653,3 +654,39 @@ load and use your copy of the locale file provided that you maintain it yourself
|
||||
|
||||
See [6382e21f](https://github.com/angular/angular.js/commit/6382e21fb28541a2484ac1a241d41cf9fbbe9d2c).
|
||||
|
||||
## Services can now return functions
|
||||
|
||||
Previously, the service constructor only returned objects regardless of whether a function was returned.
|
||||
|
||||
Now, `$injector.instantiate` (and thus `$provide.service`) behaves the same as the native
|
||||
`new` operator and allows functions to be returned as a service.
|
||||
|
||||
If using a JavaScript preprocessor it's quite possible when upgrading that services could start behaving incorrectly.
|
||||
Make sure your services return the correct type wanted.
|
||||
|
||||
**Coffeescript example**
|
||||
|
||||
```
|
||||
myApp.service 'applicationSrvc', ->
|
||||
@something = "value"
|
||||
@someFunct = ->
|
||||
"something else"
|
||||
```
|
||||
|
||||
pre 1.2 this service would return the whole object as the service.
|
||||
|
||||
post 1.2 this service returns `someFunct` as the value of the service
|
||||
|
||||
you would need to change this services to
|
||||
|
||||
```
|
||||
myApp.service 'applicationSrvc', ->
|
||||
@something = "value"
|
||||
@someFunct = ->
|
||||
"something else"
|
||||
return
|
||||
```
|
||||
|
||||
to continue to return the complete instance.
|
||||
|
||||
See [c22adbf1](https://github.com/angular/angular.js/commit/c22adbf160f32c1839fbb35382b7a8c6bcec2927).
|
||||
|
||||
@@ -4,27 +4,27 @@
|
||||
|
||||
# What is a Module?
|
||||
|
||||
Most applications have a main method which instantiates, wires, and bootstraps the application.
|
||||
You can think of a module as a container for the different parts of your app – controllers,
|
||||
services, filters, directives, etc.
|
||||
|
||||
# Why?
|
||||
|
||||
Most applications have a main method that instantiates and wires together the different parts of
|
||||
the application.
|
||||
|
||||
Angular apps don't have a main method. Instead modules declaratively specify how an application
|
||||
should be bootstrapped. There are several advantages to this approach:
|
||||
|
||||
* The process is more declarative which is easier to understand
|
||||
* In unit-testing there is no need to load all modules, which may aid in writing unit-tests.
|
||||
* Additional modules can be loaded in scenario tests, which can override some of the
|
||||
configuration and help end-to-end test the application
|
||||
* Third party code can be packaged as reusable modules.
|
||||
* The modules can be loaded in any/parallel order (due to delayed nature of module execution).
|
||||
* The declarative process is easier to understand.
|
||||
* You can package code as reusable modules.
|
||||
* The modules can be loaded in any order (or even in parallel) because modules delay execution.
|
||||
* Unit tests only have to load relevant modules, which keeps them fast.
|
||||
* End-to-end tests can use modules to override configuration.
|
||||
|
||||
|
||||
# The Basics
|
||||
|
||||
Ok, I'm in a hurry. How do I get a Hello World module working?
|
||||
|
||||
Important things to notice:
|
||||
|
||||
* {@link angular.Module Module} API
|
||||
* Notice the reference to the `myApp` module in the `<html ng-app="myApp">`, it is what
|
||||
bootstraps the app using your module.
|
||||
I'm in a hurry. How do I get a Hello World module working?
|
||||
|
||||
<example module='myApp'>
|
||||
<file name="index.html">
|
||||
@@ -47,6 +47,13 @@ Important things to notice:
|
||||
</file>
|
||||
</example>
|
||||
|
||||
Important things to notice:
|
||||
|
||||
* The {@link angular.Module Module} API
|
||||
* The reference to `myApp` module in `<html ng-app="myApp">`.
|
||||
This is what bootstraps the app using your module.
|
||||
* The empty array in `angular.module('myApp', [])`.
|
||||
This array is the list of modules `myApp` depends on.
|
||||
|
||||
|
||||
# Recommended Setup
|
||||
@@ -54,18 +61,16 @@ Important things to notice:
|
||||
While the example above is simple, it will not scale to large applications. Instead we recommend
|
||||
that you break your application to multiple modules like this:
|
||||
|
||||
* A service module, for service declaration
|
||||
* A directive module, for directive declaration
|
||||
* A filter module, for filter declaration
|
||||
* And an application level module which depends on the above modules, and which has
|
||||
* A module for each feature
|
||||
* A module for each reusable component (especially directives and filters)
|
||||
* And an application level module which depends on the above modules and contains any
|
||||
initialization code.
|
||||
|
||||
The reason for this breakup is that in your tests, it is often necessary to ignore the
|
||||
initialization code, which tends to be difficult to test. By putting it into a separate module it
|
||||
can be easily ignored in tests. The tests can also be more focused by only loading the modules
|
||||
that are relevant to tests.
|
||||
We've also
|
||||
[written a document](http://blog.angularjs.org/2014/02/an-angularjs-style-guide-and-best.html)
|
||||
on how we organize large apps at Google.
|
||||
|
||||
The above is only a suggestion, so feel free to tailor it to your needs.
|
||||
The above is a suggestion. Tailor it to your needs.
|
||||
|
||||
<example module='xmpl'>
|
||||
<file name="index.html">
|
||||
@@ -133,19 +138,19 @@ angular.module('myModule', []).
|
||||
// This is an example of config block.
|
||||
// You can have as many of these as you want.
|
||||
// You can only inject Providers (not instances)
|
||||
// into the config blocks.
|
||||
// into config blocks.
|
||||
}).
|
||||
run(function(injectables) { // instance-injector
|
||||
// This is an example of a run block.
|
||||
// You can have as many of these as you want.
|
||||
// You can only inject instances (not Providers)
|
||||
// into the run blocks
|
||||
// into run blocks
|
||||
});
|
||||
```
|
||||
|
||||
## Configuration Blocks
|
||||
|
||||
There are some convenience methods on the module which are equivalent to the config block. For
|
||||
There are some convenience methods on the module which are equivalent to the `config` block. For
|
||||
example:
|
||||
|
||||
```js
|
||||
@@ -166,8 +171,10 @@ angular.module('myModule', []).
|
||||
});
|
||||
```
|
||||
|
||||
The configuration blocks get applied in the order in which they are registered. The only exception
|
||||
to it are constant definitions, which are placed at the beginning of all configuration blocks.
|
||||
<div class="alert alert-info">
|
||||
When bootstrapping, first Angular applies all constant definitions.
|
||||
Then Angular applies configuration blocks in the same order they were registered.
|
||||
</div>
|
||||
|
||||
## Run Blocks
|
||||
|
||||
@@ -198,72 +205,73 @@ Beware that using `angular.module('myModule', [])` will create the module `myMod
|
||||
existing module named `myModule`. Use `angular.module('myModule')` to retrieve an existing module.
|
||||
|
||||
```js
|
||||
var myModule = angular.module('myModule', []);
|
||||
|
||||
// add some directives and services
|
||||
myModule.service('myService', ...);
|
||||
myModule.directive('myDirective', ...);
|
||||
var myModule = angular.module('myModule', []);
|
||||
|
||||
// overwrites both myService and myDirective by creating a new module
|
||||
var myModule = angular.module('myModule', []);
|
||||
// add some directives and services
|
||||
myModule.service('myService', ...);
|
||||
myModule.directive('myDirective', ...);
|
||||
|
||||
// throws an error because myOtherModule has yet to be defined
|
||||
var myModule = angular.module('myOtherModule');
|
||||
// overwrites both myService and myDirective by creating a new module
|
||||
var myModule = angular.module('myModule', []);
|
||||
|
||||
// throws an error because myOtherModule has yet to be defined
|
||||
var myModule = angular.module('myOtherModule');
|
||||
```
|
||||
|
||||
# Unit Testing
|
||||
|
||||
In its simplest form a unit test is a way of instantiating a subset of the application in test and
|
||||
then applying a stimulus to it. It is important to realize that each module can only be loaded
|
||||
once per injector. Typically an app has only one injector. But in tests, each test has its own
|
||||
injector, which means that the modules are loaded multiple times per VM. Properly structured
|
||||
modules can help with unit testing, as in this example:
|
||||
A unit test is a way of instantiating a subset of an application to apply stimulus to it.
|
||||
Small, structured modules help keep unit tests concise and focused.
|
||||
|
||||
<div class="did you know...">
|
||||
Each module can only be loaded once per injector.
|
||||
Usually an Angular app has only one injector and modules are only loaded once.
|
||||
Each test has its own injector and modules are loaded multiple times.
|
||||
</div>
|
||||
|
||||
In all of these examples we are going to assume this module definition:
|
||||
|
||||
```js
|
||||
angular.module('greetMod', []).
|
||||
angular.module('greetMod', []).
|
||||
|
||||
factory('alert', function($window) {
|
||||
return function(text) {
|
||||
$window.alert(text);
|
||||
}
|
||||
}).
|
||||
factory('alert', function($window) {
|
||||
return function(text) {
|
||||
$window.alert(text);
|
||||
}
|
||||
}).
|
||||
|
||||
value('salutation', 'Hello').
|
||||
value('salutation', 'Hello').
|
||||
|
||||
factory('greet', function(alert, salutation) {
|
||||
return function(name) {
|
||||
alert(salutation + ' ' + name + '!');
|
||||
}
|
||||
});
|
||||
factory('greet', function(alert, salutation) {
|
||||
return function(name) {
|
||||
alert(salutation + ' ' + name + '!');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Let's write some tests:
|
||||
Let's write some tests to show how to override configuration in tests.
|
||||
|
||||
```js
|
||||
describe('myApp', function() {
|
||||
// load the relevant application modules then load a special
|
||||
// test module which overrides the $window with a mock version,
|
||||
// so that calling window.alert() will not block the test
|
||||
// runner with a real alert box. This is an example of overriding
|
||||
// configuration information in tests.
|
||||
// load application module (`greetMod`) then load a special
|
||||
// test module which overrides `$window` with a mock version,
|
||||
// so that calling `window.alert()` will not block the test
|
||||
// runner with a real alert box.
|
||||
beforeEach(module('greetMod', function($provide) {
|
||||
$provide.value('$window', {
|
||||
alert: jasmine.createSpy('alert')
|
||||
});
|
||||
}));
|
||||
|
||||
// The inject() will create the injector and inject the greet and
|
||||
// $window into the tests. The test need not concern itself with
|
||||
// wiring of the application, only with testing it.
|
||||
// inject() will create the injector and inject the `greet` and
|
||||
// `$window` into the tests.
|
||||
it('should alert on $window', inject(function(greet, $window) {
|
||||
greet('World');
|
||||
expect($window.alert).toHaveBeenCalledWith('Hello World!');
|
||||
}));
|
||||
|
||||
// this is another way of overriding configuration in the
|
||||
// tests using an inline module and inject methods.
|
||||
// tests using inline `module` and `inject` methods.
|
||||
it('should alert using the alert service', function() {
|
||||
var alertSpy = jasmine.createSpy('alert');
|
||||
module(function($provide) {
|
||||
|
||||
@@ -143,7 +143,7 @@ primitive, object literal, function, or even an instance of a custom type.
|
||||
## Service Recipe
|
||||
|
||||
JavaScript developers often use custom types to write object-oriented code. Let's explore how we
|
||||
could launch a unicorn into the space via our `unicornLauncher` service that is an instance of
|
||||
could launch a unicorn into space via our `unicornLauncher` service that is an instance of
|
||||
custom type:
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
@ngdoc overview
|
||||
@name Services
|
||||
@description
|
||||
|
||||
# Services
|
||||
|
||||
Angular services are substitutable objects that are wired together using {@link di dependency
|
||||
injection (DI)}. You can use services to organize and share code across your app.
|
||||
|
||||
Angular services are:
|
||||
|
||||
* Lazily instantiated – Angular only instantiates a service when an application component depends
|
||||
on it.
|
||||
* Singletons – Each component dependent on a service gets a reference to the single instance
|
||||
generated by the service factory.
|
||||
|
||||
Angular offers several useful services (like {@link ng.$http `$http`}), but for most applications
|
||||
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 `$`
|
||||
(e.g. `$http`).
|
||||
</div>
|
||||
|
||||
|
||||
## Using a Service
|
||||
|
||||
To use an Angular service, you add it as a dependency for the component (controller, service,
|
||||
filter or directive) that depends on the service. Angular's {@link di dependency injection}
|
||||
subsystem takes care of the rest.
|
||||
|
||||
<example module="myServiceModule">
|
||||
<file name="index.html">
|
||||
<div id="simple" ng-controller="MyController">
|
||||
<p>Let's try this simple notify service, 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('myServiceModule', []).
|
||||
controller('MyController', ['$scope','notify', function ($scope, notify) {
|
||||
$scope.callNotify = function(msg) {
|
||||
notify(msg);
|
||||
};
|
||||
}]).
|
||||
factory('notify', ['$window', function(win) {
|
||||
var msgs = [];
|
||||
return function(msg) {
|
||||
msgs.push(msg);
|
||||
if (msgs.length == 3) {
|
||||
win.alert(msgs.join("\n"));
|
||||
msgs = [];
|
||||
}
|
||||
};
|
||||
}]);
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should test service', function() {
|
||||
expect(element(by.id('simple')).element(by.model('message')).getAttribute('value'))
|
||||
.toEqual('test');
|
||||
});
|
||||
</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>
|
||||
|
||||
|
||||
## Creating Services
|
||||
|
||||
Application developers are free to define their own services by registering the service's name and
|
||||
**service factory function**, with an Angular module.
|
||||
|
||||
The **service factory function** generates the single object or function that represents the
|
||||
service to the rest of the application. The object or function returned by the service is
|
||||
injected into any component (controller, service, filter or directive) that specifies a dependency
|
||||
on the service.
|
||||
|
||||
### Registering Services
|
||||
|
||||
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
|
||||
var myModule = angular.module('myModule', []);
|
||||
myModule.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
```
|
||||
|
||||
Note that you are not registering a **service instance**, but rather a **factory function** that
|
||||
will create this instance when called.
|
||||
|
||||
### Dependencies
|
||||
|
||||
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.
|
||||
|
||||
The example module below has two services, each with various dependencies:
|
||||
|
||||
```js
|
||||
var batchModule = angular.module('batchModule', []);
|
||||
|
||||
/**
|
||||
* The `batchLog` service allows for messages to be queued in memory and flushed
|
||||
* to the console.log every 50 seconds.
|
||||
*
|
||||
* @param {*} message Message to be logged.
|
||||
*/
|
||||
batchModule.factory('batchLog', ['$interval', '$log', function($interval, $log) {
|
||||
var messageQueue = [];
|
||||
|
||||
function log() {
|
||||
if (messageQueue.length) {
|
||||
$log.log('batchLog messages: ', messageQueue);
|
||||
messageQueue = [];
|
||||
}
|
||||
}
|
||||
|
||||
// start periodic checking
|
||||
$interval(log, 50000);
|
||||
|
||||
return function(message) {
|
||||
messageQueue.push(message);
|
||||
}
|
||||
}]);
|
||||
|
||||
/**
|
||||
* `routeTemplateMonitor` monitors each `$route` change and logs the current
|
||||
* template via the `batchLog` service.
|
||||
*/
|
||||
batchModule.factory('routeTemplateMonitor', ['$route', 'batchLog', '$rootScope',
|
||||
function($route, batchLog, $rootScope) {
|
||||
$rootScope.$on('$routeChangeSuccess', function() {
|
||||
batchLog($route.current ? $route.current.template : null);
|
||||
});
|
||||
}]);
|
||||
|
||||
```
|
||||
|
||||
In the example, note that:
|
||||
|
||||
* The `batchLog` service depends on the built-in {@link ng.$interval `$interval`} and
|
||||
{@link ng.$log `$log`} services.
|
||||
* The `routeTemplateMonitor` service depends on the built-in {@link ngRoute.$route `$route`}
|
||||
service and our custom `batchLog` service.
|
||||
* Both services use the array notation to declare their dependencies.
|
||||
* The order of identifiers in the array is the same as the order of argument
|
||||
names in the factory function.
|
||||
|
||||
### Registering a Service with `$provide`
|
||||
|
||||
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) {
|
||||
$provide.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
This technique is often used in unit tests to mock out a service's dependencies.
|
||||
|
||||
|
||||
## Unit Testing
|
||||
|
||||
The following is a unit test for the `notify` service from the {@link services#creating-services
|
||||
Creating Angular Services} example above. The unit test example uses a Jasmine spy (mock) instead
|
||||
of a real browser alert.
|
||||
|
||||
```js
|
||||
var mock, notify;
|
||||
|
||||
beforeEach(function() {
|
||||
mock = {alert: jasmine.createSpy()};
|
||||
|
||||
module(function($provide) {
|
||||
$provide.value('$window', mock);
|
||||
});
|
||||
|
||||
inject(function($injector) {
|
||||
notify = $injector.get('notify');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not alert first two notifications', function() {
|
||||
notify('one');
|
||||
notify('two');
|
||||
|
||||
expect(mock.alert).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should alert all after third notification', function() {
|
||||
notify('one');
|
||||
notify('two');
|
||||
notify('three');
|
||||
|
||||
expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree");
|
||||
});
|
||||
|
||||
it('should clear messages after alert', function() {
|
||||
notify('one');
|
||||
notify('two');
|
||||
notify('third');
|
||||
notify('more');
|
||||
notify('two');
|
||||
notify('third');
|
||||
|
||||
expect(mock.alert.callCount).toEqual(2);
|
||||
expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link guide/di Dependency Injection in AngularJS}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
* {@link angular.injector Injector API}
|
||||
@@ -2,27 +2,21 @@
|
||||
@name Templates
|
||||
@description
|
||||
|
||||
An Angular template is the declarative specification that, along with information from the model
|
||||
and controller, becomes the rendered view that a user sees in the browser. It is the static DOM,
|
||||
containing HTML, CSS, and angular-specific elements and angular-specific element attributes. The
|
||||
Angular elements and attributes direct angular to add behavior and transform the template DOM into
|
||||
the dynamic view DOM.
|
||||
In Angular, templates are written with HTML that contains Angular-specific elements and attributes.
|
||||
Angular combines the template with information from the model and controller to render the dynamic
|
||||
view that a user sees in the browser.
|
||||
|
||||
These are the types of Angular elements and element attributes you can use in a template:
|
||||
These are the types of Angular elements and attributes you can use:
|
||||
|
||||
* {@link guide/directive Directive} — An attribute or element that
|
||||
augments an existing DOM element or represents a reusable DOM component - a widget.
|
||||
* {@link ng.$interpolate Markup} — The double
|
||||
curly brace notation `{{ }}` to bind expressions to elements is built-in angular markup.
|
||||
* {@link guide/filter Filter} — Formats your data for display to the user.
|
||||
* {@link forms Form controls} — Lets you validate user input.
|
||||
augments an existing DOM element or represents a reusable DOM component.
|
||||
* {@link ng.$interpolate Markup} — The double curly brace notation `{{ }}` to bind expressions
|
||||
to elements is built-in Angular markup.
|
||||
* {@link guide/filter Filter} — Formats data for display.
|
||||
* {@link forms Form controls} — Validates user input.
|
||||
|
||||
Note: In addition to declaring the elements above in templates, you can also access these elements
|
||||
in JavaScript code.
|
||||
|
||||
The following code snippet shows a simple Angular template made up of standard HTML tags along with
|
||||
Angular {@link guide/directive directives} and curly-brace bindings
|
||||
with {@link expression expressions}:
|
||||
The following code snippet shows a template with {@link guide/directive directives} and
|
||||
curly-brace {@link expression expression} bindings:
|
||||
|
||||
```html
|
||||
<html ng-app>
|
||||
@@ -38,19 +32,20 @@ with {@link expression expressions}:
|
||||
</html>
|
||||
```
|
||||
|
||||
In a simple single-page app, the template consists of HTML, CSS, and angular directives contained
|
||||
in just one HTML file (usually `index.html`). In a more complex app, you can display multiple views
|
||||
within one main page using "partials", which are segments of template located in separate HTML
|
||||
files. You "include" the partials in the main page using the {@link ngRoute.$route
|
||||
$route} service in conjunction with the {@link ngRoute.directive:ngView ngView} directive. An
|
||||
example of this technique is shown in the {@link tutorial/ angular tutorial}, in steps seven and
|
||||
eight.
|
||||
In a simple app, the template consists of HTML, CSS, and Angular directives contained
|
||||
in just one HTML file (usually `index.html`).
|
||||
|
||||
In a more complex app, you can display multiple views within one main page using "partials" –
|
||||
segments of template located in separate HTML files. You can use the
|
||||
{@link ngRoute.directive:ngView ngView} directive to load partials based on configuration passed
|
||||
to the {@link ngRoute.$route $route} service. The {@link tutorial/ angular tutorial} shows this
|
||||
technique in steps seven and eight.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link guide/filter Angular Filters}
|
||||
* {@link forms Angular Forms}
|
||||
* {@link guide/filter Filters}
|
||||
* {@link forms Forms}
|
||||
|
||||
## Related API
|
||||
|
||||
|
||||
+7
-7
@@ -7,11 +7,11 @@ comes with almost no help from the compiler. For this reason we feel very strong
|
||||
written in JavaScript needs to come with a strong set of tests. We have built many features into
|
||||
Angular which makes testing your Angular applications easy. So there is no excuse for not testing.
|
||||
|
||||
# It is all about NOT mixing concerns
|
||||
# Separation of Concerns
|
||||
|
||||
Unit testing as the name implies is about testing individual units of code. Unit tests try to
|
||||
answer questions such as "Did I think about the logic correctly?" or "Does the sort function order the list
|
||||
in the right order?"
|
||||
answer questions such as "Did I think about the logic correctly?" or "Does the sort function order
|
||||
the list in the right order?"
|
||||
|
||||
In order to answer such a question it is very important that we can isolate the unit of code under test.
|
||||
That is because when we are testing the sort function we don't want to be forced into creating
|
||||
@@ -33,8 +33,8 @@ function has mutated the DOM in the right way.
|
||||
## With great power comes great responsibility
|
||||
|
||||
Angular is written with testability in mind, but it still requires that you do the right thing.
|
||||
We tried to make the right thing easy, but Angular is not magic. If you don't follow these guidelines
|
||||
you may very well end up with an untestable application.
|
||||
We tried to make the right thing easy, but if you ignore these guidelines you may end up with an
|
||||
untestable application.
|
||||
|
||||
## Dependency Injection
|
||||
There are several ways in which you can get a hold of a dependency. You can:
|
||||
@@ -258,7 +258,7 @@ expect($scope.strength).toEqual('weak');
|
||||
```
|
||||
|
||||
Notice that the test is not only much shorter, it is also easier to follow what is happening. We say
|
||||
that such a test tells a story, rather then asserting random bits which don't seem to be related.
|
||||
that such a test tells a story, rather than asserting random bits which don't seem to be related.
|
||||
|
||||
## Filters
|
||||
{@link ng.$filterProvider Filters} are functions which transform the data into a user readable
|
||||
@@ -321,7 +321,7 @@ describe('Unit testing great quotes', function() {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
}));
|
||||
|
||||
|
||||
it('Replaces the element with the appropriate content', function() {
|
||||
// Compile a piece of HTML containing the directive
|
||||
var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
|
||||
@@ -11,12 +11,12 @@ See the [contributing guidelines](https://github.com/angular/angular.js/blob/mas
|
||||
for how to contribute your own code to AngularJS.
|
||||
|
||||
|
||||
1. {@link #building-and-testing-angularjs_installing-dependencies Installing Dependencies}
|
||||
2. {@link #building-and-testing-angularjs_forking-angular-on-github Forking Angular on Github}
|
||||
3. {@link #building-and-testing-angularjs_building-angularjs Building AngularJS}
|
||||
4. {@link #building-and-testing-angularjs_running-a-local-development-web-server Running a Local Development Web Server}
|
||||
5. {@link #building-and-testing-angularjs_running-the-unit-test-suite Running the Unit Test Suite}
|
||||
6. {@link #building-and-testing-angularjs_running-the-end-to-end-test-suite Running the End-to-end Test Suite}
|
||||
1. {@link misc/contribute#installing-dependencies Installing Dependencies}
|
||||
2. {@link misc/contribute#forking-angular-on-github Forking Angular on Github}
|
||||
3. {@link misc/contribute#building-angularjs Building AngularJS}
|
||||
4. {@link misc/contribute#running-a-local-development-web-server Running a Local Development Web Server}
|
||||
5. {@link misc/contribute#running-the-unit-test-suite Running the Unit Test Suite}
|
||||
6. {@link misc/contribute#running-the-end-to-end-test-suite Running the End-to-end Test Suite}
|
||||
|
||||
## Installing Dependencies
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ the construction of an AngularJS web app. The app you will build is a catalog th
|
||||
of Android devices, lets you filter the list to see only devices that interest you, and then view
|
||||
details for any device.
|
||||
|
||||
<img class="diagram" src="img/tutorial/catalog_screen.png" width="488" height="413">
|
||||
<img class="diagram" src="img/tutorial/catalog_screen.png" width="488" height="413" alt="demo
|
||||
application running in the browser">
|
||||
|
||||
Work through the tutorial to see how Angular makes browsers smarter — without the use of extensions
|
||||
or plug-ins. As you work through the tutorial, you will:
|
||||
@@ -57,63 +58,71 @@ and follow the instructions for setting up your computer.
|
||||
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
|
||||
<ol>
|
||||
<li><p>You'll need Git, which you can get from
|
||||
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
|
||||
<a href="http://git-scm.com/download" title="Git site download">the Git site</a>.</p></li>
|
||||
<li><p>Clone the angular-phonecat repository located at
|
||||
<a href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
||||
<a href="https://github.com/angular/angular-phonecat" title="Github Phonecat Repo">Github</a> by
|
||||
running the following command:</p>
|
||||
<pre>git clone https://github.com/angular/angular-phonecat.git</pre>
|
||||
<p>This command creates the <code>angular-phonecat</code> directory in your current
|
||||
directory.</p></li>
|
||||
<p>This command creates the <code>angular-phonecat</code> directory in your current directory.</p></li>
|
||||
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
|
||||
<pre>cd angular-phonecat</pre>
|
||||
<p>The tutorial instructions, from now on, assume you are running all commands from the <code>angular-phonecat</code>
|
||||
directory.</p></li>
|
||||
<p>The tutorial instructions, from now on, assume you are running all commands from the
|
||||
<code>angular-phonecat</code> directory.</p></li>
|
||||
<li><p>You will also need Node.js and Karma to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.10 or better installed
|
||||
<a href="http://nodejs.org/" title="NodeJS org">Node.js</a> v0.10 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p></li>
|
||||
<pre>node --version</pre>
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> and its plugins if you
|
||||
don't have it already:</p>
|
||||
<div class="alert alert-info">**Helpful note:** If you need to run a different version of
|
||||
node.js in your local environment, consider installing
|
||||
<a href="https://github.com/creationix/nvm" title="Node Version Manager Github Repo link">
|
||||
Node Version Manager (nvm)</a>.</div>
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/" title="Karma site">Karma</a> and
|
||||
its plugins if you don't have it already:</p>
|
||||
<pre>
|
||||
npm install
|
||||
</pre></li>
|
||||
<li><p>You will need an http server running on your system. Mac and Linux machines typically
|
||||
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
|
||||
to run a simple bundled http server: <code>node scripts/web-server.js</code>.</p></li>
|
||||
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
|
||||
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane well" id="git-win" title="Git on Windows">
|
||||
<ol>
|
||||
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.10 or better installed
|
||||
<a href="http://nodejs.org/" title="NodeJS site">Node.js</a> v0.10 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p>
|
||||
<pre>node --version</pre>
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> if you
|
||||
don't have it already:</p>
|
||||
<div class="alert alert-info">**Helpful note:** If you need to run a different version of
|
||||
node.js in your local environment, consider installing
|
||||
<a href="https://github.com/creationix/nvm" title="Node Version Manager Github Repo link">
|
||||
Node Version Manager (nvm)</a>.</div>
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/" title="Karma site">Karma</a>
|
||||
if you don't have it already:</p>
|
||||
<pre>npm install -g karma</pre>
|
||||
</li>
|
||||
<li><p>You'll also need Git, which you can get from
|
||||
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
|
||||
<a href="http://git-scm.com/download" title="Git site download">the Git site</a>.</p></li>
|
||||
<li><p>Clone the angular-phonecat repository located at <a
|
||||
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
||||
<pre>git clone https://github.com/angular/angular-phonecat.git</pre>
|
||||
href="https://github.com/angular/angular-phonecat" "Github Angular-phonecat Repo">Github</a> by running
|
||||
the following command:</p><pre>git clone https://github.com/angular/angular-phonecat.git</pre>
|
||||
<p>This command creates the <code>angular-phonecat</code> directory in your current directory.</p></li>
|
||||
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
|
||||
<pre>cd angular-phonecat</pre>
|
||||
<p>The tutorial instructions assume you are running all commands from the <code>angular-phonecat</code>
|
||||
directory.</p>
|
||||
directory.</p>
|
||||
<p>You should run all <code>git</code> commands from Git bash.</p>
|
||||
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
|
||||
executed from the Windows command line.</li>
|
||||
<li><p>You need an http server running on your system, but if you don't already have one
|
||||
already installed, you can use <code>node</code> to run a simple
|
||||
bundled http server: <code>node scripts\web-server.js</code>.</p></li>
|
||||
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be executed from the
|
||||
Windows command line.</li>
|
||||
<li><p>You need an http server running on your system, but if you don't already have one already
|
||||
installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple bundled
|
||||
http server.</p></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
The last thing to do is to make sure your computer has a web browser and a good text editor
|
||||
installed. Now, let's get some cool stuff done!
|
||||
The last thing to do is to make sure your computer has a web browser and a good text editor installed. Now,
|
||||
let's get some cool stuff done!
|
||||
|
||||
{@link step_00 <span class="btn btn-primary">Get Started!</span>}
|
||||
<a href="tutorial/step_00" title="Next Step"><span class="btn btn-primary">Get Started!</span></a>
|
||||
|
||||
@@ -183,7 +183,7 @@ is available to be injected.
|
||||
### Writing and Running Tests
|
||||
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
|
||||
writing tests. Although Angular does not require you to use Jasmine, we wrote all of the tests in
|
||||
this tutorial in Jasmine. You can learn about Jasmine on the [Jasmine home page](http://pivotal.github.com/jasmine/) and at the [Jasmine docs](http://pivotal.github.io/jasmine/).
|
||||
this tutorial in Jasmine. You can learn about Jasmine on the [Jasmine home page](http://jasmine.github.io/) and at the [Jasmine docs](http://jasmine.github.io/).
|
||||
|
||||
The angular-seed project is pre-configured to run all unit tests using [Karma](http://karma-runner.github.io/). Ensure that the necessary karma plugins are installed.
|
||||
You can do this by issuing `npm install` into your terminal.
|
||||
@@ -226,6 +226,10 @@ To run the test, do the following:
|
||||
|
||||
Refresh your browser and verify that it says "Hello, World!".
|
||||
|
||||
* Update the unit test for the controler in ./tests/unit/controlersSpec.js to reflect the previous change. For example by adding:
|
||||
|
||||
expect(scope.name).toBe('World');
|
||||
|
||||
* Create a repeater that constructs a simple table:
|
||||
|
||||
<table>
|
||||
|
||||
@@ -91,7 +91,7 @@ phonecatApp.controller('PhoneListCtrl', function ($scope) {
|
||||
record. This property is used to order phones by age.
|
||||
|
||||
* We added a line to the controller that sets the default value of `orderProp` to `age`. If we had
|
||||
not set a default value here, the `orderBy` filter would remain uninitialized until our
|
||||
not set a default value here, the `orderBy` filter would remain uninitialized until our
|
||||
user picked an option from the drop down menu.
|
||||
|
||||
This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the
|
||||
@@ -117,7 +117,7 @@ describe('PhoneCat controllers', function() {
|
||||
var scope, ctrl;
|
||||
|
||||
beforeEach(module('phonecatApp'));
|
||||
|
||||
|
||||
beforeEach(inject(function($controller) {
|
||||
scope = {};
|
||||
ctrl = $controller('PhoneListCtrl', {$scope:scope});
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
|
||||
Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
|
||||
from our server using one of Angular's built-in {@link guide/dev_guide.services services} called {@link
|
||||
from our server using one of Angular's built-in {@link guide/services services} called {@link
|
||||
ng.$http $http}. We will use Angular's {@link guide/di dependency
|
||||
injection (DI)} to provide the service to the `PhoneListCtrl` controller.
|
||||
|
||||
@@ -20,7 +20,6 @@ You should now see a list of 20 phones.
|
||||
The most important changes are listed below. You can see the full diff on [GitHub](https://github.com/angular/angular-phonecat/compare/step-4...step-5):
|
||||
|
||||
## Data
|
||||
|
||||
The `app/phones/phones.json` file in your project is a dataset that contains a larger list of phones
|
||||
stored in the JSON format.
|
||||
|
||||
@@ -44,7 +43,7 @@ Following is a sample of the file:
|
||||
|
||||
We'll use Angular's {@link ng.$http $http} service in our controller to make an HTTP
|
||||
request to your web server to fetch the data in the `app/phones/phones.json` file. `$http` is just
|
||||
one of several built-in {@link guide/dev_guide.services angular services} that handle common operations
|
||||
one of several built-in {@link guide/services Angular services} that handle common operations
|
||||
in web apps. Angular injects these services for you where you need them.
|
||||
|
||||
Services are managed by Angular's {@link guide/di DI subsystem}. Dependency injection
|
||||
@@ -74,10 +73,10 @@ tutorial.)
|
||||
|
||||
The `$http` service returns a {@link ng.$q promise object} with a `success`
|
||||
method. We call this method to handle the asynchronous response and assign the phone data to the
|
||||
scope controlled by this controller, as a model called `phones`. Notice that angular detected the
|
||||
scope controlled by this controller, as a model called `phones`. Notice that Angular detected the
|
||||
json response and parsed it for us!
|
||||
|
||||
To use a service in angular, you simply declare the names of the dependencies you need as arguments
|
||||
To use a service in Angular, you simply declare the names of the dependencies you need as arguments
|
||||
to the controller's constructor function, as follows:
|
||||
|
||||
phonecatApp.controller('PhoneListCtrl', function ($scope, $http) {...}
|
||||
@@ -96,7 +95,7 @@ dependencies.
|
||||
### `$` Prefix Naming Convention
|
||||
|
||||
You can create your own services, and in fact we will do exactly that in step 11. As a naming
|
||||
convention, angular's built-in services, Scope methods and a few other Angular APIs have a `$`
|
||||
convention, Angular's built-in services, Scope methods and a few other Angular APIs have a `$`
|
||||
prefix in front of the name.
|
||||
|
||||
The `$` prefix is there to namespace Angular-provided services.
|
||||
@@ -167,7 +166,7 @@ __`test/unit/controllersSpec.js`:__
|
||||
Because we started using dependency injection and our controller has dependencies, constructing the
|
||||
controller in our tests is a bit more complicated. We could use the `new` operator and provide the
|
||||
constructor with some kind of fake `$http` implementation. However, the recommended (and easier) way
|
||||
is to create a controller in the test environment in the same way that angular does it in the
|
||||
is to create a controller in the test environment in the same way that Angular does it in the
|
||||
production code behind the scenes, as follows:
|
||||
|
||||
```js
|
||||
@@ -269,7 +268,7 @@ to the first 5 in the list. Use the following code in the `$http` callback:
|
||||
|
||||
# Summary
|
||||
|
||||
Now that you have learned how easy it is to use angular services (thanks to Angular's dependency
|
||||
Now that you have learned how easy it is to use Angular services (thanks to Angular's dependency
|
||||
injection), go to {@link step_06 step 6}, where you will add some
|
||||
thumbnail images of phones and some links.
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ the element attribute.
|
||||
|
||||
We also added phone images next to each record using an image tag with the {@link
|
||||
ng.directive:ngSrc ngSrc} directive. That directive prevents the
|
||||
browser from treating the angular `{{ expression }}` markup literally, and initiating a request to
|
||||
browser from treating the Angular `{{ expression }}` markup literally, and initiating a request to
|
||||
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
|
||||
specified an attribute binding in a regular `src` attribute (`<img src="{{phone.imageUrl}}">`).
|
||||
Using the `ngSrc` directive prevents the browser from making an http request to an invalid location.
|
||||
|
||||
@@ -114,7 +114,7 @@ Our application routes are defined as follows:
|
||||
view, Angular will use the `phone-list.html` template and the `PhoneListCtrl` controller.
|
||||
|
||||
* The phone details view will be shown when the URL hash fragment matches '/phone/:phoneId', where
|
||||
`:phoneId` is a variable part of the URL. To construct the phone details view, angular will use the
|
||||
`:phoneId` is a variable part of the URL. To construct the phone details view, Angular will use the
|
||||
`phone-detail.html` template and the `PhoneDetailCtrl` controller.
|
||||
|
||||
We reused the `PhoneListCtrl` controller that we constructed in previous steps and we added a new,
|
||||
|
||||
@@ -79,7 +79,7 @@ route by the `$route` service.
|
||||
## Template
|
||||
|
||||
The TBD placeholder line has been replaced with lists and bindings that comprise the phone details.
|
||||
Note where we use the angular `{{expression}}` markup and `ngRepeat` to project phone data from
|
||||
Note where we use the Angular `{{expression}}` markup and `ngRepeat` to project phone data from
|
||||
our model into the view.
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ __`app/partials/phone-detail.html`:__
|
||||
</dl>
|
||||
</li>
|
||||
...
|
||||
</li>
|
||||
<li>
|
||||
<span>Additional Features</span>
|
||||
<dd>{{phone.additionalFeatures}}</dd>
|
||||
</li>
|
||||
|
||||
@@ -40,13 +40,13 @@ The name of our filter is "checkmark". The `input` evaluates to either `true` or
|
||||
return one of the two unicode characters we have chosen to represent true (`\u2713` -> ✓) or false (`\u2718` -> ✘).
|
||||
|
||||
Now that our filter is ready, we need to register the `phonecatFilters` module as a dependency for
|
||||
our main `phonecat` module.
|
||||
our main `phonecatApp` module.
|
||||
|
||||
__`app/js/app.js`:__
|
||||
|
||||
```js
|
||||
...
|
||||
angular.module('phonecatApp', ['phonecatFilters']).
|
||||
angular.module('phonecatApp', ['ngRoute','phonecatControllers','phonecatFilters']).
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ The most important changes are listed below. You can see the full diff on [GitHu
|
||||
## Template
|
||||
|
||||
The custom service is defined in `app/js/services.js` so we need to include this file in our layout
|
||||
template. Additionally, we also need to load the `angular-resource.js` file, which contains the
|
||||
{@link api/ngResource ngResource} module and in it the {@link api/ngResource.$resource $resource}
|
||||
template. Additionally, we also need to load the `angular-resource.js` file, which contains the
|
||||
{@link api/ngResource ngResource} module and in it the {@link api/ngResource.$resource $resource}
|
||||
service, that we'll soon use:
|
||||
|
||||
__`app/index.html`.__
|
||||
|
||||
@@ -20,7 +20,8 @@ a dependency with the application module, will enable animations throughout the
|
||||
|
||||
Common `ng` directives automatically trigger hooks for animations to tap into. When an animation is found
|
||||
then the animation will run in between the standard DOM operation that is being issued on the element at
|
||||
the given time (e.g. inserting and removing nodes on ngRepeat or adding and removing classes on ngClass).
|
||||
the given time (e.g. inserting and removing nodes on {@link api/ng.directive:ngRepeat `ngRepeat`} or adding
|
||||
and removing classes on {@link api/ng.directive:ngClass `ngClass`}).
|
||||
|
||||
The most important changes are listed below. You can see the full diff on
|
||||
[GitHub](https://github.com/angular/angular-phonecat/compare/step-11...step-12):
|
||||
@@ -34,9 +35,10 @@ To get an idea of how animations work with AngularJS, please read the
|
||||
|
||||
## Template
|
||||
|
||||
The changes required within the HTML template code is to link the asset files which define the animations as well
|
||||
as the `angular-animate.js` file. The animation module, known as `ngAnimate`, is defined within
|
||||
`angular-animate.js` and contains the code necessary to make your application become animation aware.
|
||||
The changes required within the HTML template code is to link the asset files which define the animations as
|
||||
well as the `angular-animate.js` file. The animation module, known as {@link api/ngAnimate `ngAnimate`}, is
|
||||
defined within `angular-animate.js` and contains the code necessary to make your application become animation
|
||||
aware.
|
||||
|
||||
Here's what needs to changed in the index file:
|
||||
|
||||
@@ -83,7 +85,7 @@ __`app/js/app.js`.__
|
||||
|
||||
```js
|
||||
// ...
|
||||
angular.module('phonecat', [
|
||||
angular.module('phonecatApp', [
|
||||
'ngRoute',
|
||||
|
||||
'phonecatAnimations',
|
||||
@@ -197,7 +199,7 @@ which are described in detail below.
|
||||
|
||||
## Animating `ngView` with CSS Keyframe Animations
|
||||
|
||||
Next let's add an animation for transitions between route changes in `ngView`.
|
||||
Next let's add an animation for transitions between route changes in {@link api/ngRoute.directive:ngView `ngView`}.
|
||||
|
||||
To start, let's add a new CSS class to our HTML like we did in the example above.
|
||||
This time, instead of the `ng-repeat` element, let's add it to the element containing the ng-view directive.
|
||||
|
||||
+9
-7
@@ -1,13 +1,12 @@
|
||||
var path = require('canonical-path');
|
||||
var gruntUtils = require('../lib/grunt/utils');
|
||||
var versionInfo = require('../lib/versions/version-info');
|
||||
var basePath = __dirname;
|
||||
|
||||
var basePackage = require('./config');
|
||||
|
||||
module.exports = function(config) {
|
||||
|
||||
var version = gruntUtils.getVersion();
|
||||
var cdnUrl = "//ajax.googleapis.com/ajax/libs/angularjs/" + version.cdn;
|
||||
var cdnUrl = "//ajax.googleapis.com/ajax/libs/angularjs/" + versionInfo.currentPackage.cdnVersion;
|
||||
|
||||
var getVersion = function(component, sourceFolder, packageFile) {
|
||||
sourceFolder = sourceFolder || '../bower_components';
|
||||
@@ -25,9 +24,12 @@ module.exports = function(config) {
|
||||
{ pattern: '**/*.ngdoc', basePath: path.resolve(basePath, 'content') }
|
||||
]);
|
||||
|
||||
config.set('processing.stopOnError', true);
|
||||
|
||||
config.set('processing.errors.minerrInfoPath', path.resolve(basePath, '../build/errors.json'));
|
||||
|
||||
config.set('rendering.outputFolder', '../build/docs');
|
||||
config.set('rendering.contentsFolder', 'partials');
|
||||
|
||||
config.set('logging.level', 'info');
|
||||
|
||||
@@ -38,7 +40,7 @@ module.exports = function(config) {
|
||||
commonFiles: {
|
||||
scripts: [ '../../../angular.js' ]
|
||||
},
|
||||
dependencyPath: '../../..'
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'../angular.js',
|
||||
@@ -73,7 +75,7 @@ module.exports = function(config) {
|
||||
commonFiles: {
|
||||
scripts: [ '../../../angular.min.js' ]
|
||||
},
|
||||
dependencyPath: '../../..'
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'../angular.min.js',
|
||||
@@ -111,7 +113,7 @@ module.exports = function(config) {
|
||||
'../../../angular.js'
|
||||
]
|
||||
},
|
||||
dependencyPath: '../../..'
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'components/jquery-' + getVersion('jquery') + '/jquery.js',
|
||||
@@ -147,7 +149,7 @@ module.exports = function(config) {
|
||||
commonFiles: {
|
||||
scripts: [ cdnUrl + '/angular.min.js' ]
|
||||
},
|
||||
dependencyPath: cdnUrl
|
||||
dependencyPath: cdnUrl + '/'
|
||||
},
|
||||
scripts: [
|
||||
cdnUrl + '/angular.min.js',
|
||||
|
||||
+5
-1
@@ -49,7 +49,11 @@ gulp.task('assets', ['bower'], function() {
|
||||
|
||||
|
||||
gulp.task('doc-gen', function() {
|
||||
return docGenerator('docs.config.js').generateDocs();
|
||||
return docGenerator('docs.config.js')
|
||||
.generateDocs()
|
||||
.catch(function(error) {
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
|
||||
// JSHint the example and protractor test files
|
||||
|
||||
@@ -33,7 +33,7 @@ describe("convertDatetimeData", function() {
|
||||
AMPMS: ['AM', 'PM'],
|
||||
DATEFORMATS: ['a', 'b', 'c', 'd'],
|
||||
TIMEFORMATS: ['e', 'f', 'g', 'h'] };
|
||||
|
||||
|
||||
it('should convert empty datetime obj', function() {
|
||||
var processedData = convert(dataObj);
|
||||
expect(processedData.MONTH).toEqual(['Enero', 'Pebrero']);
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ set -xe
|
||||
# Define reasonable set of browsers in case we are running manually from commandline
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh,/Users/jenkins/bin/ie8.sh,/Users/jenkins/bin/ie9.sh"
|
||||
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh"
|
||||
fi
|
||||
|
||||
# CLEAN #
|
||||
|
||||
+6
-176
@@ -4,8 +4,9 @@ var shell = require('shelljs');
|
||||
var grunt = require('grunt');
|
||||
var spawn = require('child_process').spawn;
|
||||
var semver = require('semver');
|
||||
|
||||
var _ = require('lodash');
|
||||
var version, pkg;
|
||||
|
||||
var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP mode. */\n\n';
|
||||
|
||||
var PORT_MIN = 8000;
|
||||
@@ -23,23 +24,6 @@ var getRandomPorts = function() {
|
||||
];
|
||||
};
|
||||
|
||||
var getPackage = function() {
|
||||
if ( !pkg ) {
|
||||
|
||||
// Search up the folder hierarchy for the first package.json
|
||||
var packageFolder = path.resolve('.');
|
||||
while ( !fs.existsSync(path.join(packageFolder, 'package.json')) ) {
|
||||
var parent = path.dirname(packageFolder);
|
||||
if ( parent === packageFolder) { break; }
|
||||
packageFolder = parent;
|
||||
}
|
||||
pkg = JSON.parse(fs.readFileSync(path.join(packageFolder,'package.json'), 'UTF-8'));
|
||||
|
||||
}
|
||||
|
||||
return pkg;
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -50,160 +34,6 @@ module.exports = {
|
||||
},
|
||||
|
||||
|
||||
getGitRepoInfo: function() {
|
||||
var GITURL_REGEX = /^https:\/\/github.com\/([^\/]+)\/(.+).git$/;
|
||||
var match = GITURL_REGEX.exec(getPackage().repository.url);
|
||||
var git = {
|
||||
owner: match[1],
|
||||
repo: match[2]
|
||||
};
|
||||
return git;
|
||||
},
|
||||
|
||||
|
||||
getVersion: function(){
|
||||
if (version) return version;
|
||||
|
||||
try {
|
||||
|
||||
var gitTag = getTagOfCurrentCommit();
|
||||
var semVerVersion, codeName, fullVersion;
|
||||
if (gitTag) {
|
||||
// tagged release
|
||||
fullVersion = semVerVersion = semver.valid(gitTag);
|
||||
codeName = getTaggedReleaseCodeName(gitTag);
|
||||
} else {
|
||||
// snapshot release
|
||||
semVerVersion = getSnapshotVersion();
|
||||
fullVersion = semVerVersion + '-' + getSnapshotSuffix();
|
||||
codeName = 'snapshot';
|
||||
}
|
||||
|
||||
var versionParts = semVerVersion.match(/(\d+)\.(\d+)\.(\d+)/);
|
||||
|
||||
version = {
|
||||
full: fullVersion,
|
||||
major: versionParts[1],
|
||||
minor: versionParts[2],
|
||||
dot: versionParts[3],
|
||||
codename: codeName,
|
||||
cdn: getPackage().cdnVersion
|
||||
};
|
||||
|
||||
// Stable versions have an even minor version
|
||||
version.isStable = version.minor%2 === 0;
|
||||
|
||||
return version;
|
||||
|
||||
} catch (e) {
|
||||
grunt.fail.warn(e);
|
||||
}
|
||||
|
||||
function getTagOfCurrentCommit() {
|
||||
var gitTagResult = shell.exec('git describe --exact-match', {silent:true});
|
||||
var gitTagOutput = gitTagResult.output.trim();
|
||||
var branchVersionPattern = new RegExp(getPackage().branchVersion.replace('.', '\\.').replace('*', '\\d+'));
|
||||
if (gitTagResult.code === 0 && gitTagOutput.match(branchVersionPattern)) {
|
||||
return gitTagOutput;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getTaggedReleaseCodeName(tagName) {
|
||||
var tagMessage = shell.exec('git cat-file -p '+ tagName +' | grep "codename"', {silent:true}).output;
|
||||
var codeName = tagMessage && tagMessage.match(/codename\((.*)\)/)[1];
|
||||
if (!codeName) {
|
||||
throw new Error("Could not extract release code name. The message of tag "+tagName+
|
||||
" must match '*codename(some release name)*'");
|
||||
}
|
||||
return codeName;
|
||||
}
|
||||
|
||||
function getSnapshotVersion() {
|
||||
var oldTags = shell.exec('git tag -l v'+getPackage().branchVersion, {silent:true}).output.trim().split('\n');
|
||||
// ignore non semver versions.
|
||||
oldTags = oldTags.filter(function(version) {
|
||||
return version && semver.valid(version);
|
||||
});
|
||||
if (oldTags.length) {
|
||||
oldTags.sort(semver.compare);
|
||||
semVerVersion = oldTags[oldTags.length-1];
|
||||
if (semVerVersion.indexOf('-') !== -1) {
|
||||
semVerVersion = semver.inc(semVerVersion, 'prerelease');
|
||||
} else {
|
||||
semVerVersion = semver.inc(semVerVersion, 'patch');
|
||||
}
|
||||
} else {
|
||||
semVerVersion = semver.valid(getPackage().branchVersion.replace(/\*/g, '0'));
|
||||
}
|
||||
return semVerVersion;
|
||||
}
|
||||
|
||||
function getSnapshotSuffix() {
|
||||
var jenkinsBuild = process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD_NUMBER || 'local';
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
return 'build.'+jenkinsBuild+'+sha.'+hash;
|
||||
}
|
||||
},
|
||||
|
||||
getPreviousVersions: function() {
|
||||
var VERSION_REGEX = /([1-9]\d*)\.(\d+)\.(\d+)(?:-?rc\.?(\d+)|-(snapshot))?/;
|
||||
|
||||
// Pad out a number with zeros at the front to make it `digits` characters long
|
||||
function pad(num, digits) {
|
||||
var zeros = Array(digits+1).join('0');
|
||||
return (zeros+num).slice(-digits);
|
||||
}
|
||||
|
||||
function padVersion(version) {
|
||||
// We pad out the version numbers with 0s so they sort nicely
|
||||
// - Non-Release Candidates get 9999 for their release candidate section to make them appear earlier
|
||||
// - Snapshots get 9 added to the front to move them to the top of the list
|
||||
var maxLength = 4;
|
||||
var padded = (version.snapshot ? '9' : '0') + pad(version.major, maxLength) +
|
||||
pad(version.minor, maxLength) + pad(version.dot, maxLength) +
|
||||
pad(version.rc || 9999, maxLength);
|
||||
return padded;
|
||||
}
|
||||
|
||||
function getVersionFromTag(tag) {
|
||||
var match = VERSION_REGEX.exec(tag);
|
||||
if ( match ) {
|
||||
var version = {
|
||||
tag: tag,
|
||||
major: match[1], minor: match[2], dot: match[3], rc: match[4],
|
||||
snapshot: !!match[5] && getSnapshotSuffix()
|
||||
};
|
||||
|
||||
if(version.snapshot) {
|
||||
version.full = version.major + '.' + version.minor + '.x (edge)';
|
||||
} else {
|
||||
version.full = version.major + '.' + version.minor + '.' + version.dot +
|
||||
(version.rc ? '-rc.' + version.rc : '');
|
||||
}
|
||||
|
||||
// Stable versions have an even minor version and are not a release candidate
|
||||
version.isStable = !(version.minor%2 || version.rc);
|
||||
|
||||
// Versions before 1.0.2 had a different docs folder name
|
||||
version.docsUrl = 'http://code.angularjs.org/' + version.full + '/docs';
|
||||
if ( version.major < 1 || (version.major === 1 && version.minor === 0 && version.dot < 2 ) ) {
|
||||
version.docsUrl += '-' + version.full;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
var tags = shell.exec('git tag', {silent: true}).output.split(/\s*\n\s*/);
|
||||
return _(tags)
|
||||
.map(getVersionFromTag)
|
||||
.filter() // getVersion can map to undefined - this clears those out
|
||||
.sortBy(padVersion)
|
||||
.value();
|
||||
},
|
||||
|
||||
startKarma: function(config, singleRun, done){
|
||||
var browsers = grunt.option('browsers');
|
||||
var reporters = grunt.option('reporters');
|
||||
@@ -225,7 +55,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
|
||||
updateWebdriver: function(done){
|
||||
updateWebdriver: function(done){
|
||||
if (process.env.TRAVIS) {
|
||||
// Skip the webdriver-manager update on Travis, since the browsers will
|
||||
// be provided remotely.
|
||||
@@ -319,9 +149,9 @@ module.exports = {
|
||||
.replace(/"NG_VERSION_FULL"/g, NG_VERSION.full)
|
||||
.replace(/"NG_VERSION_MAJOR"/, NG_VERSION.major)
|
||||
.replace(/"NG_VERSION_MINOR"/, NG_VERSION.minor)
|
||||
.replace(/"NG_VERSION_DOT"/, NG_VERSION.dot)
|
||||
.replace(/"NG_VERSION_DOT"/, NG_VERSION.patch)
|
||||
.replace(/"NG_VERSION_CDN"/, NG_VERSION.cdn)
|
||||
.replace(/"NG_VERSION_CODENAME"/, NG_VERSION.codename);
|
||||
.replace(/"NG_VERSION_CODENAME"/, NG_VERSION.codeName);
|
||||
if (strict !== false) processed = this.singleStrict(processed, '\n\n', true);
|
||||
return processed;
|
||||
},
|
||||
@@ -374,7 +204,7 @@ module.exports = {
|
||||
var mapFile = minFile + '.map';
|
||||
var mapFileName = mapFile.match(/[^\/]+$/)[0];
|
||||
var errorFileName = file.replace(/\.js$/, '-errors.json');
|
||||
var versionNumber = this.getVersion().full;
|
||||
var versionNumber = grunt.config('NG_VERSION').full;
|
||||
shell.exec(
|
||||
'java ' +
|
||||
this.java32flags() + ' ' +
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var shell = require('shelljs');
|
||||
var semver = require('semver');
|
||||
var _ = require('lodash');
|
||||
|
||||
var currentPackage, previousVersions;
|
||||
|
||||
|
||||
/**
|
||||
* Load information about this project from the package.json
|
||||
* @return {Object} The package information
|
||||
*/
|
||||
var getPackage = function() {
|
||||
// Search up the folder hierarchy for the first package.json
|
||||
var packageFolder = path.resolve('.');
|
||||
while ( !fs.existsSync(path.join(packageFolder, 'package.json')) ) {
|
||||
var parent = path.dirname(packageFolder);
|
||||
if ( parent === packageFolder) { break; }
|
||||
packageFolder = parent;
|
||||
}
|
||||
return JSON.parse(fs.readFileSync(path.join(packageFolder,'package.json'), 'UTF-8'));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse the github URL for useful information
|
||||
* @return {Object} An object containing the github owner and repository name
|
||||
*/
|
||||
var getGitRepoInfo = function() {
|
||||
var GITURL_REGEX = /^https:\/\/github.com\/([^\/]+)\/(.+).git$/;
|
||||
var match = GITURL_REGEX.exec(currentPackage.repository.url);
|
||||
var git = {
|
||||
owner: match[1],
|
||||
repo: match[2]
|
||||
};
|
||||
return git;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Extract the code name from the tagged commit's message - it should contain the text of the form:
|
||||
* "codename(some-code-name)"
|
||||
* @param {String} tagName Name of the tag to look in for the codename
|
||||
* @return {String} The codename if found, otherwise null/undefined
|
||||
*/
|
||||
var getCodeName = function(tagName) {
|
||||
var tagMessage = shell.exec('git cat-file -p '+ tagName +' | grep "codename"', {silent:true}).output;
|
||||
var codeName = tagMessage && tagMessage.match(/codename\((.*)\)/)[1];
|
||||
if (!codeName) {
|
||||
throw new Error("Could not extract release code name. The message of tag "+tagName+
|
||||
" must match '*codename(some release name)*'");
|
||||
}
|
||||
return codeName;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compute a build segment for the version, from the Jenkins build number and current commit SHA
|
||||
* @return {String} The build segment of the version
|
||||
*/
|
||||
function getBuild() {
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
return 'sha.'+hash;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the current commit is tagged as a version get that version
|
||||
* @return {SemVer} The version or null
|
||||
*/
|
||||
var getTaggedVersion = function() {
|
||||
var gitTagResult = shell.exec('git describe --exact-match', {silent:true});
|
||||
|
||||
if ( gitTagResult.code === 0 ) {
|
||||
var tag = gitTagResult.output.trim();
|
||||
var version = semver.parse(tag);
|
||||
|
||||
if ( version && semver.satisfies(version, currentPackage.branchVersion)) {
|
||||
version.codeName = getCodeName(tag);
|
||||
version.full = version.version;
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stable versions have an even minor version and have no prerelease
|
||||
* @param {SemVer} version The version to test
|
||||
* @return {Boolean} True if the version is stable
|
||||
*/
|
||||
var isStable = function(version) {
|
||||
return semver.satisfies(version, '1.0 || 1.2') && version.prerelease.length === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a collection of all the previous versions sorted by semantic version
|
||||
* @return {Array.<SemVer>} The collection of previous versions
|
||||
*/
|
||||
var getPreviousVersions = function() {
|
||||
// always use the remote tags as the local clone might
|
||||
// not contain all commits when cloned with git clone --depth=...
|
||||
// Needed e.g. for Travis
|
||||
var repo_url = currentPackage.repository.url;
|
||||
var tagResults = shell.exec('git ls-remote --tags ' + repo_url + ' | grep -o -e "v[0-9].*[0-9]$"',
|
||||
{silent: true});
|
||||
if ( tagResults.code === 0 ) {
|
||||
return _(tagResults.output.trim().split('\n'))
|
||||
.map(function(tag) {
|
||||
var version = semver.parse(tag);
|
||||
return version;
|
||||
})
|
||||
.filter()
|
||||
.map(function(version) {
|
||||
version.isStable = isStable(version);
|
||||
|
||||
version.docsUrl = 'http://code.angularjs.org/' + version.version + '/docs';
|
||||
// Versions before 1.0.2 had a different docs folder name
|
||||
if ( version.major < 1 || (version.major === 1 && version.minor === 0 && version.dot < 2 ) ) {
|
||||
version.docsUrl += '-' + version.version;
|
||||
}
|
||||
return version;
|
||||
})
|
||||
.sort(semver.compare)
|
||||
.value();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the unstable snapshot version
|
||||
* @return {SemVer} The snapshot version
|
||||
*/
|
||||
var getSnapshotVersion = function() {
|
||||
version = _(previousVersions)
|
||||
.filter(function(tag) {
|
||||
return semver.satisfies(tag, currentPackage.branchVersion);
|
||||
})
|
||||
.last();
|
||||
|
||||
if ( !version ) {
|
||||
// a snapshot version before the first tag on the branch
|
||||
version = semver(currentPackage.branchVersion.replace('*','0-beta.1'));
|
||||
}
|
||||
|
||||
// We need to clone to ensure that we are not modifying another version
|
||||
version = semver(version.raw);
|
||||
|
||||
var jenkinsBuild = process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD_NUMBER;
|
||||
if (!version.prerelease || !version.prerelease.length) {
|
||||
// last release was a non beta release. Increment the patch level to
|
||||
// indicate the next release that we will be doing.
|
||||
// E.g. last release was 1.3.0, then the snapshot will be
|
||||
// 1.3.1-build.1, which is lesser than 1.3.1 accorind the semver!
|
||||
|
||||
// If the last release was a beta release we don't update the
|
||||
// beta number by purpose, as otherwise the semver comparison
|
||||
// does not work any more when the next beta is released.
|
||||
// E.g. don't generate 1.3.0-beta.2.build.1
|
||||
// as this is bigger than 1.3.0-beta.2 according to semver
|
||||
version.patch++;
|
||||
}
|
||||
version.prerelease = jenkinsBuild ? ['build', jenkinsBuild] : ['local'];
|
||||
version.build = getBuild();
|
||||
version.codeName = 'snapshot';
|
||||
version.isSnapshot = true;
|
||||
version.format();
|
||||
version.full = version.version + '+' + version.build;
|
||||
|
||||
return version;
|
||||
};
|
||||
|
||||
|
||||
exports.currentPackage = currentPackage = getPackage();
|
||||
exports.gitRepoInfo = gitRepoInfo = getGitRepoInfo();
|
||||
exports.previousVersions = previousVersions = getPreviousVersions();
|
||||
exports.currentVersion = getTaggedVersion() || getSnapshotVersion();
|
||||
Generated
+2808
File diff suppressed because it is too large
Load Diff
+8
-6
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"branchVersion": "1.2.*",
|
||||
"cdnVersion": "1.2.13",
|
||||
"cdnVersion": "1.2.14",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
@@ -16,7 +16,7 @@
|
||||
"grunt-contrib-jshint": "~0.7.2",
|
||||
"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.3.2",
|
||||
"grunt-jscs-checker": "~0.4.0",
|
||||
"grunt-merge-conflict": "~0.0.1",
|
||||
"grunt-parallel": "~0.3.1",
|
||||
"grunt-shell": "~0.4.0",
|
||||
@@ -27,7 +27,7 @@
|
||||
"q-io": "~1.10.6",
|
||||
"qq": "~0.3.5",
|
||||
"shelljs": "~0.2.6",
|
||||
"karma": "0.11.12",
|
||||
"karma": "^0.12.0",
|
||||
"karma-jasmine": "0.1.5",
|
||||
"karma-chrome-launcher": "0.1.2",
|
||||
"karma-firefox-launcher": "0.1.3",
|
||||
@@ -50,10 +50,12 @@
|
||||
"gulp-concat": "~2.1.7",
|
||||
"canonical-path": "0.0.2",
|
||||
"winston": "~0.7.2",
|
||||
"dgeni": "~0.1.0",
|
||||
"dgeni-packages": "^0.2.2",
|
||||
"dgeni": "^0.2.2",
|
||||
"dgeni-packages": "^0.8.1",
|
||||
"gulp-jshint": "~1.4.2",
|
||||
"jshint-stylish": "~0.1.5"
|
||||
"jshint-stylish": "~0.1.5",
|
||||
"node-html-encoder": "0.0.2",
|
||||
"sorted-object": "^1.0.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
|
||||
@@ -11,8 +11,11 @@ ARG_DEFS=(
|
||||
)
|
||||
|
||||
function init {
|
||||
TMP_DIR=$(resolveDir ../../tmp)
|
||||
BASE_DIR=$(resolveDir ../..)
|
||||
TMP_DIR=$BASE_DIR/tmp
|
||||
REPO_DIR=$TMP_DIR/angularjs.org
|
||||
BRANCH_PATTERN=$(readJsonProp "$BASE_DIR/package.json" "branchVersion")
|
||||
BUILD_DIR=$BASE_DIR/build
|
||||
}
|
||||
|
||||
function prepare {
|
||||
@@ -24,18 +27,24 @@ function prepare {
|
||||
#
|
||||
echo "-- Updating angularjs.org"
|
||||
cd $REPO_DIR
|
||||
VERSION_REGEX="[a-z0-9\-\.\+]+"
|
||||
VERSION_REGEX="[-a-z0-9\.\+]+"
|
||||
|
||||
replaceInFile "index.html" "(ajax\/libs\/angularjs\/)$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
replaceInFile "index.html" "(<span class=\"version\">[^<]*<span>)$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
replaceInFile "index.html" "(code.angularjs.org\/)$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
# Replace the version in the script links that reference the Google CDN
|
||||
# e.g. <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.1/angular.js"></script>
|
||||
replaceInFile "index.html" "(http:\/\/ajax.googleapis.com\/ajax\/libs\/angularjs\/)$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
|
||||
replaceInFile "js/homepage.js" "($scope.CURRENT_STABLE_VERSION[ ]*=[ ]*')$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
replaceInFile "js/homepage.js" "($scope.CURRENT_UNSTABLE_VERSION[ ]*=[ ]*')$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
# Replace the version in the script links that reference code.angularjs.org
|
||||
# e.g. <script src="http://code.angularjs.org/1.3.0-beta.1/i18n/angular-locale_sk.js"></script>
|
||||
replaceInFile "index.html" "(code\.angularjs\.org\/)$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
|
||||
# Replace the version of the branch that we are updating
|
||||
echo $BRANCH_PATTERN
|
||||
echo $CDN_VERSION
|
||||
replaceInFile "js/download-data.js" "branch:[ ]+'($BRANCH_PATTERN)',[ ]+version:[ ]+'$VERSION_REGEX'" "branch: '\1', version: '$CDN_VERSION'"
|
||||
|
||||
git add index.html
|
||||
git add js/homepage.js
|
||||
git commit -m "update(version): update angular version to $CDN_VERSION"
|
||||
git add js/download-data.js
|
||||
git commit -m "update(version): update angular version to $CDN_VERSION for branch $BRANCH_PATTERN"
|
||||
}
|
||||
|
||||
function publish {
|
||||
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* this script is just a temporary solution to deal with the issue of npm outputting the npm
|
||||
* shrinkwrap file in an unstable manner.
|
||||
*
|
||||
* See: https://github.com/npm/npm/issues/3581
|
||||
*/
|
||||
|
||||
var _ = require('lodash');
|
||||
var sorted = require('sorted-object');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
function cleanModule(module, name) {
|
||||
|
||||
// keep `from` and `resolve` properties for git dependencies, delete otherwise
|
||||
if (!(module.resolved && module.resolved.match(/^git:\/\//))) {
|
||||
delete module.from;
|
||||
delete module.resolved;
|
||||
}
|
||||
|
||||
if (name === 'chokidar') {
|
||||
if (module.version === '0.8.1') {
|
||||
delete module.dependencies;
|
||||
} else {
|
||||
throw new Error("Unfamiliar chokidar version (v" + module.version +
|
||||
") , please check status of https://github.com/paulmillr/chokidar/pull/106");
|
||||
}
|
||||
}
|
||||
|
||||
_.forEach(module.dependencies, function(mod, name) {
|
||||
cleanModule(mod, name);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
console.log('Reading npm-shrinkwrap.json');
|
||||
var shrinkwrap = require('./../npm-shrinkwrap.json');
|
||||
|
||||
console.log('Cleaning shrinkwrap object');
|
||||
cleanModule(shrinkwrap, shrinkwrap.name);
|
||||
|
||||
console.log('Writing cleaned npm-shrinkwrap.json');
|
||||
fs.writeFileSync('./npm-shrinkwrap.json', JSON.stringify(sorted(shrinkwrap), null, 2) + "\n");
|
||||
@@ -55,19 +55,37 @@ function prepare {
|
||||
git commit -m "v$NEW_VERSION"
|
||||
}
|
||||
|
||||
function publish {
|
||||
if [[ $IS_SNAPSHOT_BUILD ]]; then
|
||||
echo "-- Updating snapshot version"
|
||||
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
function _update_snapshot() {
|
||||
for backend in "$@" ; do
|
||||
echo "-- Updating snapshot version: backend=$backend"
|
||||
curl -G --data-urlencode "ver=$NEW_VERSION" http://$backend:8003/fetchLatestSnapshot.php
|
||||
done
|
||||
}
|
||||
|
||||
function _update_code() {
|
||||
cd $REPO_DIR
|
||||
|
||||
echo "-- Pushing code.angularjs.org"
|
||||
git push origin master
|
||||
|
||||
echo "-- Refreshing code.angularjs.org"
|
||||
curl http://code.angularjs.org/gitFetchSite.php
|
||||
for backend in "$@" ; do
|
||||
echo "-- Refreshing code.angularjs.org: backend=$backend"
|
||||
curl http://$backend:8003/gitFetchSite.php
|
||||
done
|
||||
}
|
||||
|
||||
function publish {
|
||||
# The TXT record for backends.angularjs.org is a CSV of the IP addresses for
|
||||
# the currently serving Compute Engine backends.
|
||||
# code.angularjs.org is served out of port 8003 on these backends.
|
||||
backends=("$(dig backends.angularjs.org +short TXT | python -c 'print raw_input()[1:-1].replace(",", "\n")')")
|
||||
|
||||
if [[ $IS_SNAPSHOT_BUILD ]]; then
|
||||
_update_snapshot ${backends[@]}
|
||||
else
|
||||
_update_code ${backends[@]}
|
||||
fi
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
|
||||
@@ -23,7 +23,7 @@ ARG_DEFS=(
|
||||
)
|
||||
|
||||
function init {
|
||||
if [[ $(git rev-parse --short HEAD) != $COMMIT_SHA ]]; then
|
||||
if [[ $(git rev-parse HEAD) != $(git rev-parse $COMMIT_SHA) ]]; then
|
||||
echo "HEAD is not at $COMMIT_SHA"
|
||||
usage
|
||||
fi
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@
|
||||
# 0. Set the current directory to the directory of the script. By this
|
||||
# the script can be called from anywhere.
|
||||
# 1. Parse the named arguments
|
||||
# 2. If the parameter "git_push_dryrun" is set, all calls the `git push` in this script
|
||||
# 2. If the parameter "git_push_dryrun" is set, all calls to `git push` in this script
|
||||
# or in child scripts will be intercepted so that the `--dry-run` and `--porcelain` is added
|
||||
# to show what the push would do but not actually do it.
|
||||
# 3. If the parameter "verbose" is set, the `-x` flag will be set in bash.
|
||||
@@ -36,7 +36,7 @@
|
||||
# with the name of the parameter in upper case (with dash converted to underscore).
|
||||
#
|
||||
# Special arguments that are always available:
|
||||
# - "--action=.*": This parameter will be used to dispatch to a function with that name when the
|
||||
# - "--action=.*": This parameter will be used to execute a function with that name when the
|
||||
# script is started
|
||||
# - "--git_push_dryrun=true": This will intercept all calls to `git push` in this script
|
||||
# or in child scripts so that the `--dry-run` and `--porcelain` is added
|
||||
@@ -195,7 +195,7 @@ function isFunction {
|
||||
}
|
||||
|
||||
# readJsonProp(jsonFile, property)
|
||||
# - restriction: property needs to be on an own line!
|
||||
# - restriction: property needs to be on a single line!
|
||||
function readJsonProp {
|
||||
echo $(sed -En 's/.*"'$2'"[ ]*:[ ]*"(.*)".*/\1/p' $1)
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"isWindow": false,
|
||||
"isScope": false,
|
||||
"isFile": false,
|
||||
"isBlob": false,
|
||||
"isBoolean": false,
|
||||
"trim": false,
|
||||
"isElement": false,
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
-isWindow,
|
||||
-isScope,
|
||||
-isFile,
|
||||
-isBlob,
|
||||
-isBoolean,
|
||||
-trim,
|
||||
-isElement,
|
||||
@@ -566,6 +567,11 @@ function isFile(obj) {
|
||||
}
|
||||
|
||||
|
||||
function isBlob(obj) {
|
||||
return toString.call(obj) === '[object Blob]';
|
||||
}
|
||||
|
||||
|
||||
function isBoolean(value) {
|
||||
return typeof value === 'boolean';
|
||||
}
|
||||
@@ -1235,6 +1241,41 @@ function angularInit(element, bootstrap) {
|
||||
* Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
|
||||
* They must use {@link ng.directive:ngApp ngApp}.
|
||||
*
|
||||
* Angular will detect if it has been loaded into the browser more than once and only allow the
|
||||
* first loaded script to be bootstrapped and will report a warning to the browser console for
|
||||
* each of the subsequent scripts. This prevents strange results in applications, where otherwise
|
||||
* multiple instances of Angular try to work on the DOM.
|
||||
*
|
||||
* <example name="multi-bootstrap" module="multi-bootstrap">
|
||||
* <file name="index.html">
|
||||
* <script src="../../../angular.js"></script>
|
||||
* <div ng-controller="BrokenTable">
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th ng-repeat="heading in headings">{{heading}}</th>
|
||||
* </tr>
|
||||
* <tr ng-repeat="filling in fillings">
|
||||
* <td ng-repeat="fill in filling">{{fill}}</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="controller.js">
|
||||
* var app = angular.module('multi-bootstrap', [])
|
||||
*
|
||||
* .controller('BrokenTable', function($scope) {
|
||||
* $scope.headings = ['One', 'Two', 'Three'];
|
||||
* $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
|
||||
* });
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
* it('should only insert one table cell for each item in $scope.fillings', function() {
|
||||
* expect(element.all(by.css('td')).count())
|
||||
* .toBe(9);
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* @param {Element} element DOM element which is the root of angular application.
|
||||
* @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
|
||||
* Each item in the array should be the name of a predefined module or a (DI annotated)
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
if (window.angular.bootstrap) {
|
||||
//AngularJS is already loaded, so we can return here...
|
||||
console.log('WARNING: Tried to load angular more than once.');
|
||||
return;
|
||||
}
|
||||
|
||||
//try to bind to jquery now so that one can write angular.element().read()
|
||||
//but we will rebind on bootstrap again.
|
||||
bindJQuery();
|
||||
|
||||
+7
-3
@@ -364,11 +364,15 @@ function jqLiteInheritedData(element, name, value) {
|
||||
var names = isArray(name) ? name : [name];
|
||||
|
||||
while (element.length) {
|
||||
|
||||
var node = element[0];
|
||||
for (var i = 0, ii = names.length; i < ii; i++) {
|
||||
if ((value = element.data(names[i])) !== undefined) return value;
|
||||
}
|
||||
element = element.parent();
|
||||
|
||||
// If dealing with a document fragment node with a host element, and no parent, use the host
|
||||
// element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
|
||||
// to lookup parent controllers.
|
||||
element = jqLite(node.parentNode || (node.nodeType === 11 && node.host));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,7 +461,7 @@ forEach({
|
||||
return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
|
||||
},
|
||||
|
||||
controller: jqLiteController ,
|
||||
controller: jqLiteController,
|
||||
|
||||
injector: function(element) {
|
||||
return jqLiteInheritedData(element, '$injector');
|
||||
|
||||
+4
-6
@@ -55,16 +55,16 @@ function setupModuleLoader(window) {
|
||||
* myModule.value('appName', 'MyCoolApp');
|
||||
*
|
||||
* // configure existing services inside initialization blocks.
|
||||
* myModule.config(function($locationProvider) {
|
||||
* myModule.config(['$locationProvider', function($locationProvider) {
|
||||
* // Configure existing providers
|
||||
* $locationProvider.hashPrefix('!');
|
||||
* });
|
||||
* }]);
|
||||
* ```
|
||||
*
|
||||
* Then you can create an injector and load your modules like this:
|
||||
*
|
||||
* ```js
|
||||
* var injector = angular.injector(['ng', 'MyModule'])
|
||||
* var injector = angular.injector(['ng', 'myModule'])
|
||||
* ```
|
||||
*
|
||||
* However it's more likely that you'll just use
|
||||
@@ -73,7 +73,7 @@ function setupModuleLoader(window) {
|
||||
*
|
||||
* @param {!string} name The name of the module to create or retrieve.
|
||||
* @param {Array.<string>=} requires If specified then new module is being created. If
|
||||
* unspecified then the the module is being retrieved for further configuration.
|
||||
* unspecified then the module is being retrieved for further configuration.
|
||||
* @param {Function} configFn Optional configuration function for the module. Same as
|
||||
* {@link angular.Module#config Module#config()}.
|
||||
* @returns {module} new module with the {@link angular.Module} api.
|
||||
@@ -114,7 +114,6 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc property
|
||||
* @name angular.Module#requires
|
||||
* @module ng
|
||||
* @propertyOf angular.Module
|
||||
* @returns {Array.<string>} List of module names which must be loaded before this module.
|
||||
* @description
|
||||
* Holds the list of modules which the injector will load before the current module is
|
||||
@@ -126,7 +125,6 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc property
|
||||
* @name angular.Module#name
|
||||
* @module ng
|
||||
* @propertyOf angular.Module
|
||||
* @returns {string} Name of the module.
|
||||
* @description
|
||||
*/
|
||||
|
||||
+1
-1
@@ -194,7 +194,6 @@ function Browser(window, document, $log, $sniffer) {
|
||||
|
||||
/**
|
||||
* @name $browser#onUrlChange
|
||||
* @TODO(vojta): refactor to use node's syntax for events
|
||||
*
|
||||
* @description
|
||||
* Register callback function that will be called, when url changes.
|
||||
@@ -215,6 +214,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
|
||||
*/
|
||||
self.onUrlChange = function(callback) {
|
||||
// TODO(vojta): refactor to use node's syntax for events
|
||||
if (!urlChangeInit) {
|
||||
// We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
|
||||
// don't fire popstate when user change the address bar and don't fire hashchange when url
|
||||
|
||||
@@ -208,15 +208,11 @@ function $CacheFactoryProvider() {
|
||||
* `$templateCache` service directly.
|
||||
*
|
||||
* Adding via the `script` tag:
|
||||
*
|
||||
* ```html
|
||||
* <html ng-app>
|
||||
* <head>
|
||||
* <script type="text/ng-template" id="templateId.html">
|
||||
* This is the content of the template
|
||||
* </script>
|
||||
* </head>
|
||||
* ...
|
||||
* </html>
|
||||
* <script type="text/ng-template" id="templateId.html">
|
||||
* <p>This is the content of the template</p>
|
||||
* </script>
|
||||
* ```
|
||||
*
|
||||
* **Note:** the `script` tag containing the template does not need to be included in the `head` of
|
||||
|
||||
+8
-9
@@ -503,7 +503,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
Suffix = 'Directive',
|
||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
||||
TABLE_CONTENT_REGEXP = /^<\s*(tr|th|td|tbody)(\s+[^>]*)?>/i;
|
||||
TABLE_CONTENT_REGEXP = /^<\s*(tr|th|td|thead|tbody|tfoot)(\s+[^>]*)?>/i;
|
||||
|
||||
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
|
||||
// The assumption is that future DOM event attribute names will begin with
|
||||
@@ -1649,16 +1649,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
template = trim(template);
|
||||
if ((type = TABLE_CONTENT_REGEXP.exec(template))) {
|
||||
type = type[1].toLowerCase();
|
||||
var table = jqLite('<table>' + template + '</table>'),
|
||||
tbody = table.children('tbody'),
|
||||
leaf = /(td|th)/.test(type) && table.find('tr');
|
||||
if (tbody.length && type !== 'tbody') {
|
||||
table = tbody;
|
||||
var table = jqLite('<table>' + template + '</table>');
|
||||
if (/(thead|tbody|tfoot)/.test(type)) {
|
||||
return table.children(type);
|
||||
}
|
||||
if (leaf && leaf.length) {
|
||||
table = leaf;
|
||||
table = table.children('tbody');
|
||||
if (type === 'tr') {
|
||||
return table.children('tr');
|
||||
}
|
||||
return table.contents();
|
||||
return table.children('tr').contents();
|
||||
}
|
||||
return jqLite('<div>' +
|
||||
template +
|
||||
|
||||
@@ -277,7 +277,7 @@
|
||||
* such as selected. (Their presence means true and their absence means false.)
|
||||
* If we put an Angular interpolation expression into such an attribute then the
|
||||
* binding information would be lost when the browser removes the attribute.
|
||||
* The `ngSelected` directive solves this problem for the `selected` atttribute.
|
||||
* The `ngSelected` directive solves this problem for the `selected` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
|
||||
@@ -360,8 +360,6 @@ function FormController(element, attrs, $scope, $animate) {
|
||||
</file>
|
||||
</example>
|
||||
*
|
||||
* @param {string=} name Name of the form. If specified, the form controller will be published into
|
||||
* related scope, under this name.
|
||||
*/
|
||||
var formDirectiveFactory = function(isNgForm) {
|
||||
return ['$timeout', function($timeout) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
|
||||
* `{{ expression }}` which is similar but less verbose.
|
||||
*
|
||||
* It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
|
||||
* It is preferable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
|
||||
* displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
|
||||
* element attribute, it makes the bindings invisible to the user while the page is loading.
|
||||
*
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
* @priority 400
|
||||
*
|
||||
* @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
|
||||
* make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
|
||||
* make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
|
||||
* @param {string=} onload Expression to evaluate when a new partial is loaded.
|
||||
*
|
||||
* @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
|
||||
@@ -146,7 +146,6 @@
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngInclude#$includeContentRequested
|
||||
* @eventOf ng.directive:ngInclude
|
||||
* @eventType emit on the scope ngInclude was declared in
|
||||
* @description
|
||||
* Emitted every time the ngInclude content is requested.
|
||||
@@ -156,7 +155,6 @@
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngInclude#$includeContentLoaded
|
||||
* @eventOf ng.directive:ngInclude
|
||||
* @eventType emit on the current ngInclude scope
|
||||
* @description
|
||||
* Emitted every time the ngInclude content is reloaded.
|
||||
|
||||
@@ -68,9 +68,11 @@
|
||||
* as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
|
||||
*
|
||||
* @animations
|
||||
* enter - when a new item is added to the list or when an item is revealed after a filter
|
||||
* leave - when an item is removed from the list or when an item is filtered out
|
||||
* move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
|
||||
* **.enter** - when a new item is added to the list or when an item is revealed after a filter
|
||||
*
|
||||
* **.leave** - when an item is removed from the list or when an item is filtered out
|
||||
*
|
||||
* **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
|
||||
*
|
||||
* @element ANY
|
||||
* @scope
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
* @scope
|
||||
* @priority 800
|
||||
* @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
|
||||
* @paramDescription
|
||||
* On child elements add:
|
||||
*
|
||||
* * `ngSwitchWhen`: the case statement to match against. If match then this
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
|
||||
* assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
|
||||
*
|
||||
* @param {'text/ng-template'} type Must be set to `'text/ng-template'`.
|
||||
* @param {string} type Must be set to `'text/ng-template'`.
|
||||
* @param {string} id Cache name of the template.
|
||||
*
|
||||
* @example
|
||||
|
||||
@@ -394,6 +394,12 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
value = valueFn(scope, locals);
|
||||
}
|
||||
}
|
||||
// Update the null option's selected property here so $render cleans it up correctly
|
||||
if (optionGroupsCache[0].length > 1) {
|
||||
if (optionGroupsCache[0][1].id !== key) {
|
||||
optionGroupsCache[0][1].selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctrl.$setViewValue(value);
|
||||
});
|
||||
@@ -531,7 +537,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
lastElement.val(existingOption.id = option.id);
|
||||
}
|
||||
// lastElement.prop('selected') provided by jQuery has side-effects
|
||||
if (lastElement[0].selected !== option.selected) {
|
||||
if (existingOption.selected !== option.selected) {
|
||||
lastElement.prop('selected', (existingOption.selected = option.selected));
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,22 @@
|
||||
*
|
||||
* @description
|
||||
* A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<div ng-controller="MainCtrl">
|
||||
<p>$document title: <b ng-bind="title"></b></p>
|
||||
<p>window.document title: <b ng-bind="windowTitle"></b></p>
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
function MainCtrl($scope, $document) {
|
||||
$scope.title = $document[0].title;
|
||||
$scope.windowTitle = angular.element(window.document)[0].title;
|
||||
}
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
function $DocumentProvider(){
|
||||
this.$get = ['$window', function(window){
|
||||
|
||||
@@ -441,7 +441,7 @@ function dateFilter($locale) {
|
||||
* @returns {string} JSON string.
|
||||
*
|
||||
*
|
||||
* @example:
|
||||
* @example
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<pre>{{ {'name':'value'} | json }}</pre>
|
||||
|
||||
@@ -74,6 +74,12 @@ function orderByFilter($parse){
|
||||
predicate = predicate.substring(1);
|
||||
}
|
||||
get = $parse(predicate);
|
||||
if (get.constant) {
|
||||
var key = get();
|
||||
return reverseComparator(function(a,b) {
|
||||
return compare(a[key], b[key]);
|
||||
}, descending);
|
||||
}
|
||||
}
|
||||
return reverseComparator(function(a,b){
|
||||
return compare(get(a),get(b));
|
||||
|
||||
+4
-6
@@ -103,7 +103,7 @@ function $HttpProvider() {
|
||||
|
||||
// transform outgoing request data
|
||||
transformRequest: [function(d) {
|
||||
return isObject(d) && !isFile(d) ? toJson(d) : d;
|
||||
return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
|
||||
}],
|
||||
|
||||
// default headers
|
||||
@@ -236,9 +236,8 @@ function $HttpProvider() {
|
||||
*
|
||||
* # Shortcut methods
|
||||
*
|
||||
* Since all invocations of the $http service require passing in an HTTP method and URL, and
|
||||
* POST/PUT requests require request data to be provided as well, shortcut methods
|
||||
* were created:
|
||||
* Shortcut methods are also available. All shortcut methods require passing in the URL, and
|
||||
* request data must be passed in for POST/PUT requests.
|
||||
*
|
||||
* ```js
|
||||
* $http.get('/someUrl').success(successCallback);
|
||||
@@ -573,7 +572,7 @@ function $HttpProvider() {
|
||||
* - **headers** – `{function([headerName])}` – Header getter function.
|
||||
* - **config** – `{Object}` – The configuration object that was used to generate the request.
|
||||
*
|
||||
* @property {Array.<Object>} pendingRequests Array of config objects for currently pending
|
||||
* @property {Array.<Object>} pendingRequests Array of config objects for currently pending
|
||||
* requests. This is primarily meant to be used for debugging purposes.
|
||||
*
|
||||
*
|
||||
@@ -875,7 +874,6 @@ function $HttpProvider() {
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $http#defaults
|
||||
* @propertyOf ng.$http
|
||||
*
|
||||
* @description
|
||||
* Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
|
||||
|
||||
@@ -144,9 +144,11 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
||||
jsonpDone = xhr = null;
|
||||
|
||||
// fix status code when it is 0 (0 status is undocumented).
|
||||
// Occurs when accessing file resources.
|
||||
// On Android 4.1 stock browser it occurs while retrieving files from application cache.
|
||||
status = (status === 0) ? (response ? 200 : 404) : status;
|
||||
// Occurs when accessing file resources or on Android 4.1 stock browser
|
||||
// while retrieving files from application cache.
|
||||
if (status === 0) {
|
||||
status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
|
||||
}
|
||||
|
||||
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
|
||||
status = status == 1223 ? 204 : status;
|
||||
|
||||
+1
-1
@@ -168,7 +168,7 @@ function $IntervalProvider() {
|
||||
* @description
|
||||
* Cancels a task associated with the `promise`.
|
||||
*
|
||||
* @param {number} promise Promise returned by the `$interval` function.
|
||||
* @param {promise} promise returned by the `$interval` function.
|
||||
* @returns {boolean} Returns `true` if the task was successfully canceled.
|
||||
*/
|
||||
interval.cancel = function(promise) {
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@
|
||||
*
|
||||
* Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
|
||||
* property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
|
||||
* make your code IE8 compatible.
|
||||
* make your code IE8 and Android 2.x compatible.
|
||||
*
|
||||
* # Chaining promises
|
||||
*
|
||||
|
||||
+21
-10
@@ -1,21 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
function $$RAFProvider(){ //rAF
|
||||
this.$get = ['$window', function($window) {
|
||||
this.$get = ['$window', '$timeout', function($window, $timeout) {
|
||||
var requestAnimationFrame = $window.requestAnimationFrame ||
|
||||
$window.webkitRequestAnimationFrame;
|
||||
$window.webkitRequestAnimationFrame ||
|
||||
$window.mozRequestAnimationFrame;
|
||||
|
||||
var cancelAnimationFrame = $window.cancelAnimationFrame ||
|
||||
$window.webkitCancelAnimationFrame;
|
||||
$window.webkitCancelAnimationFrame ||
|
||||
$window.mozCancelAnimationFrame ||
|
||||
$window.webkitCancelRequestAnimationFrame;
|
||||
|
||||
var raf = function(fn) {
|
||||
var id = requestAnimationFrame(fn);
|
||||
return function() {
|
||||
cancelAnimationFrame(id);
|
||||
};
|
||||
};
|
||||
var rafSupported = !!requestAnimationFrame;
|
||||
var raf = rafSupported
|
||||
? function(fn) {
|
||||
var id = requestAnimationFrame(fn);
|
||||
return function() {
|
||||
cancelAnimationFrame(id);
|
||||
};
|
||||
}
|
||||
: function(fn) {
|
||||
var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
|
||||
return function() {
|
||||
$timeout.cancel(timer);
|
||||
};
|
||||
};
|
||||
|
||||
raf.supported = !!requestAnimationFrame;
|
||||
raf.supported = rafSupported;
|
||||
|
||||
return raf;
|
||||
}];
|
||||
|
||||
+47
-12
@@ -139,7 +139,6 @@ function $RootScopeProvider(){
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $rootScope.Scope#$id
|
||||
* @propertyOf ng.$rootScope.Scope
|
||||
* @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
|
||||
* debugging.
|
||||
*/
|
||||
@@ -399,30 +398,40 @@ function $RootScopeProvider(){
|
||||
* {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
|
||||
* collection will trigger a call to the `listener`.
|
||||
*
|
||||
* @param {function(newCollection, oldCollection, scope)} listener a callback function that is
|
||||
* fired with both the `newCollection` and `oldCollection` as parameters.
|
||||
* The `newCollection` object is the newly modified data obtained from the `obj` expression
|
||||
* and the `oldCollection` object is a copy of the former collection data.
|
||||
* The `scope` refers to the current scope.
|
||||
* @param {function(newCollection, oldCollection, scope)} listener a callback function called
|
||||
* when a change is detected.
|
||||
* - The `newCollection` object is the newly modified data obtained from the `obj` expression
|
||||
* - The `oldCollection` object is a copy of the former collection data.
|
||||
* Due to performance considerations, the`oldCollection` value is computed only if the
|
||||
* `listener` function declares two or more arguments.
|
||||
* - The `scope` argument refers to the current scope.
|
||||
*
|
||||
* @returns {function()} Returns a de-registration function for this listener. When the
|
||||
* de-registration function is executed, the internal watch operation is terminated.
|
||||
*/
|
||||
$watchCollection: function(obj, listener) {
|
||||
var self = this;
|
||||
var oldValue;
|
||||
// the current value, updated on each dirty-check run
|
||||
var newValue;
|
||||
// a shallow copy of the newValue from the last dirty-check run,
|
||||
// updated to match newValue during dirty-check run
|
||||
var oldValue;
|
||||
// a shallow copy of the newValue from when the last change happened
|
||||
var veryOldValue;
|
||||
// only track veryOldValue if the listener is asking for it
|
||||
var trackVeryOldValue = (listener.length > 1);
|
||||
var changeDetected = 0;
|
||||
var objGetter = $parse(obj);
|
||||
var internalArray = [];
|
||||
var internalObject = {};
|
||||
var initRun = true;
|
||||
var oldLength = 0;
|
||||
|
||||
function $watchCollectionWatch() {
|
||||
newValue = objGetter(self);
|
||||
var newLength, key;
|
||||
|
||||
if (!isObject(newValue)) {
|
||||
if (!isObject(newValue)) { // if primitive
|
||||
if (oldValue !== newValue) {
|
||||
oldValue = newValue;
|
||||
changeDetected++;
|
||||
@@ -444,7 +453,9 @@ function $RootScopeProvider(){
|
||||
}
|
||||
// copy the items to oldValue and look for changes.
|
||||
for (var i = 0; i < newLength; i++) {
|
||||
if (oldValue[i] !== newValue[i]) {
|
||||
var bothNaN = (oldValue[i] !== oldValue[i]) &&
|
||||
(newValue[i] !== newValue[i]);
|
||||
if (!bothNaN && (oldValue[i] !== newValue[i])) {
|
||||
changeDetected++;
|
||||
oldValue[i] = newValue[i];
|
||||
}
|
||||
@@ -488,7 +499,32 @@ function $RootScopeProvider(){
|
||||
}
|
||||
|
||||
function $watchCollectionAction() {
|
||||
listener(newValue, oldValue, self);
|
||||
if (initRun) {
|
||||
initRun = false;
|
||||
listener(newValue, newValue, self);
|
||||
} else {
|
||||
listener(newValue, veryOldValue, self);
|
||||
}
|
||||
|
||||
// make a copy for the next time a collection is changed
|
||||
if (trackVeryOldValue) {
|
||||
if (!isObject(newValue)) {
|
||||
//primitive
|
||||
veryOldValue = newValue;
|
||||
} else if (isArrayLike(newValue)) {
|
||||
veryOldValue = new Array(newValue.length);
|
||||
for (var i = 0; i < newValue.length; i++) {
|
||||
veryOldValue[i] = newValue[i];
|
||||
}
|
||||
} else { // if object
|
||||
veryOldValue = {};
|
||||
for (var key in newValue) {
|
||||
if (hasOwnProperty.call(newValue, key)) {
|
||||
veryOldValue[key] = newValue[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.$watch($watchCollectionWatch, $watchCollectionAction);
|
||||
@@ -652,7 +688,6 @@ function $RootScopeProvider(){
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name $rootScope.Scope#$destroy
|
||||
* @eventOf ng.$rootScope.Scope
|
||||
* @eventType broadcast on scope being destroyed
|
||||
*
|
||||
* @description
|
||||
@@ -870,7 +905,7 @@ function $RootScopeProvider(){
|
||||
* - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
|
||||
*
|
||||
* @param {string} name Event name to listen on.
|
||||
* @param {function(event, args...)} listener Function to call when the event is emitted.
|
||||
* @param {function(event, ...args)} listener Function to call when the event is emitted.
|
||||
* @returns {function()} Returns a deregistration function for this listener.
|
||||
*/
|
||||
$on: function(name, listener) {
|
||||
|
||||
+1
-1
@@ -521,7 +521,7 @@ function $SceDelegateProvider() {
|
||||
* |---------------------|----------------|
|
||||
* | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
|
||||
* | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. |
|
||||
* | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`<a href=` and `<img src=` sanitize their urls and don't consititute an SCE context. |
|
||||
* | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`<a href=` and `<img src=` sanitize their urls and don't constitute an SCE context. |
|
||||
* | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contens are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
|
||||
* | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. |
|
||||
*
|
||||
|
||||
@@ -701,8 +701,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
/**
|
||||
*
|
||||
* @ngdoc function
|
||||
* @name ng.$animate#setClass
|
||||
* @methodOf ng.$animate
|
||||
* @name $animate#setClass
|
||||
* @function
|
||||
* @description Adds and/or removes the given CSS classes to and from the element.
|
||||
* Once complete, the done() callback will be fired (if provided).
|
||||
@@ -771,7 +770,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
fireDOMOperation();
|
||||
fireBeforeCallbackAsync();
|
||||
fireAfterCallbackAsync();
|
||||
fireDoneCallbackAsync();
|
||||
closeAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -950,7 +949,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
animation, but class-based animations don't. An example of this
|
||||
failing would be when a parent HTML tag has a ng-class attribute
|
||||
causing ALL directives below to skip animations during the digest */
|
||||
if(runner.isClassBased) {
|
||||
if(runner && runner.isClassBased) {
|
||||
cleanup(element, className);
|
||||
} else {
|
||||
$$asyncCallback(function() {
|
||||
|
||||
@@ -25,8 +25,9 @@ angular.module('ngCookies', ['ng']).
|
||||
* @description
|
||||
* Provides read/write access to browser's cookies.
|
||||
*
|
||||
* Only a simple Object is exposed and by adding or removing properties to/from
|
||||
* this object, new cookies are created/deleted at the end of current $eval.
|
||||
* Only a simple Object is exposed and by adding or removing properties to/from this object, new
|
||||
* cookies are created/deleted at the end of current $eval.
|
||||
* The object's properties can only be strings.
|
||||
*
|
||||
* Requires the {@link ngCookies `ngCookies`} module to be installed.
|
||||
*
|
||||
@@ -94,12 +95,10 @@ angular.module('ngCookies', ['ng']).
|
||||
for(name in cookies) {
|
||||
value = cookies[name];
|
||||
if (!angular.isString(value)) {
|
||||
if (angular.isDefined(lastCookies[name])) {
|
||||
cookies[name] = lastCookies[name];
|
||||
} else {
|
||||
delete cookies[name];
|
||||
}
|
||||
} else if (value !== lastCookies[name]) {
|
||||
value = '' + value;
|
||||
cookies[name] = value;
|
||||
}
|
||||
if (value !== lastCookies[name]) {
|
||||
$browser.cookies(name, value);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
Vendored
+9
-10
@@ -498,7 +498,7 @@ angular.mock.$IntervalProvider = function() {
|
||||
* @description
|
||||
* Cancels a task associated with the `promise`.
|
||||
*
|
||||
* @param {number} promise A promise from calling the `$interval` function.
|
||||
* @param {promise} promise A promise from calling the `$interval` function.
|
||||
* @returns {boolean} Returns `true` if the task was successfully cancelled.
|
||||
*/
|
||||
$interval.cancel = function(promise) {
|
||||
@@ -960,13 +960,12 @@ angular.mock.dump = function(object) {
|
||||
*
|
||||
* # Flushing HTTP requests
|
||||
*
|
||||
* The $httpBackend used in production always responds to requests with responses asynchronously.
|
||||
* If we preserved this behavior in unit testing we'd have to create async unit tests, which are
|
||||
* hard to write, understand, and maintain. However, the testing mock can't respond
|
||||
* synchronously because that would change the execution of the code under test. For this reason the
|
||||
* mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
|
||||
* requests and thus preserve the async api of the backend while allowing the test to execute
|
||||
* synchronously.
|
||||
* The $httpBackend used in production always responds to requests asynchronously. If we preserved
|
||||
* this behavior in unit testing, we'd have to create async unit tests, which are hard to write,
|
||||
* to follow and to maintain. But neither can the testing mock respond synchronously; that would
|
||||
* change the execution of the code under test. For this reason, the mock $httpBackend has a
|
||||
* `flush()` method, which allows the test to explicitly flush pending requests. This preserves
|
||||
* the async api of the backend, while allowing the test to execute synchronously.
|
||||
*
|
||||
*
|
||||
* # Unit testing with mock $httpBackend
|
||||
@@ -1822,8 +1821,8 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* an array containing response status (number), response data (string) and response headers
|
||||
* (Object).
|
||||
* - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
|
||||
* handler, will be pass through to the real backend (an XHR request will be made to the
|
||||
* server.
|
||||
* handler will be passed through to the real backend (an XHR request will be made to the
|
||||
* server.)
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -97,7 +97,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
* If the parameter value is prefixed with `@` then the value of that parameter is extracted from
|
||||
* the data object (useful for non-GET operations).
|
||||
*
|
||||
* @param {Object.<Object>=} actions Hash with declaration of custom action that should extend
|
||||
* @param {Object.<Object>=} actions Hash with declaration of custom action that should extend
|
||||
* the default set of resource actions. The declaration should be created in the format of {@link
|
||||
* ng.$http#usage_parameters $http.config}:
|
||||
*
|
||||
@@ -253,7 +253,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
|
||||
```js
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
var user = User.get({userId:123}, function() {
|
||||
User.get({userId:123}, function(user) {
|
||||
user.abc = true;
|
||||
user.$save();
|
||||
});
|
||||
@@ -273,6 +273,16 @@ function shallowClearAndCopy(src, dst) {
|
||||
});
|
||||
});
|
||||
```
|
||||
*
|
||||
* You can also access the raw `$http` promise via the `$promise` property on the object returned
|
||||
*
|
||||
```
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
User.get({userId:123})
|
||||
.$promise.then(function(user) {
|
||||
$scope.user = user;
|
||||
});
|
||||
```
|
||||
|
||||
* # Creating a custom 'PUT' request
|
||||
* In this example we create a custom method on our resource to make a PUT request
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user