Skip to content

Commit 62ef3d7

Browse files
committed
fix subscript/superscript problem I just created
and test these as well as tag auto-close/open
1 parent 4e4b8c8 commit 62ef3d7

File tree

2 files changed

+65
-7
lines changed

2 files changed

+65
-7
lines changed

src/lib/svg_text_utils.js

+15-6
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,11 @@ var SPLIT_TAGS = /(<[^<>]*>)/;
264264

265265
var ONE_TAG = /<(\/?)([^ >]*)(\s+(.*))?>/i;
266266

267-
var QUOTEDATTR = '\\s*=\\s*("([^"]*)"|\'([^\']*)\')';
268-
var STYLEMATCH = new RegExp('(^|[\\s"\'])style' + QUOTEDATTR, 'i');
269-
var HREFMATCH = new RegExp('(^|[\\s"\'])href' + QUOTEDATTR, 'i');
267+
// Style and href: pull them out of either single or double quotes.
268+
// Because we hack in other attributes with style (sub & sup), drop any trailing
269+
// semicolon in user-supplied styles so we can consistently append the tag-dependent style
270+
var STYLEMATCH = /(^|[\s"'])style\s*=\s*("([^"]*);?"|'([^']*);?')/i;
271+
var HREFMATCH = /(^|[\s"'])href\s*=\s*("([^"]*)"|'([^']*)')/i;
270272

271273
var COLORMATCH = /(^|;)\s*color:/;
272274

@@ -362,9 +364,11 @@ function convertToSVG(_str) {
362364
// but font color is different (uses fill). Let our users ignore this.
363365
var cssMatch = extra && extra.match(STYLEMATCH);
364366
var css = cssMatch && (cssMatch[3] || cssMatch[4]);
365-
if(css) css = encodeForHTML(css.replace(COLORMATCH, '$1 fill:'));
366-
367-
if(tagStyle) css = tagStyle + ';' + (css || '');
367+
if(css) {
368+
css = encodeForHTML(css.replace(COLORMATCH, '$1 fill:'));
369+
if(tagStyle) css += ';' + tagStyle;
370+
}
371+
else if(tagStyle) css = tagStyle;
368372

369373
if(css) return out + ' style="' + css + '">';
370374

@@ -376,6 +380,11 @@ function convertToSVG(_str) {
376380
});
377381

378382
// now deal with line breaks
383+
// TODO: this next section attempts to close and reopen tags that
384+
// span a line break. But
385+
// a) it only closes and reopens one tag, and
386+
// b) all tags are treated like equivalent tspans (even <a> which isn't a tspan even now!)
387+
// we should really do this in a type-aware way *before* converting to tspans.
379388
var indices = [];
380389
for(var index = result.indexOf('<br>'); index > 0; index = result.indexOf('<br>', index + 1)) {
381390
indices.push(index);

test/jasmine/tests/svg_text_utils_test.js

+50-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ describe('svg+text utils', function() {
4545

4646
expect(hasWrongAttr).toBe(false);
4747

48-
expect(a.attr('style')).toBe('cursor:pointer;' + (style || ''));
48+
var fullStyle = style || '';
49+
if(style) fullStyle += ';';
50+
fullStyle += 'cursor:pointer';
51+
52+
expect(a.attr('style')).toBe(fullStyle);
4953
}
5054

5155
function listAttributes(node) {
@@ -226,5 +230,50 @@ describe('svg+text utils', function() {
226230

227231
expect(node.text()).toEqual('100μ & < 10 > 0  100 × 20 ± 0.5 °');
228232
});
233+
234+
it('supports superscript by itself', function() {
235+
var node = mockTextSVGElement('<sup>123</sup>');
236+
expect(node.html()).toBe(
237+
'​<tspan style="font-size:70%" dy="-0.6em">123</tspan>' +
238+
'<tspan dy="0.42em">​</tspan>');
239+
});
240+
241+
it('supports subscript by itself', function() {
242+
var node = mockTextSVGElement('<sub>123</sub>');
243+
expect(node.html()).toBe(
244+
'​<tspan style="font-size:70%" dy="0.3em">123</tspan>' +
245+
'<tspan dy="-0.21em">​</tspan>');
246+
});
247+
248+
it('supports superscript and subscript together with normal text', function() {
249+
var node = mockTextSVGElement('SO<sub>4</sub><sup>2-</sup>');
250+
expect(node.html()).toBe(
251+
'SO​<tspan style="font-size:70%" dy="0.3em">4</tspan>' +
252+
'<tspan dy="-0.21em">​</tspan>​' +
253+
'<tspan style="font-size:70%" dy="-0.6em">2-</tspan>' +
254+
'<tspan dy="0.42em">​</tspan>');
255+
});
256+
257+
it('allows one <b> to span <br>s', function() {
258+
var node = mockTextSVGElement('be <b>Bold<br>and<br><i>Strong</i></b>');
259+
expect(node.html()).toBe(
260+
'<tspan class="line" dy="0em">be ' +
261+
'<tspan style="font-weight:bold">Bold</tspan></tspan>' +
262+
'<tspan class="line" dy="1.3em">' +
263+
'<tspan style="font-weight:bold">and</tspan></tspan>' +
264+
'<tspan class="line" dy="2.6em">' +
265+
'<tspan style="font-weight:bold">' +
266+
'<tspan style="font-style:italic">Strong</tspan></tspan></tspan>');
267+
});
268+
269+
it('allows one <sub> to span <br>s', function() {
270+
var node = mockTextSVGElement('SO<sub>4<br>44</sub>');
271+
expect(node.html()).toBe(
272+
'<tspan class="line" dy="0em">SO​' +
273+
'<tspan style="font-size:70%" dy="0.3em">4</tspan></tspan>' +
274+
'<tspan class="line" dy="1.3em">​' +
275+
'<tspan style="font-size:70%" dy="0.3em">44</tspan>' +
276+
'<tspan dy="-0.21em">​</tspan></tspan>');
277+
});
229278
});
230279
});

0 commit comments

Comments
 (0)