0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-06 14:22:52 +00:00

Parse mustache "style" properties into object instead of string

This commit is contained in:
Trevor Buckner
2025-01-23 00:54:07 -05:00
parent bd5c85147d
commit 8e99d47869
2 changed files with 26 additions and 15 deletions

View File

@@ -173,8 +173,8 @@ const mustacheSpans = {
return `<span` + return `<span` +
`${tags.classes ? ` class="${tags.classes}"` : ''}` + `${tags.classes ? ` class="${tags.classes}"` : ''}` +
`${tags.id ? ` id="${tags.id}"` : ''}` + `${tags.id ? ` id="${tags.id}"` : ''}` +
`${tags.styles ? ` style="${tags.styles}"` : ''}` + `${tags.styles ? ` style="${Object.entries(tags.styles).map(([key, value])=>`${key}:${value};`).join(' ')}"` : ''}` +
`${tags.attributes ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` + `${tags.attributes ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` +
`>${this.parser.parseInline(token.tokens)}</span>`; // parseInline to turn child tokens into HTML `>${this.parser.parseInline(token.tokens)}</span>`; // parseInline to turn child tokens into HTML
} }
}; };
@@ -229,7 +229,7 @@ const mustacheDivs = {
return `<div` + return `<div` +
`${tags.classes ? ` class="${tags.classes}"` : ''}` + `${tags.classes ? ` class="${tags.classes}"` : ''}` +
`${tags.id ? ` id="${tags.id}"` : ''}` + `${tags.id ? ` id="${tags.id}"` : ''}` +
`${tags.styles ? ` style="${tags.styles}"` : ''}` + `${tags.styles ? ` style="${Object.entries(tags.styles).map(([key, value])=>`${key}:${value};`).join(' ')}"` : ''}` +
`${tags.attributes ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` + `${tags.attributes ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` +
`>${this.parser.parse(token.tokens)}</div>`; // parse to turn child tokens into HTML `>${this.parser.parse(token.tokens)}</div>`; // parse to turn child tokens into HTML
} }
@@ -272,7 +272,7 @@ const mustacheInjectInline = {
return `${openingTag[1]}` + return `${openingTag[1]}` +
`${tags.classes ? ` class="${tags.classes}"` : ''}` + `${tags.classes ? ` class="${tags.classes}"` : ''}` +
`${tags.id ? ` id="${tags.id}"` : ''}` + `${tags.id ? ` id="${tags.id}"` : ''}` +
`${tags.styles ? ` style="${tags.styles}"` : ''}` + `${!_.isEmpty(tags.styles) ? ` style="${Object.entries(tags.styles).map(([key, value])=>`${key}:${value};`).join(' ')}"` : ''}` +
`${!_.isEmpty(tags.attributes) ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` + `${!_.isEmpty(tags.attributes) ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` +
`${openingTag[2]}`; // parse to turn child tokens into HTML `${openingTag[2]}`; // parse to turn child tokens into HTML
} }
@@ -316,7 +316,7 @@ const mustacheInjectBlock = {
return `${openingTag[1]}` + return `${openingTag[1]}` +
`${tags.classes ? ` class="${tags.classes}"` : ''}` + `${tags.classes ? ` class="${tags.classes}"` : ''}` +
`${tags.id ? ` id="${tags.id}"` : ''}` + `${tags.id ? ` id="${tags.id}"` : ''}` +
`${tags.styles ? ` style="${tags.styles}"` : ''}` + `${!_.isEmpty(tags.styles) ? ` style="${Object.entries(tags.styles).map(([key, value])=>`${key}:${value};`).join(' ')}"` : ''}` +
`${!_.isEmpty(tags.attributes) ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` + `${!_.isEmpty(tags.attributes) ? ` ${Object.entries(tags.attributes).map(([key, value])=>`${key}="${value}"`).join(' ')}` : ''}` +
`${openingTag[2]}`; // parse to turn child tokens into HTML `${openingTag[2]}`; // parse to turn child tokens into HTML
} }
@@ -861,15 +861,20 @@ const processStyleTags = (string)=>{
const index = attr.indexOf('='); const index = attr.indexOf('=');
let [key, value] = [attr.substring(0, index), attr.substring(index + 1)]; let [key, value] = [attr.substring(0, index), attr.substring(index + 1)];
value = value.replace(/"/g, ''); value = value.replace(/"/g, '');
obj[key] = value; obj[key.trim()] = value.trim();
return obj; return obj;
}, {}) || null; }, {}) || null;
const styles = tags?.length ? tags.map((tag)=>tag.replace(/:"?([^"]*)"?/g, ':$1;').trim()).join(' ') : null; const styles = tags?.length ? tags.reduce((styleObj, style) => {
const index = style.indexOf(':');
const [key, value] = [style.substring(0, index), style.substring(index + 1)];
styleObj[key.trim()] = value.replace(/"?([^"]*)"?/g, '$1').trim();
return styleObj;
}, {}) : null;
return { return {
id : id, id : id,
classes : classes, classes : classes,
styles : styles, styles : _.isEmpty(styles) ? null : styles,
attributes : _.isEmpty(attributes) ? null : attributes attributes : _.isEmpty(attributes) ? null : attributes
}; };
}; };
@@ -879,21 +884,27 @@ const extractHTMLStyleTags = (htmlString)=>{
const firstElementOnly = htmlString.split('>')[0]; const firstElementOnly = htmlString.split('>')[0];
const id = firstElementOnly.match(/id="([^"]*)"/)?.[1] || null; const id = firstElementOnly.match(/id="([^"]*)"/)?.[1] || null;
const classes = firstElementOnly.match(/class="([^"]*)"/)?.[1] || null; const classes = firstElementOnly.match(/class="([^"]*)"/)?.[1] || null;
const styles = firstElementOnly.match(/style="([^"]*)"/)?.[1] || null; const styles = firstElementOnly.match(/style="([^"]*)"/)?.[1]
?.split(';').reduce((styleObj, style) => {
if (style.trim() === '') return styleObj;
const index = style.indexOf(':');
const [key, value] = [style.substring(0, index), style.substring(index + 1)];
styleObj[key.trim()] = value.trim();
return styleObj;
}, {}) || null;
const attributes = firstElementOnly.match(/[a-zA-Z]+="[^"]*"/g) const attributes = firstElementOnly.match(/[a-zA-Z]+="[^"]*"/g)
?.filter((attr)=>!attr.startsWith('class="') && !attr.startsWith('style="') && !attr.startsWith('id="')) ?.filter((attr)=>!attr.startsWith('class="') && !attr.startsWith('style="') && !attr.startsWith('id="'))
.reduce((obj, attr)=>{ .reduce((obj, attr)=>{
const index = attr.indexOf('='); const index = attr.indexOf('=');
let [key, value] = [attr.substring(0, index), attr.substring(index + 1)]; let [key, value] = [attr.substring(0, index), attr.substring(index + 1)];
value = value.replace(/"/g, ''); obj[key.trim()] = value.replace(/"/g, '');
obj[key] = value;
return obj; return obj;
}, {}) || null; }, {}) || null;
return { return {
id : id, id : id,
classes : classes, classes : classes,
styles : styles, styles : _.isEmpty(styles) ? null : styles,
attributes : _.isEmpty(attributes) ? null : attributes attributes : _.isEmpty(attributes) ? null : attributes
}; };
}; };
@@ -902,7 +913,7 @@ const mergeHTMLTags = (originalTags, newTags) => {
return { return {
id : newTags.id || originalTags.id || null, id : newTags.id || originalTags.id || null,
classes : [originalTags.classes, newTags.classes].join(' ').trim() || null, classes : [originalTags.classes, newTags.classes].join(' ').trim() || null,
styles : [originalTags.styles, newTags.styles].join(' ').trim() || null, styles : Object.assign(originalTags.styles ?? {}, newTags.styles ?? {}),
attributes : Object.assign(originalTags.attributes ?? {}, newTags.attributes ?? {}) attributes : Object.assign(originalTags.attributes ?? {}, newTags.attributes ?? {})
}; };
}; };

