JSFiddle - React, Tailwind, and code Playground
JavaScript
// --- парсилка --------------------
var parseStrWithTags = (function() {
var RX_TPL = /<\s*\/\s*(tags)\s*>|<\s*(tags)(\s+(?:"[^"]*"|'[^']*'|[^>"'])*)?\s*>/.toString().slice(1, -1);
function parseTags(str, tags, callback) {
var repl = tags && Object.keys(tags).join('|') || '[\\w-]+';
var rxTag = new RegExp(RX_TPL.replace(/tags/g, repl), 'gi');
var m, lastIndex = 0;
while (m = rxTag.exec(str)) {
var openTag = m[2] && m[2].toLowerCase();
var closeTag = m[1] && m[1].toLowerCase();
if (lastIndex < m.index) {
callback('content', str.substring(lastIndex, m.index));
}
lastIndex = rxTag.lastIndex;
var type = openTag ? 'open' : closeTag ? 'close' : 'end';
callback(type, m[0], openTag || closeTag, m[3]);
}
if (lastIndex < str.length) {
callback('content', str.substring(lastIndex, str.length));
}
callback('end');
}
function parseAttrs(attrs) {
var rxAttrs = /([\w-]+)(?:\s*[:=]\s*("[^"]*"|'[^']*'|[\w-]+))?/g;
var rxTrim = /^['"]|['"]$/g;
var m, data = Object.create(null);
if (attrs) {
while (m = rxAttrs.exec(attrs)) {
data[m[1]] = m[2] ? m[2].replace(rxTrim, '') : true;
}
}
return data;
}
function parseStr(str, tags) {
tags = tags || {};
var data = {}, tag, m, lastIndex = -1, currentTag, stack = [];
parseTags(str, tags, function(type, text, tagName, attrs) {
switch (type) {
case 'content':
if (currentTag) {
currentTag.content += text;
}
break;
case 'open':
tag = {
tag: tagName,
attrs: parseAttrs(attrs),
content: ''
};
data[tagName] = data[tagName] || [];
data[tagName].push(tag);
if (!tags[tagName].empty) {
if (currentTag) {
stack.push(currentTag);
}
currentTag = tag;
}
break;
case 'close':
if (currentTag) {
if (tagName === currentTag.tag) {
currentTag = stack.pop();
} else {
currentTag.content +=...