svg-text
Version:
Utilities for working with SVG, including SvgText for multiline text.
80 lines (71 loc) • 1.79 kB
JavaScript
const TEXT = 'TEXT';
const ELEMENT = 'ELEMENT';
let tag;
let quote;
let status;
export default function extractElements(text) {
const chars = text.split('');
const tags = [];
reset();
chars.forEach((c, index) => {
switch (status) {
case TEXT:
if (c === '<') {
tag = startTag(c, index);
}
break;
case ELEMENT:
tag.markup += c;
const match = c.match(/['"]/);
if (match) {
quote = (quote === match[0]) ? null : match[0];
} else if (!quote && /</.test(c)) {
tag = startTag(c, index);
} else if (!quote && />/.test(c)) {
tags.push(tag);
status = TEXT;
}
break;
}
});
let markupLen = 0;
tags.forEach(tag => {
tag.type = /^<\s*\//.test(tag.markup) ? 'close' : 'open';
tag.name = tag.markup.match(/^<\s*\/*\s*([A-Z][A-Z0-9]*)/i)[1];
tag.index -= markupLen;
markupLen += tag.markup.length;
text = [
text.substr(0, tag.index),
text.substr(tag.index + tag.markup.length),
].join('');
});
linkOpenToCloseTags(tags);
return { tags, text, chars: text.split('') };
}
function linkOpenToCloseTags(tags) {
let n = 0;
while (n < tags.length) {
const tag = tags[n];
if (tag.type === 'open') {
for (let i = n + 1; i < tags.length; i++) {
const tagNext = tags[i];
if (tagNext.type === 'close' && tag.name === tagNext.name) {
tag.close = tagNext;
// tag.markupClose = tagNext.markup;
// tags.splice(i, 1);
}
}
} else {
// tags.splice(n, 1);
}
n++;
}
}
function reset() {
tag = quote = null;
status = TEXT;
}
function startTag(markup, index) {
status = ELEMENT;
return { markup, index };
}