Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d01cae2a0d | |||
| d015c8a80b | |||
| 8d2717146b | |||
| 3d598dae64 | |||
| 0a58986f52 | |||
| 6e69b85f9a | |||
| 7a9e336028 | |||
| 9b8df52aa9 | |||
| 7fab29fbe1 | |||
| 1a47fcbb8b | |||
| ffd4dab611 | |||
| 13edaa95c7 | |||
| 47b1f54bba | |||
| cdc7280dd3 | |||
| 0bb282bc6d | |||
| fdb09ef858 | |||
| 5e69cb2f9f | |||
| 5c2da38e3f | |||
| 3a799df0f1 | |||
| 511c765a44 | |||
| bf55d76d27 | |||
| c9efc80cd0 | |||
| fa15f2a6df | |||
| c023a0bfbb | |||
| b470e005e8 | |||
| c959191882 |
+3
-3
@@ -87,7 +87,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
* Please sign our [Contributor License Agreement (CLA)](#cla) before sending pull
|
||||
requests. We cannot accept code without this.
|
||||
* Make your changes in a new git branch
|
||||
* Make your changes in a new git branch:
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
@@ -107,7 +107,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
```
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
|
||||
* Build your changes locally to ensure all the tests pass
|
||||
* Build your changes locally to ensure all the tests pass:
|
||||
|
||||
```shell
|
||||
grunt test
|
||||
@@ -120,7 +120,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
```
|
||||
|
||||
* In GitHub, send a pull request to `angular:master`.
|
||||
* If we suggest changes then
|
||||
* If we suggest changes then:
|
||||
* Make the required updates.
|
||||
* Re-run the Angular test suite to ensure tests are still passing.
|
||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
|
||||
@@ -415,7 +415,7 @@ iframe.example {
|
||||
|
||||
.main-body-grid .side-navigation {
|
||||
position:relative;
|
||||
padding-bottom:120px;
|
||||
padding-bottom:50px;
|
||||
}
|
||||
|
||||
.main-body-grid .side-navigation.ng-hide {
|
||||
@@ -546,10 +546,10 @@ h4 {
|
||||
margin-left:10px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
color:black!important;
|
||||
.btn:hover, .btn:focus {
|
||||
color: black!important;
|
||||
border: 1px solid #ddd!important;
|
||||
background:white!important;
|
||||
background: white!important;
|
||||
}
|
||||
|
||||
.view-source, .improve-docs {
|
||||
@@ -656,14 +656,14 @@ ul.events > li {
|
||||
}
|
||||
.toc-close {
|
||||
position: absolute;
|
||||
bottom: -50px;
|
||||
bottom: 5px;
|
||||
left: 50%;
|
||||
margin-left: -50%;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
background: #eee;
|
||||
border-radius: 5px;
|
||||
width: 90%;
|
||||
width: 100%;
|
||||
border:1px solid #ddd;
|
||||
box-shadow:0 0 10px #bbb;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ Reserved names include:
|
||||
- `this`
|
||||
- `undefined`
|
||||
- `$parent`
|
||||
- `$id`
|
||||
- `$root`
|
||||
- `$even`
|
||||
- `$odd`
|
||||
- `$first`
|
||||
|
||||
@@ -751,9 +751,12 @@ own behavior to it.
|
||||
angular.module('docsIsoFnBindExample', [])
|
||||
.controller('Controller', ['$scope', '$timeout', function($scope, $timeout) {
|
||||
$scope.name = 'Tobias';
|
||||
$scope.hideDialog = function () {
|
||||
$scope.message = '';
|
||||
$scope.hideDialog = function (message) {
|
||||
$scope.message = message;
|
||||
$scope.dialogIsHidden = true;
|
||||
$timeout(function () {
|
||||
$scope.message = '';
|
||||
$scope.dialogIsHidden = false;
|
||||
}, 2000);
|
||||
};
|
||||
@@ -771,14 +774,15 @@ own behavior to it.
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()">
|
||||
{{message}}
|
||||
<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog(message)">
|
||||
Check out the contents, {{name}}!
|
||||
</my-dialog>
|
||||
</div>
|
||||
</file>
|
||||
<file name="my-dialog-close.html">
|
||||
<div class="alert">
|
||||
<a href class="close" ng-click="close()">×</a>
|
||||
<a href class="close" ng-click="close({message: 'closing for now'})">×</a>
|
||||
<div ng-transclude></div>
|
||||
</div>
|
||||
</file>
|
||||
@@ -795,9 +799,15 @@ callback functions to directive behaviors.
|
||||
|
||||
When the user clicks the `x` in the dialog, the directive's `close` function is called, thanks to
|
||||
`ng-click.` This call to `close` on the isolated scope actually evaluates the expression
|
||||
`hideDialog()` in the context of the original scope, thus running `Controller`'s `hideDialog`
|
||||
`hideDialog(message)` in the context of the original scope, thus running `Controller`'s `hideDialog`
|
||||
function.
|
||||
|
||||
Often it's desirable to pass data from the isolate scope via an expression to the
|
||||
parent scope, this can be done by passing a map of local variable names and values into the expression
|
||||
wrapper fn. For example, the hideDialog function takes a message to display when the dialog is hidden.
|
||||
This is specified in the directive by calling `close({message: 'closing for now'})`. Then the local
|
||||
variable `message` will be available within the `on-close` expression.
|
||||
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** use `&attr` in the `scope` option when you want your directive
|
||||
to expose an API for binding to behaviors.
|
||||
|
||||
@@ -15,6 +15,44 @@ which drives many of these changes.
|
||||
|
||||
# Migrating from 1.2 to 1.3
|
||||
|
||||
## Controllers
|
||||
|
||||
Due to [3f2232b5](https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018),
|
||||
`$controller` will no longer look for controllers on `window`.
|
||||
The old behavior of looking on `window` for controllers was originally intended
|
||||
for use in examples, demos, and toy apps. We found that allowing global controller
|
||||
functions encouraged poor practices, so we resolved to disable this behavior by
|
||||
default.
|
||||
|
||||
To migrate, register your controllers with modules rather than exposing them
|
||||
as globals:
|
||||
|
||||
Before:
|
||||
|
||||
```javascript
|
||||
function MyController() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```javascript
|
||||
angular.module('myApp', []).controller('MyController', [function() {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
Although it's not recommended, you can re-enable the old behavior like this:
|
||||
|
||||
```javascript
|
||||
angular.module('myModule').config(['$controllerProvider', function($controllerProvider) {
|
||||
// this option might be handy for migrating old apps, but please don't use it
|
||||
// in new ones!
|
||||
$controllerProvider.allowGlobals();
|
||||
}]);
|
||||
```
|
||||
|
||||
## Angular Expression Parsing (`$parse` + `$interpolate`)
|
||||
|
||||
- due to [77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5),
|
||||
|
||||
@@ -33,6 +33,9 @@ To see the app running in a browser, open a *separate* terminal/command line tab
|
||||
run `npm start` to start the web server. Now, open a browser window for the app and navigate to
|
||||
<a href="http://localhost:8000/app/" target="_blank">`http://localhost:8000/app/`</a>
|
||||
|
||||
Note that if you already ran the master branch app prior to checking out step-0, you may see the cached
|
||||
master version of the app in your browser window at this point. Just hit refresh to re-load the page.
|
||||
|
||||
You can now see the page in your browser. It's not very exciting, but that's OK.
|
||||
|
||||
The HTML page that displays "Nothing here yet!" was constructed with the HTML code shown below.
|
||||
|
||||
@@ -21,7 +21,7 @@ multiple views by adding routing, using an Angular module called 'ngRoute'.
|
||||
The routing functionality added by this step is provided by angular in the `ngRoute` module, which
|
||||
is distributed separately from the core Angular framework.
|
||||
|
||||
We are using [Bower][bower] to install client side dependencies. This step updates the
|
||||
We are using [Bower][bower] to install client-side dependencies. This step updates the
|
||||
`bower.json` configuration file to include the new dependency:
|
||||
|
||||
```json
|
||||
@@ -46,7 +46,7 @@ The new dependency `"angular-route": "~1.3.0"` tells bower to install a version
|
||||
angular-route component that is compatible with version 1.3.x. We must tell bower to download
|
||||
and install this dependency.
|
||||
|
||||
If you have bower installed globally then you can run `bower install` but for this project we have
|
||||
If you have bower installed globally, then you can run `bower install` but for this project, we have
|
||||
preconfigured npm to run bower install for us:
|
||||
|
||||
```
|
||||
@@ -70,7 +70,7 @@ the current "route" — the view that is currently displayed to the user.
|
||||
Application routes in Angular are declared via the {@link ngRoute.$routeProvider $routeProvider},
|
||||
which is the provider of the {@link ngRoute.$route $route service}. This service makes it easy to
|
||||
wire together controllers, view templates, and the current URL location in the browser. Using this
|
||||
feature we can implement [deep linking](http://en.wikipedia.org/wiki/Deep_linking), which lets us
|
||||
feature, we can implement [deep linking](http://en.wikipedia.org/wiki/Deep_linking), which lets us
|
||||
utilize the browser's history (back and forward navigation) and bookmarks.
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ AngularJS, so it's important for you to understand a thing or two about how it w
|
||||
|
||||
When the application bootstraps, Angular creates an injector that will be used to find and inject all
|
||||
of the services that are required by your app. The injector itself doesn't know anything about what
|
||||
`$http` or `$route` services do, in fact it doesn't even know about the existence of these services
|
||||
`$http` or `$route` services do. In fact, the injector doesn't even know about the existence of these services
|
||||
unless it is configured with proper module definitions.
|
||||
|
||||
The injector only carries out the following steps :
|
||||
@@ -295,7 +295,7 @@ phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams',
|
||||
|
||||
Again, note that we created a new module called `phonecatControllers`. For small AngularJS
|
||||
applications, it's common to create just one module for all of your controllers if there are just a
|
||||
few. As your application grows it is quite common to refactor your code into additional modules.
|
||||
few. As your application grows, it is quite common to refactor your code into additional modules.
|
||||
For larger apps, you will probably want to create separate modules for each major feature of
|
||||
your app.
|
||||
|
||||
@@ -349,7 +349,7 @@ the same binding into the `phone-list.html` template, the binding will work as e
|
||||
|
||||
<div style="display: none">
|
||||
* In `PhoneCatCtrl`, create a new model called "`hero`" with `this.hero = 'Zoro'`. In
|
||||
`PhoneListCtrl` let's shadow it with `this.hero = 'Batman'`, and in `PhoneDetailCtrl` we'll use
|
||||
`PhoneListCtrl`, let's shadow it with `this.hero = 'Batman'`. In `PhoneDetailCtrl`, we'll use
|
||||
`this.hero = "Captain Proton"`. Then add the `<p>hero = {{hero}}</p>` to all three of our templates
|
||||
(`index.html`, `phone-list.html`, and `phone-detail.html`). Open the app and you'll see scope
|
||||
inheritance and model property shadowing do some wonders.
|
||||
|
||||
@@ -31,7 +31,7 @@ phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$h
|
||||
|
||||
$scope.setImage = function(imageUrl) {
|
||||
$scope.mainImageUrl = imageUrl;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
```
|
||||
|
||||
|
||||
@@ -35,18 +35,18 @@ module.exports = function(config, specificOptions) {
|
||||
'SL_Chrome': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'chrome',
|
||||
version: '34'
|
||||
version: '39'
|
||||
},
|
||||
'SL_Firefox': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'firefox',
|
||||
version: '26'
|
||||
version: '31'
|
||||
},
|
||||
'SL_Safari': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.9',
|
||||
version: '7'
|
||||
platform: 'OS X 10.10',
|
||||
version: '8'
|
||||
},
|
||||
'SL_IE_9': {
|
||||
base: 'SauceLabs',
|
||||
@@ -71,13 +71,13 @@ module.exports = function(config, specificOptions) {
|
||||
base: 'BrowserStack',
|
||||
browser: 'chrome',
|
||||
os: 'OS X',
|
||||
os_version: 'Mountain Lion'
|
||||
os_version: 'Yosemite'
|
||||
},
|
||||
'BS_Safari': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'safari',
|
||||
os: 'OS X',
|
||||
os_version: 'Mountain Lion'
|
||||
os_version: 'Yosemite'
|
||||
},
|
||||
'BS_Firefox': {
|
||||
base: 'BrowserStack',
|
||||
|
||||
+1
-1
@@ -1338,7 +1338,7 @@ function angularInit(element, bootstrap) {
|
||||
* @param {DOMElement} element DOM element which is the root of angular application.
|
||||
* @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
|
||||
* Each item in the array should be the name of a predefined module or a (DI annotated)
|
||||
* function that will be invoked by the injector as a run block.
|
||||
* function that will be invoked by the injector as a `config` block.
|
||||
* See: {@link angular.module modules}
|
||||
* @param {Object=} config an object for defining configuration options for the application. The
|
||||
* following keys are supported:
|
||||
|
||||
@@ -829,7 +829,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
// Check if Type is annotated and use just the given function at n-1 as parameter
|
||||
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
||||
// Object creation: http://jsperf.com/create-constructor/2
|
||||
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype);
|
||||
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
|
||||
var returnedValue = invoke(Type, instance, locals, serviceName);
|
||||
|
||||
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
|
||||
|
||||
@@ -1450,6 +1450,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
// use class as directive
|
||||
className = node.className;
|
||||
if (isObject(className)) {
|
||||
// Maybe SVGAnimatedString
|
||||
className = className.animVal;
|
||||
}
|
||||
if (isString(className) && className !== '') {
|
||||
while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
|
||||
nName = directiveNormalize(match[2]);
|
||||
|
||||
@@ -111,7 +111,7 @@ function $ControllerProvider() {
|
||||
// Object creation: http://jsperf.com/create-constructor/2
|
||||
var controllerPrototype = (isArray(expression) ?
|
||||
expression[expression.length - 1] : expression).prototype;
|
||||
instance = Object.create(controllerPrototype);
|
||||
instance = Object.create(controllerPrototype || null);
|
||||
|
||||
if (identifier) {
|
||||
addIdentifier(locals, identifier, instance, constructor || expression.name);
|
||||
|
||||
@@ -163,6 +163,9 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
forEach(form.$error, function(value, name) {
|
||||
form.$setValidity(name, null, control);
|
||||
});
|
||||
forEach(form.$$success, function(value, name) {
|
||||
form.$setValidity(name, null, control);
|
||||
});
|
||||
|
||||
arrayRemove(controls, control);
|
||||
};
|
||||
@@ -180,23 +183,23 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
addSetValidityMethod({
|
||||
ctrl: this,
|
||||
$element: element,
|
||||
set: function(object, property, control) {
|
||||
set: function(object, property, controller) {
|
||||
var list = object[property];
|
||||
if (!list) {
|
||||
object[property] = [control];
|
||||
object[property] = [controller];
|
||||
} else {
|
||||
var index = list.indexOf(control);
|
||||
var index = list.indexOf(controller);
|
||||
if (index === -1) {
|
||||
list.push(control);
|
||||
list.push(controller);
|
||||
}
|
||||
}
|
||||
},
|
||||
unset: function(object, property, control) {
|
||||
unset: function(object, property, controller) {
|
||||
var list = object[property];
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
arrayRemove(list, control);
|
||||
arrayRemove(list, controller);
|
||||
if (list.length === 0) {
|
||||
delete object[property];
|
||||
}
|
||||
|
||||
@@ -141,8 +141,9 @@ function classDirective(name, selector) {
|
||||
* new classes are added.
|
||||
*
|
||||
* @animations
|
||||
* add - happens just before the class is applied to the element
|
||||
* remove - happens just before the class is removed from the element
|
||||
* **add** - happens just before the class is applied to the elements
|
||||
*
|
||||
* **remove** - happens just before the class is removed from the element
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} ngClass {@link guide/expression Expression} to eval. The result
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
* @name ngInclude#$includeContentError
|
||||
* @eventType emit on the scope ngInclude was declared in
|
||||
* @description
|
||||
* Emitted when a template HTTP request yields an erronous response (status < 200 || status > 299)
|
||||
* Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {String} src URL of content to load.
|
||||
|
||||
+14
-13
@@ -1247,22 +1247,22 @@ function addSetValidityMethod(context) {
|
||||
|
||||
ctrl.$setValidity = setValidity;
|
||||
|
||||
function setValidity(validationErrorKey, state, options) {
|
||||
function setValidity(validationErrorKey, state, controller) {
|
||||
if (state === undefined) {
|
||||
createAndSet('$pending', validationErrorKey, options);
|
||||
createAndSet('$pending', validationErrorKey, controller);
|
||||
} else {
|
||||
unsetAndCleanup('$pending', validationErrorKey, options);
|
||||
unsetAndCleanup('$pending', validationErrorKey, controller);
|
||||
}
|
||||
if (!isBoolean(state)) {
|
||||
unset(ctrl.$error, validationErrorKey, options);
|
||||
unset(ctrl.$$success, validationErrorKey, options);
|
||||
unset(ctrl.$error, validationErrorKey, controller);
|
||||
unset(ctrl.$$success, validationErrorKey, controller);
|
||||
} else {
|
||||
if (state) {
|
||||
unset(ctrl.$error, validationErrorKey, options);
|
||||
set(ctrl.$$success, validationErrorKey, options);
|
||||
unset(ctrl.$error, validationErrorKey, controller);
|
||||
set(ctrl.$$success, validationErrorKey, controller);
|
||||
} else {
|
||||
set(ctrl.$error, validationErrorKey, options);
|
||||
unset(ctrl.$$success, validationErrorKey, options);
|
||||
set(ctrl.$error, validationErrorKey, controller);
|
||||
unset(ctrl.$$success, validationErrorKey, controller);
|
||||
}
|
||||
}
|
||||
if (ctrl.$pending) {
|
||||
@@ -1290,20 +1290,21 @@ function addSetValidityMethod(context) {
|
||||
} else {
|
||||
combinedState = null;
|
||||
}
|
||||
|
||||
toggleValidationCss(validationErrorKey, combinedState);
|
||||
parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
|
||||
}
|
||||
|
||||
function createAndSet(name, value, options) {
|
||||
function createAndSet(name, value, controller) {
|
||||
if (!ctrl[name]) {
|
||||
ctrl[name] = {};
|
||||
}
|
||||
set(ctrl[name], value, options);
|
||||
set(ctrl[name], value, controller);
|
||||
}
|
||||
|
||||
function unsetAndCleanup(name, value, options) {
|
||||
function unsetAndCleanup(name, value, controller) {
|
||||
if (ctrl[name]) {
|
||||
unset(ctrl[name], value, options);
|
||||
unset(ctrl[name], value, controller);
|
||||
}
|
||||
if (isObjectEmpty(ctrl[name])) {
|
||||
ctrl[name] = undefined;
|
||||
|
||||
@@ -23,6 +23,29 @@
|
||||
* Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
|
||||
* This may be useful when, for instance, nesting ngRepeats.
|
||||
*
|
||||
* # Iterating over object properties
|
||||
*
|
||||
* It is possible to get `ngRepeat` to iterate over the properties of an object using the following
|
||||
* syntax:
|
||||
*
|
||||
* ```js
|
||||
* <div ng-repeat="(key, value) in myObj"> ... </div>
|
||||
* ```
|
||||
*
|
||||
* You need to be aware that the JavaScript specification does not define what order
|
||||
* it will return the keys for an object. In order to have a guaranteed deterministic order
|
||||
* for the keys, Angular versions up to and including 1.3 **sort the keys alphabetically**.
|
||||
*
|
||||
* If this is not desired, the recommended workaround is to convert your object into an array
|
||||
* that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
|
||||
* do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
|
||||
* or implement a `$watch` on the object yourself.
|
||||
*
|
||||
* In version 1.4 we will remove the sorting, since it seems that browsers generally follow the
|
||||
* strategy of providing keys in the order in which they were defined, although there are exceptions
|
||||
* when keys are deleted and reinstated.
|
||||
*
|
||||
*
|
||||
* # Special repeat start and end points
|
||||
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
|
||||
* the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
|
||||
@@ -267,7 +290,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
var keyIdentifier = match[2];
|
||||
|
||||
if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
|
||||
/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent)$/.test(aliasAs))) {
|
||||
/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
|
||||
throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
|
||||
aliasAs);
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d
|
||||
* * `'m'`: Minute in hour (0-59)
|
||||
* * `'ss'`: Second in minute, padded (00-59)
|
||||
* * `'s'`: Second in minute (0-59)
|
||||
* * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
|
||||
* * `'sss'`: Millisecond in second, padded (000-999)
|
||||
* * `'a'`: AM/PM marker
|
||||
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
|
||||
* * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
|
||||
|
||||
+1
-1
@@ -1045,7 +1045,7 @@ function $RootScopeProvider() {
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Schedule the invokation of $apply to occur at a later time. The actual time difference
|
||||
* Schedule the invocation of $apply to occur at a later time. The actual time difference
|
||||
* varies across browsers, but is typically around ~10 milliseconds.
|
||||
*
|
||||
* This can be used to queue up multiple expressions which need to be evaluated in the same
|
||||
|
||||
@@ -22,8 +22,7 @@ var $compileMinErr = minErr('$compile');
|
||||
function $TemplateRequestProvider() {
|
||||
this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) {
|
||||
function handleRequestFn(tpl, ignoreRequestError) {
|
||||
var self = handleRequestFn;
|
||||
self.totalPendingRequests++;
|
||||
handleRequestFn.totalPendingRequests++;
|
||||
|
||||
var transformResponse = $http.defaults && $http.defaults.transformResponse;
|
||||
|
||||
@@ -41,13 +40,14 @@ function $TemplateRequestProvider() {
|
||||
};
|
||||
|
||||
return $http.get(tpl, httpOptions)
|
||||
.finally(function() {
|
||||
handleRequestFn.totalPendingRequests--;
|
||||
})
|
||||
.then(function(response) {
|
||||
self.totalPendingRequests--;
|
||||
return response.data;
|
||||
}, handleError);
|
||||
|
||||
function handleError(resp) {
|
||||
self.totalPendingRequests--;
|
||||
if (!ignoreRequestError) {
|
||||
throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
|
||||
}
|
||||
|
||||
@@ -1869,7 +1869,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
return;
|
||||
}
|
||||
|
||||
if (!staggerTime && styles) {
|
||||
if (!staggerTime && styles && Object.keys(styles).length > 0) {
|
||||
if (!timings.transitionDuration) {
|
||||
element.css('transition', timings.animationDuration + 's linear all');
|
||||
appliedStyles.push('transition');
|
||||
|
||||
@@ -173,7 +173,7 @@ angular.module('ngMessages', [])
|
||||
* at a time and this depends on the prioritization of the messages within the template. (This can
|
||||
* be changed by using the ng-messages-multiple on the directive container.)
|
||||
*
|
||||
* A remote template can also be used to promote message reuseability and messages can also be
|
||||
* A remote template can also be used to promote message reusability and messages can also be
|
||||
* overridden.
|
||||
*
|
||||
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
|
||||
|
||||
@@ -9,22 +9,29 @@ describe('private mocks', function() {
|
||||
var doc = $document[0];
|
||||
var count = doc.styleSheets.length;
|
||||
var stylesheet = createMockStyleSheet($document, $window);
|
||||
expect(doc.styleSheets.length).toBe(count + 1);
|
||||
var elm;
|
||||
runs(function() {
|
||||
expect(doc.styleSheets.length).toBe(count + 1);
|
||||
|
||||
angular.element(doc.body).append($rootElement);
|
||||
angular.element(doc.body).append($rootElement);
|
||||
|
||||
var elm = $compile('<div class="padded">...</div>')($rootScope);
|
||||
$rootElement.append(elm);
|
||||
elm = $compile('<div class="padded">...</div>')($rootScope);
|
||||
$rootElement.append(elm);
|
||||
|
||||
expect(getStyle(elm, 'paddingTop')).toBe('0px');
|
||||
expect(getStyle(elm, 'paddingTop')).toBe('0px');
|
||||
|
||||
stylesheet.addRule('.padded', 'padding-top:2px');
|
||||
stylesheet.addRule('.padded', 'padding-top:2px');
|
||||
});
|
||||
|
||||
expect(getStyle(elm, 'paddingTop')).toBe('2px');
|
||||
waitsFor(function() {
|
||||
return getStyle(elm, 'paddingTop') === '2px';
|
||||
});
|
||||
|
||||
stylesheet.destroy();
|
||||
runs(function() {
|
||||
stylesheet.destroy();
|
||||
|
||||
expect(getStyle(elm, 'paddingTop')).toBe('0px');
|
||||
expect(getStyle(elm, 'paddingTop')).toBe('0px');
|
||||
});
|
||||
|
||||
function getStyle(element, key) {
|
||||
var node = element[0];
|
||||
|
||||
@@ -443,6 +443,17 @@ describe('$compile', function() {
|
||||
}));
|
||||
|
||||
|
||||
it('should allow directives in SVG element classes', inject(function($compile, $rootScope, log) {
|
||||
if (!window.SVGElement) return;
|
||||
element = $compile('<svg><text class="greet: angular; log:123;"></text></svg>')($rootScope);
|
||||
var text = element.children().eq(0);
|
||||
// In old Safari, SVG elements don't have innerHTML, so element.html() won't work
|
||||
// (https://bugs.webkit.org/show_bug.cgi?id=136903)
|
||||
expect(text.text()).toEqual('Hello angular');
|
||||
expect(log).toEqual('123');
|
||||
}));
|
||||
|
||||
|
||||
it('should ignore not set CSS classes on SVG elements', inject(function($compile, $rootScope, log) {
|
||||
if (!window.SVGElement) return;
|
||||
// According to spec SVG element className property is readonly, but only FF
|
||||
|
||||
@@ -27,6 +27,18 @@ describe('$controller', function() {
|
||||
expect(ctrl instanceof FooCtrl).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow registration of bound controller functions', function() {
|
||||
var FooCtrl = function($scope) { $scope.foo = 'bar'; },
|
||||
scope = {},
|
||||
ctrl;
|
||||
|
||||
var BoundFooCtrl = FooCtrl.bind(null);
|
||||
|
||||
$controllerProvider.register('FooCtrl', ['$scope', BoundFooCtrl]);
|
||||
ctrl = $controller('FooCtrl', {$scope: scope});
|
||||
|
||||
expect(scope.foo).toBe('bar');
|
||||
});
|
||||
|
||||
it('should allow registration of map of controllers', function() {
|
||||
var FooCtrl = function($scope) { $scope.foo = 'foo'; },
|
||||
|
||||
@@ -463,7 +463,7 @@ describe('form', function() {
|
||||
doc = jqLite(
|
||||
'<form name="parent">' +
|
||||
'<div class="ng-form" name="child">' +
|
||||
'<input ng-if="inputPresent" ng-model="modelA" name="inputA" required>' +
|
||||
'<input ng-if="inputPresent" ng-model="modelA" name="inputA" required maxlength="10">' +
|
||||
'</div>' +
|
||||
'</form>');
|
||||
$compile(doc)(scope);
|
||||
@@ -476,23 +476,75 @@ describe('form', function() {
|
||||
|
||||
expect(parent).toBeDefined();
|
||||
expect(child).toBeDefined();
|
||||
|
||||
expect(parent.$error.required).toEqual([child]);
|
||||
expect(parent.$$success.maxlength).toEqual([child]);
|
||||
|
||||
expect(child.$error.required).toEqual([input]);
|
||||
expect(child.$$success.maxlength).toEqual([input]);
|
||||
|
||||
expect(doc.hasClass('ng-invalid')).toBe(true);
|
||||
expect(doc.hasClass('ng-invalid-required')).toBe(true);
|
||||
expect(doc.hasClass('ng-valid-maxlength')).toBe(true);
|
||||
expect(doc.find('div').hasClass('ng-invalid')).toBe(true);
|
||||
expect(doc.find('div').hasClass('ng-invalid-required')).toBe(true);
|
||||
expect(doc.find('div').hasClass('ng-valid-maxlength')).toBe(true);
|
||||
|
||||
//remove child input
|
||||
scope.inputPresent = false;
|
||||
scope.$apply();
|
||||
scope.$apply('inputPresent = false');
|
||||
|
||||
expect(parent.$error.required).toBeFalsy();
|
||||
expect(parent.$$success.maxlength).toBeFalsy();
|
||||
|
||||
expect(child.$error.required).toBeFalsy();
|
||||
expect(child.$$success.maxlength).toBeFalsy();
|
||||
|
||||
expect(doc.hasClass('ng-valid')).toBe(true);
|
||||
expect(doc.hasClass('ng-valid-required')).toBe(false);
|
||||
expect(doc.hasClass('ng-invalid-required')).toBe(false);
|
||||
expect(doc.hasClass('ng-valid-maxlength')).toBe(false);
|
||||
expect(doc.hasClass('ng-invalid-maxlength')).toBe(false);
|
||||
|
||||
expect(doc.find('div').hasClass('ng-valid')).toBe(true);
|
||||
expect(doc.find('div').hasClass('ng-valid-required')).toBe(false);
|
||||
expect(doc.find('div').hasClass('ng-invalid-required')).toBe(false);
|
||||
expect(doc.find('div').hasClass('ng-valid-maxlength')).toBe(false);
|
||||
expect(doc.find('div').hasClass('ng-invalid-maxlength')).toBe(false);
|
||||
});
|
||||
|
||||
it('should deregister a input that is $pending when it is removed from DOM', function() {
|
||||
doc = jqLite(
|
||||
'<form name="parent">' +
|
||||
'<div class="ng-form" name="child">' +
|
||||
'<input ng-if="inputPresent" ng-model="modelA" name="inputA">' +
|
||||
'</div>' +
|
||||
'</form>');
|
||||
$compile(doc)(scope);
|
||||
scope.$apply('inputPresent = true');
|
||||
|
||||
var parent = scope.parent;
|
||||
var child = scope.child;
|
||||
var input = child.inputA;
|
||||
|
||||
scope.$apply(child.inputA.$setValidity('fake', undefined));
|
||||
|
||||
expect(parent).toBeDefined();
|
||||
expect(child).toBeDefined();
|
||||
|
||||
expect(parent.$pending.fake).toEqual([child]);
|
||||
expect(child.$pending.fake).toEqual([input]);
|
||||
|
||||
expect(doc.hasClass('ng-pending')).toBe(true);
|
||||
expect(doc.find('div').hasClass('ng-pending')).toBe(true);
|
||||
|
||||
//remove child input
|
||||
scope.$apply('inputPresent = false');
|
||||
|
||||
expect(parent.$pending).toBeUndefined();
|
||||
expect(child.$pending).toBeUndefined();
|
||||
|
||||
expect(doc.hasClass('ng-pending')).toBe(false);
|
||||
expect(doc.find('div').hasClass('ng-pending')).toBe(false);
|
||||
});
|
||||
|
||||
it('should leave the parent form invalid when deregister a removed input', function() {
|
||||
|
||||
@@ -37,6 +37,10 @@ describe('ngController', function() {
|
||||
this.mark = 'works';
|
||||
});
|
||||
|
||||
var Foo = function($scope) {
|
||||
$scope.mark = 'foo';
|
||||
};
|
||||
$controllerProvider.register('BoundFoo', ['$scope', Foo.bind(null)]);
|
||||
}));
|
||||
|
||||
afterEach(function() {
|
||||
@@ -50,6 +54,11 @@ describe('ngController', function() {
|
||||
expect(element.text()).toBe('Hello Misko!');
|
||||
}));
|
||||
|
||||
it('should instantiate bound constructor functions', inject(function($compile, $rootScope) {
|
||||
element = $compile('<div ng-controller="BoundFoo">{{mark}}</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.text()).toBe('foo');
|
||||
}));
|
||||
|
||||
it('should publish controller into scope', inject(function($compile, $rootScope) {
|
||||
element = $compile('<div ng-controller="Public as p">{{p.mark}}</div>')($rootScope);
|
||||
|
||||
@@ -474,6 +474,8 @@ describe('ngRepeat', function() {
|
||||
'this',
|
||||
'undefined',
|
||||
'$parent',
|
||||
'$root',
|
||||
'$id',
|
||||
'$index',
|
||||
'$first',
|
||||
'$middle',
|
||||
|
||||
@@ -1381,6 +1381,25 @@ describe("ngAnimate", function() {
|
||||
expect(element.attr('style')).toContain('border-color: blue');
|
||||
}));
|
||||
|
||||
it("should not apply a piggy-back-transition if the styles object contains no styles",
|
||||
inject(function($compile, $animate, $rootScope, $sniffer) {
|
||||
|
||||
if (!$sniffer.animations) return;
|
||||
|
||||
$animate.enabled(true);
|
||||
ss.addRule('.on', '-webkit-animation: 1s super-animation; animation: 1s super-animation;');
|
||||
|
||||
element = $compile(html('<div>1</div>'))($rootScope);
|
||||
|
||||
$animate.addClass(element, 'on', {
|
||||
to: {}
|
||||
});
|
||||
|
||||
$rootScope.$digest();
|
||||
$animate.triggerReflow();
|
||||
expect(element.attr('style')).not.toMatch(/transition/);
|
||||
}));
|
||||
|
||||
it("should pause the playstate when performing a stagger animation",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user