With this change, $browser.cookies()["foo"] will behave like
docCookies.getItem("foo") where docCookies is defined at
https://developer.mozilla.org/en-US/docs/DOM/document.cookie
This fixes the issue where, if there's a value for the XSRF-TOKEN cookie
value with the path /, then that value is used for all applications in
the domain even if they set path specific values for XSRF-TOKEN.
Closes#2635
BREAKING CHANGE: css classes foo-setup/foo-start become foo/foo-active
The CSS transition classes have changed suffixes. To migrate rename
.foo-setup {...} to .foo {...}
.foo-start {...} to .foo-active {...}
or for type: enter, leave, move, show, hide
.foo-type-setup {...} to .foo-type {...}
.foo-type-start {...} to .foo-type-active {...}
This date {{2003-09-10T13:02:03.123456Z | date: yyyy-mm-dd ss} is now
treated as having 123.45ms. Previously it had 123456ms so 123 seconds
were added to the formatted date.
Use local date in unit tests so they work in any time zone
Fix a check inside render for select elements with ngOptions, which
compares the selected property of an element with it's desired state.
Ensure the placeholder, if available, is explicitly selected if the model
value can not be found in the option list.
Without these fixes it's up to the browser implementation to decide which
option to choose. In most browsers, this has the effect of displaying the
first item in the list. In IE9 however, this causes the select to display
nothing.
Closes#2150, #1826
In older Android browsers, `undefined` does not act like `0` in some
arithmetic operations. This leads to dates being formatted with `NaN`
strings in the dateFilter because the implementation of the `dateGetter`
function allows offset to be an optional parameter.
The fix is to convert offset to 0 if it is undefined.
Closes#2277, #2275
Adding a $includeContentRequested event in order to better keep track of
how many includes are sent and be able to compare it with how many have
finished.
Documentation implies that timeout works for all requests, though it
only works with XHR. To implement:
- Change $httpBackend to set a timeout for JSONP requests which will
immediately resolve the request when fired.
- Cancel the timeout when requests are completed.
Fix a context duplication and invocation to a previous context when
doing an access modifier function on the result of a function
Currently, when doing `foo().bar()`, `foo` is called twice, the first
time to get the context and the second one for `bar` to get the
underlying object. Then the call to `bar` is called using the second
instance as self
This is equivalent to doing:
```
var instance1 = foo();
var instance2 = foo();
instance2.bar.apply(instance1);
```
Closes#2496
Change modulo % 2 operations to bitwise & 1
Read about this in Nicholas C. Zakas book "High Performance JavaScript"(ISBN: 978-0-596-80279-0)
Use the Fast Parts --> Bitwise Operators --> Page 156++
Proven at http://jsperf.com/modulo-vs-bitwise/11
Support ng-controller="MyController as my" syntax
which publishes the controller instance to the
current scope.
Also supports exporting a controller defined with route:
````javascript
angular.module('routes', [], function($routeProvider) {
$routeProvider.when('/home', {controller: 'Ctrl as home', templateUrl: '...'});
});
````
This directive is adapted from ui-if in the AngularUI project and provides a complement
to the ngShow/ngHide directives that only change the visibility of the DOM element and
ngSwitch which does change the DOM but is more verbose.
In IE the model is not updated when the input value is modified using the context
menu, e.g. pasting from the clipboard, or cutting all or part of the current value.
To capture these changes, we bind to the proprietary 'paste' and 'cut' events.
Closes#1462
If you wire up ngClass directly to an object on the scope, e.g. ng-class="myClasses",
where scope.myClasses = { 'classA': true, 'classB': false },
there was a bug that changing scope.myClasses.classA = false, was not being picked
up and classA was not being removed from the element's CSS classes.
This fix uses angular.equals for the comparison and ensures that oldVal is a copy of
(rather than a reference to) the newVal.
I hope this helps someone, I ran into some issues when following the API as described - handlers of this event receive 3 arguments, not 2.
Although this is mentioned [elsewhere](http://docs.angularjs.org/api/ng.$rootScope.Scope#$on) it's not clear when viewing the docs for this behaviour in isolation.
The first argument is an Event Object, not the current route. The previous route argument can also be omitted on occasions.
In situations where path() matched basepath and we needed to
convert from html5 url to hashbang url, the $location service
considered the url to be already rewritten, which resulted in
an error.
Preserve the order of the elements that are not part of a case nor default in
a ng-switch directive
BREAKING CHANGE: elements not in the ng-switch were rendered after the
ng-switch elements. Now they are rendered in-place.
Ng-switch directives should be updated with non ng-switch elements
in render-order. e.g.
The following was previously rendered with <li>1</li> after "2":
<ul ng-switch="select">
<li>1</li>
<li ng-switch-when="option">2</li>
</ul>
To keep the old behaviour, say:
<ul ng-switch="select">
<li ng-switch-when="1">2</li>
<li>1</li>
</ul>
Closes#1074
the `nextRoute` object available in `$routeChangeStart` handler
accidentaly leaked property which pointed to the route definition
currently being matched.
this was done just for the internal needs of the `$route` implementation
and was never documented as public api.
Some confusion arouse around why the $route property was not always
available on the `nextRoute` object (see #1907). The right thing for us
to do is to prefix the property with $$ for now and refactor the code
to remove the property completely in the future. Application developers
should use the `nextRoute` object itself rather than its `$route` property.
The main diff is that nextRoute inherits from the object referenced by $route.
BREAKING CHANGE: in $routeChangeStart event, nextRoute.$route property is gone.
Use the nextRoute object instead of nextRoute.$route.
Closes#1907
When we need more control over http caching, we may want to provide
a custom cache to be used in all http requests by default.
To skip default cache, set {cache: false} in request configuration.
To use other cache, set {cache: cache} as before.
See #2079
A directive can now set/update/remove attribute values even those containing
interpolation during the compile phase and have the new value be picked up
during the compilation.
For example in template:
<div replace-directive some-attr-or-directive="{{originalInterpolationValue}}"></div>
the replace-directive can now replace the value of some-attr-or-directive during compilation
which produces this intermitent template:
<div replace-directive some-attr-or-directive="{{replacedInterpolationValue}}"></div>
or even
<div replace-directive some-attr-or-directive="replacedStaticValue"></div>
as well as
<div replace-directive some-attr-or-directive></div>
Sometimes is not desirable to use interpolation on attributes because
the user agent parses them before the interpolation takes place. I.e:
<svg>
<circle cx="{{cx}}" cy="{{cy}}" r="{{r}}"></circle>
</svg>
The snippet throws three browser errors, one for each attribute.
For some attributes, AngularJS fixes that behaviour introducing special
directives like ng-href or ng-src.
This commit is a more general solution that allows prefixing any
attribute with "ng-attr-", "ng:attr:" or "ng_attr_" so it will
be set only when the binding is done. The prefix is then removed.
Example usage:
<svg>
<circle ng-attr-cx="{{cx}}" ng-attr-cy="{{cy}}" ng:attr-r="{{r}}"></circle>
</svg>
Closes#1050Closes#1925
Passing DOMNode#childNodes to compileNodes when compiling remote
template, so that directives with replace:true can be compiled.
The previous version used jqLite#contents which returned collection
that was not updated during the compilation.
Closes#1859
If you bind using '=' to a non-existant parent property, the compiler
will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception, which is right
because the model doesn't exist.
This enhancement allow to specify that a binding is optional so it
won't complain if the parent property is not defined. In order to mantain
backward compability, the new behaviour must be specified using '=?' instead
of '='. The local property will be undefined is these cases.
Closes#909Closes#1435
When waiting for several promises at once, it is often desirable to
have them by name, not just by index in array.
Example of this kind of interface already implemented would be a
$routeProvider.when(url, {resolve: <hash of promises>}), where
resources/promises are given by names, and then results accessed
by names in controller.
If responseType is defined and the request fails for one reason or another
the .response property returned falsy value which caused dereferencing of
.responseText. If the responseType was a blob or document then an error
was thrown.
To prevent this, I'm checking for responseType first and based on that
dereferencing .response or .responseText.
We need to keep on checking .responseText because that's the original XHR
response api that is still needed for IE8 and 9.
Closes#1922
ngClassWatchAction, when called as a $watch function, gets the wrong old
value after it has been invoked previously due to observation of the
interpolated class attribute. As a result it doesn't remove classes
properly. Keeping track of the old value manually seems to fix this.
Closes#1637
The change to prevent <span> elements being wrapped around empty text nodes caused these empty text nodes to have scopes and controllers attached, through jqLite.data() calls, which led to memory leaks and errors in IE8.
Now we exclude all but document nodes and elements from having jqLite.data() set both in the compiler and in ng-view.
Fixes: #1968 and #1876
This allows routeProvider to accept parameters that matches
substrings even when they contain slashes if they are prefixed
with an asterisk instead of a colon.
For example, routes like edit/color/:color/largecode/*largecode
will match with something like this
http://appdomain.com/edit/color/brown/largecode/code/with/slashs.
A workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=608735
In FF getAllResponseHeaders() returns null if the request is the result of CORS.
Tried to format the code so that when a FF patch is released and gains enough
traction it can easily be selected and deleted. Heavily inspired by jQuery's
patch for the same bug. This patch falls short of passing through custom headers
but covers all of the "simple response headers" in the spec at
http://www.w3.org/TR/cors/
This commit should get reverted once Firefox 21 gets out.
Closes#1468
Apparently there is a really weird bug in IE6-8 that causes anchor textContent
to be reset with href content when both contain @ symbol.
Inserting a bogus comment node into all anchor elements in IE works around this
browser bug.
I'm fixing the issue via directive because that way we'll fix it for jQuery as
well.
I fixed an e2e test too because it was incorrect.
Closes#1949
encodeURIComponent is too aggressive and doesn't follow http://www.ietf.org/rfc/rfc3986.txt
with regards to the character set (pchar) allowed in path segments so we need
this test to make sure that we don't over-encode the params and break stuff
like buzz api which uses @self.
This is has already been fixed in `$resource`. This commit fixes it in a same way
for `$http` as well.
BREAKING CHANGE: $http does follow RFC3986 and does not encode special characters
like `$@,:` in params. If your application needs to encode these characters, encode
them manually, before sending the request.
* `literal` is set to true if the expression's top-level is a JavaScript
literal (number, string, boolean, null/undefined, array, object), even
if it contains non-literals inside.
* `constant` is set to true if the expression is known to be made
entirely of constant values, i.e., evaluating it will always yield the
same result.
A consequence is that a JSON expression is guaranteed to be both literal
and constant.
Add optional comparator function argument to $filter('filter')(array,
expression, comparator) such that the comparator function is used to
compare the values and predicates. When true, defaults to equality.
When missing defaults to substring matching.
When checking to add decimal and trialing 0s number filter used to check
trueness of fractionSize. "0" evaluating to true causes "123" to return "123."
Directives was observing different instances of Attributes than the one
that interpolation was registered with because we failed to realize
that the compile node and link node were the same (one of them
was a wrapper rather than raw node)
Closes#1941
Safari and IE don't like being told to store cookies with path set to
undefined. This change ensures that if base[href] (from which cookie path
is derived) is undefined then the cookie path defaults to ''.
The test verifies that the cookie is set instead of checking that cookie has correct path,
this is due to that cookie meta information is not avabile once the cookie is set.
Closes#1190, #1191
Add 'xsrfCookieName' and 'xsrfHeaderName' property to $httpProvider.defaults and
http config object, which give the name of the cookie the XSRF token is found
in, and the name of the header it is sent in, respectively.
This allows interop with servers with built-in XSRF support that use different
names.
The defaults match the current hard-coded values of 'XSRF-TOKEN' and
'X-XSRF-TOKEN'.
This commit fixes#1261 and #1532. This covers
two separate issues:
- Positive timezones were being formatted without
a leading `+` resulting in a formatting string
like: "HH:MM:ssZ" giving "12:13:141000" instead
of "12:13:14+1000". Fixed by checking if timezone
is > 0 and adding a leading "+".
- Timezone output signs were inverted.
mock.TzDate expects the timezone _offset_ as it's
first argument, _not_ the timezone. This means
that a mock.TzDate with a positive offset should
result in a date string with a negative timezone,
and vice-versa.
Closes#1261, #1532
The leak can occur when ngSwich is used inside ngRepeat or any other
directive which is destroyed while its transcluded content (which
includes ngSwitch) is not attached to the DOM.
Refactor ngSwitch to use controller instead of storing data on compile
node. This means that we don't need to clean up the jq data cache.
Controller reference is released when the linking fn is released.
Closes#1621
Update src/ng/exceptionHandler.js
Here's an iniitla attempt at documenting how one might write a
test using $exceptionHandlerProvider. The key take-away is the use
of this pattern:
it(...
module(...
$exceptionHandlerProvider.mode('log');
});
inject(...
);
});
If the $last property is calculated from the original collectionLength
on an object and properties starting with $ were filtered out, then $last
is never applied and $middle is applied erroniously.
Closes#1789
Commit 773ac4a broke support for route parameters that are not seperated
from other route parts by slashes, which this change fixes. It also adds
some documentation about path parameters to the when() method and
escapes all regular expression special characters in the URL, not just
some.
Support modifying the DOM structure in the post link function of a directive
by creating a defensive copy of the node list, as opposed to a live DOM list.
This is useful for directives to actually replace their entire DOM fragment,
e.g. with the HTML fragment generated by a 3rd party component (Closure, Bootstrap ...).
Fix the indentation of the compileNodes function (was one too little).
previously we were always parsing the string input as UTC which cased issues like:
{{ '2012-04-01' | date:'d MMM yyyy' }} renders as 31 Mar 2012
BREAKING CHANGE: string input without timezone info is now parsed as local time/date
Closes#847
the warning is defunct (and the test is incorrect) so obviously nobody is using
it and it just takes up space.
also the browser behavior varies (ff and chrome allow up to 150 cookies, safari
even more), so it's not very useful.
Closes#1712
This reverts commit c81d8176cc.
This commit causes several issues (#1651, #1674, #1662) and doesn't even
contain a test that proves that anything on Opera got actually fixed.
If the original Opera resurfaces, we'll fix it properly.
Routes like '/bar/foovalue/barvalue' matching '/bar/:foo/:bar'
now are well mapped in $routeParams to:
{bar:'barvalue', foo:'foovalue'}
Closes: #1501
Signed-off-by: Gonzalo Ruiz de Villa <gonzaloruizdevilla@gmail.com>
This is needed to prevent CORS preflight checks. The XSFR token
is quite useless for CORS requests anyway.
BREAKING CHANGE: X-XSFR-TOKEN is no longer send for cross domain
requests. This shouldn't affect any known production service.
Closes#1096
X-Requested-With header is rarely used in practice and by using
it all the time we are triggering preflight checks for crossdomain
requests.
We could try detecting if we are doing CORS requests or not, but
it doesn't look like it's worth the trouble.
BREAKING CHANGE: X-Requested-With header is not set by $http service
any more. If anyone actually uses this header it's quite easy to add
it back via:
```
myAppModule.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
}]);
```
Closes#1004
I'm reverting changes that were originally done to ngRepeat to fix#933,
because these are now not necessary after the previous changes to keep
ngModel always synced with the DOM.
In cases when we reuse elements in a repeater but associate
them with a new scope (see #933 - repeating over array of
primitives) it's possible for the internal ngModel state and
the scope state to get out of sync. This change ensure that
the two are always sync-ed up even in cases where we
reassociate an element with a different (but similar) scope.
In the case of repeating over array of primitives it's still
possible to run into issue if we iterate over primitives and
use form controls or similar widgets without ngModel - oh well,
we'd likely need a special repeater for primitives to deal
with this properly, even then there might be cornercases.
Closes#933
I'm keeping this in for future reference. The issue with this solution
is that if we shift() the first item in the array, the whole repeater
DOM will be rebuilt from scratch, we need to do better than that.
Today, calling e.g. $http(url, { params: { a: [1,2,3] } }) results in a query
string like "?a=%5B1%2C2%2C3%5D" which is undesirable. This commit enhances
buildURL to createa query string like "?a=1&a=2&a=3".
BREAKING CHANGE: if the server relied on the buggy behavior then either the
backend should be fixed or a simple serialization of the array should be done
on the client before calling the $http service.
Closes#1363
window.SecurityPolicy.isActive() is now window.securityPolicy.isActive
since this is available only in Chrome Canary which has already been
updated, we can safely make this change without worrying about
backwards compatilibty.
Closes#1577
Bug caused by the use of the `||` operator to replace all non-truthy
values with an empty string. Changed to replace only `undefined` values.
Closes#1401
This fixes the issue that caused two attr interpolation observers
to be registered for the same attribute as a result of isolate
scope definition with attr (@) property for this attribute.
Duplicate observers would then fight with each other updating the
model.
The issue occured only when this directive was used in a repeater
because that's when we clone the template node which caused the
two observers to point to two different sets of $attr instances.
Closes#1166, #836
IEEE 754 floating point sometimes results in values that are very small,
rather than zero. One example is 1.0 + 1.07 - 2.07, which returns
4.440892098500626e-16 instead of 0.
This change tweaks the number formatting logic so that an exponential
value with a negative exponent that is larger than the precision+1
returns 0 instead. For example: with precision 2, anything with an
exponent of -4, -5 or more would become 0. 9e-3 = 0.009 = 0.01, but 9e-4
= 0.0009 = 0.001 = 0.00. This detail is unlikely to matter since this
quirk is usually only triggered with values very close to zero.
Closes#1469
This was really corner case:
Watcher needs to return changed value, to notify that model might have changed and one more $digest cycle needs to be performed.
The watcher, that takes care of reference binding into an isolate scope ("="), did not return changed value, if the change was from the isolate scope to the parent.
If any other watcher returned change, it worked fine, as this change caused re-digest.
Closes#1272
Having one async queue per scope complicates the matters when users wish to do
partial scope updates, since many services put events on the rootScope. By
having single queue the programing model is simplified.
Current implementation of ngSrc may lead to empty src attribute when page is loading.
For example:
<img ng-src="{{image.url}}">
can be temporarily rendered as
<img src="">
before the image resource is loaded.
Some browser emits a request to the current page when seeing <img src=""> (Firefox13 and IE8 will, Chromium20 won't), which leads to performance problems.
Makes the time zone optional in the date filter
Problem with the current R_ISO8601_STR regex was that the time was optional, but the zone was not.
This results in the filter not formatting local date times, which it could easily do.
For example:
2012-08-30 -> formatted
2012-08-30T06:06:06.123Z -> formatted
2012-08-30T06:06:06.123 -> NOT formatted
A simple change in the regex fixes this. Arguably this is closer to the ISO8601 spec which specifies
local dates being in the "current time zone" and not requiring a Z. In any case it behaves more like
a user would expect.
if an exception occurs during interpolation of a string
(e.g. name() in "Hello, {{name()}}!" throws an exception) we now print
an error message with the expression that was being evaluated when the
exception was thrown.
it turns out that some stuff doesn't work in xhtml as it does in html.
for example can't be innerHTML-ed and auto-closing of elements
doesn't work.
the reporter of the referenced issue claimed that innerHTML vs text on
script made a difference but that doesn't appear to be true in my testing.
I'm not including test for this because testacular doesn't currently
run tests in xhtml yet.
Closes#1301
Since developers are allowed to customize start/end interpolation
strings, but third-party directive creators don't know about these
customizations, we should standardize on {{ }} in templates of
reusable (third-party) directives. During the compilation, these
templates are then denormalized to use whatever the custom
start/end symbol is, effectively translating the template into the
syntax of the runtime environment.
This addresses an issue raised at http://goo.gl/e8VPV
Existing code should not be affected by this change since project
that do use custom interpolation markers are not expected to use
{{ }} in existing directive templates.
previously we expected to find option elements only within select element and if
that was not the case we throw an error. This made it impossible to include datalist
element with nested option elements in the template.
Closes#1165
this fix ensures that we prevent the default action on form submission
(full page reload) even in cases when the form is being destroyed as
a result of the submit event handler (e.g. when route change is
triggered).
The fix is more complicated than I'd like it to be mainly because
we need to ensure that we don't create circular references between
js closures and dom elements via DOM event handlers that would then
result in a memory leak.
Also the differences between IE8, IE9 and normal browsers make testing
this ugly.
Closes#1238
When user clicks a link, $location needs to intercept this event. The <a> doesn't have to be target element of the DOM event, so it needs to traverse the DOM, to find first <a> parent.
If the target element was removed from DOM, during the same event, it would throw an exception. This fixes the issue.
Closes#1058
This is a second fix for a regression that was introduced by 92a2e180.
The fix addresses scenarios when the $location service is configured with
a hash prefix.
Closes#1037
we now have two types of namespaces:
- true namespace: angular.* - used for all global apis
- virtual namespace: ng.*, ngMock.*, ... - used for all DI modules
the virual namespaces have services under the second namespace level (e.g. ng.)
and filters and directives prefixed with filter: and directive: respectively
(e.g. ng.filter:orderBy, ng.directive:ngRepeat)
this simplifies urls and makes them a lot shorter while still avoiding name collisions
Changed the isolate scope binding options to:
- @attr - attribute binding (including interpolation)
- =model - by-directional model binding
- &expr - expression execution binding
This change simplifies the terminology as well as
number of choices available to the developer. It
also supports local name aliasing from the parent.
BREAKING CHANGE: isolate scope bindings definition has changed and
the inject option for the directive controller injection was removed.
To migrate the code follow the example below:
Before:
scope: {
myAttr: 'attribute',
myBind: 'bind',
myExpression: 'expression',
myEval: 'evaluate',
myAccessor: 'accessor'
}
After:
scope: {
myAttr: '@',
myBind: '@',
myExpression: '&',
// myEval - usually not useful, but in cases where the expression is assignable, you can use '='
myAccessor: '=' // in directive's template change myAccessor() to myAccessor
}
The removed `inject` wasn't generaly useful for directives so there should be no code using it.
attr.$observe used to call function only if there was interpolation
on that attribute. We now call the observation function all the time
but we only save the reference to it if interpolation is present.
$timeout has a better name ($defer got often confused with something related to $q) and
is actually promise based with cancelation support.
With this commit the $defer service is deprecated and will be removed before 1.0.
Closes#704, #532
$position marker doesn't work well in cases when we have just one item
in the list because then the item is both the first and last. To solve
this properly we need to expose individual $first and $middle and $last
flags.
BREAKING CHANGE: $position is not exposed in repeater scopes any more
To update, search for $position and replace it with one of $first,
$middle or $last.
Closes#912
The url used for location parsing was quite strict and did not support
custom url schemes like "chrome-extension://". With this change the only
requirement for scheme is that it doesn't contain ":" character.
The real issue is in FF, see https://bugzilla.mozilla.org/show_bug.cgi?id=407172.
FF overly encodes stuff which breaks our expectations and then we fail .url() != currentUrl.absUrl()
comparison unexpectidly, which leads to infinite digest.
The workaround is to correct for this inconsistency in $browser and decode any single quotes in urls.
Closes#920
IE9 ignores setAttribute('src', val) calls on img if "ng:src" attribute
is present. It only fetches the image if element property is updated as well.
Closes#935
On IE9 the input event is not fired when backspace or delete key are pressed or when
cut is performed. This makes listening on the input event unreliable and therefore
it's better for us to just use keydown/change events instead.
Closes#879
the old implementation didn't reattach jquery/jqlite data which caused
things like to be lost
I tried various implementations but it appears that by reattaching the data
to the new node by copying the expando property is the most reliable of all.
This stuff was never documented and is an accidental leftover from the time
when the compiler was rewritten.
If any code depends on this, it should be rewritten to use ngTransclude directive
intead.
CSP (content security policy) forbids apps to use eval or
Function(string) generated functions (among other things). For us to be
compatible, we just need to implement the "getterFn" in $parse without
violating any of these restrictions.
We currently use Function(string) generated functions as a speed
optimization. With this change, it will be possible to opt into the CSP
compatible mode using the ngCsp directive. When this mode is on Angular
will evaluate all expressions up to 30% slower than in non-CSP mode, but
no security violations will be raised.
In order to use this feature put ngCsp directive on the root element of
the application. For example:
<!doctype html>
<html ng-app ng-csp>
...
...
</html>
Closes#893
Previously only when ngOptions was used, we correctly handled situations
when model was set to an unknown value. With this change, we'll add/remove
extra unknown option or reuse an existing empty option (option with value
set to "") when model is undefined.
previously we were doing all kinds of checks to see if we should rewrite the url or not and we
were missing many scenarios. not any more.
with this change, we rewrite the url unless:
- the href is not set
- link has target attribute
- the absolute url of the link doesn't match the absolute prefix for all urls in our app
This also means that ng-ext-link attribute which we previously used to distinguish external
links from app links is not necessary any more. apps can just set target=_self to prevent
rewriting.
BREAKING CHANGE: ng-ext-link directive was removed because it's unnecessary
apps that relied on ng-ext-link should simply replace it with target=_self