From 93fa9917887c1a77b6ed01be78624e7cf0ef8147 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Mon, 20 Jan 2014 11:21:50 -0500 Subject: [PATCH] fix(a): don't preventDefault on click when SVGAElement has an xlink:href attribute Before this change, an SVGAElement with an xlink:href attribute and no href or name attribute which was compiled by the angular HTML compiler would never be clickable, due to the htmlAnchorDirective calling event.preventDefault() due to the missing href attribute. This change corrects this behaviour by also testing the xlink:href attribute if the element in question is determined to be an SVG anchor tag (with the href property having type SVGAnimatedString) Closes #5896 --- src/ng/directive/a.js | 7 ++-- test/ng/directive/aSpec.js | 67 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/ng/directive/a.js b/src/ng/directive/a.js index fe50a79b19a3..9887cba535ce 100644 --- a/src/ng/directive/a.js +++ b/src/ng/directive/a.js @@ -32,11 +32,14 @@ var htmlAnchorDirective = valueFn({ element.append(document.createComment('IE fix')); } - if (!attr.href && !attr.name) { + if (!attr.href && !attr.xlinkHref && !attr.name) { return function(scope, element) { + // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute. + var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ? + 'xlink:href' : 'href'; element.on('click', function(event){ // if we have no href url, then don't navigate anywhere. - if (!element.attr('href')) { + if (!element.attr(href)) { event.preventDefault(); } }); diff --git a/test/ng/directive/aSpec.js b/test/ng/directive/aSpec.js index dc0de729fe58..bd9f246dc0cd 100644 --- a/test/ng/directive/aSpec.js +++ b/test/ng/directive/aSpec.js @@ -84,4 +84,71 @@ describe('a', function() { expect(jq.prototype.on).not.toHaveBeenCalled(); }); + + + if (isDefined(window.SVGElement)) { + describe('SVGAElement', function() { + it('should prevent default action to be executed when href is empty', function() { + var orgLocation = document.location.href, + preventDefaultCalled = false, + event, + child; + + element = $compile('empty link')($rootScope); + child = element.children('a'); + + if (msie < 9) { + + event = document.createEventObject(); + expect(event.returnValue).not.toBeDefined(); + child[0].fireEvent('onclick', event); + expect(event.returnValue).toEqual(false); + + } else { + + event = document.createEvent('MouseEvent'); + event.initMouseEvent( + 'click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + + event.preventDefaultOrg = event.preventDefault; + event.preventDefault = function() { + preventDefaultCalled = true; + if (this.preventDefaultOrg) this.preventDefaultOrg(); + }; + + child[0].dispatchEvent(event); + + expect(preventDefaultCalled).toEqual(true); + } + + expect(document.location.href).toEqual(orgLocation); + }); + + + it('should not link and hookup an event if xlink:href is present at compile', function() { + var jq = jQuery || jqLite; + element = jq('hello@you'); + var linker = $compile(element); + + spyOn(jq.prototype, 'on'); + + linker($rootScope); + + expect(jq.prototype.on).not.toHaveBeenCalled(); + }); + + + it('should not link and hookup an event if name is present at compile', function() { + var jq = jQuery || jqLite; + element = jq('hello@you'); + var linker = $compile(element); + + spyOn(jq.prototype, 'on'); + + linker($rootScope); + + expect(jq.prototype.on).not.toHaveBeenCalled(); + }); + }); + } });