Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30cd764b6d | |||
| 38b75cdb2d | |||
| 6cb8b39af8 | |||
| ebaa336614 | |||
| ef5f567f91 | |||
| 64e5afc478 | |||
| 1e582e4fa4 | |||
| 7421235f24 | |||
| 09ba69078d | |||
| 3536e83d8a | |||
| 3bb1dd5d7f | |||
| 95f964b827 | |||
| c8f78a8ca9 | |||
| f34d48087b | |||
| 2c9ecd01b1 | |||
| a584fb6e15 | |||
| 1f13313f40 | |||
| 5b60303781 | |||
| 10e2552a7d | |||
| ef48b0aa55 | |||
| f57872bca0 | |||
| 2deaf2877e | |||
| 7a146c9cd5 | |||
| 2796ec172b | |||
| 6997c1bf0c | |||
| 4a030f3834 | |||
| f78d8b8ff3 | |||
| f27d19ed60 | |||
| 4a5eaf7bec | |||
| 8513674911 | |||
| 97b74ad6fb | |||
| a47ea79023 | |||
| 5ca0de6487 | |||
| 50a449f053 | |||
| d7422da7d7 | |||
| c7cbc978c6 | |||
| 27146e8a7f | |||
| 5e418b1145 | |||
| f4bb973eb7 | |||
| 848857aa5b | |||
| ee8a05d3f1 | |||
| 275ebbf0ec | |||
| 0f23df4c06 | |||
| 11f700f7bd | |||
| 5785f2a991 | |||
| 2546c29f81 | |||
| 19ea708c9d | |||
| 5cf05d67f2 | |||
| 0377c6f0e8 | |||
| 9c13866824 | |||
| 419a4813e3 | |||
| 131af8272d | |||
| c219a46f59 | |||
| 25f008f541 | |||
| 4a593db79b | |||
| ad4fef0431 | |||
| 8a15fcc1f5 | |||
| f01212ab52 | |||
| 28693a1a67 | |||
| 29fd499552 | |||
| 2f97d9d647 | |||
| 4146b38459 | |||
| 05aab660ce | |||
| 5ecb64849e | |||
| 59dfe1b5a0 | |||
| 50ebfb735c | |||
| 0bdbfe5069 | |||
| 3fc4d6028c | |||
| 2eb12a052b | |||
| bd63b2235c | |||
| f418ffd083 | |||
| 6ab5f8ce4b | |||
| becfeb5aa3 | |||
| eb968c4a68 | |||
| 7f2af3f923 | |||
| cce98ff53a | |||
| b607618342 | |||
| fa50fbaf57 | |||
| f135e2dc05 | |||
| 780351db5e | |||
| a50bb0bfec | |||
| 4d86df6f48 | |||
| bb464d16b4 | |||
| 85b2eb1472 | |||
| 7608f92c6a | |||
| c0bf8db63c | |||
| c95a6737fb | |||
| cd43d24402 | |||
| 086c5d0354 | |||
| 2a2ac5f53a | |||
| 21deaf637a | |||
| 72e15a3a83 | |||
| 174cb4a8c8 | |||
| 33f769b0a1 | |||
| c8abf20558 | |||
| 6dbb183e75 | |||
| bc4844d3b2 | |||
| 708f8b47de | |||
| 5518126d42 | |||
| 5fe73fdc3a | |||
| 394c496bf2 | |||
| 8e1aeba715 | |||
| 0e6e7eb477 | |||
| 183f636816 | |||
| 5f8ed63f2a | |||
| e4f3c94e31 | |||
| 1e5cbcbd93 | |||
| dcf3ec160f | |||
| a7beb5b6d3 | |||
| 1d3b65adc2 | |||
| d528644fe3 | |||
| 6f1bcfc14e | |||
| 996914c6b0 | |||
| fff048d099 | |||
| dcb0da8225 | |||
| b664e20d12 | |||
| 3d68b95028 | |||
| 163aca336d | |||
| e922c38612 | |||
| 1b7ddd3491 | |||
| 4c5afb5cc2 | |||
| f0dc288824 | |||
| 70490ef717 | |||
| dfef3bf2d4 | |||
| f727adddeb | |||
| fc89a85406 | |||
| b4f5377a2f | |||
| 7a667c77e3 | |||
| 752b1e69b7 | |||
| 1102c84f59 | |||
| 245b27101a | |||
| f5d2bf3d6e | |||
| 9c2d0b8af3 | |||
| 465d173455 | |||
| f1db7d735b | |||
| b77defde81 | |||
| afafb7a8ab | |||
| f04fcdfe9f | |||
| 5dd3a35f47 | |||
| ca139dee8e | |||
| 099083352a | |||
| f54e9242fc | |||
| d003ec1d41 | |||
| aadee894da | |||
| ad4e86a582 | |||
| e8f9cbfdce | |||
| d4863a82fa | |||
| 736b6c7fed | |||
| 1dedcdf2bc | |||
| 05c3336f92 | |||
| d1e4f5728c | |||
| 9f61e74be3 | |||
| 4059600d20 | |||
| c625b0d568 | |||
| 04cbe1e74f | |||
| 9399d68d98 | |||
| 4a320ab9f0 | |||
| 44f9ae6126 | |||
| cdb9e08f4e |
+5
-12
@@ -1,7 +1,7 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '4.4'
|
||||
- '6'
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -36,19 +36,12 @@ addons:
|
||||
packages:
|
||||
- g++-4.8
|
||||
|
||||
install:
|
||||
# Check the size of caches
|
||||
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
|
||||
# - npm config set registry http://23.251.144.68
|
||||
# Disable the spinner, it looks bad on Travis
|
||||
- npm config set spin false
|
||||
# Log HTTP requests
|
||||
- npm config set loglevel http
|
||||
#- npm install -g npm@2.5
|
||||
# Install npm dependencies and ensure that npm cache is not stale
|
||||
- npm install
|
||||
before_install:
|
||||
- curl -o- -L https://raw.githubusercontent.com/yarnpkg/yarn/2a0afc73210c7a82082585283e518eeb88ca19ae/scripts/install-latest.sh | bash -s -- --version 0.17.9
|
||||
- export PATH=$HOME/.yarn/bin:$PATH
|
||||
|
||||
before_script:
|
||||
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
|
||||
- ./scripts/travis/before_build.sh
|
||||
|
||||
script:
|
||||
|
||||
+1888
-12
File diff suppressed because it is too large
Load Diff
+7
-3
@@ -209,7 +209,9 @@ We have very precise rules over how our git commit messages can be formatted. T
|
||||
readable messages** that are easy to follow when looking through the **project history**. But also,
|
||||
we use the git commit messages to **generate the AngularJS change log**.
|
||||
|
||||
The commit message formatting can be added using a typical git workflow or through the use of a CLI wizard ([Commitizen](https://github.com/commitizen/cz-cli)). To use the wizard, run `npm run commit` in your terminal after staging your changes in git.
|
||||
The commit message formatting can be added using a typical git workflow or through the use of a CLI
|
||||
wizard ([Commitizen](https://github.com/commitizen/cz-cli)). To use the wizard, run `yarn run commit`
|
||||
in your terminal after staging your changes in git.
|
||||
|
||||
### Commit Message Format
|
||||
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
|
||||
@@ -229,7 +231,8 @@ Any line of the commit message cannot be longer 100 characters! This allows the
|
||||
to read on GitHub as well as in various git tools.
|
||||
|
||||
### Revert
|
||||
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
|
||||
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit.
|
||||
In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
|
||||
|
||||
### Type
|
||||
Must be one of the following:
|
||||
@@ -266,7 +269,8 @@ The body should include the motivation for the change and contrast this with pre
|
||||
The footer should contain any information about **Breaking Changes** and is also the place to
|
||||
[reference GitHub issues that this commit closes][closing-issues].
|
||||
|
||||
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
|
||||
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines.
|
||||
The rest of the commit message is then used for this.
|
||||
|
||||
A detailed explanation can be found in this [document][commit-message-format].
|
||||
|
||||
|
||||
+56
-16
@@ -10,26 +10,63 @@ var path = require('path');
|
||||
var e2e = require('./test/e2e/tools');
|
||||
|
||||
var semver = require('semver');
|
||||
var fs = require('fs');
|
||||
var exec = require('shelljs').exec;
|
||||
var pkg = require(__dirname + '/package.json');
|
||||
|
||||
var useNodeVersion = fs.readFileSync('.nvmrc', 'utf8');
|
||||
if (!semver.satisfies(process.version, useNodeVersion)) {
|
||||
throw new Error('Invalid node version; please use node v' + useNodeVersion);
|
||||
// Node.js version checks
|
||||
if (!semver.satisfies(process.version, pkg.engines.node)) {
|
||||
reportOrFail('Invalid node version (' + process.version + '). ' +
|
||||
'Please use a version that satisfies ' + pkg.engines.node);
|
||||
}
|
||||
|
||||
// Yarn version checks
|
||||
var expectedYarnVersion = pkg.engines.yarn;
|
||||
var currentYarnVersion = exec('yarn --version', {silent: true}).stdout.trim();
|
||||
if (!semver.satisfies(currentYarnVersion, expectedYarnVersion)) {
|
||||
reportOrFail('Invalid yarn version (' + currentYarnVersion + '). ' +
|
||||
'Please use a version that satisfies ' + expectedYarnVersion);
|
||||
}
|
||||
|
||||
// Grunt CLI version checks
|
||||
var expectedGruntVersion = pkg.engines.grunt;
|
||||
var currentGruntVersions = exec('grunt --version', {silent: true}).stdout;
|
||||
var match = /^grunt-cli v(.+)$/m.exec(currentGruntVersions);
|
||||
if (!match) {
|
||||
reportOrFail('Unable to compute the current grunt-cli version. We found:\n' +
|
||||
currentGruntVersions);
|
||||
} else {
|
||||
if (!semver.satisfies(match[1], expectedGruntVersion)) {
|
||||
reportOrFail('Invalid grunt-cli version (' + match[1] + '). ' +
|
||||
'Please use a version that satisfies ' + expectedGruntVersion);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure Node.js dependencies have been installed
|
||||
if (!process.env.TRAVIS && !process.env.JENKINS_HOME) {
|
||||
var yarnOutput = exec('yarn install');
|
||||
if (yarnOutput.code !== 0) {
|
||||
throw new Error('Yarn install failed: ' + yarnOutput.stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = function(grunt) {
|
||||
//grunt plugins
|
||||
|
||||
// this loads all the node_modules that start with `grunt-` as plugins
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
// load additional grunt tasks
|
||||
grunt.loadTasks('lib/grunt');
|
||||
grunt.loadNpmTasks('angular-benchpress');
|
||||
|
||||
// compute version related info for this build
|
||||
var NG_VERSION = versionInfo.currentVersion;
|
||||
NG_VERSION.cdn = versionInfo.cdnVersion;
|
||||
var dist = 'angular-' + NG_VERSION.full;
|
||||
|
||||
if (versionInfo.cdnVersion == null) {
|
||||
throw new Error('Unable to read CDN version, are you offline or has the CDN not been properly pushed?');
|
||||
throw new Error('Unable to read CDN version, are you offline or has the CDN not been properly pushed?\n' +
|
||||
'Perhaps you want to set the NG1_BUILD_NO_REMOTE_VERSION_REQUESTS environment variable?');
|
||||
}
|
||||
|
||||
//config
|
||||
@@ -292,10 +329,9 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
shell: {
|
||||
'npm-install': {
|
||||
command: 'node scripts/npm/check-node-modules.js'
|
||||
'install-node-dependencies': {
|
||||
command: 'yarn'
|
||||
},
|
||||
|
||||
'promises-aplus-tests': {
|
||||
options: {
|
||||
stdout: false,
|
||||
@@ -322,13 +358,6 @@ module.exports = function(grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
// global beforeEach task
|
||||
if (!process.env.TRAVIS) {
|
||||
grunt.task.run('shell:npm-install');
|
||||
}
|
||||
|
||||
|
||||
|
||||
//alias tasks
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['eslint', 'package', 'test:unit', 'test:promises-aplus', 'tests:docs', 'test:protractor']);
|
||||
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
|
||||
@@ -350,3 +379,14 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'eslint']);
|
||||
grunt.registerTask('default', ['package']);
|
||||
};
|
||||
|
||||
|
||||
function reportOrFail(message) {
|
||||
if (process.env.TRAVIS || process.env.JENKINS_HOME) {
|
||||
throw new Error(message);
|
||||
} else {
|
||||
console.log('===============================================================================');
|
||||
console.log(message);
|
||||
console.log('===============================================================================');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
Copyright (c) 2010-2017 Google, Inc. http://angularjs.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ You can mention him in the relevant thread like this: `@btford`.
|
||||
|
||||
> Thanks for submitting this issue!
|
||||
> Unfortunately, we don't think this functionality belongs in core.
|
||||
> The good news is that you could easily implement this as a third-party module and publish it on Bower and/or npm.
|
||||
> The good news is that you could easily implement this as a third-party module and publish it on Bower and/or to the npm repository.
|
||||
|
||||
|
||||
## Assigning Work
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('animationBenchmark', ['ngAnimate'], config)
|
||||
.controller('BenchmarkController', BenchmarkController);
|
||||
|
||||
// Functions - Definitions
|
||||
function config($compileProvider) {
|
||||
$compileProvider
|
||||
.commentDirectivesEnabled(false)
|
||||
.cssClassDirectivesEnabled(false)
|
||||
.debugInfoEnabled(false);
|
||||
}
|
||||
|
||||
function BenchmarkController($scope) {
|
||||
var self = this;
|
||||
var itemCount = 1000;
|
||||
var items = (new Array(itemCount + 1)).join('.').split('');
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'create',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
self.items = items;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: '$digest',
|
||||
fn: function() {
|
||||
$scope.$root.$digest();
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'destroy',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
self.items = [];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [
|
||||
{
|
||||
id: 'jquery',
|
||||
src: 'jquery-noop.js'
|
||||
}, {
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
}, {
|
||||
id: 'angular-animate',
|
||||
src: '/build/angular-animate.js'
|
||||
}, {
|
||||
src: 'app.js'
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
// Override me with ?jquery=/bower_components/jquery/dist/jquery.js
|
||||
@@ -0,0 +1,28 @@
|
||||
<style>
|
||||
[ng-cloak] { display: none !important; }
|
||||
.animation-container .ng-enter,
|
||||
.animation-container .ng-leave {
|
||||
transition: all 0.1s;
|
||||
}
|
||||
|
||||
.animation-container .ng-enter,
|
||||
.animation-container .ng-leave.ng-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.animation-container .ng-enter.ng-enter-active,
|
||||
.animation-container .ng-leave {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
<div ng-app="animationBenchmark" ng-cloak ng-controller="BenchmarkController as bm">
|
||||
<div class="container-fluid">
|
||||
<h2>Large collection of elements animated in and out with ngAnimate</h2>
|
||||
|
||||
<div class="animation-container">
|
||||
<div ng-repeat="i in bm.items track by $index">
|
||||
Just a plain ol' element
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,108 @@
|
||||
'use strict';
|
||||
|
||||
var app = angular.module('ngClassBenchmark', []);
|
||||
|
||||
app.controller('DataController', function DataController($scope) {
|
||||
|
||||
this.init = function() {
|
||||
this.numberOfTodos = 1000;
|
||||
this.implementation = 'tableOptimized';
|
||||
this.completedPeriodicity = 3;
|
||||
this.importantPeriodicity = 13;
|
||||
this.urgentPeriodicity = 29;
|
||||
|
||||
this.createTodos(100);
|
||||
this.setTodosValuesWithSeed(0);
|
||||
};
|
||||
|
||||
this.clearTodos = function() {
|
||||
this.todos = null;
|
||||
};
|
||||
|
||||
this.createTodos = function(count) {
|
||||
var i;
|
||||
this.todos = [];
|
||||
for (i = 0; i < count; i++) {
|
||||
this.todos.push({
|
||||
id: i + 1,
|
||||
completed: false,
|
||||
important: false,
|
||||
urgent: false
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.setTodosValuesWithSeed = function(offset) {
|
||||
var i, todo;
|
||||
for (i = 0; i < this.todos.length; i++) {
|
||||
todo = this.todos[i];
|
||||
todo.completed = 0 === (i + offset) % this.completedPeriodicity;
|
||||
todo.important = 0 === (i + offset) % this.importantPeriodicity;
|
||||
todo.urgent = 0 === (i + offset) % this.urgentPeriodicity;
|
||||
}
|
||||
};
|
||||
|
||||
this.init();
|
||||
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'setup',
|
||||
fn: function() {
|
||||
$scope.$apply();
|
||||
this.clearTodos();
|
||||
this.createTodos(this.numberOfTodos);
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'create',
|
||||
fn: function() {
|
||||
// initialize data for first time that will construct the DOM
|
||||
this.setTodosValuesWithSeed(0);
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: '$apply',
|
||||
fn: function() {
|
||||
$scope.$apply();
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'update',
|
||||
fn: function() {
|
||||
// move everything but completed
|
||||
this.setTodosValuesWithSeed(3);
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'unclass',
|
||||
fn: function() {
|
||||
// remove all classes
|
||||
this.setTodosValuesWithSeed(NaN);
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'class',
|
||||
fn: function() {
|
||||
// add all classes as the initial state
|
||||
this.setTodosValuesWithSeed(0);
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'destroy',
|
||||
fn: function() {
|
||||
this.clearTodos();
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [{
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
},
|
||||
{
|
||||
src: 'app.js'
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
<style>
|
||||
.gold {
|
||||
background: gold;
|
||||
}
|
||||
.silver {
|
||||
background: silver;
|
||||
}
|
||||
.table tbody tr > td.success {
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
|
||||
.table tbody tr > td.error {
|
||||
background-color: #f2dede;
|
||||
}
|
||||
|
||||
.table tbody tr > td.warning {
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
|
||||
.table tbody tr > td.info {
|
||||
background-color: #d9edf7;
|
||||
}
|
||||
.completed {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.important {
|
||||
font-weight: bold;
|
||||
}
|
||||
.urgent {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
<div ng-app="ngClassBenchmark" ng-cloak class="container-fluid">
|
||||
<div ng-controller="DataController as benchmark" class="row">
|
||||
<div class="col-lg-12">
|
||||
|
||||
<div class="well">
|
||||
<h3>Parameters</h3>
|
||||
|
||||
<br>
|
||||
<p>
|
||||
<label>Number of todos</label><br>
|
||||
<input type="number" ng-model="benchmark.numberOfTodos">
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<p>
|
||||
<label>Implementation</label><br>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="tableOptimized"
|
||||
type="radio" name="implementation">
|
||||
Table optimized <br>
|
||||
<code>ng-class="todo.completed && 'success'"</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="table"
|
||||
type="radio" name="implementation">
|
||||
Table <br>
|
||||
<code>ng-class="{success: todo.completed}"</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="list"
|
||||
type="radio" name="implementation">
|
||||
List <br>
|
||||
<code>ng-class="{completed: todo.completed, urgent: todo.urgent, important: todo.important"}</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="singleOptimized"
|
||||
type="radio" name="implementation">
|
||||
Single ngClass optimized <br>
|
||||
<code>
|
||||
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}"
|
||||
</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="single"
|
||||
type="radio" name="implementation">
|
||||
Single ngClass <br>
|
||||
<code>
|
||||
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}"
|
||||
</code>
|
||||
</label>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h3>Example</h3>
|
||||
<div ng-switch="benchmark.implementation">
|
||||
|
||||
<table ng-switch-when="tableOptimized" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>todo #id</th>
|
||||
<th>completed?</th>
|
||||
<th>urgent?</th>
|
||||
<th>important?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="todo in benchmark.todos track by todo.id"
|
||||
ng-class="todo.completed && 'active'"
|
||||
ng-class-even="todo.completed && todo.important && 'gold'"
|
||||
ng-class-odd="todo.completed && todo.important && 'silver'"
|
||||
>
|
||||
<td>#{{todo.id}}</td>
|
||||
<td>{{todo.completed}}</td>
|
||||
<td ng-class="todo.urgent && 'danger'">{{todo.urgent}}</td>
|
||||
<td ng-class="todo.important && 'success'">{{todo.important}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table ng-switch-when="table" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>todo #id</th>
|
||||
<th>completed?</th>
|
||||
<th>urgent?</th>
|
||||
<th>important?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="todo in benchmark.todos track by todo.id"
|
||||
ng-class="{active: todo.completed}"
|
||||
ng-class-even="{gold: todo.completed && todo.important}"
|
||||
ng-class-odd="{silver: todo.completed && todo.important}"
|
||||
>
|
||||
<td>#{{todo.id}}</td>
|
||||
<td>{{todo.completed}}</td>
|
||||
<td ng-class="{danger: todo.urgent}">{{todo.urgent}}</td>
|
||||
<td ng-class="{success: todo.important}">{{todo.important}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<ul ng-switch-when="list">
|
||||
<li ng-repeat="todo in benchmark.todos track by todo.id"
|
||||
ng-class="{
|
||||
completed: todo.completed,
|
||||
urgent: todo.urgent,
|
||||
important: todo.important
|
||||
}">#{{todo.id}}</li>
|
||||
</ul>
|
||||
|
||||
<div ng-switch-when="singleOptimized"
|
||||
class="panel"
|
||||
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Information</h3>
|
||||
</div>
|
||||
<div class="panel-body"> The title is green because there are todos... </div>
|
||||
</div>
|
||||
|
||||
<div ng-switch-when="single"
|
||||
class="panel"
|
||||
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Information</h3>
|
||||
</div>
|
||||
<div class="panel-body"> The title is green because there are todos... </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br><br><br>
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// TODO(vojta): pre-commit hook for validating messages
|
||||
// TODO(vojta): report errors, currently Q silence everything which really sucks
|
||||
|
||||
'use strict';
|
||||
|
||||
var child = require('child_process');
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
var q = require('qq');
|
||||
|
||||
var GIT_LOG_CMD = 'git log --grep="%s" -E --format=%s %s..HEAD';
|
||||
var GIT_TAG_CMD = 'git describe --tags --abbrev=0';
|
||||
|
||||
var HEADER_TPL = '<a name="%s"></a>\n# %s (%s)\n\n';
|
||||
var LINK_ISSUE = '[#%s](https://github.com/angular/angular.js/issues/%s)';
|
||||
var LINK_COMMIT = '[%s](https://github.com/angular/angular.js/commit/%s)';
|
||||
|
||||
var EMPTY_COMPONENT = '$$';
|
||||
|
||||
|
||||
var warn = function() {
|
||||
console.log('WARNING:', util.format.apply(null, arguments));
|
||||
};
|
||||
|
||||
|
||||
var parseRawCommit = function(raw) {
|
||||
if (!raw) return null;
|
||||
|
||||
var lines = raw.split('\n');
|
||||
var msg = {}, match;
|
||||
|
||||
msg.hash = lines.shift();
|
||||
msg.subject = lines.shift();
|
||||
msg.closes = [];
|
||||
msg.breaks = [];
|
||||
|
||||
lines.forEach(function(line) {
|
||||
match = line.match(/(?:Closes|Fixes)\s#(\d+)/);
|
||||
if (match) msg.closes.push(parseInt(match[1], 10));
|
||||
});
|
||||
|
||||
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
|
||||
if (match) {
|
||||
msg.breaking = match[1];
|
||||
}
|
||||
|
||||
|
||||
msg.body = lines.join('\n');
|
||||
match = msg.subject.match(/^(.*)\((.*)\):\s(.*)$/);
|
||||
|
||||
if (!match || !match[1] || !match[3]) {
|
||||
warn('Incorrect message: %s %s', msg.hash, msg.subject);
|
||||
return null;
|
||||
}
|
||||
|
||||
msg.type = match[1];
|
||||
msg.component = match[2];
|
||||
msg.subject = match[3];
|
||||
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
var linkToIssue = function(issue) {
|
||||
return util.format(LINK_ISSUE, issue, issue);
|
||||
};
|
||||
|
||||
|
||||
var linkToCommit = function(hash) {
|
||||
return util.format(LINK_COMMIT, hash.substr(0, 8), hash);
|
||||
};
|
||||
|
||||
|
||||
var currentDate = function() {
|
||||
var now = new Date();
|
||||
var pad = function(i) {
|
||||
return ('0' + i).substr(-2);
|
||||
};
|
||||
|
||||
return util.format('%d-%s-%s', now.getFullYear(), pad(now.getMonth() + 1), pad(now.getDate()));
|
||||
};
|
||||
|
||||
|
||||
var printSection = function(stream, title, section, printCommitLinks) {
|
||||
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks;
|
||||
var components = Object.getOwnPropertyNames(section).sort();
|
||||
|
||||
if (!components.length) return;
|
||||
|
||||
stream.write(util.format('\n## %s\n\n', title));
|
||||
|
||||
components.forEach(function(name) {
|
||||
var prefix = '-';
|
||||
var nested = section[name].length > 1;
|
||||
|
||||
if (name !== EMPTY_COMPONENT) {
|
||||
if (nested) {
|
||||
stream.write(util.format('- **%s:**\n', name));
|
||||
prefix = ' -';
|
||||
} else {
|
||||
prefix = util.format('- **%s:**', name);
|
||||
}
|
||||
}
|
||||
|
||||
section[name].forEach(function(commit) {
|
||||
if (printCommitLinks) {
|
||||
stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash)));
|
||||
if (commit.closes.length) {
|
||||
stream.write(',\n ' + commit.closes.map(linkToIssue).join(', '));
|
||||
}
|
||||
stream.write(')\n');
|
||||
} else {
|
||||
stream.write(util.format('%s %s\n', prefix, commit.subject));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
stream.write('\n');
|
||||
};
|
||||
|
||||
|
||||
var readGitLog = function(grep, from) {
|
||||
var deferred = q.defer();
|
||||
|
||||
// TODO(vojta): if it's slow, use spawn and stream it instead
|
||||
child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) {
|
||||
var commits = [];
|
||||
|
||||
stdout.split('\n==END==\n').forEach(function(rawCommit) {
|
||||
var commit = parseRawCommit(rawCommit);
|
||||
if (commit) commits.push(commit);
|
||||
});
|
||||
|
||||
deferred.resolve(commits);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
|
||||
var writeChangelog = function(stream, commits, version) {
|
||||
var sections = {
|
||||
fix: {},
|
||||
feat: {},
|
||||
perf: {},
|
||||
breaks: {}
|
||||
};
|
||||
|
||||
commits.forEach(function(commit) {
|
||||
var section = sections[commit.type];
|
||||
var component = commit.component || EMPTY_COMPONENT;
|
||||
|
||||
if (section) {
|
||||
section[component] = section[component] || [];
|
||||
section[component].push(commit);
|
||||
}
|
||||
|
||||
if (commit.breaking) {
|
||||
sections.breaks[component] = sections.breaks[component] || [];
|
||||
sections.breaks[component].push({
|
||||
subject: util.format('due to %s,\n %s', linkToCommit(commit.hash), commit.breaking),
|
||||
hash: commit.hash,
|
||||
closes: []
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
|
||||
printSection(stream, 'Bug Fixes', sections.fix);
|
||||
printSection(stream, 'Features', sections.feat);
|
||||
printSection(stream, 'Performance Improvements', sections.perf);
|
||||
printSection(stream, 'Breaking Changes', sections.breaks, false);
|
||||
};
|
||||
|
||||
|
||||
var getPreviousTag = function() {
|
||||
var deferred = q.defer();
|
||||
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
|
||||
if (code) deferred.reject('Cannot get the previous tag.');
|
||||
else deferred.resolve(stdout.replace('\n', ''));
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
|
||||
var generate = function(version, file) {
|
||||
|
||||
getPreviousTag().then(function(tag) {
|
||||
console.log('Reading git log since', tag);
|
||||
readGitLog('^fix|^feat|^perf|BREAKING', tag).then(function(commits) {
|
||||
console.log('Parsed', commits.length, 'commits');
|
||||
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
|
||||
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// publish for testing
|
||||
exports.parseRawCommit = parseRawCommit;
|
||||
exports.printSection = printSection;
|
||||
|
||||
// hacky start if not run by jasmine :-D
|
||||
if (process.argv.join('').indexOf('jasmine-node') === -1) {
|
||||
generate(process.argv[2], process.argv[3]);
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/* global describe: false, beforeEach: false, afterEach: false, it: false, expect: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('changelog.js', function() {
|
||||
var ch = require('./changelog');
|
||||
|
||||
describe('parseRawCommit', function() {
|
||||
it('should parse raw commit', function() {
|
||||
var msg = ch.parseRawCommit(
|
||||
'9b1aff905b638aa274a5fc8f88662df446d374bd\n' +
|
||||
'feat(scope): broadcast $destroy event on scope destruction\n' +
|
||||
'perf testing shows that in chrome this change adds 5-15% overhead\n' +
|
||||
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
|
||||
|
||||
expect(msg.type).toBe('feat');
|
||||
expect(msg.hash).toBe('9b1aff905b638aa274a5fc8f88662df446d374bd');
|
||||
expect(msg.subject).toBe('broadcast $destroy event on scope destruction');
|
||||
expect(msg.body).toBe('perf testing shows that in chrome this change adds 5-15% overhead\n' +
|
||||
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
|
||||
expect(msg.component).toBe('scope');
|
||||
});
|
||||
|
||||
|
||||
it('should parse closed issues', function() {
|
||||
var msg = ch.parseRawCommit(
|
||||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
|
||||
'feat(ng-list): Allow custom separator\n' +
|
||||
'bla bla bla\n\n' +
|
||||
'Closes #123\nCloses #25\n');
|
||||
|
||||
expect(msg.closes).toEqual([123, 25]);
|
||||
});
|
||||
|
||||
|
||||
it('should parse breaking changes', function() {
|
||||
var msg = ch.parseRawCommit(
|
||||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
|
||||
'feat(ng-list): Allow custom separator\n' +
|
||||
'bla bla bla\n\n' +
|
||||
'BREAKING CHANGE: first breaking change\nsomething else\n' +
|
||||
'another line with more info\n');
|
||||
|
||||
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
|
||||
});
|
||||
});
|
||||
|
||||
describe('printSection', function() {
|
||||
var output;
|
||||
var streamMock = {
|
||||
write: function(str) {
|
||||
output += str;
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
output = '';
|
||||
});
|
||||
|
||||
it('should add a new line at the end of each breaking change list item ' +
|
||||
'when there is 1 item per component', function() {
|
||||
var title = 'test';
|
||||
var printCommitLinks = false;
|
||||
|
||||
var section = {
|
||||
module1: [{subject: 'breaking change 1'}],
|
||||
module2: [{subject: 'breaking change 2'}]
|
||||
};
|
||||
var expectedOutput =
|
||||
'\n## test\n\n' +
|
||||
'- **module1:** breaking change 1\n' +
|
||||
'- **module2:** breaking change 2\n' +
|
||||
'\n';
|
||||
|
||||
ch.printSection(streamMock, title, section, printCommitLinks);
|
||||
expect(output).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
it('should add a new line at the end of each breaking change list item ' +
|
||||
'when there are multiple items per component', function() {
|
||||
var title = 'test';
|
||||
var printCommitLinks = false;
|
||||
|
||||
var section = {
|
||||
module1: [
|
||||
{subject: 'breaking change 1.1'},
|
||||
{subject: 'breaking change 1.2'}
|
||||
],
|
||||
module2: [
|
||||
{subject: 'breaking change 2.1'},
|
||||
{subject: 'breaking change 2.2'}
|
||||
]
|
||||
};
|
||||
var expectedOutput =
|
||||
'\n## test\n\n' +
|
||||
'- **module1:**\n' +
|
||||
' - breaking change 1.1\n' +
|
||||
' - breaking change 1.2\n' +
|
||||
'- **module2:**\n' +
|
||||
' - breaking change 2.1\n' +
|
||||
' - breaking change 2.2\n' +
|
||||
'\n';
|
||||
|
||||
ch.printSection(streamMock, title, section, printCommitLinks);
|
||||
expect(output).toBe(expectedOutput);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
.visible-phone{display:none}.visible-desktop{display:block}.navbar{display:block}.navbar .container{padding:0 16px;width:auto}.navbar .brand{float:left;margin:8px 80px 0 8px;padding:0}.navbar .brand a{display:block;height:30px;margin:6px 0 5px 0;overflow:hidden;padding:0;width:117px}.navbar .nav{float:right}.navbar .nav .dropdown-toggle{color:rgba(255,255,255,0.87);font-size:16px;font-weight:300;line-height:56px;padding:0 24px;text-transform:uppercase;transition:all .3s}.navbar .nav .dropdown-toggle:hover,.navbar .nav .dropdown-toggle:active,.navbar .nav .dropdown-toggle:focus{background:#37474F;color:#fff}.navbar .nav .dropdown-menu{background:#37474F;border:none;border-radius:0;box-shadow:0 0 16px rgba(0,0,0,0.12),0 16px 16px rgba(0,0,0,0.24);color:#fff;left:auto;margin:0;padding:0;right:0}.navbar .nav .dropdown-menu:after,.navbar .nav .dropdown-menu:before{display:none}.navbar .nav .dropdown-menu li{border-bottom:1px solid rgba(38,50,56,0.56);box-sizing:border-box;line-height:48px}.navbar .nav .dropdown-menu li:last-child{border:none}.navbar .nav .dropdown-menu a{background:#37474F;color:#fff;font-weight:300;line-height:48px;padding:0 16px;transition:all .2s}.navbar .nav .dropdown-menu a:hover,.navbar .nav .dropdown-menu a:focus{background:#455A64}.navbar .navbar-search{left:200px;margin:0;position:absolute;right:440px;top:8px;width:auto}.navbar .navbar-search i{color:#546E7A;font-size:16px;left:12px;position:absolute;top:11px}.navbar .navbar-search .search-query{background:#37474F;border:none;border-radius:2px;box-shadow:none;box-sizing:border-box;color:#546E7A;font-size:14px;height:40px;width:100%;padding:0 16px 0 32px;text-shadow:none;transition:all .3s}.navbar .navbar-search .search-query:-webkit-autofill,.navbar .navbar-search .search-query:-webkit-autofill:hover,.navbar .navbar-search .search-query:-webkit-autofill:focus{background-color:#fff;transition:background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#455A64}.navbar .navbar-search .search-query:hover,.navbar .navbar-search .search-query:active,.navbar .navbar-search .search-query:focus{background:#fff;box-shadow:inset 0 2px 4px rgba(0,0,0,0.24);color:#2196F3}.navbar .navbar-search .search-query::-webkit-input-placeholder{color:#546E7A}.navbar .navbar-search .search-query::-moz-placeholder{color:#546E7A}.navbar .navbar-search .search-query:-ms-input-placeholder{color:#546E7A}.navbar .navbar-search .search-query:-moz-placeholder{color:#546E7A}#navbar-main .navbar-inner{background:#263238;height:56px}#navbar-notice{z-index:1029;top:56px}#navbar-notice .navbar-inner{background:#ECEFF1;box-shadow:0 0 3px rgba(0,0,0,0.12),0 3px 3px rgba(0,0,0,0.24);height:auto}.site-notice{padding:4px 0;text-align:center;font-size:13px;margin:0}@media handheld and (max-width: 800px), screen and (max-device-width: 800px), screen and (max-width: 800px){.visible-phone{display:block}.visible-desktop{display:none}}@media handheld and (max-width: 800px), screen and (max-device-width: 800px), screen and (max-width: 800px){.homepage .container{padding:16px;width:auto}.homepage .span1{width:auto}.homepage .span2{width:auto}.homepage .span3{width:auto}.homepage .span4{width:auto}.homepage .span5{width:auto}.homepage .span6{width:auto}.homepage .span7{width:auto}.homepage .span8{width:auto}.homepage .span9{width:auto}.homepage .span10{width:auto}.homepage .navbar .container{padding:0 8px}.homepage #navbar-main .navbar-inner{height:40px}.homepage #navbar-main .brand{margin:6px 0 0 0}.homepage #navbar-main .brand a{margin:0}.homepage #navbar-main .nav{margin:0}.homepage #navbar-main .nav .dropdown-toggle{font-size:12px;line-height:40px;padding:0 8px}.homepage #navbar-main .dropdown-menu a{padding:0 8px}.homepage #navbar-main .navbar-search{background:#263238;border-bottom:1px solid #263238;left:0;right:0;top:100%}.homepage #navbar-main .navbar-search i{left:12px;top:7px}.homepage #navbar-main .navbar-search .search-query{border-radius:0;height:32px}.homepage #navbar-notice{top:40px}.homepage #navbar-notice .site-notice{font-size:11px}.homepage .hero{padding:80px 32px 32px 32px}.homepage .hero h2{background-size:230px 60px;height:60px;width:230px}}
|
||||
@@ -53,13 +53,13 @@ h1,h2,h3,h4,h5,h6 {
|
||||
}
|
||||
|
||||
.header .brand {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.header .brand img {
|
||||
margin-top: 5px;
|
||||
height: 30px;
|
||||
margin-top: 0;
|
||||
height: auto;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.docs-search {
|
||||
@@ -82,6 +82,11 @@ h1,h2,h3,h4,h5,h6 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.navbar .navbar-search i {
|
||||
top: 13px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.docs-search > .search-query:focus {
|
||||
outline: 0;
|
||||
}
|
||||
@@ -297,6 +302,7 @@ iframe.example {
|
||||
}
|
||||
|
||||
.search-results-container {
|
||||
position: relative;
|
||||
padding-bottom: 1em;
|
||||
border-top: 1px solid #111;
|
||||
background: #181818;
|
||||
@@ -435,15 +441,17 @@ iframe.example {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.sup-header {
|
||||
#navbar-sub {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
background: rgba(245,245,245,0.88);
|
||||
box-shadow: 0 0 2px #999;
|
||||
z-index: 1028;
|
||||
top: 83px;
|
||||
}
|
||||
|
||||
.main-body-grid {
|
||||
margin-top: 120px;
|
||||
margin-top: 144px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -454,7 +462,7 @@ iframe.example {
|
||||
|
||||
.main-body-grid > .grid-left {
|
||||
position: fixed;
|
||||
top: 120px;
|
||||
top: 144px;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -662,6 +670,10 @@ ul.events > li {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.deprecation {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.deprecation .title {
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
@@ -823,3 +835,86 @@ ul.events > li {
|
||||
iframe[name="example-anchoringExample"] {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
/*
|
||||
angular-topnav.css and bootstrap overrides
|
||||
*/
|
||||
|
||||
.navbar .navbar-inner .container {
|
||||
padding: 0 16px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.navbar .nav > li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.navbar-nav .open .dropdown-menu {
|
||||
position: absolute;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.navbar-nav .open .dropdown-menu > li > a {
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
#navbar-main .navbar-inner, #navbar-notice .navbar-inner {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#navbar-sub .container {
|
||||
max-width: 970px;
|
||||
}
|
||||
|
||||
.nav .open > a, .nav .open > a:hover, .nav .open > a:focus {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
@media handheld and (max-width:800px), screen and (max-device-width:800px), screen and (max-width:800px) {
|
||||
.navbar {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.search-results-container {
|
||||
top: 32px;
|
||||
overflow: auto;
|
||||
max-height: 85vh;
|
||||
padding-bottom: 0;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.search-close {
|
||||
right: 1px;
|
||||
margin-left: 0;
|
||||
top: 41px;
|
||||
padding: 5px 10px;
|
||||
border-top-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
box-shadow: none;
|
||||
width: auto;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.navbar-nav .open .dropdown-menu > li > a, .navbar-nav .open .dropdown-menu .dropdown-header {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.homepage #navbar-notice {
|
||||
top: 72px;
|
||||
}
|
||||
|
||||
#navbar-notice .navbar-inner {
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, .12), 0 3px 3px rgba(0, 0, 0, .24)
|
||||
}
|
||||
|
||||
#navbar-sub {
|
||||
position: relative;
|
||||
top: 17px;
|
||||
margin-top: 80px;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/* global importScripts, lunr */
|
||||
|
||||
// Load up the lunr library
|
||||
importScripts('../components/lunr.js-0.5.12/lunr.min.js');
|
||||
importScripts('../components/lunr-0.7.2/lunr.min.js');
|
||||
|
||||
// Create the lunr index - the docs should be an array of object, each object containing
|
||||
// the path and search terms for a page
|
||||
|
||||
@@ -18,8 +18,8 @@ describe('doc.angularjs.org', function() {
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('ngClick');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('ngClick');
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -44,30 +44,31 @@ describe('docs.angularjs.org', function() {
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('ngClick');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('ngClick');
|
||||
});
|
||||
|
||||
|
||||
|
||||
it('should be resilient to trailing slashes', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing "index"', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/index');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing "index/"', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/ng/function/angular.noop/index/');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
@@ -78,7 +79,8 @@ describe('docs.angularjs.org', function() {
|
||||
|
||||
it('should display an error if the page does not exist', function() {
|
||||
browser.get('build/docs/index-production.html#!/api/does/not/exist');
|
||||
expect(element(by.css('h1')).getText()).toBe('Oops!');
|
||||
var mainHeader = element(by.css('.main-body h1 '));
|
||||
expect(mainHeader.getText()).toEqual('Oops!');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ angular.module('DocsController', ['currentVersionData'])
|
||||
$scope.loading = 0;
|
||||
|
||||
|
||||
var INDEX_PATH = /^(\/|\/index[^\.]*.html)$/;
|
||||
var INDEX_PATH = /^(\/|\/index[^.]*.html)$/;
|
||||
if (!$location.path() || INDEX_PATH.test($location.path())) {
|
||||
$location.path('/api').replace();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
angular.module('errors', ['ngSanitize'])
|
||||
|
||||
.filter('errorLink', ['$sanitize', function($sanitize) {
|
||||
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.;,\(\)\{\}<>]/g,
|
||||
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/g,
|
||||
MAILTO_REGEXP = /^mailto:/,
|
||||
STACK_TRACE_REGEXP = /:\d+:\d+$/;
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ angular.module('examples', [])
|
||||
|
||||
ctrl.prepareExampleData = function() {
|
||||
if (ctrl.example.manifest) {
|
||||
return $q.when(ctrl.example);
|
||||
return $q.resolve(ctrl.example);
|
||||
}
|
||||
|
||||
return getExampleData(ctrl.examplePath).then(function(data) {
|
||||
@@ -159,10 +159,11 @@ angular.module('examples', [])
|
||||
|
||||
};
|
||||
|
||||
// Initialize the example data, so it's ready when clicking the open button.
|
||||
// Otherwise pop-up blockers will prevent a new window from opening
|
||||
ctrl.prepareExampleData(ctrl.example.path);
|
||||
|
||||
ctrl.$onInit = function() {
|
||||
// Initialize the example data, so it's ready when clicking the open button.
|
||||
// Otherwise pop-up blockers will prevent a new window from opening
|
||||
ctrl.prepareExampleData(ctrl.example.path);
|
||||
};
|
||||
}]
|
||||
};
|
||||
}])
|
||||
|
||||
@@ -72,7 +72,7 @@ angular.module('search', [])
|
||||
|
||||
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch',
|
||||
function($scope, $location, docsSearch) {
|
||||
docsSearch($location.path().split(/[\/\.:]/).pop()).then(function(results) {
|
||||
docsSearch($location.path().split(/[/.:]/).pop()).then(function(results) {
|
||||
$scope.results = {};
|
||||
angular.forEach(results, function(result) {
|
||||
var area = $scope.results[result.area] || [];
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "AngularJS-docs-app",
|
||||
"dependencies": {
|
||||
"jquery": "2.2.3",
|
||||
"lunr.js": "0.5.12",
|
||||
"open-sans-fontface": "1.0.4",
|
||||
"google-code-prettify": "1.0.1",
|
||||
"bootstrap": "3.1.1"
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ var packagePath = __dirname;
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
// Create and export a new Dgeni package called angularjs. This package depends upon
|
||||
// the ngdoc, nunjucks, and examples packages defined in the dgeni-packages npm module.
|
||||
// the ngdoc, nunjucks, and examples packages defined in the dgeni-packages node module.
|
||||
module.exports = new Package('angularjs', [
|
||||
require('dgeni-packages/ngdoc'),
|
||||
require('dgeni-packages/nunjucks'),
|
||||
|
||||
@@ -34,7 +34,7 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
var areasToSearch;
|
||||
|
||||
// Keywords start with "ng:" or one of $, _ or a letter
|
||||
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
|
||||
var KEYWORD_REGEX = /^((ng:|[$_a-z])[\w\-_]+)/;
|
||||
|
||||
// Load up the keywords to ignore, if specified in the config
|
||||
if (this.ignoreWordsFile) {
|
||||
@@ -67,7 +67,7 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
|
||||
function extractWords(text, words, keywordMap) {
|
||||
|
||||
var tokens = text.toLowerCase().split(/[\.\s,`'"#]+/mg);
|
||||
var tokens = text.toLowerCase().split(/[.\s,`'"#]+/mg);
|
||||
_.forEach(tokens, function(token) {
|
||||
var match = token.match(KEYWORD_REGEX);
|
||||
if (match) {
|
||||
|
||||
@@ -13,14 +13,14 @@ module.exports = function generateVersionDocProcessor(gitData) {
|
||||
return {
|
||||
$runAfter: ['generatePagesDataProcessor'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
// the blacklist is to remove rogue builds that are in npm but not on code.angularjs.org
|
||||
// the blacklist is to remove rogue builds that are in the npm repository but not on code.angularjs.org
|
||||
blacklist: ['1.3.4-build.3588'],
|
||||
$process: function(docs) {
|
||||
|
||||
var blacklist = this.blacklist;
|
||||
var currentVersion = require('../../../build/version.json');
|
||||
var output = exec('npm info angular versions --json', { silent: true }).stdout;
|
||||
var allVersions = processAllVersionsResponse(JSON.parse(output));
|
||||
var output = exec('yarn info angular versions --json', { silent: true }).stdout.split('\n')[0];
|
||||
var allVersions = processAllVersionsResponse(JSON.parse(output).data);
|
||||
|
||||
docs.push({
|
||||
docType: 'current-version-data',
|
||||
|
||||
@@ -17,9 +17,9 @@ module.exports = function debugDeployment(getVersion) {
|
||||
'../angular-sanitize.js',
|
||||
'../angular-touch.js',
|
||||
'../angular-animate.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'components/marked-' + getVersion('marked') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.js',
|
||||
'components/lunr-' + getVersion('lunr') + '/lunr.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/current-version-data.js',
|
||||
@@ -32,6 +32,7 @@ module.exports = function debugDeployment(getVersion) {
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/angular-topnav.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
|
||||
@@ -17,9 +17,9 @@ module.exports = function defaultDeployment(getVersion) {
|
||||
'../angular-sanitize.min.js',
|
||||
'../angular-touch.min.js',
|
||||
'../angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'components/marked-' + getVersion('marked') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.min.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/current-version-data.js',
|
||||
@@ -32,6 +32,7 @@ module.exports = function defaultDeployment(getVersion) {
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/angular-topnav.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
|
||||
+3
-2
@@ -21,9 +21,9 @@ module.exports = function jqueryDeployment(getVersion) {
|
||||
'../angular-sanitize.min.js',
|
||||
'../angular-touch.min.js',
|
||||
'../angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'components/marked-' + getVersion('marked') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.min.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/current-version-data.js',
|
||||
@@ -36,6 +36,7 @@ module.exports = function jqueryDeployment(getVersion) {
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/angular-topnav.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
|
||||
@@ -13,9 +13,9 @@ var cdnUrl = googleCdnUrl + versionInfo.cdnVersion;
|
||||
// The currentVersion may not be available on the cdn (e.g. if built locally, or hasn't been pushed
|
||||
// yet). This will lead to a 404, but this is preferable to loading a version with which the example
|
||||
// might not work (possibly in subtle ways).
|
||||
var examplesCdnUrl = versionInfo.isSnapshot ?
|
||||
var examplesCdnUrl = versionInfo.currentVersion.isSnapshot ?
|
||||
(angularCodeUrl + 'snapshot') :
|
||||
(googleCdnUrl + (versionInfo.version || versionInfo.currentVersion));
|
||||
(googleCdnUrl + (versionInfo.currentVersion.version || versionInfo.currentVersion));
|
||||
|
||||
module.exports = function productionDeployment(getVersion) {
|
||||
return {
|
||||
@@ -34,9 +34,9 @@ module.exports = function productionDeployment(getVersion) {
|
||||
cdnUrl + '/angular-sanitize.min.js',
|
||||
cdnUrl + '/angular-touch.min.js',
|
||||
cdnUrl + '/angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'components/marked-' + getVersion('marked') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.min.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/lunr-' + getVersion('lunr') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/current-version-data.js',
|
||||
@@ -49,6 +49,7 @@ module.exports = function productionDeployment(getVersion) {
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/angular-topnav.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
|
||||
@@ -4,14 +4,14 @@ var path = require('canonical-path');
|
||||
/**
|
||||
* dgService getVersion
|
||||
* @description
|
||||
* Find the current version of the bower component (or npm module)
|
||||
* Find the current version of the bower component (or node module)
|
||||
*/
|
||||
module.exports = function getVersion(readFilesProcessor) {
|
||||
var basePath = readFilesProcessor.basePath;
|
||||
|
||||
return function(component, sourceFolder, packageFile) {
|
||||
sourceFolder = path.resolve(basePath, sourceFolder || 'docs/bower_components');
|
||||
packageFile = packageFile || 'bower.json';
|
||||
sourceFolder = path.resolve(basePath, sourceFolder || 'node_modules');
|
||||
packageFile = packageFile || 'package.json';
|
||||
return require(path.join(sourceFolder,component,packageFile)).version;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -68,101 +68,95 @@
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<body class="homepage">
|
||||
<div id="wrapper">
|
||||
<header scroll-y-offset-element class="header header-fixed">
|
||||
<section class="navbar navbar-inverse docs-navbar-primary" ng-controller="DocsSearchCtrl">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-9 header-branding">
|
||||
<a class="brand navbar-brand" href="http://angularjs.org">
|
||||
<img width="117" height="30" class="logo" alt="Link to Angular JS Homepage" ng-src="img/angularjs-for-header-only.svg">
|
||||
</a>
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="http://angularjs.org"><i class="icon-home icon-white"></i> Home</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="disabled"><a href="http://angularjs.org/">Why AngularJS?</a></li>
|
||||
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
|
||||
<li><a href="tutorial">Tutorial</a></li>
|
||||
<li><a href="https://www.madewithangular.com/">Case Studies</a></li>
|
||||
<li><a href="https://github.com/angular/angular-seed">Seed App project template</a></li>
|
||||
<li><a href="misc/faq">FAQ</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown active">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="tutorial">Tutorial</a></li>
|
||||
<li><a href="guide">Developer Guide</a></li>
|
||||
<li><a href="api">API Reference</a></li>
|
||||
<li><a href="error">Error Reference</a></li>
|
||||
<li><a href="misc/contribute">Contribute</a></li>
|
||||
<li><a href="http://code.angularjs.org/">Download</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-comment icon-white"></i> Discuss <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://blog.angularjs.org">Blog</a></li>
|
||||
<li><a href="http://groups.google.com/group/angular">Mailing List</a></li>
|
||||
<li><a href="http://webchat.freenode.net/?channels=angularjs&uio=d4">Chat Room</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="https://twitter.com/#!/angularjs">Twitter</a></li>
|
||||
<li><a href="https://plus.google.com/110323587230527980117">Google+</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="https://github.com/angular/angular.js">GitHub</a></li>
|
||||
<li><a href="https://github.com/angular/angular.js/issues">Issue Tracker</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<form ng-class="{focus:focus}" class="navbar-search col-md-3 docs-search" ng-submit="submit()">
|
||||
<span class="glyphicon glyphicon-search search-icon"></span>
|
||||
<input type="text"
|
||||
name="as_q"
|
||||
class="search-query"
|
||||
placeholder="Click or press / to search"
|
||||
ng-focus="focus=true"
|
||||
ng-blur="focus=false"
|
||||
ng-change="search(q)"
|
||||
ng-model="q"
|
||||
docs-search-input
|
||||
autocomplete="off" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-results-container" ng-show="hasResults">
|
||||
<header class="header" scroll-y-offset-element>
|
||||
<nav id="navbar-main" class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner" ng-controller="DocsSearchCtrl">
|
||||
<div class="container">
|
||||
<div class="search-results-frame">
|
||||
<div ng-repeat="(key, value) in results track by key" class="search-results-group" ng-class="colClassName + ' col-group-' + key" ng-show="value.length > 0">
|
||||
<h4 class="search-results-group-heading">{{ key }}</h4>
|
||||
<ul class="search-results">
|
||||
<!-- Do not insert a line break between li and a. Chrome will insert an actual line-break, which breaks the list item view.
|
||||
TODO: use a html minifier instead -->
|
||||
<li ng-repeat="item in value" class="search-result"><a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a></li>
|
||||
<h1 class="brand"><a href="http://angularjs.org"><img width="117" height="30" src="img/angularjs-for-header-only.svg" alt="AngularJS"></a></h1>
|
||||
|
||||
<form class="navbar-search" ng-submit="submit()">
|
||||
<i class="glyphicon glyphicon-search search-icon"></i>
|
||||
<input type="text" name="as_q" class="search-query" placeholder="SEARCH"
|
||||
ng-focus="focus=true"
|
||||
ng-blur="focus=false"
|
||||
ng-change="search(q)"
|
||||
ng-model="q"
|
||||
ng-model-options="{debounce: 150}"
|
||||
docs-search-input
|
||||
autocomplete="off">
|
||||
</form>
|
||||
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown" uib-dropdown>
|
||||
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Learn</a>
|
||||
<ul class="dropdown-menu" uib-dropdown-menu>
|
||||
<li><a href="tutorial">Tutorial</a></li>
|
||||
<li><a href="misc/faq">FAQ</a></li>
|
||||
<li><a href="https://www.youtube.com/user/angularjs">Videos</a></li>
|
||||
<li><a href="http://angular.codeschool.com/">Free Course</a></li>
|
||||
<li><a href="https://www.madewithangular.com/">Case Studies</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown" uib-dropdown>
|
||||
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Develop</a>
|
||||
<ul class="dropdown-menu" uib-dropdown-menu>
|
||||
<li><a href="guide">Developer Guide</a></li>
|
||||
<li><a href="api">API Reference</a></li>
|
||||
<li><a href="error">Error Reference</a></li>
|
||||
<li><a href="misc/contribute">Contribute</a></li>
|
||||
<li><a href="https://github.com/angular/angular-seed">Seed App project template</a></li>
|
||||
<li><a href="https://github.com/angular/angular.js">GitHub</a></li>
|
||||
<li><a href="http://code.angularjs.org/">Download</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown" uib-dropdown>
|
||||
<a href="#" class="dropdown-toggle" uib-dropdown-toggle>Discuss</a>
|
||||
<ul class="dropdown-menu" uib-dropdown-menu>
|
||||
<li><a href="http://blog.angularjs.org">Blog</a></li>
|
||||
<li><a href="https://twitter.com/angular">Twitter</a></li>
|
||||
<li><a href="https://plus.google.com/110323587230527980117">Google+</a></li>
|
||||
<li><a href="https://github.com/angular/angular.js/issues">Feature & Bug Tracker</a></li>
|
||||
<li><a href="http://groups.google.com/group/angular">Mailing List</a></li>
|
||||
<li><a href="http://webchat.freenode.net/?channels=angularjs&uio=d4">IRC</a></li>
|
||||
<li><a href="https://gitter.im/angular/angular.js">Gitter</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="search-results-container" ng-show="hasResults">
|
||||
<div class="container">
|
||||
<div class="search-results-frame">
|
||||
<div ng-repeat="(key, value) in results track by key" class="search-results-group" ng-class="colClassName + ' col-group-' + key" ng-show="value.length > 0">
|
||||
<h4 class="search-results-group-heading">{{ key }}</h4>
|
||||
<ul class="search-results">
|
||||
<li ng-repeat="item in value" class="search-result"><a ng-click="hideResults()" ng-href="{{ item.path }}">{{ item.name }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<a href="" ng-click="hideResults()" class="search-close">
|
||||
<span class="glyphicon glyphicon-remove search-close-icon"></span> Close
|
||||
</a>
|
||||
</div>
|
||||
<a href="" ng-click="hideResults()" class="search-close">
|
||||
<span class="glyphicon glyphicon-remove search-close-icon"></span> Close
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="sup-header">
|
||||
</nav>
|
||||
<nav id="navbar-notice" class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<p class="site-notice visible-phone">
|
||||
This site refers to AngularJS (v1.x). <a href="https://angular.io/">Go to the latest Angular</a>.
|
||||
</p>
|
||||
<p class="site-notice visible-desktop">
|
||||
This site and all of its contents are referring to AngularJS (version 1.x),
|
||||
if you are looking for the latest Angular, please visit <a href="https://angular.io/">angular.io</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<nav id="navbar-sub" class="sup-header navbar navbar-fixed-top">
|
||||
<div class="container main-grid main-header-grid">
|
||||
<div class="grid-left">
|
||||
<version-picker></version-picker>
|
||||
@@ -176,7 +170,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section role="main" class="container main-body">
|
||||
@@ -214,7 +208,7 @@
|
||||
<p class="pull-right"><a back-to-top>Back to top</a></p>
|
||||
|
||||
<p>
|
||||
Super-powered by Google ©2010-2016
|
||||
Super-powered by Google ©2010-2017
|
||||
(<a id="version"
|
||||
ng-href="https://github.com/angular/angular.js/blob/master/CHANGELOG.md#{{versionNumber}}"
|
||||
ng-bind-template="v{{version}}" title="Changelog of this version of Angular JS">
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
{% block examples %}
|
||||
{%- if doc.examples %}
|
||||
<h2 id="example">Example</h2>
|
||||
<h2 id="example">Examples</h2>
|
||||
{%- for example in doc.examples -%}
|
||||
{$ example | marked $}
|
||||
{%- endfor -%}
|
||||
|
||||
@@ -61,12 +61,12 @@
|
||||
</div>
|
||||
{% endblock -%}
|
||||
|
||||
{% include "lib/params.template.html" %}
|
||||
{% include "lib/events.template.html" %}
|
||||
|
||||
{%- if doc.animations %}
|
||||
<h2 id="animations">Animations</h2>
|
||||
{$ doc.animations | marked $}
|
||||
{$ 'module:ngAnimate.$animate' | link('Click here', doc) $} to learn more about the steps involved in the animation.
|
||||
{%- endif -%}
|
||||
|
||||
{% include "lib/params.template.html" %}
|
||||
{% include "lib/events.template.html" %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.npmjs.com/">NPM</a> e.g.
|
||||
{% code %}npm install {$ doc.packageName $}@X.Y.Z{% endcode %}
|
||||
{% code %}npm install --save {$ doc.packageName $}@X.Y.Z{% endcode %}
|
||||
or
|
||||
{% code %}yarn add {$ doc.packageName $}@X.Y.Z{% endcode %}
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://bower.io">Bower</a> e.g.
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
{$ lib.typeInfo(method.returns) $}
|
||||
{% endif %}
|
||||
|
||||
{%- if method.examples %}
|
||||
<h4 id="{$ doc.name $}.{$ method.name $}-examples">Examples</h4>
|
||||
{%- for example in method.examples -%}
|
||||
{$ example | marked $}
|
||||
{%- endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
</li>
|
||||
{% endfor -%}
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
@ngdoc error
|
||||
@name $animate:nongcls
|
||||
@fullName `ng-animate` class not allowed
|
||||
@description
|
||||
|
||||
This error occurs, when trying to set `$animateProvider.classNameFilter()` to a RegExp containing
|
||||
the reserved `ng-animate` class. Since `.ng-animate` will be added/removed by `$animate` itself,
|
||||
using it as part of the `classNameFilter` RegExp is not allowed.
|
||||
@@ -0,0 +1,11 @@
|
||||
@ngdoc error
|
||||
@name $sanitize:elclob
|
||||
@fullName Failed to sanitize html because the element is clobbered
|
||||
@description
|
||||
|
||||
This error occurs when `$sanitize` sanitizer is unable to traverse the HTML because one or more of the elements in the
|
||||
HTML have been "clobbered". This could be a sign that the payload contains code attempting to cause a DoS attack on the
|
||||
browser.
|
||||
|
||||
Typically clobbering breaks the `nextSibling` property on an element so that it points to one of its child nodes. This
|
||||
makes it impossible to walk the HTML tree without getting stuck in an infinite loop, which causes the browser to freeze.
|
||||
@@ -0,0 +1,7 @@
|
||||
@ngdoc error
|
||||
@name ng:aobj
|
||||
@fullName Invalid Argument
|
||||
@description
|
||||
|
||||
The argument passed should be an object. Check the value that was passed to the function where
|
||||
this error was thrown.
|
||||
@@ -232,27 +232,27 @@ than the hash fragment was changed.
|
||||
### Example
|
||||
|
||||
```js
|
||||
it('should show example', inject(
|
||||
function($locationProvider) {
|
||||
it('should show example', function() {
|
||||
module(function($locationProvider) {
|
||||
$locationProvider.html5Mode(false);
|
||||
$locationProvider.hashPrefix('!');
|
||||
},
|
||||
function($location) {
|
||||
});
|
||||
inject(function($location) {
|
||||
// open http://example.com/base/index.html#!/a
|
||||
$location.absUrl() === 'http://example.com/base/index.html#!/a'
|
||||
$location.path() === '/a'
|
||||
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/a');
|
||||
expect($location.path()).toBe('/a');
|
||||
|
||||
$location.path('/foo')
|
||||
$location.absUrl() === 'http://example.com/base/index.html#!/foo'
|
||||
$location.path('/foo');
|
||||
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo');
|
||||
|
||||
$location.search() === {}
|
||||
expect($location.search()).toEqual({});
|
||||
$location.search({a: 'b', c: true});
|
||||
$location.absUrl() === 'http://example.com/base/index.html#!/foo?a=b&c'
|
||||
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo?a=b&c');
|
||||
|
||||
$location.path('/new').search('x=y');
|
||||
$location.absUrl() === 'http://example.com/base/index.html#!/new?x=y'
|
||||
}
|
||||
));
|
||||
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/new?x=y');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## HTML5 mode
|
||||
@@ -274,40 +274,50 @@ and updates the url in a way that never performs a full page reload.
|
||||
### Example
|
||||
|
||||
```js
|
||||
it('should show example', inject(
|
||||
function($locationProvider) {
|
||||
it('should show example', function() {
|
||||
module(function($locationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
$locationProvider.hashPrefix('!');
|
||||
},
|
||||
function($location) {
|
||||
});
|
||||
inject(function($location) {
|
||||
// in browser with HTML5 history support:
|
||||
// open http://example.com/#!/a -> rewrite to http://example.com/a
|
||||
// (replacing the http://example.com/#!/a history record)
|
||||
$location.path() === '/a'
|
||||
expect($location.path()).toBe('/a');
|
||||
|
||||
$location.path('/foo');
|
||||
$location.absUrl() === 'http://example.com/foo'
|
||||
expect($location.absUrl()).toBe('http://example.com/foo');
|
||||
|
||||
$location.search() === {}
|
||||
expect($location.search()).toEqual({});
|
||||
$location.search({a: 'b', c: true});
|
||||
$location.absUrl() === 'http://example.com/foo?a=b&c'
|
||||
expect($location.absUrl()).toBe('http://example.com/foo?a=b&c');
|
||||
|
||||
$location.path('/new').search('x=y');
|
||||
$location.url() === 'new?x=y'
|
||||
$location.absUrl() === 'http://example.com/new?x=y'
|
||||
expect($location.url()).toBe('/new?x=y');
|
||||
expect($location.absUrl()).toBe('http://example.com/new?x=y');
|
||||
});
|
||||
});
|
||||
|
||||
it('should show example (when browser doesn\'t support HTML5 mode', function() {
|
||||
module(function($provide, $locationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
$locationProvider.hashPrefix('!');
|
||||
$provide.value('$sniffer', {history: false});
|
||||
});
|
||||
inject(initBrowser({ url: 'http://example.com/new?x=y', basePath: '/' }),
|
||||
function($location) {
|
||||
// in browser without html5 history support:
|
||||
// open http://example.com/new?x=y -> redirect to http://example.com/#!/new?x=y
|
||||
// (again replacing the http://example.com/new?x=y history item)
|
||||
$location.path() === '/new'
|
||||
$location.search() === {x: 'y'}
|
||||
expect($location.path()).toBe('/new');
|
||||
expect($location.search()).toEqual({x: 'y'});
|
||||
|
||||
$location.path('/foo/bar');
|
||||
$location.path() === '/foo/bar'
|
||||
$location.url() === '/foo/bar?x=y'
|
||||
$location.absUrl() === 'http://example.com/#!/foo/bar?x=y'
|
||||
}
|
||||
));
|
||||
expect($location.path()).toBe('/foo/bar');
|
||||
expect($location.url()).toBe('/foo/bar?x=y');
|
||||
expect($location.absUrl()).toBe('http://example.com/#!/foo/bar?x=y');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Fallback for legacy browsers
|
||||
@@ -555,7 +565,7 @@ In these examples we use `<base href="/base/index.html" />`. The inputs represen
|
||||
|
||||
</example>
|
||||
|
||||
####Browser in HTML5 Fallback mode (Hashbang mode)
|
||||
#### Browser in HTML5 Fallback mode (Hashbang mode)
|
||||
<example module="hashbang-mode" name="location-hashbang-mode">
|
||||
<file name="index.html">
|
||||
<div ng-controller="LocationController">
|
||||
|
||||
@@ -122,7 +122,7 @@ The same approach to animation can be used using JavaScript code (**jQuery is us
|
||||
```js
|
||||
myModule.animation('.repeated-item', function() {
|
||||
return {
|
||||
enter : function(element, done) {
|
||||
enter: function(element, done) {
|
||||
element.css('opacity',0);
|
||||
jQuery(element).animate({
|
||||
opacity: 1
|
||||
@@ -137,7 +137,7 @@ myModule.animation('.repeated-item', function() {
|
||||
}
|
||||
}
|
||||
},
|
||||
leave : function(element, done) {
|
||||
leave: function(element, done) {
|
||||
element.css('opacity', 1);
|
||||
jQuery(element).animate({
|
||||
opacity: 0
|
||||
@@ -152,7 +152,7 @@ myModule.animation('.repeated-item', function() {
|
||||
}
|
||||
}
|
||||
},
|
||||
move : function(element, done) {
|
||||
move: function(element, done) {
|
||||
element.css('opacity', 0);
|
||||
jQuery(element).animate({
|
||||
opacity: 1
|
||||
@@ -169,8 +169,8 @@ myModule.animation('.repeated-item', function() {
|
||||
},
|
||||
|
||||
// you can also capture these animation events
|
||||
addClass : function(element, className, done) {},
|
||||
removeClass : function(element, className, done) {}
|
||||
addClass: function(element, className, done) {},
|
||||
removeClass: function(element, className, done) {}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
@@ -149,7 +149,7 @@ You can see the complete application running below.
|
||||
<h1 class="title">Component Router</h1>
|
||||
<app></app>
|
||||
|
||||
<!-- Load up the router library - normally you might use npm and host it locally -->
|
||||
<!-- Load up the router library - normally you might use npm/yarn and host it locally -->
|
||||
<script src="https://unpkg.com/@angular/router@0.2.0/angular1/angular_1_router.js"></script>
|
||||
</file>
|
||||
|
||||
@@ -215,7 +215,7 @@ You can see the complete application running below.
|
||||
|
||||
|
||||
function HeroService($q) {
|
||||
var heroesPromise = $q.when([
|
||||
var heroesPromise = $q.resolve([
|
||||
{ id: 11, name: 'Mr. Nice' },
|
||||
{ id: 12, name: 'Narco' },
|
||||
{ id: 13, name: 'Bombasto' },
|
||||
@@ -308,7 +308,7 @@ You can see the complete application running below.
|
||||
|
||||
|
||||
function CrisisService($q) {
|
||||
var crisesPromise = $q.when([
|
||||
var crisesPromise = $q.resolve([
|
||||
{id: 1, name: 'Princess Held Captive'},
|
||||
{id: 2, name: 'Dragon Burning Cities'},
|
||||
{id: 3, name: 'Giant Asteroid Heading For Earth'},
|
||||
@@ -415,7 +415,7 @@ You can see the complete application running below.
|
||||
|
||||
function DialogService($q) {
|
||||
this.confirm = function(message) {
|
||||
return $q.when(window.confirm(message || 'Is it OK?'));
|
||||
return $q.resolve(window.confirm(message || 'Is it OK?'));
|
||||
};
|
||||
}
|
||||
</file>
|
||||
@@ -467,13 +467,12 @@ to display list and detail views of Heroes and Crises.
|
||||
|
||||
## Install the libraries
|
||||
|
||||
It is easier to use npm to install the **Component Router** module. For this guide we will also install
|
||||
AngularJS itself via npm:
|
||||
It is easier to use [Yarn](https://yarnpkg.com) or [npm](https://www.npmjs.com) to install the
|
||||
**Component Router** module. For this guide we will also install AngularJS itself via Yarn:
|
||||
|
||||
```bash
|
||||
npm init
|
||||
npm install angular@1.5.x --save
|
||||
npm install @angular/router@0.2.0 --save
|
||||
yarn init
|
||||
yarn add angular@1.5.x @angular/router@0.2.0
|
||||
```
|
||||
|
||||
|
||||
@@ -714,7 +713,7 @@ making an actual server request, perhaps over HTTP.
|
||||
|
||||
```js
|
||||
function HeroService($q) {
|
||||
var heroesPromise = $q.when([
|
||||
var heroesPromise = $q.resolve([
|
||||
{ id: 11, name: 'Mr. Nice' },
|
||||
...
|
||||
]);
|
||||
@@ -991,7 +990,7 @@ have made. The result of the prompt is a promise that can be used in a `$routerC
|
||||
|
||||
function DialogService($q) {
|
||||
this.confirm = function(message) {
|
||||
return $q.when(window.confirm(message || 'Is it OK?'));
|
||||
return $q.resolve(window.confirm(message || 'Is it OK?'));
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
@@ -78,6 +78,7 @@ It's also possible to add components via {@link $compileProvider#component} in a
|
||||
| link functions | Yes | No |
|
||||
| multiElement | Yes | No |
|
||||
| priority | Yes | No |
|
||||
| replace | Yes (deprecated) | No |
|
||||
| require | Yes | Yes |
|
||||
| restrict | Yes | No (restricted to elements only) |
|
||||
| scope | Yes (default: false) | No (scope is always isolate) |
|
||||
|
||||
@@ -120,11 +120,13 @@ The other forms shown above are accepted for legacy reasons but we advise you to
|
||||
|
||||
### Directive types
|
||||
|
||||
`$compile` can match directives based on element names, attributes, class names, as well as comments.
|
||||
`$compile` can match directives based on element names (E), attributes (A), class names (C),
|
||||
and comments (M).
|
||||
|
||||
All of the Angular-provided directives match attribute name, tag name, comments, or class name.
|
||||
The following demonstrates the various ways a directive (`myDir` in this case) can be referenced
|
||||
from within a template:
|
||||
The built-in the AngularJS directives show in their documentation page which type of matching they support.
|
||||
|
||||
The following demonstrates the various ways a directive that matches all 4 types
|
||||
(`myDir` in this case) can be referenced from within a template.
|
||||
|
||||
```html
|
||||
<my-dir></my-dir>
|
||||
@@ -133,6 +135,10 @@ from within a template:
|
||||
<span class="my-dir: exp;"></span>
|
||||
```
|
||||
|
||||
A directive can specify which of the 4 matching types it supports in the
|
||||
{@link ng.$compile#-restrict- `restrict`} property of the directive definition object.
|
||||
The default is `EA`.
|
||||
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** Prefer using directives via tag name and attributes over comment and class names.
|
||||
Doing so generally makes it easier to determine what directives a given element matches.
|
||||
|
||||
@@ -241,7 +241,7 @@ An expression that starts with `::` is considered a one-time expression. One-tim
|
||||
will stop recalculating once they are stable, which happens after the first digest if the expression
|
||||
result is a non-undefined value (see value stabilization algorithm below).
|
||||
|
||||
<example module="oneTimeBidingExampleApp" name="expression-one-time">
|
||||
<example module="oneTimeBindingExampleApp" name="expression-one-time">
|
||||
<file name="index.html">
|
||||
<div ng-controller="EventController">
|
||||
<button ng-click="clickMe($event)">Click Me</button>
|
||||
@@ -250,7 +250,7 @@ result is a non-undefined value (see value stabilization algorithm below).
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('oneTimeBidingExampleApp', []).
|
||||
angular.module('oneTimeBindingExampleApp', []).
|
||||
controller('EventController', ['$scope', function($scope) {
|
||||
var counter = 0;
|
||||
var names = ['Igor', 'Misko', 'Chirayu', 'Lucas'];
|
||||
@@ -265,24 +265,24 @@ result is a non-undefined value (see value stabilization algorithm below).
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should freeze binding after its value has stabilized', function() {
|
||||
var oneTimeBiding = element(by.id('one-time-binding-example'));
|
||||
var oneTimeBinding = element(by.id('one-time-binding-example'));
|
||||
var normalBinding = element(by.id('normal-binding-example'));
|
||||
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding:');
|
||||
expect(oneTimeBinding.getText()).toEqual('One time binding:');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding:');
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Igor');
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Misko');
|
||||
|
||||
element(by.buttonText('Click Me')).click();
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Lucas');
|
||||
});
|
||||
</file>
|
||||
|
||||
@@ -119,7 +119,8 @@ You can find a larger list of Angular external libraries at [ngmodules.org](http
|
||||
### Books
|
||||
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
|
||||
* [AngularJS Essentials (Free eBook)](https://www.packtpub.com/packt/free-ebook/angularjs-essentials) by Rodrigo Branas
|
||||
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
|
||||
* [AngularJS in Action](https://www.manning.com/books/angularjs-in-action) by Lukas Ruebbelke
|
||||
* [AngularJS: Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
|
||||
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
|
||||
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
|
||||
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
|
||||
|
||||
@@ -28,8 +28,8 @@ for other directives to augment its behavior.
|
||||
<form novalidate class="simple-form">
|
||||
<label>Name: <input type="text" ng-model="user.name" /></label><br />
|
||||
<label>E-mail: <input type="email" ng-model="user.email" /></label><br />
|
||||
Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
|
||||
<label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
|
||||
Best Editor: <label><input type="radio" ng-model="user.preference" value="vi" />vi</label>
|
||||
<label><input type="radio" ng-model="user.preference" value="emacs" />emacs</label><br />
|
||||
<input type="button" ng-click="reset()" value="Reset" />
|
||||
<input type="submit" ng-click="update(user)" value="Save" />
|
||||
</form>
|
||||
@@ -363,7 +363,7 @@ In the following example we create two directives:
|
||||
<file name="script.js">
|
||||
var app = angular.module('form-example1', []);
|
||||
|
||||
var INTEGER_REGEXP = /^\-?\d+$/;
|
||||
var INTEGER_REGEXP = /^-?\d+$/;
|
||||
app.directive('integer', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
@@ -396,7 +396,7 @@ In the following example we create two directives:
|
||||
|
||||
if (ctrl.$isEmpty(modelValue)) {
|
||||
// consider empty model valid
|
||||
return $q.when();
|
||||
return $q.resolve();
|
||||
}
|
||||
|
||||
var def = $q.defer();
|
||||
|
||||
@@ -26,7 +26,7 @@ directive}. Additionally, you can use {@link guide/i18n#messageformat-extension
|
||||
All localizable Angular components depend on locale-specific rule sets managed by the {@link
|
||||
ng.$locale `$locale` service}.
|
||||
|
||||
There a few examples that showcase how to use Angular filters with various locale rule sets in the
|
||||
There are a few examples that showcase how to use Angular filters with various locale rule sets in the
|
||||
[`i18n/e2e` directory](https://github.com/angular/angular.js/tree/master/i18n/e2e) of the Angular
|
||||
source code.
|
||||
|
||||
@@ -85,7 +85,7 @@ requires German locale, you would serve index_de-de.html which will look somethi
|
||||
|
||||
Both approaches described above require you to prepare different `index.html` pages or JavaScript
|
||||
files for each locale that your app may use. You also need to configure your server to serve
|
||||
the correct file that correspond to the desired locale.
|
||||
the correct file that corresponds to the desired locale.
|
||||
|
||||
The second approach (including the locale JavaScript file in `index.html`) may be slower because
|
||||
an extra script needs to be loaded.
|
||||
|
||||
@@ -88,7 +88,9 @@ commits for more info.
|
||||
|
||||
- **jqLite** is more aligned to jQuery 3, which required the following changes
|
||||
(see [details](guide/migration#migrate1.5to1.6-ng-misc-jqLite) below):
|
||||
- Keys passed to `.data()` and `.css()` are now camelCased in the same as jQuery does it.
|
||||
- Keys passed to `.data()` and `.css()` are now camelCased in the same way as the jQuery methods
|
||||
do.
|
||||
- Getting/setting boolean attributes no longer takes the corresponding properties into account.
|
||||
- Setting boolean attributes to empty string no longer removes the attribute.
|
||||
- Calling `.val()` on a multiple select will always return an array, even if no option is
|
||||
selected.
|
||||
@@ -114,6 +116,7 @@ Below is the full list of breaking changes:
|
||||
- Core:
|
||||
- [Directives](guide/migration#migrate1.5to1.6-ng-directives)
|
||||
- [form](guide/migration#migrate1.5to1.6-ng-directives-form)
|
||||
- [input[number]](guide/migration#migrate1.5to1.6-ng-directives-input[number])
|
||||
- [input[radio]](guide/migration#migrate1.5to1.6-ng-directives-input[radio])
|
||||
- [input[range]](guide/migration#migrate1.5to1.6-ng-directives-input[range])
|
||||
- [ngBind](guide/migration#migrate1.5to1.6-ng-directives-ngBind)
|
||||
@@ -166,6 +169,38 @@ $scope.$watch('something', function() {
|
||||
or you can use `Function.prototype.bind` or `angular.bind`.
|
||||
|
||||
|
||||
<a name="migrate1.5to1.6-ng-directives-input[number]"></a>
|
||||
#### **input[type=number]**:
|
||||
|
||||
<minor />
|
||||
**Due to [e1da4be](https://github.com/angular/angular.js/commit/e1da4bed8e291003d485a8ad346ab80bed8ae2e3)**,
|
||||
number inputs that use `ngModel` and specify a `step` constraint (via `step`/`ngStep` attributes)
|
||||
will now have a new validator (`step`), which will verify that the current value is valid under the
|
||||
`step` constraint (according to the [spec](https://www.w3.org/TR/html5/forms.html#the-step-attribute)).
|
||||
Previously, the `step` constraint was ignored by `ngModel`, treating values as valid even when there
|
||||
was a step-mismatch.
|
||||
|
||||
If you want to restore the previous behavior (use the `step` attribute while disabling step
|
||||
validation), you can overwrite the built-in `step` validator with a custom directive. For example:
|
||||
|
||||
```js
|
||||
// For all `input` elements...
|
||||
.directive('input', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: '?ngModel',
|
||||
link: function (scope, elem, attrs, ngModelCtrl) {
|
||||
// ...that are of type "number" and have `ngModel`...
|
||||
if ((attrs.type === 'number') && ngModelCtrl) {
|
||||
// ...remove the `step` validator.
|
||||
delete ngModelCtrl.$validators.step;
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
<a name="migrate1.5to1.6-ng-directives-input[radio]"></a>
|
||||
#### **input[type=radio]**:
|
||||
|
||||
@@ -382,9 +417,9 @@ it back on, which should help during the migration. Pre-assigning bindings has b
|
||||
will be removed in a future version, so we strongly recommend migrating your applications to not
|
||||
rely on it as soon as possible.
|
||||
|
||||
Initialization logic that relies on relies on bindings being present should be put in the
|
||||
controller's `$onInit()` method, which is guarranteed to always be called _after_ the bindings have
|
||||
been assigned.
|
||||
Initialization logic that relies on bindings being present should be put in the controller's
|
||||
`$onInit()` method, which is guaranteed to always be called _after_ the bindings have been
|
||||
assigned.
|
||||
|
||||
Before:
|
||||
|
||||
@@ -468,7 +503,7 @@ running at `https://docs.angularjs.org` then the following will fail:
|
||||
<link href="{{ 'http://mydomain.org/unsafe.css' }}" rel="stylesheet" />
|
||||
```
|
||||
|
||||
By default, only URLs with the same domain and prototocl as the application document are considered
|
||||
By default, only URLs with the same domain and protocol as the application document are considered
|
||||
safe in the `RESOURCE_URL` context. To use URLs from other domains and/or protocols, you may either
|
||||
whitelist them or wrap them into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
|
||||
|
||||
@@ -847,6 +882,48 @@ var bgColor = elem.css('background-color');
|
||||
var bgColor = elem.css('backgroundColor');
|
||||
```
|
||||
|
||||
<hr />
|
||||
<major />
|
||||
**Due to [7ceb5f](https://github.com/angular/angular.js/commit/7ceb5f6fcc43d35d1b66c3151ce6a71c60309304)**,
|
||||
getting/setting boolean attributes will no longer take the corresponding properties into account.
|
||||
Previously, all boolean attributes were reflected into the corresponding property when calling a
|
||||
setter and from the corresponding property when calling a getter, even on elements that don't treat
|
||||
those attributes in a special way. Now Angular doesn't do it by itself, but relies on browsers to
|
||||
know when to reflect the property. Note that this browser-level conversion differs between browsers;
|
||||
if you need to dynamically change the state of an element, you should modify the property, not the
|
||||
attribute. See https://jquery.com/upgrade-guide/1.9/#attr-versus-prop- for a more detailed
|
||||
description about a related change in jQuery 1.9.
|
||||
|
||||
This change aligns jqLite with jQuery 3. To migrate the code follow the example below:
|
||||
|
||||
Before:
|
||||
|
||||
```css
|
||||
/* CSS */
|
||||
|
||||
input[checked="checked"] { ... }
|
||||
```
|
||||
```js
|
||||
// JS
|
||||
|
||||
elem1.attr('checked', 'checked');
|
||||
elem2.attr('checked', false);
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```css
|
||||
/* CSS */
|
||||
|
||||
input:checked { ... }
|
||||
```
|
||||
```js
|
||||
// JS
|
||||
|
||||
elem1.prop('checked', true);
|
||||
elem2.prop('checked', false);
|
||||
```
|
||||
|
||||
<hr />
|
||||
<major />
|
||||
**Due to [3faf45](https://github.com/angular/angular.js/commit/3faf4505732758165083c9d21de71fa9b6983f4a)**,
|
||||
@@ -1136,7 +1213,7 @@ with an unencoded `;` character.
|
||||
Previously, in cases where `ngView` was loaded asynchronously, `$route` (and its dependencies) might
|
||||
also have been instantiated asynchronously.
|
||||
|
||||
Although this is not expected to have unwanted side-effects in normal application bebavior, it may
|
||||
Although this is not expected to have unwanted side-effects in normal application behavior, it may
|
||||
affect your unit tests: When testing a module that (directly or indirectly) depends on `ngRoute`, a
|
||||
request will be made for the default route's template. If not properly "trained", `$httpBackend`
|
||||
will complain about this unexpected request. You can restore the previous behavior (and avoid
|
||||
@@ -1241,6 +1318,11 @@ and was not consistent with other filters (e.g. `filter`).
|
||||
Objects considered array-like include: arrays, array subclasses, strings, NodeLists,
|
||||
jqLite/jQuery collections
|
||||
|
||||
#### Helper Functions:
|
||||
|
||||
The {@link angular.lowercase `angular.lowercase`} and {@link angular.uppercase `angular.uppercase`} functions have been **deprecated** and will be removed
|
||||
in version 1.7.0. It is recommended to use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) and [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) functions instead.
|
||||
|
||||
|
||||
### ngAria
|
||||
|
||||
@@ -1372,9 +1454,8 @@ For more info on the topic, you can take a look at this
|
||||
|
||||
## Migrating from 1.3 to 1.4
|
||||
|
||||
Angular 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
|
||||
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions `and some fixes to core filters:
|
||||
`limitTo` and `filter`.
|
||||
AngularJS 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
|
||||
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions`, `ngPattern`, `pattern` and some fixes to core filters: `limitTo` and `filter`.
|
||||
|
||||
The reason for the ngAnimate refactor was to fix timing issues and to expose new APIs to allow
|
||||
for developers to construct more versatile animations. We now have access to `$animateCss`
|
||||
@@ -1387,9 +1468,9 @@ to render error messages with ngMessages that are listed with a directive such a
|
||||
involves pulling error message data from a server and then displaying that data via the mechanics of ngMessages. Be
|
||||
sure to read the breaking change involved with `ngMessagesInclude` to upgrade your template code.
|
||||
|
||||
Other changes, such as the ordering of elements with ngRepeat and ngOptions, may also affect the behavior of your
|
||||
application. And be sure to also read up on the changes to `$cookies`. The migration jump from 1.3 to 1.4 should be
|
||||
relatively straightforward otherwise.
|
||||
Other changes, such as the ordering of elements with ngRepeat and ngOptions and the way ngPattern and pattern directives
|
||||
validate the regex, may also affect the behavior of your application. And be sure to also read up on the changes to `$cookies`.
|
||||
The migration jump from 1.3 to 1.4 should be relatively straightforward otherwise.
|
||||
|
||||
|
||||
|
||||
@@ -1493,7 +1574,7 @@ class based animations (animations triggered via ngClass) in order to ensure tha
|
||||
|
||||
|
||||
|
||||
### Forms (`ngMessages`, `ngOptions`, `select`)
|
||||
### Forms (`ngMessages`, `ngOptions`, `select`, `ngPattern` and `pattern`)
|
||||
|
||||
#### ngMessages
|
||||
The ngMessages module has also been subject to an internal refactor to allow it to be more flexible
|
||||
@@ -1601,6 +1682,79 @@ ngModelCtrl.$formatters.push(function(value) {
|
||||
});
|
||||
```
|
||||
|
||||
#### ngPattern and pattern
|
||||
|
||||
Due to [0e001084](https://github.com/angular/angular.js/commit/0e001084ffff8674efad289d37cb16cc4e46b50a),
|
||||
The `ngPattern` and `pattern` directives will validate the regex
|
||||
against the `$viewValue` of `ngModel`, i.e. the value of the model
|
||||
before the $parsers are applied. Previously, the `$modelValue`
|
||||
(the result of the $parsers) was validated.
|
||||
|
||||
This fixes issues where `input[date]` and `input[number]` cannot
|
||||
be validated because the `$viewValue` string is parsed into
|
||||
`Date` and `Number` respectively (starting with Angular 1.3).
|
||||
It also brings the directives in line with HTML5 constraint
|
||||
validation, which validates against the input value.
|
||||
|
||||
This change is unlikely to cause applications to fail, because even
|
||||
in Angular 1.2, the value that was validated by pattern could have
|
||||
been manipulated by the $parsers, as all validation was done
|
||||
inside this pipeline.
|
||||
|
||||
If you rely on the pattern being validated against the `$modelValue`,
|
||||
you must create your own validator directive that overwrites
|
||||
the built-in pattern validator:
|
||||
|
||||
```
|
||||
.directive('patternModelOverwrite', function patternModelOverwriteDirective() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '?ngModel',
|
||||
priority: 1,
|
||||
compile: function() {
|
||||
var regexp, patternExp;
|
||||
|
||||
return {
|
||||
pre: function(scope, elm, attr, ctrl) {
|
||||
if (!ctrl) return;
|
||||
|
||||
attr.$observe('pattern', function(regex) {
|
||||
/**
|
||||
* The built-in directive will call our overwritten validator
|
||||
* (see below). We just need to update the regex.
|
||||
* The preLink fn guaranetees our observer is called first.
|
||||
*/
|
||||
if (isString(regex) && regex.length > 0) {
|
||||
regex = new RegExp('^' + regex + '$');
|
||||
}
|
||||
|
||||
if (regex && !regex.test) {
|
||||
//The built-in validator will throw at this point
|
||||
return;
|
||||
}
|
||||
|
||||
regexp = regex || undefined;
|
||||
});
|
||||
|
||||
},
|
||||
post: function(scope, elm, attr, ctrl) {
|
||||
if (!ctrl) return;
|
||||
|
||||
regexp, patternExp = attr.ngPattern || attr.pattern;
|
||||
|
||||
//The postLink fn guarantees we overwrite the built-in pattern validator
|
||||
ctrl.$validators.pattern = function(value) {
|
||||
return ctrl.$isEmpty(value) ||
|
||||
isUndefined(regexp) ||
|
||||
regexp.test(value);
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### form
|
||||
|
||||
@@ -2567,7 +2721,7 @@ See [38deedd6](https://github.com/angular/angular.js/commit/38deedd6e3d806eb8262
|
||||
|
||||
### Interpolations inside DOM event handlers are now disallowed
|
||||
|
||||
DOM event handlers execute arbitrary Javascript code. Using an interpolation for such handlers
|
||||
DOM event handlers execute arbitrary JavaScript code. Using an interpolation for such handlers
|
||||
means that the interpolated value is a JS string that is evaluated. Storing or generating such
|
||||
strings is error prone and leads to XSS vulnerabilities. On the other hand, `ngClick` and other
|
||||
Angular specific event handlers evaluate Angular expressions in non-window (Scope) context which
|
||||
|
||||
@@ -221,8 +221,8 @@ it('should clear messages after alert', function() {
|
||||
notify('two');
|
||||
notify('third');
|
||||
|
||||
expect(mock.alert.callCount).toEqual(2);
|
||||
expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]);
|
||||
expect(mock.alert.calls.count()).toEqual(2);
|
||||
expect(mock.alert.calls.mostRecent().args).toEqual(["more\ntwo\nthird"]);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ curly-brace {@link expression expression} bindings:
|
||||
<!-- Body tag augmented with ngController directive -->
|
||||
<body ng-controller="MyController">
|
||||
<input ng-model="foo" value="bar">
|
||||
<!-- Button tag with ng-click directive, and
|
||||
<!-- Button tag with ngClick directive, and
|
||||
string expression 'buttonText'
|
||||
wrapped in "{{ }}" markup -->
|
||||
<button ng-click="changeFoo()">{{buttonText}}</button>
|
||||
|
||||
@@ -59,7 +59,7 @@ Karma to run against a number of browsers, which is useful for being confident t
|
||||
works on all browsers you need to support. Karma is executed on the command line and will display
|
||||
the results of your tests on the command line once they have run in the browser.
|
||||
|
||||
Karma is a NodeJS application, and should be installed through npm. Full installation instructions
|
||||
Karma is a NodeJS application, and should be installed through npm/yarn. Full installation instructions
|
||||
are available on [the Karma website](http://karma-runner.github.io/0.12/intro/installation.html).
|
||||
|
||||
### Jasmine
|
||||
@@ -461,7 +461,7 @@ describe("Deep Thought", function() {
|
||||
}));
|
||||
|
||||
it("has calculated the answer correctly", inject(function(DeepThought) {
|
||||
// Because of sharedInjector, we have access to the instance of the DeepThought service
|
||||
// Because of sharedInjector, we have access to the instance of the DeepThought service
|
||||
// that was provided to the beforeAll() hook. Therefore we can test the generated answer
|
||||
expect(DeepThought.answer).toBe(42);
|
||||
}));
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Building and Testing AngularJS
|
||||
|
||||
This document describes how to set up your development environment to build and test AngularJS, and
|
||||
explains the basic mechanics of using `git`, `node`, `npm`, `grunt`, and `bower`.
|
||||
explains the basic mechanics of using `git`, `node`, `yarn`, `grunt`, and `bower`.
|
||||
|
||||
See the [contributing guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md)
|
||||
for how to contribute your own code to AngularJS.
|
||||
@@ -24,20 +24,27 @@ Before you can build AngularJS, you must install and configure the following dep
|
||||
machine:
|
||||
|
||||
* [Git](http://git-scm.com/): The [Github Guide to
|
||||
Installing Git](https://help.github.com/articles/set-up-git) is a good source of information.
|
||||
Installing Git](https://help.github.com/articles/set-up-git) is a good source of information.
|
||||
|
||||
* [Node.js v4.x](http://nodejs.org): We use Node to generate the documentation, run a
|
||||
development web server, run tests, and generate distributable files. Depending on your system, you can install Node either from source or as a
|
||||
pre-packaged bundle. (Currently our build does not work properly on Node v5 or greater - please use v4.x.)
|
||||
* [Node.js v6.x (LTS)](http://nodejs.org): We use Node to generate the documentation, run a
|
||||
development web server, run tests, and generate distributable files. Depending on your system,
|
||||
you can install Node either from source or as a pre-packaged bundle.
|
||||
|
||||
We recommend using [nvm](https://github.com/creationix/nvm) (or [nvm-windows](https://github.com/coreybutler/nvm-windows))
|
||||
to manage and install Node.js, which makes it easy to change the version of Node.js per project.
|
||||
|
||||
* [Yarn](https://yarnpkg.com): We use Yarn to install our Node.js module dependencies (rather than using npm).
|
||||
There are detailed installation instructions available at https://yarnpkg.com/en/docs/install.
|
||||
|
||||
* [Java](http://www.java.com): We minify JavaScript using our
|
||||
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 7 or higher) installed
|
||||
and included in your [PATH](http://docs.oracle.com/javase/tutorial/essential/environment/paths.html) variable.
|
||||
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 7 or higher)
|
||||
installed and included in your [PATH](http://docs.oracle.com/javase/tutorial/essential/environment/paths.html)
|
||||
variable.
|
||||
|
||||
* [Grunt](http://gruntjs.com): We use Grunt as our build system. Install the grunt command-line tool globally with:
|
||||
|
||||
```shell
|
||||
npm install -g grunt-cli
|
||||
yarn global add grunt-cli
|
||||
```
|
||||
|
||||
## Forking Angular on Github
|
||||
@@ -62,12 +69,9 @@ cd angular.js
|
||||
git remote add upstream "https://github.com/angular/angular.js.git"
|
||||
|
||||
# Install node.js dependencies:
|
||||
npm install
|
||||
yarn install
|
||||
|
||||
# Install bower components:
|
||||
bower install
|
||||
|
||||
# Build AngularJS:
|
||||
# Build AngularJS (which will install `bower` dependencies automatically):
|
||||
grunt package
|
||||
```
|
||||
|
||||
@@ -78,11 +82,11 @@ Administrator). This is because `grunt package` creates some symbolic links.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** If you're using Linux, and npm install fails with the message
|
||||
'Please try running this command again as root/Administrator.', you may need to globally install grunt and bower:
|
||||
**Note:** If you're using Linux, and `yarn install` fails with the message
|
||||
'Please try running this command again as root/Administrator.', you may need to globally install `grunt` and `bower`:
|
||||
<ul>
|
||||
<li>sudo npm install -g grunt-cli</li>
|
||||
<li>sudo npm install -g bower</li>
|
||||
<li>sudo yarn global add grunt-cli</li>
|
||||
<li>sudo yarn global add bower</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
@@ -136,13 +140,13 @@ tests once on Chrome run:
|
||||
grunt test:unit
|
||||
```
|
||||
|
||||
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
|
||||
To run the tests on other browsers (Chrome, ChromeCanary, Firefox and Safari are pre-configured) use:
|
||||
|
||||
```shell
|
||||
grunt test:unit --browsers=Opera,Firefox
|
||||
grunt test:unit --browsers=Chrome,Firefox
|
||||
```
|
||||
|
||||
Note there should be _no spaces between browsers_. `Opera, Firefox` is INVALID.
|
||||
Note there should be _no spaces between browsers_. `Chrome, Firefox` is INVALID.
|
||||
|
||||
During development, however, it's more productive to continuously run unit tests every time the source or test files
|
||||
change. To execute tests in this mode run:
|
||||
|
||||
@@ -77,6 +77,8 @@ AngularJS was designed to be compatible with other security measures like Conten
|
||||
(CSP), HTTPS (SSL/TLS) and server-side authentication and authorization that greatly reduce the
|
||||
possible attack vectors and we highly recommend their use.
|
||||
|
||||
Please read {@link security} for more detailed information about securing Angular apps.
|
||||
|
||||
|
||||
### Can I download the source, build, and host the AngularJS environment locally?
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ tutorials.
|
||||
## Subscribe
|
||||
|
||||
* Subscribe to the [mailing list](http://groups.google.com/forum/?fromgroups#!forum/angular). Ask questions here!
|
||||
* Follow us on [Twitter](https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F®ion=follow_link&screen_name=angularjs&source=followbutton&variant=2.0)
|
||||
* Follow us on [Twitter](https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F®ion=follow_link&screen_name=angular&source=followbutton&variant=2.0)
|
||||
* Add us to your circles on [Google+](https://plus.google.com/110323587230527980117/posts)
|
||||
|
||||
## Read more
|
||||
|
||||
@@ -54,7 +54,7 @@ We will keep this in mind though, as we add more features.
|
||||
So, now that we learned we should put everything in its own file, our `app/` directory will soon be
|
||||
full with dozens of files and specs (remember we keep our unit test files next to the corresponding
|
||||
source code files). What's more important, logically related files will not be grouped together; it
|
||||
will be really difficult of locate all files related to a specific section of the application and
|
||||
will be really difficult to locate all files related to a specific section of the application and
|
||||
make a change or fix a bug.
|
||||
|
||||
So, what shall we do?
|
||||
|
||||
@@ -194,7 +194,7 @@ angular.module('phonecatApp', [
|
||||
```
|
||||
|
||||
Now, in addition to the core services and directives, we can also configure the `$route` service
|
||||
(using it's provider) for our application. In order to be able to quickly locate the configuration
|
||||
(using its provider) for our application. In order to be able to quickly locate the configuration
|
||||
code, we put it into a separate file and used the `.config` suffix.
|
||||
|
||||
<br />
|
||||
|
||||
@@ -173,7 +173,10 @@ angular.module('phoneList', ['core.phone']);
|
||||
**`app/phone-detail/phone-detail.module.js`:**
|
||||
|
||||
```js
|
||||
angular.module('phoneDetail', ['core.phone']);
|
||||
angular.module('phoneDetail', [
|
||||
'ngRoute',
|
||||
'core.phone'
|
||||
]);
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
+6
-21
@@ -1,10 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var gulp = require('gulp');
|
||||
var log = require('gulp-util').log;
|
||||
var concat = require('gulp-concat');
|
||||
var eslint = require('gulp-eslint');
|
||||
var bower = require('bower');
|
||||
var Dgeni = require('dgeni');
|
||||
var merge = require('event-stream').merge;
|
||||
var path = require('canonical-path');
|
||||
@@ -18,7 +16,6 @@ var rename = require('gulp-rename');
|
||||
// See clean and bower for async tasks, and see assets and doc-gen for dependent tasks below
|
||||
|
||||
var outputFolder = '../build/docs';
|
||||
var bowerFolder = 'bower_components';
|
||||
|
||||
var src = 'app/src/**/*.js';
|
||||
var ignoredFiles = '!src/angular.bind.js';
|
||||
@@ -57,8 +54,8 @@ var getMergedEslintConfig = function(filepath) {
|
||||
|
||||
var copyComponent = function(component, pattern, sourceFolder, packageFile) {
|
||||
pattern = pattern || '/**/*';
|
||||
sourceFolder = sourceFolder || bowerFolder;
|
||||
packageFile = packageFile || 'bower.json';
|
||||
sourceFolder = sourceFolder || '../node_modules';
|
||||
packageFile = packageFile || 'package.json';
|
||||
var version = require(path.resolve(sourceFolder, component, packageFile)).version;
|
||||
return gulp
|
||||
.src(sourceFolder + '/' + component + pattern)
|
||||
@@ -66,18 +63,6 @@ var copyComponent = function(component, pattern, sourceFolder, packageFile) {
|
||||
};
|
||||
|
||||
|
||||
gulp.task('bower', function() {
|
||||
var bowerTask = bower.commands.install();
|
||||
bowerTask.on('log', function(result) {
|
||||
log('bower:', result.id, result.data.endpoint.name);
|
||||
});
|
||||
bowerTask.on('error', function(error) {
|
||||
log(error);
|
||||
});
|
||||
return bowerTask;
|
||||
});
|
||||
|
||||
|
||||
gulp.task('build-app', function() {
|
||||
var file = 'docs.js';
|
||||
var minFile = 'docs.min.js';
|
||||
@@ -94,7 +79,7 @@ gulp.task('build-app', function() {
|
||||
});
|
||||
|
||||
|
||||
gulp.task('assets', ['bower'], function() {
|
||||
gulp.task('assets', function() {
|
||||
var JS_EXT = /\.js$/;
|
||||
return merge(
|
||||
gulp.src(['img/**/*']).pipe(gulp.dest(outputFolder + '/img')),
|
||||
@@ -113,15 +98,15 @@ gulp.task('assets', ['bower'], function() {
|
||||
})),
|
||||
copyComponent('bootstrap', '/dist/**/*'),
|
||||
copyComponent('open-sans-fontface'),
|
||||
copyComponent('lunr.js', '/*.js'),
|
||||
copyComponent('lunr', '/*.js'),
|
||||
copyComponent('google-code-prettify'),
|
||||
copyComponent('jquery', '/dist/*.js'),
|
||||
copyComponent('marked', '/**/*.js', '../node_modules', 'package.json')
|
||||
copyComponent('marked', '/**/*.js')
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
gulp.task('doc-gen', ['bower'], function() {
|
||||
gulp.task('doc-gen', function() {
|
||||
var dgeni = new Dgeni([require('./config')]);
|
||||
return dgeni.generate().catch(function() {
|
||||
process.exit(1);
|
||||
|
||||
+4
-5
@@ -3,14 +3,13 @@
|
||||
set -e
|
||||
|
||||
BASE_DIR=`dirname $0`
|
||||
cd $BASE_DIR
|
||||
|
||||
npm run test-i18n
|
||||
yarn run test-i18n
|
||||
|
||||
node src/closureSlurper.js
|
||||
node $BASE_DIR/src/closureSlurper.js
|
||||
|
||||
npm run test-i18n-ucd
|
||||
yarn run test-i18n-ucd
|
||||
|
||||
echo "Generating ngParseExt"
|
||||
node ucd/src/extract.js
|
||||
node $BASE_DIR/ucd/src/extract.js
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Script to initialize angular repo
|
||||
# - install required node packages
|
||||
# - install Karma
|
||||
# - install git hooks
|
||||
|
||||
|
||||
node=`which node 2>&1`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Please install NodeJS."
|
||||
echo "http://nodejs.org/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
npm=`which npm 2>&1`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Please install NPM."
|
||||
fi
|
||||
|
||||
|
||||
echo "Installing required npm packages..."
|
||||
npm install
|
||||
|
||||
karma=`which karma 2>&1`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Installing Karma..."
|
||||
npm install -g karma
|
||||
fi
|
||||
|
||||
echo "Installing git hooks..."
|
||||
ln -sf ../../validate-commit-msg.js .git/hooks/commit-msg
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
var bower = require('bower');
|
||||
var util = require('./utils.js');
|
||||
var shelljs = require('shelljs');
|
||||
var npmRun = require('npm-run');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
@@ -39,10 +39,7 @@ module.exports = function(grunt) {
|
||||
|
||||
|
||||
grunt.registerTask('docs', 'create angular docs', function() {
|
||||
var gruntProc = shelljs.exec('npm run gulp -- --gulpfile docs/gulpfile.js');
|
||||
if (gruntProc.code !== 0) {
|
||||
throw new Error('doc generation failed');
|
||||
}
|
||||
npmRun.execSync('gulp --gulpfile docs/gulpfile.js', {stdio: 'inherit'});
|
||||
});
|
||||
|
||||
|
||||
|
||||
+5
-5
@@ -3,7 +3,7 @@
|
||||
var fs = require('fs');
|
||||
var shell = require('shelljs');
|
||||
var grunt = require('grunt');
|
||||
var spawn = require('cross-spawn');
|
||||
var spawn = require('npm-run').spawn;
|
||||
|
||||
var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP mode. */\n\n';
|
||||
|
||||
@@ -15,7 +15,7 @@ module.exports = {
|
||||
var reporters = grunt.option('reporters');
|
||||
var noColor = grunt.option('no-colors');
|
||||
var port = grunt.option('port');
|
||||
var p = spawn('./node_modules/.bin/karma', ['start', config,
|
||||
var p = spawn('karma', ['start', config,
|
||||
singleRun ? '--single-run=true' : '',
|
||||
reporters ? '--reporters=' + reporters : '',
|
||||
browsers ? '--browsers=' + browsers : '',
|
||||
@@ -38,7 +38,7 @@ module.exports = {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
var p = spawn('./node_modules/.bin/webdriver-manager', ['update']);
|
||||
var p = spawn('webdriver-manager', ['update']);
|
||||
p.stdout.pipe(process.stdout);
|
||||
p.stderr.pipe(process.stderr);
|
||||
p.on('exit', function(code) {
|
||||
@@ -65,7 +65,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
|
||||
var p = spawn('./node_modules/.bin/protractor', args);
|
||||
var p = spawn('protractor', args);
|
||||
p.stdout.pipe(process.stdout);
|
||||
p.stderr.pipe(process.stderr);
|
||||
p.on('exit', function(code) {
|
||||
@@ -178,7 +178,7 @@ module.exports = {
|
||||
var classPathSep = (process.platform === 'win32') ? ';' : ':';
|
||||
var minFile = file.replace(/\.js$/, '.min.js');
|
||||
var mapFile = minFile + '.map';
|
||||
var mapFileName = mapFile.match(/[^\/]+$/)[0];
|
||||
var mapFileName = mapFile.match(/[^/]+$/)[0];
|
||||
var errorFileName = file.replace(/\.js$/, '-errors.json');
|
||||
var versionNumber = grunt.config('NG_VERSION').full;
|
||||
var compilationLevel = (file === 'build/angular-message-format.js') ?
|
||||
|
||||
@@ -11,7 +11,7 @@ set -e
|
||||
# Curl and run this script as part of your .travis.yml before_script section:
|
||||
# before_script:
|
||||
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
|
||||
SC_VERSION="4.3.16"
|
||||
SC_VERSION="4.4.1"
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-$SC_VERSION-linux.tar.gz"
|
||||
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
|
||||
CONNECT_DOWNLOAD="sc-$SC_VERSION-linux.tar.gz"
|
||||
|
||||
@@ -35,7 +35,7 @@ var getPackage = function() {
|
||||
* @return {Object} An object containing the github owner and repository name
|
||||
*/
|
||||
var getGitRepoInfo = function() {
|
||||
var GITURL_REGEX = /^https:\/\/github.com\/([^\/]+)\/(.+).git$/;
|
||||
var GITURL_REGEX = /^https:\/\/github.com\/([^/]+)\/(.+).git$/;
|
||||
var match = GITURL_REGEX.exec(currentPackage.repository.url);
|
||||
var git = {
|
||||
owner: match[1],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Generated
-15811
File diff suppressed because it is too large
Load Diff
+14
-9
@@ -1,41 +1,42 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"license": "MIT",
|
||||
"branchVersion": "^1.5.8",
|
||||
"branchVersion": "^1.6.0",
|
||||
"branchPattern": "1.6.*",
|
||||
"distTag": "next",
|
||||
"distTag": "latest",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": "<5",
|
||||
"npm": "~2.5"
|
||||
"node": "^6.9.1",
|
||||
"yarn": ">=0.17.9",
|
||||
"grunt": "^1.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "node scripts/npm/check-node-modules.js --purge",
|
||||
"postinstall": "node scripts/npm/copy-npm-shrinkwrap.js",
|
||||
"commit": "git-cz",
|
||||
"test-i18n": "jasmine-node i18n/spec",
|
||||
"test-i18n-ucd": "jasmine-node i18n/ucd/spec",
|
||||
"gulp": "gulp"
|
||||
"grunt": "grunt"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-benchpress": "0.x.x",
|
||||
"benchmark": "1.x.x",
|
||||
"bootstrap": "3.1.1",
|
||||
"bower": "~1.3.9",
|
||||
"browserstacktunnel-wrapper": "^1.4.2",
|
||||
"canonical-path": "0.0.2",
|
||||
"changez": "^2.1.1",
|
||||
"changez-angular": "^2.1.0",
|
||||
"changez-angular": "^2.1.3",
|
||||
"cheerio": "^0.17.0",
|
||||
"commitizen": "^2.3.0",
|
||||
"cross-spawn": "^4.0.0",
|
||||
"cz-conventional-changelog": "1.1.4",
|
||||
"dgeni": "^0.4.0",
|
||||
"dgeni-packages": "^0.16.0",
|
||||
"dgeni-packages": "^0.16.4",
|
||||
"event-stream": "~3.1.0",
|
||||
"glob": "^6.0.1",
|
||||
"google-code-prettify": "1.0.1",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt-bump": "^0.8.0",
|
||||
"grunt-cli": "^1.2.0",
|
||||
@@ -58,6 +59,7 @@
|
||||
"jasmine-core": "^2.4.0",
|
||||
"jasmine-node": "^2.0.0",
|
||||
"jasmine-reporters": "^2.2.0",
|
||||
"jquery": "^3.1.1",
|
||||
"karma": "^1.1.2",
|
||||
"karma-browserstack-launcher": "^1.0.1",
|
||||
"karma-chrome-launcher": "^1.0.1",
|
||||
@@ -70,8 +72,11 @@
|
||||
"load-grunt-tasks": "^3.5.0",
|
||||
"lodash": "~2.4.1",
|
||||
"log4js": "^0.6.27",
|
||||
"lunr": "^0.7.2",
|
||||
"marked": "~0.3.0",
|
||||
"node-html-encoder": "0.0.2",
|
||||
"npm-run": "^4.1.0",
|
||||
"open-sans-fontface": "^1.4.0",
|
||||
"promises-aplus-tests": "~2.1.0",
|
||||
"protractor": "^4.0.10",
|
||||
"q": "~1.0.0",
|
||||
|
||||
@@ -15,7 +15,7 @@ function init {
|
||||
BUILD_DIR=$(resolveDir ../../build)
|
||||
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
|
||||
PROJECT_DIR=$(resolveDir ../..)
|
||||
# get the npm dist-tag from a custom property (distTag) in package.json
|
||||
# get the dist-tag for this release from a custom property (distTag) in package.json
|
||||
DIST_TAG=$(readJsonProp "$PROJECT_DIR/package.json" "distTag")
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ function prepare {
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
echo "-- Cloning bower-$repo"
|
||||
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
|
||||
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo --depth=1
|
||||
done
|
||||
|
||||
|
||||
@@ -96,9 +96,9 @@ function publish {
|
||||
git push origin master
|
||||
git push origin v$NEW_VERSION
|
||||
|
||||
# don't publish every build to npm
|
||||
# don't publish every build to the npm repository
|
||||
if [ "${NEW_VERSION/+sha}" = "$NEW_VERSION" ] ; then
|
||||
echo "-- Publishing to npm as $DIST_TAG"
|
||||
echo "-- Publishing to the npm repository as $DIST_TAG"
|
||||
npm publish --tag=$DIST_TAG
|
||||
fi
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ then(allInSeries(function(branch) {
|
||||
line = line.split(' ');
|
||||
var sha = line.shift();
|
||||
var msg = line.join(' ');
|
||||
return sha + ((/fix\([^\)]+\):/i.test(msg)) ? ' * ' : ' ') + msg;
|
||||
return sha + ((/fix\([^)]+\):/i.test(msg)) ? ' * ' : ' ') + msg;
|
||||
});
|
||||
branch.log = log.map(function(line) {
|
||||
return line.substr(41);
|
||||
@@ -4,7 +4,7 @@ echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
|
||||
source scripts/jenkins/set-node-version.sh
|
||||
source scripts/jenkins/init-node.sh
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
@@ -12,7 +12,7 @@ set -xe
|
||||
# This is the default set of browsers to use on the CI server unless overridden via env variable
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh"
|
||||
BROWSERS="Chrome,Firefox,/Users/jenkins/bin/safari.sh"
|
||||
fi
|
||||
|
||||
# CLEAN #
|
||||
@@ -21,23 +21,21 @@ rm -f angular.js.size
|
||||
|
||||
|
||||
# BUILD #
|
||||
npm install -g grunt-cli
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
yarn run grunt -- ci-checks package --no-color
|
||||
|
||||
mkdir -p test_out
|
||||
|
||||
# UNIT TESTS #
|
||||
grunt test:unit --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
|
||||
yarn run grunt -- test:unit --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
# END TO END TESTS #
|
||||
grunt test:ci-protractor
|
||||
yarn run grunt -- test:ci-protractor
|
||||
|
||||
# DOCS APP TESTS #
|
||||
grunt test:docs --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
|
||||
yarn run grunt -- test:docs --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
# Promises/A+ TESTS #
|
||||
grunt test:promises-aplus --no-color
|
||||
yarn run grunt -- test:promises-aplus --no-color
|
||||
|
||||
|
||||
# CHECK SIZE #
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install nvm for this shell
|
||||
source ~/.nvm/nvm.sh
|
||||
|
||||
# Use version of node.js found in .nvmrc
|
||||
nvm install
|
||||
|
||||
# clean out and install yarn
|
||||
rm -rf ~/.yarn
|
||||
curl -o- -L https://raw.githubusercontent.com/yarnpkg/yarn/2a0afc73210c7a82082585283e518eeb88ca19ae/scripts/install-latest.sh | bash -s -- --version 0.17.9
|
||||
export PATH="$HOME/.yarn/bin:$PATH"
|
||||
|
||||
# Ensure that we have the local dependencies installed
|
||||
yarn install
|
||||
|
||||
echo testing grunt version
|
||||
yarn run grunt -- --version
|
||||
@@ -35,12 +35,9 @@ function init {
|
||||
}
|
||||
|
||||
function build {
|
||||
source ./set-node-version.sh
|
||||
cd ../..
|
||||
|
||||
npm install -g grunt-cli
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
source scripts/jenkins/init-node.sh
|
||||
yarn run grunt -- ci-checks package --no-color
|
||||
|
||||
cd $SCRIPT_DIR
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install nvm for this shell
|
||||
source ~/.nvm/nvm.sh
|
||||
|
||||
# Use node.js at 4.2.x
|
||||
nvm install 4.4
|
||||
@@ -1,75 +0,0 @@
|
||||
// Implementation based on:
|
||||
// https://github.com/angular/angular/blob/3b9c08676a4c921bbfa847802e08566fb601ba7a/tools/npm/check-node-modules.js
|
||||
'use strict';
|
||||
|
||||
// Imports
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// Constants
|
||||
var PROJECT_ROOT = path.join(__dirname, '../../');
|
||||
var NODE_MODULES_DIR = 'node_modules';
|
||||
var NPM_SHRINKWRAP_FILE = 'npm-shrinkwrap.json';
|
||||
var NPM_SHRINKWRAP_CACHED_FILE = NODE_MODULES_DIR + '/npm-shrinkwrap.cached.json';
|
||||
|
||||
// Run
|
||||
_main();
|
||||
|
||||
// Functions - Definitions
|
||||
function _main() {
|
||||
var purgeIfStale = process.argv.indexOf('--purge') !== -1;
|
||||
|
||||
process.chdir(PROJECT_ROOT);
|
||||
checkNodeModules(purgeIfStale);
|
||||
}
|
||||
|
||||
function checkNodeModules(purgeIfStale) {
|
||||
var nodeModulesOk = compareMarkerFiles(NPM_SHRINKWRAP_FILE, NPM_SHRINKWRAP_CACHED_FILE);
|
||||
|
||||
if (nodeModulesOk) {
|
||||
console.log(':-) npm dependencies are looking good!');
|
||||
} else if (purgeIfStale) {
|
||||
console.log(':-( npm dependencies are stale or in an unknown state!');
|
||||
console.log(' Purging \'' + NODE_MODULES_DIR + '\'...');
|
||||
deleteDirSync(NODE_MODULES_DIR);
|
||||
} else {
|
||||
var separator = new Array(81).join('!');
|
||||
|
||||
console.warn(separator);
|
||||
console.warn(':-( npm dependencies are stale or in an unknown state!');
|
||||
console.warn('You can rebuild the dependencies by running `npm install`.');
|
||||
console.warn(separator);
|
||||
}
|
||||
|
||||
return nodeModulesOk;
|
||||
}
|
||||
|
||||
function compareMarkerFiles(markerFilePath, cachedMarkerFilePath) {
|
||||
if (!fs.existsSync(markerFilePath)) return false;
|
||||
if (!fs.existsSync(cachedMarkerFilePath)) return false;
|
||||
|
||||
var opts = {encoding: 'utf-8'};
|
||||
var markerContent = fs.readFileSync(markerFilePath, opts);
|
||||
var cachedMarkerContent = fs.readFileSync(cachedMarkerFilePath, opts);
|
||||
|
||||
return markerContent === cachedMarkerContent;
|
||||
}
|
||||
|
||||
// Custom implementation of `rm -rf` that works consistently across OSes
|
||||
function deleteDirSync(path) {
|
||||
if (fs.existsSync(path)) {
|
||||
fs.readdirSync(path).forEach(deleteDirOrFileSync);
|
||||
fs.rmdirSync(path);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
function deleteDirOrFileSync(subpath) {
|
||||
var curPath = path + '/' + subpath;
|
||||
|
||||
if (fs.lstatSync(curPath).isDirectory()) {
|
||||
deleteDirSync(curPath);
|
||||
} else {
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* 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');
|
||||
var path = require('path');
|
||||
|
||||
|
||||
function cleanModule(module, name) {
|
||||
|
||||
// keep `resolve` properties for git dependencies, delete otherwise
|
||||
delete module.from;
|
||||
if (!(module.resolved && module.resolved.match(/^git(\+[a-z]+)?:\/\//))) {
|
||||
delete module.resolved;
|
||||
}
|
||||
|
||||
_.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);
|
||||
|
||||
var cleanShrinkwrapPath = path.join(__dirname, '..', '..', 'npm-shrinkwrap.clean.json');
|
||||
console.log('Writing cleaned to', cleanShrinkwrapPath);
|
||||
fs.writeFileSync(cleanShrinkwrapPath, JSON.stringify(sorted(shrinkwrap), null, 2) + '\n');
|
||||
@@ -1,60 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// Imports
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// Constants
|
||||
var PROJECT_ROOT = path.join(__dirname, '../../');
|
||||
var NODE_MODULES_DIR = 'node_modules';
|
||||
var NPM_SHRINKWRAP_FILE = 'npm-shrinkwrap.json';
|
||||
var NPM_SHRINKWRAP_CACHED_FILE = NODE_MODULES_DIR + '/npm-shrinkwrap.cached.json';
|
||||
|
||||
// Run
|
||||
_main();
|
||||
|
||||
// Functions - Definitions
|
||||
function _main() {
|
||||
process.chdir(PROJECT_ROOT);
|
||||
copyFile(NPM_SHRINKWRAP_FILE, NPM_SHRINKWRAP_CACHED_FILE, onCopied);
|
||||
}
|
||||
|
||||
// Implementation based on:
|
||||
// https://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js#answer-21995878
|
||||
function copyFile(srcPath, dstPath, callback) {
|
||||
var callbackCalled = false;
|
||||
|
||||
if (!fs.existsSync(srcPath)) {
|
||||
done(new Error('Missing source file: ' + srcPath));
|
||||
return;
|
||||
}
|
||||
|
||||
var rs = fs.createReadStream(srcPath);
|
||||
rs.on('error', done);
|
||||
|
||||
var ws = fs.createWriteStream(dstPath);
|
||||
ws.on('error', done);
|
||||
ws.on('finish', done);
|
||||
|
||||
rs.pipe(ws);
|
||||
|
||||
// Helpers
|
||||
function done(err) {
|
||||
if (callback && !callbackCalled) {
|
||||
callbackCalled = true;
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onCopied(err) {
|
||||
if (err) {
|
||||
var separator = new Array(81).join('!');
|
||||
|
||||
console.error(separator);
|
||||
console.error(
|
||||
'Failed to copy `' + NPM_SHRINKWRAP_FILE + '` to `' + NPM_SHRINKWRAP_CACHED_FILE + '`:');
|
||||
console.error(err);
|
||||
console.error(separator);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
set -e
|
||||
|
||||
yarn global add grunt-cli@1.2.0
|
||||
|
||||
mkdir -p $LOGS_DIR
|
||||
|
||||
if [ $JOB != "ci-checks" ]; then
|
||||
@@ -9,8 +11,6 @@ if [ $JOB != "ci-checks" ]; then
|
||||
./scripts/travis/start_browser_provider.sh
|
||||
fi
|
||||
|
||||
npm install -g grunt-cli
|
||||
|
||||
if [ $JOB != "ci-checks" ]; then
|
||||
grunt package
|
||||
echo "wait_for_browser_provider"
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# normalize the working dir to the directory of the script
|
||||
cd $(dirname $0);
|
||||
|
||||
cd ../..
|
||||
curl "http://23.251.148.50:8000/tar/$TRAVIS_REPO_SLUG/$TRAVIS_COMMIT" | tar xz || true
|
||||
+4
-1
@@ -15,6 +15,9 @@
|
||||
"splice": false,
|
||||
"push": false,
|
||||
"toString": false,
|
||||
"minErrConfig": false,
|
||||
"errorHandlingConfig": false,
|
||||
"isValidObjectMaxDepth": false,
|
||||
"ngMinErr": false,
|
||||
"_angular": false,
|
||||
"angularModule": false,
|
||||
@@ -150,7 +153,7 @@
|
||||
|
||||
/* apis.js */
|
||||
"hashKey": false,
|
||||
"HashMap": false,
|
||||
"NgMap": false,
|
||||
|
||||
/* urlUtils.js */
|
||||
"urlResolve": false,
|
||||
|
||||
+139
-32
@@ -10,6 +10,9 @@
|
||||
splice,
|
||||
push,
|
||||
toString,
|
||||
minErrConfig,
|
||||
errorHandlingConfig,
|
||||
isValidObjectMaxDepth,
|
||||
ngMinErr,
|
||||
angularModule,
|
||||
uid,
|
||||
@@ -122,9 +125,85 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
|
||||
// This is used so that it's possible for internal tests to create mock ValidityStates.
|
||||
var VALIDITY_STATE_PROPERTY = 'validity';
|
||||
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
var minErrConfig = {
|
||||
objectMaxDepth: 5
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.errorHandlingConfig
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Configure several aspects of error handling in AngularJS if used as a setter or return the
|
||||
* current configuration if used as a getter. The following options are supported:
|
||||
*
|
||||
* - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
|
||||
*
|
||||
* Omitted or undefined options will leave the corresponding configuration values unchanged.
|
||||
*
|
||||
* @param {Object=} config - The configuration object. May only contain the options that need to be
|
||||
* updated. Supported keys:
|
||||
*
|
||||
* * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a
|
||||
* non-positive or non-numeric value, removes the max depth limit.
|
||||
* Default: 5
|
||||
*/
|
||||
function errorHandlingConfig(config) {
|
||||
if (isObject(config)) {
|
||||
if (isDefined(config.objectMaxDepth)) {
|
||||
minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN;
|
||||
}
|
||||
} else {
|
||||
return minErrConfig;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} maxDepth
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isValidObjectMaxDepth(maxDepth) {
|
||||
return isNumber(maxDepth) && maxDepth > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.lowercase
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.5.0"
|
||||
* removeVersion="1.7.0"
|
||||
* Use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) instead.
|
||||
*
|
||||
* @description Converts the specified string to lowercase.
|
||||
* @param {string} string String to be converted to lowercase.
|
||||
* @returns {string} Lowercased string.
|
||||
*/
|
||||
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.uppercase
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.5.0"
|
||||
* removeVersion="1.7.0"
|
||||
* Use [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) instead.
|
||||
*
|
||||
* @description Converts the specified string to uppercase.
|
||||
* @param {string} string String to be converted to uppercase.
|
||||
* @returns {string} Uppercased string.
|
||||
*/
|
||||
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
|
||||
|
||||
|
||||
@@ -678,7 +757,7 @@ function isPromiseLike(obj) {
|
||||
}
|
||||
|
||||
|
||||
var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
|
||||
var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/;
|
||||
function isTypedArray(value) {
|
||||
return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
|
||||
}
|
||||
@@ -697,7 +776,7 @@ var trim = function(value) {
|
||||
// Prereq: s is a string.
|
||||
var escapeForRegexp = function(s) {
|
||||
return s
|
||||
.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1')
|
||||
.replace(/([-()[\]{}+?*.$^|,:#<!\\])/g, '\\$1')
|
||||
// eslint-disable-next-line no-control-regex
|
||||
.replace(/\x08/g, '\\x08');
|
||||
};
|
||||
@@ -815,9 +894,10 @@ function arrayRemove(array, value) {
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
function copy(source, destination) {
|
||||
function copy(source, destination, maxDepth) {
|
||||
var stackSource = [];
|
||||
var stackDest = [];
|
||||
maxDepth = isValidObjectMaxDepth(maxDepth) ? maxDepth : NaN;
|
||||
|
||||
if (destination) {
|
||||
if (isTypedArray(destination) || isArrayBuffer(destination)) {
|
||||
@@ -840,35 +920,39 @@ function copy(source, destination) {
|
||||
|
||||
stackSource.push(source);
|
||||
stackDest.push(destination);
|
||||
return copyRecurse(source, destination);
|
||||
return copyRecurse(source, destination, maxDepth);
|
||||
}
|
||||
|
||||
return copyElement(source);
|
||||
return copyElement(source, maxDepth);
|
||||
|
||||
function copyRecurse(source, destination) {
|
||||
function copyRecurse(source, destination, maxDepth) {
|
||||
maxDepth--;
|
||||
if (maxDepth < 0) {
|
||||
return '...';
|
||||
}
|
||||
var h = destination.$$hashKey;
|
||||
var key;
|
||||
if (isArray(source)) {
|
||||
for (var i = 0, ii = source.length; i < ii; i++) {
|
||||
destination.push(copyElement(source[i]));
|
||||
destination.push(copyElement(source[i], maxDepth));
|
||||
}
|
||||
} else if (isBlankObject(source)) {
|
||||
// createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
|
||||
for (key in source) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
destination[key] = copyElement(source[key], maxDepth);
|
||||
}
|
||||
} else if (source && typeof source.hasOwnProperty === 'function') {
|
||||
// Slow path, which must rely on hasOwnProperty
|
||||
for (key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
destination[key] = copyElement(source[key], maxDepth);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Slowest path --- hasOwnProperty can't be called as a method
|
||||
for (key in source) {
|
||||
if (hasOwnProperty.call(source, key)) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
destination[key] = copyElement(source[key], maxDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -876,7 +960,7 @@ function copy(source, destination) {
|
||||
return destination;
|
||||
}
|
||||
|
||||
function copyElement(source) {
|
||||
function copyElement(source, maxDepth) {
|
||||
// Simple values
|
||||
if (!isObject(source)) {
|
||||
return source;
|
||||
@@ -905,7 +989,7 @@ function copy(source, destination) {
|
||||
stackDest.push(destination);
|
||||
|
||||
return needsRecurse
|
||||
? copyRecurse(source, destination)
|
||||
? copyRecurse(source, destination, maxDepth)
|
||||
: destination;
|
||||
}
|
||||
|
||||
@@ -941,7 +1025,7 @@ function copy(source, destination) {
|
||||
return new source.constructor(source.valueOf());
|
||||
|
||||
case '[object RegExp]':
|
||||
var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
||||
var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]);
|
||||
re.lastIndex = source.lastIndex;
|
||||
return re;
|
||||
|
||||
@@ -1318,7 +1402,7 @@ function startingTag(element) {
|
||||
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
|
||||
elemHtml.
|
||||
match(/^(<[^>]+>)/)[1].
|
||||
replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
|
||||
replace(/^<([\w-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
|
||||
} catch (e) {
|
||||
return lowercase(elemHtml);
|
||||
}
|
||||
@@ -1447,28 +1531,51 @@ function getNgAttribute(element, ngAttr) {
|
||||
}
|
||||
|
||||
function allowAutoBootstrap(document) {
|
||||
if (!document.currentScript) {
|
||||
var script = document.currentScript;
|
||||
|
||||
if (!script) {
|
||||
// IE does not have `document.currentScript`
|
||||
return true;
|
||||
}
|
||||
var src = document.currentScript.getAttribute('src');
|
||||
var link = document.createElement('a');
|
||||
link.href = src;
|
||||
var scriptProtocol = link.protocol;
|
||||
var docLoadProtocol = document.location.protocol;
|
||||
if (docLoadProtocol === scriptProtocol) {
|
||||
return true;
|
||||
|
||||
// If the `currentScript` property has been clobbered just return false, since this indicates a probable attack
|
||||
if (!(script instanceof window.HTMLScriptElement || script instanceof window.SVGScriptElement)) {
|
||||
return false;
|
||||
}
|
||||
switch (scriptProtocol) {
|
||||
case 'http:':
|
||||
case 'https:':
|
||||
case 'ftp:':
|
||||
case 'blob:':
|
||||
case 'file:':
|
||||
case 'data:':
|
||||
|
||||
var attributes = script.attributes;
|
||||
var srcs = [attributes.getNamedItem('src'), attributes.getNamedItem('href'), attributes.getNamedItem('xlink:href')];
|
||||
|
||||
return srcs.every(function(src) {
|
||||
if (!src) {
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
if (!src.value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var link = document.createElement('a');
|
||||
link.href = src.value;
|
||||
|
||||
if (document.location.origin === link.origin) {
|
||||
// Same-origin resources are always allowed, even for non-whitelisted schemes.
|
||||
return true;
|
||||
}
|
||||
// Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
|
||||
// This is to prevent angular.js bundled with browser extensions from being used to bypass the
|
||||
// content security policy in web pages and other browser extensions.
|
||||
switch (link.protocol) {
|
||||
case 'http:':
|
||||
case 'https:':
|
||||
case 'ftp:':
|
||||
case 'blob:':
|
||||
case 'file:':
|
||||
case 'data:':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Cached as it has to run during loading so that document.currentScript is available.
|
||||
@@ -1832,7 +1939,7 @@ function bindJQuery() {
|
||||
extend(jQuery.fn, {
|
||||
scope: JQLitePrototype.scope,
|
||||
isolateScope: JQLitePrototype.isolateScope,
|
||||
controller: JQLitePrototype.controller,
|
||||
controller: /** @type {?} */ (JQLitePrototype).controller,
|
||||
injector: JQLitePrototype.injector,
|
||||
inheritedData: JQLitePrototype.inheritedData
|
||||
});
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
$$ForceReflowProvider,
|
||||
$InterpolateProvider,
|
||||
$IntervalProvider,
|
||||
$$HashMapProvider,
|
||||
$HttpProvider,
|
||||
$HttpParamSerializerProvider,
|
||||
$HttpParamSerializerJQLikeProvider,
|
||||
@@ -79,6 +78,7 @@
|
||||
$jsonpCallbacksProvider,
|
||||
$LocationProvider,
|
||||
$LogProvider,
|
||||
$$MapProvider,
|
||||
$ParseProvider,
|
||||
$RootScopeProvider,
|
||||
$QProvider,
|
||||
@@ -126,6 +126,7 @@ var version = {
|
||||
|
||||
function publishExternalAPI(angular) {
|
||||
extend(angular, {
|
||||
'errorHandlingConfig': errorHandlingConfig,
|
||||
'bootstrap': bootstrap,
|
||||
'copy': copy,
|
||||
'extend': extend,
|
||||
@@ -260,9 +261,10 @@ function publishExternalAPI(angular) {
|
||||
$window: $WindowProvider,
|
||||
$$rAF: $$RAFProvider,
|
||||
$$jqLite: $$jqLiteProvider,
|
||||
$$HashMap: $$HashMapProvider,
|
||||
$$Map: $$MapProvider,
|
||||
$$cookieReader: $$CookieReaderProvider
|
||||
});
|
||||
}
|
||||
]);
|
||||
])
|
||||
.info({ angularVersion: '"NG_VERSION_FULL"' });
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2017 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window) {
|
||||
|
||||
+55
-36
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
/**
|
||||
* Computes a hash of an 'obj'.
|
||||
* Hash of a:
|
||||
@@ -33,49 +32,69 @@ function hashKey(obj, nextUidFn) {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* HashMap which can use objects as keys
|
||||
*/
|
||||
function HashMap(array, isolatedUid) {
|
||||
if (isolatedUid) {
|
||||
var uid = 0;
|
||||
this.nextUid = function() {
|
||||
return ++uid;
|
||||
};
|
||||
}
|
||||
forEach(array, this.put, this);
|
||||
// A minimal ES2015 Map implementation.
|
||||
// Should be bug/feature equivalent to the native implementations of supported browsers
|
||||
// (for the features required in Angular).
|
||||
// See https://kangax.github.io/compat-table/es6/#test-Map
|
||||
var nanKey = Object.create(null);
|
||||
function NgMapShim() {
|
||||
this._keys = [];
|
||||
this._values = [];
|
||||
this._lastKey = NaN;
|
||||
this._lastIndex = -1;
|
||||
}
|
||||
HashMap.prototype = {
|
||||
/**
|
||||
* Store key value pair
|
||||
* @param key key to store can be any type
|
||||
* @param value value to store can be any type
|
||||
*/
|
||||
put: function(key, value) {
|
||||
this[hashKey(key, this.nextUid)] = value;
|
||||
NgMapShim.prototype = {
|
||||
_idx: function(key) {
|
||||
if (key === this._lastKey) {
|
||||
return this._lastIndex;
|
||||
}
|
||||
this._lastKey = key;
|
||||
this._lastIndex = this._keys.indexOf(key);
|
||||
return this._lastIndex;
|
||||
},
|
||||
_transformKey: function(key) {
|
||||
return isNumberNaN(key) ? nanKey : key;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @returns {Object} the value for the key
|
||||
*/
|
||||
get: function(key) {
|
||||
return this[hashKey(key, this.nextUid)];
|
||||
key = this._transformKey(key);
|
||||
var idx = this._idx(key);
|
||||
if (idx !== -1) {
|
||||
return this._values[idx];
|
||||
}
|
||||
},
|
||||
set: function(key, value) {
|
||||
key = this._transformKey(key);
|
||||
var idx = this._idx(key);
|
||||
if (idx === -1) {
|
||||
idx = this._lastIndex = this._keys.length;
|
||||
}
|
||||
this._keys[idx] = key;
|
||||
this._values[idx] = value;
|
||||
|
||||
/**
|
||||
* Remove the key/value pair
|
||||
* @param key
|
||||
*/
|
||||
remove: function(key) {
|
||||
var value = this[key = hashKey(key, this.nextUid)];
|
||||
delete this[key];
|
||||
return value;
|
||||
// Support: IE11
|
||||
// Do not `return this` to simulate the partial IE11 implementation
|
||||
},
|
||||
delete: function(key) {
|
||||
key = this._transformKey(key);
|
||||
var idx = this._idx(key);
|
||||
if (idx === -1) {
|
||||
return false;
|
||||
}
|
||||
this._keys.splice(idx, 1);
|
||||
this._values.splice(idx, 1);
|
||||
this._lastKey = NaN;
|
||||
this._lastIndex = -1;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var $$HashMapProvider = [/** @this */function() {
|
||||
// For now, always use `NgMapShim`, even if `window.Map` is available. Some native implementations
|
||||
// are still buggy (often in subtle ways) and can cause hard-to-debug failures. When native `Map`
|
||||
// implementations get more stable, we can reconsider switching to `window.Map` (when available).
|
||||
var NgMap = NgMapShim;
|
||||
|
||||
var $$MapProvider = [/** @this */function() {
|
||||
this.$get = [function() {
|
||||
return HashMap;
|
||||
return NgMap;
|
||||
}];
|
||||
}];
|
||||
|
||||
+29
-9
@@ -63,19 +63,15 @@
|
||||
* Implicit module which gets automatically added to each {@link auto.$injector $injector}.
|
||||
*/
|
||||
|
||||
var ARROW_ARG = /^([^\(]+?)=>/;
|
||||
var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
|
||||
var ARROW_ARG = /^([^(]+?)=>/;
|
||||
var FN_ARGS = /^[^(]*\(\s*([^)]*)\)/m;
|
||||
var FN_ARG_SPLIT = /,/;
|
||||
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
|
||||
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
||||
var $injectorMinErr = minErr('$injector');
|
||||
|
||||
function stringifyFn(fn) {
|
||||
// Support: Chrome 50-51 only
|
||||
// Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
|
||||
// (See https://github.com/angular/angular.js/issues/14487.)
|
||||
// TODO (gkalpak): Remove workaround when Chrome v52 is released
|
||||
return Function.prototype.toString.call(fn) + ' ';
|
||||
return Function.prototype.toString.call(fn);
|
||||
}
|
||||
|
||||
function extractArgs(fn) {
|
||||
@@ -184,6 +180,28 @@ function annotate(fn, strictDi, name) {
|
||||
* As an array of injection names, where the last item in the array is the function to call.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $injector#modules
|
||||
* @type {Object}
|
||||
* @description
|
||||
* A hash containing all the modules that have been loaded into the
|
||||
* $injector.
|
||||
*
|
||||
* You can use this property to find out information about a module via the
|
||||
* {@link angular.Module#info `myModule.info(...)`} method.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```
|
||||
* var info = $injector.modules['ngAnimate'].info();
|
||||
* ```
|
||||
*
|
||||
* **Do not use this property to attempt to modify the modules after the application
|
||||
* has been bootstrapped.**
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $injector#get
|
||||
@@ -649,7 +667,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
var INSTANTIATING = {},
|
||||
providerSuffix = 'Provider',
|
||||
path = [],
|
||||
loadedModules = new HashMap([], true),
|
||||
loadedModules = new NgMap(),
|
||||
providerCache = {
|
||||
$provide: {
|
||||
provider: supportObject(provider),
|
||||
@@ -677,6 +695,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
instanceInjector = protoInstanceInjector;
|
||||
|
||||
providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
|
||||
instanceInjector.modules = providerInjector.modules = createMap();
|
||||
var runBlocks = loadModules(modulesToLoad);
|
||||
instanceInjector = protoInstanceInjector.get('$injector');
|
||||
instanceInjector.strictDi = strictDi;
|
||||
@@ -757,7 +776,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
var runBlocks = [], moduleFn;
|
||||
forEach(modulesToLoad, function(module) {
|
||||
if (loadedModules.get(module)) return;
|
||||
loadedModules.put(module, true);
|
||||
loadedModules.set(module, true);
|
||||
|
||||
function runInvokeQueue(queue) {
|
||||
var i, ii;
|
||||
@@ -772,6 +791,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
try {
|
||||
if (isString(module)) {
|
||||
moduleFn = angularModule(module);
|
||||
instanceInjector.modules[module] = moduleFn;
|
||||
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
|
||||
runInvokeQueue(moduleFn._invokeQueue);
|
||||
runInvokeQueue(moduleFn._configBlocks);
|
||||
|
||||
+8
-5
@@ -979,12 +979,15 @@ forEach({
|
||||
|
||||
after: function(element, newElement) {
|
||||
var index = element, parent = element.parentNode;
|
||||
newElement = new JQLite(newElement);
|
||||
|
||||
for (var i = 0, ii = newElement.length; i < ii; i++) {
|
||||
var node = newElement[i];
|
||||
parent.insertBefore(node, index.nextSibling);
|
||||
index = node;
|
||||
if (parent) {
|
||||
newElement = new JQLite(newElement);
|
||||
|
||||
for (var i = 0, ii = newElement.length; i < ii; i++) {
|
||||
var node = newElement[i];
|
||||
parent.insertBefore(node, index.nextSibling);
|
||||
index = node;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -79,6 +79,9 @@ function setupModuleLoader(window) {
|
||||
* @returns {angular.Module} new module with the {@link angular.Module} api.
|
||||
*/
|
||||
return function module(name, requires, configFn) {
|
||||
|
||||
var info = {};
|
||||
|
||||
var assertNotHasOwnProperty = function(name, context) {
|
||||
if (name === 'hasOwnProperty') {
|
||||
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
|
||||
@@ -114,6 +117,45 @@ function setupModuleLoader(window) {
|
||||
_configBlocks: configBlocks,
|
||||
_runBlocks: runBlocks,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#info
|
||||
* @module ng
|
||||
*
|
||||
* @param {Object=} info Information about the module
|
||||
* @returns {Object|Module} The current info object for this module if called as a getter,
|
||||
* or `this` if called as a setter.
|
||||
*
|
||||
* @description
|
||||
* Read and write custom information about this module.
|
||||
* For example you could put the version of the module in here.
|
||||
*
|
||||
* ```js
|
||||
* angular.module('myModule', []).info({ version: '1.0.0' });
|
||||
* ```
|
||||
*
|
||||
* The version could then be read back out by accessing the module elsewhere:
|
||||
*
|
||||
* ```
|
||||
* var version = angular.module('myModule').info().version;
|
||||
* ```
|
||||
*
|
||||
* You can also retrieve this information during runtime via the
|
||||
* {@link $injector#modules `$injector.modules`} property:
|
||||
*
|
||||
* ```js
|
||||
* var version = $injector.modules['myModule'].info().version;
|
||||
* ```
|
||||
*/
|
||||
info: function(value) {
|
||||
if (isDefined(value)) {
|
||||
if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value');
|
||||
info = value;
|
||||
return this;
|
||||
}
|
||||
return info;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name angular.Module#requires
|
||||
|
||||
+5
-2
@@ -1,8 +1,11 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2017 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
'use strict';
|
||||
(function() {
|
||||
function isFunction(value) {return typeof value === 'function';};
|
||||
function isFunction(value) {return typeof value === 'function';}
|
||||
function isDefined(value) {return typeof value !== 'undefined';}
|
||||
function isObject(value) {return value !== null && typeof value === 'object';}
|
||||
|
||||
|
||||
+10
-12
@@ -33,20 +33,19 @@
|
||||
function minErr(module, ErrorConstructor) {
|
||||
ErrorConstructor = ErrorConstructor || Error;
|
||||
return function() {
|
||||
var SKIP_INDEXES = 2;
|
||||
|
||||
var templateArgs = arguments,
|
||||
code = templateArgs[0],
|
||||
var code = arguments[0],
|
||||
template = arguments[1],
|
||||
message = '[' + (module ? module + ':' : '') + code + '] ',
|
||||
template = templateArgs[1],
|
||||
templateArgs = sliceArgs(arguments, 2).map(function(arg) {
|
||||
return toDebugString(arg, minErrConfig.objectMaxDepth);
|
||||
}),
|
||||
paramPrefix, i;
|
||||
|
||||
message += template.replace(/\{\d+\}/g, function(match) {
|
||||
var index = +match.slice(1, -1),
|
||||
shiftedIndex = index + SKIP_INDEXES;
|
||||
var index = +match.slice(1, -1);
|
||||
|
||||
if (shiftedIndex < templateArgs.length) {
|
||||
return toDebugString(templateArgs[shiftedIndex]);
|
||||
if (index < templateArgs.length) {
|
||||
return templateArgs[index];
|
||||
}
|
||||
|
||||
return match;
|
||||
@@ -55,9 +54,8 @@ function minErr(module, ErrorConstructor) {
|
||||
message += '\nhttp://errors.angularjs.org/"NG_VERSION_FULL"/' +
|
||||
(module ? module + '/' : '') + code;
|
||||
|
||||
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
||||
message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
|
||||
encodeURIComponent(toDebugString(templateArgs[i]));
|
||||
for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
||||
message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]);
|
||||
}
|
||||
|
||||
return new ErrorConstructor(message);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2017 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {
|
||||
|
||||
+11
-9
@@ -60,7 +60,7 @@ var $$CoreAnimateJsProvider = /** @this */ function() {
|
||||
// this is prefixed with Core since it conflicts with
|
||||
// the animateQueueProvider defined in ngAnimate/animateQueue.js
|
||||
var $$CoreAnimateQueueProvider = /** @this */ function() {
|
||||
var postDigestQueue = new HashMap();
|
||||
var postDigestQueue = new NgMap();
|
||||
var postDigestElements = [];
|
||||
|
||||
this.$get = ['$$AnimateRunner', '$rootScope',
|
||||
@@ -139,7 +139,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
|
||||
jqLiteRemoveClass(elm, toRemove);
|
||||
}
|
||||
});
|
||||
postDigestQueue.remove(element);
|
||||
postDigestQueue.delete(element);
|
||||
}
|
||||
});
|
||||
postDigestElements.length = 0;
|
||||
@@ -154,7 +154,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
|
||||
|
||||
if (classesAdded || classesRemoved) {
|
||||
|
||||
postDigestQueue.put(element, data);
|
||||
postDigestQueue.set(element, data);
|
||||
postDigestElements.push(element);
|
||||
|
||||
if (postDigestElements.length === 1) {
|
||||
@@ -179,6 +179,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
|
||||
*/
|
||||
var $AnimateProvider = ['$provide', /** @this */ function($provide) {
|
||||
var provider = this;
|
||||
var classNameFilter = null;
|
||||
|
||||
this.$$registeredAnimations = Object.create(null);
|
||||
|
||||
@@ -247,15 +248,16 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {
|
||||
*/
|
||||
this.classNameFilter = function(expression) {
|
||||
if (arguments.length === 1) {
|
||||
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
|
||||
if (this.$$classNameFilter) {
|
||||
var reservedRegex = new RegExp('(\\s+|\\/)' + NG_ANIMATE_CLASSNAME + '(\\s+|\\/)');
|
||||
if (reservedRegex.test(this.$$classNameFilter.toString())) {
|
||||
throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
|
||||
classNameFilter = (expression instanceof RegExp) ? expression : null;
|
||||
if (classNameFilter) {
|
||||
var reservedRegex = new RegExp('[(\\s|\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\s|\\/)]');
|
||||
if (reservedRegex.test(classNameFilter.toString())) {
|
||||
classNameFilter = null;
|
||||
throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.$$classNameFilter;
|
||||
return classNameFilter;
|
||||
};
|
||||
|
||||
this.$get = ['$$animateQueue', function($$animateQueue) {
|
||||
|
||||
+12
-11
@@ -96,7 +96,6 @@ function Browser(window, document, $log, $sniffer) {
|
||||
};
|
||||
|
||||
cacheState();
|
||||
lastHistoryState = cachedState;
|
||||
|
||||
/**
|
||||
* @name $browser#url
|
||||
@@ -150,8 +149,6 @@ function Browser(window, document, $log, $sniffer) {
|
||||
if ($sniffer.history && (!sameBase || !sameState)) {
|
||||
history[replace ? 'replaceState' : 'pushState'](state, '', url);
|
||||
cacheState();
|
||||
// Do the assignment again so that those two variables are referentially identical.
|
||||
lastHistoryState = cachedState;
|
||||
} else {
|
||||
if (!sameBase) {
|
||||
pendingLocation = url;
|
||||
@@ -200,8 +197,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
|
||||
function cacheStateAndFireUrlChange() {
|
||||
pendingLocation = null;
|
||||
cacheState();
|
||||
fireUrlChange();
|
||||
fireStateOrUrlChange();
|
||||
}
|
||||
|
||||
// This variable should be used *only* inside the cacheState function.
|
||||
@@ -215,11 +211,16 @@ function Browser(window, document, $log, $sniffer) {
|
||||
if (equals(cachedState, lastCachedState)) {
|
||||
cachedState = lastCachedState;
|
||||
}
|
||||
|
||||
lastCachedState = cachedState;
|
||||
lastHistoryState = cachedState;
|
||||
}
|
||||
|
||||
function fireUrlChange() {
|
||||
if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
|
||||
function fireStateOrUrlChange() {
|
||||
var prevLastHistoryState = lastHistoryState;
|
||||
cacheState();
|
||||
|
||||
if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,8 +255,8 @@ function Browser(window, document, $log, $sniffer) {
|
||||
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
|
||||
// We listen on both (hashchange/popstate) when available, as some browsers don't
|
||||
// fire popstate when user changes the address bar and don't fire hashchange when url
|
||||
// changed by push/replaceState
|
||||
|
||||
// html5 history api - popstate event
|
||||
@@ -285,7 +286,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* Needs to be exported to be able to check for changes that have been done in sync,
|
||||
* as hashchange/popstate events fire in async.
|
||||
*/
|
||||
self.$$checkUrlChange = fireUrlChange;
|
||||
self.$$checkUrlChange = fireStateOrUrlChange;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Misc API
|
||||
@@ -302,7 +303,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
*/
|
||||
self.baseHref = function() {
|
||||
var href = baseElement.attr('href');
|
||||
return href ? href.replace(/^(https?:)?\/\/[^\/]*/, '') : '';
|
||||
return href ? href.replace(/^(https?:)?\/\/[^/]*/, '') : '';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+12
-9
@@ -128,7 +128,8 @@
|
||||
* * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
|
||||
* `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
|
||||
* object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
|
||||
* component such as cloning the bound value to prevent accidental mutation of the outer value.
|
||||
* component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will
|
||||
* also be called when your bindings are initialized.
|
||||
* * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
|
||||
* changes. Any actions that you wish to take in response to the changes that you detect must be
|
||||
* invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
|
||||
@@ -276,10 +277,12 @@
|
||||
* the directive's element. If multiple directives on the same element request a new scope,
|
||||
* only one new scope is created.
|
||||
*
|
||||
* * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
|
||||
* 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
|
||||
* scope. This is useful when creating reusable components, which should not accidentally read or modify
|
||||
* data in the parent scope.
|
||||
* * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's template.
|
||||
* The 'isolate' scope differs from normal scope in that it does not prototypically
|
||||
* inherit from its parent scope. This is useful when creating reusable components, which should not
|
||||
* accidentally read or modify data in the parent scope. Note that an isolate scope
|
||||
* directive without a `template` or `templateUrl` will not apply the isolate scope
|
||||
* to its children elements.
|
||||
*
|
||||
* The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
|
||||
* directive's element. These local properties are useful for aliasing values for templates. The keys in
|
||||
@@ -971,8 +974,8 @@ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
|
||||
function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var hasDirectives = {},
|
||||
Suffix = 'Directive',
|
||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive:\s*([\w\-]+)\s+(.*)$/,
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?::([^;]+))?;?)/,
|
||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive:\s*([\w-]+)\s+(.*)$/,
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\w-]+)(?::([^;]+))?;?)/,
|
||||
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
|
||||
REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
|
||||
|
||||
@@ -983,7 +986,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var bindingCache = createMap();
|
||||
|
||||
function parseIsolateBindings(scope, directiveName, isController) {
|
||||
var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
|
||||
var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*([\w$]*)\s*$/;
|
||||
|
||||
var bindings = createMap();
|
||||
|
||||
@@ -3155,7 +3158,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (error instanceof Error) {
|
||||
$exceptionHandler(error);
|
||||
}
|
||||
}).catch(noop);
|
||||
});
|
||||
|
||||
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
|
||||
var childBoundTranscludeFn = boundTranscludeFn;
|
||||
|
||||
@@ -14,6 +14,14 @@ function $$CookieReader($document) {
|
||||
var lastCookies = {};
|
||||
var lastCookieString = '';
|
||||
|
||||
function safeGetCookie(rawDocument) {
|
||||
try {
|
||||
return rawDocument.cookie || '';
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function safeDecodeURIComponent(str) {
|
||||
try {
|
||||
return decodeURIComponent(str);
|
||||
@@ -24,7 +32,7 @@ function $$CookieReader($document) {
|
||||
|
||||
return function() {
|
||||
var cookieArray, cookie, i, index, name;
|
||||
var currentCookieString = rawDocument.cookie || '';
|
||||
var currentCookieString = safeGetCookie(rawDocument);
|
||||
|
||||
if (currentCookieString !== lastCookieString) {
|
||||
lastCookieString = currentCookieString;
|
||||
|
||||
@@ -159,7 +159,8 @@
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* This directive sets the `disabled` attribute on the element if the
|
||||
* This directive sets the `disabled` attribute on the element (typically a form control,
|
||||
* e.g. `input`, `button`, `select` etc.) if the
|
||||
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
|
||||
*
|
||||
* A special directive is necessary because we cannot use interpolation inside the `disabled`
|
||||
|
||||
@@ -21,11 +21,11 @@ var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-
|
||||
// 7. Path
|
||||
// 8. Query
|
||||
// 9. Fragment
|
||||
// 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
|
||||
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
|
||||
// 1111111111111111 222 333333 44444 55555555555555555555555 666 77777777 8888888 999
|
||||
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
|
||||
// eslint-disable-next-line max-len
|
||||
var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
|
||||
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
|
||||
var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
|
||||
var NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
|
||||
var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
|
||||
var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
|
||||
var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
|
||||
@@ -688,7 +688,7 @@ var inputType = {
|
||||
* but does not trigger HTML5 native validation. Takes an expression.
|
||||
* @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint.
|
||||
* Can be interpolated.
|
||||
* @param {string=} ngStep Like `step`, sets the `max` validation error key if the value entered does not fit the `ngStep` constraint,
|
||||
* @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint,
|
||||
* but does not trigger HTML5 native validation. Takes an expression.
|
||||
* @param {string=} required Sets `required` validation error key if the value is not entered.
|
||||
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
||||
@@ -1565,15 +1565,27 @@ function isValidForStep(viewValue, stepBase, step) {
|
||||
// and `viewValue` is expected to be a valid stringified number.
|
||||
var value = Number(viewValue);
|
||||
|
||||
var isNonIntegerValue = !isNumberInteger(value);
|
||||
var isNonIntegerStepBase = !isNumberInteger(stepBase);
|
||||
var isNonIntegerStep = !isNumberInteger(step);
|
||||
|
||||
// Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
|
||||
// `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
|
||||
if (!isNumberInteger(value) || !isNumberInteger(stepBase) || !isNumberInteger(step)) {
|
||||
var decimalCount = Math.max(countDecimals(value), countDecimals(stepBase), countDecimals(step));
|
||||
if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) {
|
||||
var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0;
|
||||
var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0;
|
||||
var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0;
|
||||
|
||||
var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals);
|
||||
var multiplier = Math.pow(10, decimalCount);
|
||||
|
||||
value = value * multiplier;
|
||||
stepBase = stepBase * multiplier;
|
||||
step = step * multiplier;
|
||||
|
||||
if (isNonIntegerValue) value = Math.round(value);
|
||||
if (isNonIntegerStepBase) stepBase = Math.round(stepBase);
|
||||
if (isNonIntegerStep) step = Math.round(step);
|
||||
}
|
||||
|
||||
return (value - stepBase) % step === 0;
|
||||
@@ -2130,7 +2142,10 @@ var ngValueDirective = function() {
|
||||
* makes it possible to use ngValue as a sort of one-way bind.
|
||||
*/
|
||||
function updateElementValue(element, attr, value) {
|
||||
element.prop('value', value);
|
||||
// Support: IE9 only
|
||||
// In IE9 values are converted to string (e.g. `input.value = null` results in `input.value === 'null'`).
|
||||
var propValue = isDefined(value) ? value : (msie === 9) ? '' : null;
|
||||
element.prop('value', propValue);
|
||||
attr.$set('value', value);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user