diff --git a/src/lib/svg_text_utils.js b/src/lib/svg_text_utils.js
index 0f1d538b6a4..10242e4a639 100644
--- a/src/lib/svg_text_utils.js
+++ b/src/lib/svg_text_utils.js
@@ -282,11 +282,36 @@ var SPLIT_TAGS = /(<[^<>]*>)/;
var ONE_TAG = /<(\/?)([^ >]*)(\s+(.*))?>/i;
-// Style and href: pull them out of either single or double quotes.
-// Because we hack in other attributes with style (sub & sup), drop any trailing
-// semicolon in user-supplied styles so we can consistently append the tag-dependent style
+/*
+ * style and href: pull them out of either single or double quotes. Also
+ * - target: (_blank|_self|_parent|_top|framename)
+ * note that you can't use target to get a popup but if you use popup,
+ * a `framename` will be passed along as the name of the popup window.
+ * per the spec, cannot contain whitespace.
+ * for backward compatibility we default to '_blank'
+ * - popup: a custom one for us to enable popup (new window) links. String
+ * for window.open -> strWindowFeatures, like 'menubar=yes,width=500,height=550'
+ * note that at least in Chrome, you need to give at least one property
+ * in this string or the page will open in a new tab anyway. We follow this
+ * convention and will not make a popup if this string is empty.
+ * per the spec, cannot contain whitespace.
+ *
+ * Because we hack in other attributes with style (sub & sup), drop any trailing
+ * semicolon in user-supplied styles so we can consistently append the tag-dependent style
+ */
var STYLEMATCH = /(^|[\s"'])style\s*=\s*("([^"]*);?"|'([^']*);?')/i;
var HREFMATCH = /(^|[\s"'])href\s*=\s*("([^"]*)"|'([^']*)')/i;
+var TARGETMATCH = /(^|[\s"'])target\s*=\s*("([^"\s]*)"|'([^'\s]*)')/i;
+var POPUPMATCH = /(^|[\s"'])popup\s*=\s*("([^"\s]*)"|'([^'\s]*)')/i;
+
+// dedicated matcher for these quoted regexes, that can return their results
+// in two different places
+function getQuotedMatch(_str, re) {
+ if(!_str) return null;
+ var match = _str.match(re);
+ return match && (match[3] || match[4]);
+}
+
var COLORMATCH = /(^|;)\s*color:/;
@@ -297,14 +322,14 @@ exports.plainText = function(_str) {
};
function replaceFromMapObject(_str, list) {
- var out = _str || '';
+ if(!_str) return '';
for(var i = 0; i < list.length; i++) {
var item = list[i];
- out = out.replace(item.regExp, item.sub);
+ _str = _str.replace(item.regExp, item.sub);
}
- return out;
+ return _str;
}
function convertEntities(_str) {
@@ -354,8 +379,7 @@ function convertToSVG(_str) {
// anchor is the only tag that doesn't turn into a tspan
if(tag === 'a') {
- var hrefMatch = extra && extra.match(HREFMATCH);
- var href = hrefMatch && (hrefMatch[3] || hrefMatch[4]);
+ var href = getQuotedMatch(extra, HREFMATCH);
out = 'link');
+ assertAnchorLink(node, 'x', spec.target, spec.show, spec.target);
+ });
+ });
+
+ it('attaches onclick if popup is specified', function() {
+ var node = mockTextSVGElement('link');
+ assertAnchorLink(node, 'x', 'fred', 'new');
+ assertAnchorAttrs(node, {onclick: 'window.open(\'x\',\'fred\',\'width=500,height=400\');return false;'});
+ });
+
it('keeps query parameters in href', function() {
var textCases = [
'abc.com?shared-key',
@@ -171,9 +202,9 @@ describe('svg+text utils', function() {
textCases.forEach(function(textCase) {
var node = mockTextSVGElement(textCase);
- assertAnchorAttrs(node);
- expect(node.text()).toEqual('abc.com?shared-key');
- assertAnchorLink(node, 'https://abc.com/myFeature.jsp?name=abc&pwd=def');
+ assertAnchorAttrs(node, {}, textCase);
+ expect(node.text()).toEqual('abc.com?shared-key', textCase);
+ assertAnchorLink(node, 'https://abc.com/myFeature.jsp?name=abc&pwd=def', undefined, undefined, textCase);
});
});