View File

@@ -300,7 +300,7 @@ describe('Injection: When an injection tag follows an element', ()=>{
it('Renders a span "text" with its own styles, appended with injected styles', function() { it('Renders a span "text" with its own styles, appended with injected styles', function() {
const source = '{{color:blue,height:10px text}}{width:10px,color:red}'; const source = '{{color:blue,height:10px text}}{width:10px,color:red}';
const rendered = Markdown.render(source); const rendered = Markdown.render(source);
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:blue; height:10px; width:10px; color:red;">text</span>'); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<span class="inline-block" style="color:red; height:10px; width:10px;">text</span>');
}); });
it('Renders a span "text" with its own classes, appended with injected classes', function() { it('Renders a span "text" with its own classes, appended with injected classes', function() {
@@ -429,7 +429,7 @@ describe('Injection: When an injection tag follows an element', ()=>{
}} }}
{width:10px,color:red}`; {width:10px,color:red}`;
const rendered = Markdown.render(source).trimReturns(); const rendered = Markdown.render(source).trimReturns();
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" style="color:blue; height:10px; width:10px; color:red;"><p>text</p></div>'); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('<div class="block" style="color:red; height:10px; width:10px;"><p>text</p></div>');
}); });
it('Renders a span "text" with its own classes, appended with injected classes', function() { it('Renders a span "text" with its own classes, appended with injected classes', function() {