Comparing changes
Open a pull request
While $location expects that $browser stores the URL unchanged, "some browsers" transform the URL when setting or defer the acutal update. To work around this, $browser.url() kept the unchanged URL in pendingLocation. However, it failed to update pendingLocation in all code paths, causing $browser.url() to sometimes incorrectly report previous URLs, which horribly confused $location. This fix ensures that pendingLocation is always updated if set, causing url() to report the current url. Fixes #14427 Closes #14499
If the `from` element of an animation does not actually have an animation then there will be no animation runner on that element. This is possible if the element has the `ng-animate-ref` attribute but does not have any CSS animations or transitions defined. In this case, it is not necessary to try to update the host of the non-existent runner. Fixes #14641 Closes #14645
Update the link to Google's JavaScript style guide to the updated version Closes #14652
Messages imported with `ngMessagesInclude` are loaded asynchronously and they can arrive after the ngMessages element has already been removed from DOM. Previously we tried to compile these messages and that caused a `$compile:ctreq` error. Now they are silently ignored if `ngMessagesInclude`'s scope has already been destroyed. Closes #12695 Closes #14640
Explains what could generate a `reqslot` error. Closes #14618
…ation Change a sentence which describes how currencyConverter service is instantiated
This now uses the same technique as ngRepeat.
- +1 −1 CONTRIBUTING.md
- +66 −0 docs/config/templates/api/api.template.html
- +1 −1 docs/config/templates/api/module.template.html
- +47 −0 docs/content/error/$compile/reqslot.ngdoc
- +0 −1 docs/content/guide/component-router.ngdoc
- +2 −2 docs/content/guide/concepts.ngdoc
- +2 −11 docs/content/misc/contribute.ngdoc
- +21 −0 src/Angular.js
- +4 −1 src/ng/browser.js
- +3 −2 src/ng/compile.js
- +5 −5 src/ng/directive/input.js
- +3 −1 src/ng/directive/ngClass.js
- +19 −0 src/ng/interpolate.js
- +1 −1 src/ng/sniffer.js
- +2 −1 src/ngAnimate/animation.js
- +2 −0 src/ngMessages/messages.js
- +20 −11 src/ngMock/angular-mocks.js
- +39 −0 test/ng/browserSpecs.js
- +88 −0 test/ng/compileSpec.js
- +18 −0 test/ngAnimate/animateCssSpec.js
- +1 −1 test/ngAnimate/animateSpec.js
- +19 −0 test/ngMessages/messagesSpec.js
- +5 −0 test/ngMock/angular-mocksSpec.js
| @@ -280,7 +280,7 @@ You can find out more detailed information about contributing in the | ||
| [groups]: https://groups.google.com/forum/?fromgroups#!forum/angular | ||
| [individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html | ||
| [irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4 | ||
| [js-style-guide]: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml | ||
| [js-style-guide]: https://google.github.io/styleguide/javascriptguide.xml | ||
| [jsfiddle]: http://jsfiddle.net/ | ||
| [list]: https://groups.google.com/forum/?fromgroups#!forum/angular | ||
| [ngDocs]: https://github.com/angular/angular.js/wiki/Writing-AngularJS-Documentation | ||
| @@ -0,0 +1,66 @@ | ||
| {% extends "base.template.html" %} | ||
|
|
||
| {% block content %} | ||
|
|
||
| <a href='https://github.com/{$ git.info.owner $}/{$ git.info.repo $}/tree/{$ git.version.isSnapshot and 'master' or git.version.raw $}/{$ doc.fileInfo.projectRelativePath $}#L{$ doc.startingLine $}' class='view-source pull-right btn btn-primary'> | ||
| <i class="glyphicon glyphicon-zoom-in"> </i>View Source | ||
| </a> | ||
|
|
||
| {% block header %} | ||
| <header class="api-profile-header"> | ||
| <h1 class="api-profile-header-heading">{$ doc.name $}</h1> | ||
| <ol class="api-profile-header-structure naked-list step-list"> | ||
| {% block related_components %}{% endblock %} | ||
| <li> | ||
| - {$ doc.docType $} in module <a href="{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.name $}</a> | ||
| </li> | ||
| </ol> | ||
| </header> | ||
| {% endblock %} | ||
|
|
||
| {% block description %} | ||
| <div class="api-profile-description"> | ||
| {$ doc.description | marked $} | ||
| </div> | ||
| {% endblock %} | ||
|
|
||
| {% if doc.knownIssues %} | ||
| <h2 id="known-issues">Known Issues</h2> | ||
| {% for issue in doc.knownIssues -%} | ||
| <div class="known-issue"> | ||
| {$ issue | marked $} {% if not loop.last %}<hr>{% endif %} | ||
| </div> | ||
| {% endfor -%} | ||
| {% endif %} | ||
|
|
||
| {% if doc.deprecated %} | ||
| <fieldset class="deprecated"> | ||
| <legend>Deprecated API</legend> | ||
| {$ doc.deprecated| marked $} | ||
| </fieldset> | ||
| {% endif %} | ||
|
|
||
| <div> | ||
| {% block dependencies %} | ||
| {%- if doc.requires %} | ||
| <h2 id="dependencies">Dependencies</h2> | ||
| <ul> | ||
| {% for require in doc.requires %}<li>{$ require | link $}</li>{% endfor %} | ||
| </ul> | ||
| {% endif -%} | ||
| {% endblock %} | ||
|
|
||
| {% block additional %} | ||
| {% endblock %} | ||
|
|
||
| {% block examples %} | ||
| {%- if doc.examples %} | ||
| <h2 id="example">Example</h2> | ||
| {%- for example in doc.examples -%} | ||
| {$ example | marked $} | ||
| {%- endfor -%} | ||
| {% endif -%} | ||
| {% endblock %} | ||
| </div> | ||
|
|
||
| {% endblock %} |
| @@ -59,7 +59,7 @@ <h2 id="known-issues">Known Issues</h2> | ||
| <td>{$ issueDoc.id | link(issueDoc.name, issueDoc) $}</td> | ||
| <td> | ||
| {% for issue in issueDoc.knownIssues -%} | ||
| {$ issue | marked $} | ||
| {$ issue | marked $} {% if not loop.last %}<hr>{% endif %} | ||
| {% endfor -%} | ||
| </td> | ||
| </tr> | ||
| @@ -0,0 +1,47 @@ | ||
| @ngdoc error | ||
| @name $compile:reqslot | ||
| @fullName Required transclusion slot | ||
| @description | ||
|
|
||
| This error occurs when a directive or component try to transclude a slot that is not provided. | ||
|
|
||
| Transcluded elements must contain something. This error could happen when you try to transclude a self closing tag element. | ||
| Also you can make a transclusion slot optional with a `?` prefix. | ||
|
|
||
| ```js | ||
| // In this example the <my-component> must have an <important-component> inside to transclude it. | ||
| // If not, a reqslot error will be generated. | ||
|
|
||
| var componentConfig = { | ||
| template: 'path/to/template.html', | ||
| tranclude: { | ||
| importantSlot: 'importantComponent', // mandatory transclusion | ||
| optionalSlot: '?optionalComponent', // optional transclusion | ||
| } | ||
| }; | ||
|
|
||
| angular | ||
| .module('doc') | ||
| .component('myComponent', componentConfig) | ||
|
|
||
| ``` | ||
|
|
||
| ```html | ||
| <!-- Will not work because <important-component> is missing --> | ||
| <my-component> | ||
| </my-component> | ||
|
|
||
| <my-component> | ||
| <optional-component></optional-component> | ||
| </my-component> | ||
|
|
||
| <!-- Will work --> | ||
| <my-component> | ||
| <important-component></important-component> | ||
| </my-component> | ||
|
|
||
| <my-component> | ||
| <optional-component></optional-component> | ||
| <important-component></important-component> | ||
| </my-component> | ||
| ``` |
| @@ -854,7 +854,6 @@ Router itself, which was made available by the binding in the **Component Defini | ||
| function HeroDetailComponent(heroService) { | ||
| ... | ||
| this.gotoHeroes = function() { | ||
| var heroId = this.hero && this.hero.id; | ||
| this.$router.navigate(['HeroList']); | ||
| }; | ||
| ``` | ||
| @@ -277,8 +277,8 @@ Now that Angular knows of all the parts of the application, it needs to create t | ||
| In the previous section we saw that controllers are created using a factory function. | ||
| For services there are multiple ways to define their factory | ||
| (see the {@link services service guide}). | ||
| In the example above, we are using a function that returns the `currencyConverter` function as the factory | ||
| for the service. | ||
| In the example above, we are using an anonymous function as the factory function for `currencyConverter` service. | ||
| This function should return the `currencyConverter` service instance. | ||
|
|
||
| Back to the initial question: How does the `InvoiceController` get a reference to the `currencyConverter` function? | ||
| In Angular, this is done by simply defining arguments on the constructor function. With this, the injector | ||
| @@ -26,9 +26,9 @@ 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. | ||
|
|
||
| * [Node.js](http://nodejs.org): We use Node to generate the documentation, run a | ||
| * [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. | ||
| pre-packaged bundle. (Currently our build does not work properly on Node v5 or greater - please use v4.x.) | ||
|
|
||
| * [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 | ||
| @@ -40,15 +40,6 @@ and included in your [PATH](http://docs.oracle.com/javase/tutorial/essential/env | ||
| npm install -g grunt-cli | ||
| ``` | ||
|
|
||
| * [Bower](http://bower.io/): We use Bower to manage client-side packages for the docs. Install the `bower` command-line tool globally with: | ||
|
|
||
| ```shell | ||
| npm install -g bower | ||
| ``` | ||
|
|
||
| **Note:** You may need to use sudo (for OSX, *nix, BSD etc) or run your command shell as Administrator (for Windows) to install Grunt & | ||
| Bower globally. | ||
|
|
||
| ## Forking Angular on Github | ||
|
|
||
| To create a Github account, follow the instructions [here](https://github.com/signup/free). | ||
| @@ -1235,6 +1235,27 @@ function toJsonReplacer(key, value) { | ||
| * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace. | ||
| * If set to an integer, the JSON output will contain that many spaces per indentation. | ||
| * @returns {string|undefined} JSON-ified string representing `obj`. | ||
| * @knownIssue | ||
| * | ||
| * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date` | ||
| * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the | ||
| * `Date.prototype.toJSON` method as follows: | ||
| * | ||
| * ``` | ||
| * var _DatetoJSON = Date.prototype.toJSON; | ||
| * Date.prototype.toJSON = function() { | ||
| * try { | ||
| * return _DatetoJSON.call(this); | ||
| * } catch(e) { | ||
| * if (e instanceof RangeError) { | ||
| * return null; | ||
| * } | ||
| * throw e; | ||
| * } | ||
| * }; | ||
| * ``` | ||
| * | ||
| * See https://github.com/angular/angular.js/pull/14221 for more information. | ||
| */ | ||
| function toJson(obj, pretty) { | ||
| if (isUndefined(obj)) return undefined; | ||
| @@ -153,7 +153,7 @@ function Browser(window, document, $log, $sniffer) { | ||
| // Do the assignment again so that those two variables are referentially identical. | ||
| lastHistoryState = cachedState; | ||
| } else { | ||
| if (!sameBase || pendingLocation) { | ||
| if (!sameBase) { | ||
| pendingLocation = url; | ||
| } | ||
| if (replace) { | ||
| @@ -167,6 +167,9 @@ function Browser(window, document, $log, $sniffer) { | ||
| pendingLocation = url; | ||
| } | ||
| } | ||
| if (pendingLocation) { | ||
| pendingLocation = url; | ||
| } | ||
| return self; | ||
| // getter | ||
| } else { | ||
| @@ -2354,10 +2354,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { | ||
| } else if (directive.compile) { | ||
| try { | ||
| linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn); | ||
| var context = directive.$$originalDirective || directive; | ||
| if (isFunction(linkFn)) { | ||
| addLinkFns(null, linkFn, attrStart, attrEnd); | ||
| addLinkFns(null, bind(context, linkFn), attrStart, attrEnd); | ||
| } else if (linkFn) { | ||
| addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd); | ||
| addLinkFns(bind(context, linkFn.pre), bind(context, linkFn.post), attrStart, attrEnd); | ||
| } | ||
| } catch (e) { | ||
| $exceptionHandler(e, startingTag($compileNode)); | ||
| @@ -100,11 +100,11 @@ var inputType = { | ||
| <span class="error" ng-show="myForm.input.$error.pattern"> | ||
| Single word only!</span> | ||
| </div> | ||
| <tt>text = {{example.text}}</tt><br/> | ||
| <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/> | ||
| <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/> | ||
| <tt>myForm.$valid = {{myForm.$valid}}</tt><br/> | ||
| <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/> | ||
| <code>text = {{example.text}}</code><br/> | ||
| <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br/> | ||
| <code>myForm.input.$error = {{myForm.input.$error}}</code><br/> | ||
| <code>myForm.$valid = {{myForm.$valid}}</code><br/> | ||
| <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br/> | ||
| </form> | ||
| </file> | ||
| <file name="protractor.js" type="protractor"> | ||
| @@ -69,7 +69,9 @@ function classDirective(name, selector) { | ||
| } | ||
|
|
||
| function ngClassWatchAction(newVal) { | ||
| if (selector === true || scope.$index % 2 === selector) { | ||
| // jshint bitwise: false | ||
| if (selector === true || (scope.$index & 1) === selector) { | ||
| // jshint bitwise: true | ||
| var newClasses = arrayClasses(newVal || []); | ||
| if (!oldVal) { | ||
| addClasses(newClasses); | ||
| @@ -221,6 +221,25 @@ function $InterpolateProvider() { | ||
| * symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e. | ||
| * an interpolated expression consisting of a single-quote (`'`) and the `' }}` string. | ||
| * | ||
| * @knownIssue | ||
| * All directives and components must use the standard `{{` `}}` interpolation symbols | ||
| * in their templates. If you change the application interpolation symbols the {@link $compile} | ||
| * service will attempt to denormalize the standard symbols to the custom symbols. | ||
| * The denormalization process is not clever enough to know not to replace instances of the standard | ||
| * symbols where they would not normally be treated as interpolation symbols. For example in the following | ||
| * code snippet the closing braces of the literal object will get incorrectly denormalized: | ||
| * | ||
| * ``` | ||
| * <div data-context='{"context":{"id":3,"type":"page"}}"> | ||
| * ``` | ||
| * | ||
| * The workaround is to ensure that such instances are separated by whitespace: | ||
| * ``` | ||
| * <div data-context='{"context":{"id":3,"type":"page"} }"> | ||
| * ``` | ||
| * | ||
| * See https://github.com/angular/angular.js/pull/14610#issuecomment-219401099 for more information. | ||
| * | ||
| * @param {string} text The text with markup to interpolate. | ||
| * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have | ||
| * embedded expression in order to return an interpolation function. Strings with no | ||
| @@ -36,7 +36,7 @@ function $SnifferProvider() { | ||
| for (var prop in bodyStyle) { | ||
| if (match = vendorRegex.exec(prop)) { | ||
| vendorPrefix = match[0]; | ||
| vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1); | ||
| vendorPrefix = vendorPrefix[0].toUpperCase() + vendorPrefix.substr(1); | ||
| break; | ||
| } | ||
| } | ||
| @@ -378,7 +378,8 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { | ||
| } | ||
|
|
||
| function update(element) { | ||
| getRunner(element).setHost(newRunner); | ||
| var runner = getRunner(element); | ||
| if (runner) runner.setHost(newRunner); | ||
| } | ||
| } | ||
|
|
||
| @@ -550,6 +550,8 @@ angular.module('ngMessages', []) | ||
| link: function($scope, element, attrs) { | ||
| var src = attrs.ngMessagesInclude || attrs.src; | ||
| $templateRequest(src).then(function(html) { | ||
| if ($scope.$$destroyed) return; | ||
|
|
||
| $compile(html)($scope, function(contents) { | ||
| element.after(contents); | ||
|
|
||
| @@ -220,13 +220,13 @@ angular.mock.$ExceptionHandlerProvider = function() { | ||
| * @param {string} mode Mode of operation, defaults to `rethrow`. | ||
| * | ||
| * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` | ||
| * mode stores an array of errors in `$exceptionHandler.errors`, to allow later | ||
| * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and | ||
| * {@link ngMock.$log#reset reset()} | ||
| * mode stores an array of errors in `$exceptionHandler.errors`, to allow later assertion of | ||
| * them. See {@link ngMock.$log#assertEmpty assertEmpty()} and | ||
| * {@link ngMock.$log#reset reset()}. | ||
| * - `rethrow`: If any errors are passed to the handler in tests, it typically means that there | ||
| * is a bug in the application or test, so this mock will make these tests fail. | ||
| * For any implementations that expect exceptions to be thrown, the `rethrow` mode | ||
| * will also maintain a log of thrown errors. | ||
| * is a bug in the application or test, so this mock will make these tests fail. For any | ||
| * implementations that expect exceptions to be thrown, the `rethrow` mode will also maintain | ||
| * a log of thrown errors in `$exceptionHandler.errors`. | ||
| */ | ||
| this.mode = function(mode) { | ||
|
|
||
| @@ -1871,6 +1871,15 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { | ||
|
|
||
| function MockHttpExpectation(method, url, data, headers, keys) { | ||
|
|
||
| function getUrlParams(u) { | ||
| var params = u.slice(u.indexOf('?') + 1).split('&'); | ||
| return params.sort(); | ||
| } | ||
|
|
||
| function compareUrl(u) { | ||
| return (url.slice(0, url.indexOf('?')) == u.slice(0, u.indexOf('?')) && getUrlParams(url).join() == getUrlParams(u).join()); | ||
| } | ||
|
|
||
| this.data = data; | ||
| this.headers = headers; | ||
|
|
||
| @@ -1886,7 +1895,7 @@ function MockHttpExpectation(method, url, data, headers, keys) { | ||
| if (!url) return true; | ||
| if (angular.isFunction(url.test)) return url.test(u); | ||
| if (angular.isFunction(url)) return url(u); | ||
| return url == u; | ||
| return (url == u || compareUrl(u)); | ||
| }; | ||
|
|
||
| this.matchHeaders = function(h) { | ||
| @@ -2255,11 +2264,11 @@ angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compi | ||
| * | ||
| * First, download the file: | ||
| * * [Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs) e.g. | ||
| * `"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/"` | ||
| * * [NPM](https://www.npmjs.com/) e.g. `npm install {$ doc.packageName $}@X.Y.Z` | ||
| * * [Bower](http://bower.io) e.g. `bower install {$ doc.packageName $}@X.Y.Z` | ||
| * `"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-mocks.js"` | ||
| * * [NPM](https://www.npmjs.com/) e.g. `npm install angular-mocks@X.Y.Z` | ||
| * * [Bower](http://bower.io) e.g. `bower install angular-mocks@X.Y.Z` | ||
| * * [code.angularjs.org](https://code.angularjs.org/) (discouraged for production use) e.g. | ||
| * `"//code.angularjs.org/X.Y.Z/{$ doc.packageFile $}"` | ||
| * `"//code.angularjs.org/X.Y.Z/angular-mocks.js"` | ||
| * | ||
| * where X.Y.Z is the AngularJS version you are running. | ||
| * | ||
Showing you all comments on commits in this comparison.
This comment has been minimized.
This comment has been minimized.
|
Are there any decent performance-tests to check if this helps? http://jsbin.com/manufayizo/edit?html,js,output EDIT: I see there's a perfTest in #4359, but it's unavailable. |
This comment has been minimized.
This comment has been minimized.
|
Micro benchmarks are probably not indicative of real performance |
This comment has been minimized.
This comment has been minimized.
|
I agree. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Indeed. But the test is not available anymore, and it has the extreme claims of being 99% faster, which my test does not show at all. |
This comment has been minimized.
This comment has been minimized.
Do you suggest we replicate all POC jsperf tests which are mentioned in every commit ever merged into master?
99% faster isn't as extreme; it's twice as fast. This result doesn't indeed seem to still be true for today's browsers, but this was almost 3 years ago - browsers and especially JS engines have seem major improvements, so situations like these are expected. |