Skip to content

Commit 03ab27f

Browse files
committed
fix(a): handle SVGAElement differently from HTML anchor tag
Before this change, SVG elements without an 'href' attribute (but with an xlink:href attribute) within the application would always have their click event preventDefault, due to the href attribute being falsy. This change fixes this by giving an SVGAElement a separate link function which is concerned with the xlink:href attribute. Closes angular#5896
1 parent 8b395ff commit 03ab27f

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

src/ng/directive/a.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,18 @@ var htmlAnchorDirective = valueFn({
3232
element.append(document.createComment('IE fix'));
3333
}
3434

35-
if (!attr.href && !attr.name) {
35+
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
36+
if (toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
37+
if (!attr.xlinkHref && !attr.name) {
38+
return function(scope, element) {
39+
element.on('click', function(event) {
40+
if (!element.attr('xlink:href')) {
41+
event.preventDefault();
42+
}
43+
});
44+
};
45+
}
46+
} else if (!attr.href && !attr.name) {
3647
return function(scope, element) {
3748
element.on('click', function(event){
3849
// if we have no href url, then don't navigate anywhere.

test/ng/directive/aSpec.js

+67
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,71 @@ describe('a', function() {
8484

8585
expect(jq.prototype.on).not.toHaveBeenCalled();
8686
});
87+
88+
89+
if (isDefined(window.SVGElement)) {
90+
describe('SVGAElement', function() {
91+
it('should prevent default action to be executed when href is empty', function() {
92+
var orgLocation = document.location.href,
93+
preventDefaultCalled = false,
94+
event,
95+
child;
96+
97+
element = $compile('<svg><a xlink:href="">empty link</a></svg>')($rootScope);
98+
child = element.children('a');
99+
100+
if (msie < 9) {
101+
102+
event = document.createEventObject();
103+
expect(event.returnValue).not.toBeDefined();
104+
child[0].fireEvent('onclick', event);
105+
expect(event.returnValue).toEqual(false);
106+
107+
} else {
108+
109+
event = document.createEvent('MouseEvent');
110+
event.initMouseEvent(
111+
'click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
112+
113+
event.preventDefaultOrg = event.preventDefault;
114+
event.preventDefault = function() {
115+
preventDefaultCalled = true;
116+
if (this.preventDefaultOrg) this.preventDefaultOrg();
117+
};
118+
119+
child[0].dispatchEvent(event);
120+
121+
expect(preventDefaultCalled).toEqual(true);
122+
}
123+
124+
expect(document.location.href).toEqual(orgLocation);
125+
});
126+
127+
128+
it('should not link and hookup an event if xlink:href is present at compile', function() {
129+
var jq = jQuery || jqLite;
130+
element = jq('<svg><a xlink:href="bobby">hello@you</a></svg>');
131+
var linker = $compile(element);
132+
133+
spyOn(jq.prototype, 'on');
134+
135+
linker($rootScope);
136+
137+
expect(jq.prototype.on).not.toHaveBeenCalled();
138+
});
139+
140+
141+
it('should not link and hookup an event if name is present at compile', function() {
142+
var jq = jQuery || jqLite;
143+
element = jq('<svg><a name="bobby">hello@you</a></svg>');
144+
var linker = $compile(element);
145+
146+
spyOn(jq.prototype, 'on');
147+
148+
linker($rootScope);
149+
150+
expect(jq.prototype.on).not.toHaveBeenCalled();
151+
});
152+
});
153+
}
87154
});

0 commit comments

Comments
 (0)