From c58c8777f1d9fc9fe46671471c0fd6b9d5219c2f Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 7 Nov 2023 17:43:24 -0600 Subject: [PATCH] Add arbitrary tag attr assign. in moustaches This adds the ability to include attribute values for any element that can be altered by a moustache. Form: ``` {attribute=value} example: ![homebrew mug](https://i.imgur.com/hMna6G0.png) {position:absolute,bottom:20px,left:130px,width:220px,a=b and c,g=h} ``` In order to permit spaces, the pattern matches for moustache code had to remove the space character as a delimiter. I believe I have adequate compensated. This should solve #1488 --- client/homebrew/editor/editor.jsx | 6 +++--- shared/naturalcrit/markdown.js | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index b4f1fc824..f2fd81646 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -162,7 +162,7 @@ const Editor = createClass({ // Highlight injectors {style} if(line.includes('{') && line.includes('}')){ - const regex = /(?:^|[^{\n])({(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\s]*)*))\2})/gm; + const regex = /(?:^|[^{\n])({(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\n\r\t\f]*)*))\2})/gm; let match; while ((match = regex.exec(line)) != null) { codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[1]) }, { line: lineNumber, ch: line.indexOf(match[1]) + match[1].length }, { className: 'injection' }); @@ -170,7 +170,7 @@ const Editor = createClass({ } // Highlight inline spans {{content}} if(line.includes('{{') && line.includes('}}')){ - const regex = /{{(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\s]*)*))\1 *|}}/g; + const regex = /{{(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\n\r\t\f]*)*))\1 *|}}/g; let match; let blockCount = 0; while ((match = regex.exec(line)) != null) { @@ -189,7 +189,7 @@ const Editor = createClass({ // Highlight block divs {{\n Content \n}} let endCh = line.length+1; - const match = line.match(/^ *{{(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\s]*)*))\1 *$|^ *}}$/); + const match = line.match(/^ *{{(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\n\r\t\f]*)*))\1 *$|^ *}}$/); if(match) endCh = match.index+match[0].length; codeMirror.markText({ line: lineNumber, ch: 0 }, { line: lineNumber, ch: endCh }, { className: 'block' }); diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 114229887..0fd4fdd8f 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -132,7 +132,7 @@ const mustacheInjectInline = { level : 'inline', start(src) { return src.match(/ *{[^{\n]/)?.index; }, // Hint to Marked.js to stop and check for a match tokenizer(src, tokens) { - const inlineRegex = /^ *{(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\s]*)*))\1}/g; + const inlineRegex = /^ *{(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\n\r\t\f]*)*))\1}/g; const match = inlineRegex.exec(src); if(match) { const lastToken = tokens[tokens.length - 1]; @@ -167,7 +167,7 @@ const mustacheInjectBlock = { level : 'block', start(src) { return src.match(/\n *{[^{\n]/m)?.index; }, // Hint to Marked.js to stop and check for a match tokenizer(src, tokens) { - const inlineRegex = /^ *{(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\s]*)*))\1}/ym; + const inlineRegex = /^ *{(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\n\r\t\f]*)*))\1}/ym; const match = inlineRegex.exec(src); if(match) { const lastToken = tokens[tokens.length - 1]; @@ -328,14 +328,23 @@ const voidTags = new Set([ const processStyleTags = (string)=>{ //split tags up. quotes can only occur right after colons. //TODO: can we simplify to just split on commas? - const tags = string.match(/(?:[^, ":]+|:(?:"[^"]*"|))+/g); + const tags = string.match(/(?:[^,":]+|:(?:"[^"]*"|))+/g); if(!tags) return '"'; - const id = _.remove(tags, (tag)=>tag.startsWith('#')).map((tag)=>tag.slice(1))[0]; - const classes = _.remove(tags, (tag)=>!tag.includes(':')); - const styles = tags.map((tag)=>tag.replace(/:"?([^"]*)"?/g, ':$1;')); - return `${classes.join(' ')}" ${id ? `id="${id}"` : ''} ${styles.length ? `style="${styles.join(' ')}"` : ''}`; + const id = _.remove(tags, (tag)=>tag.startsWith('#')).map((tag)=>tag.slice(1))[0]; + const classes = _.remove(tags, (tag)=>(!tag.includes(':')) && (!tag.includes('='))); + let attributes = _.remove(tags, (tag)=>(!tag.includes(':')) && (!tag.includes('#'))); + const styles = tags.map((tag)=>tag.replace(/:"?([^"]*)"?/g, ':$1;').trim()); + + if(attributes.length) { + attributes = attributes.map((attribute)=>attribute.replace(/(\w+)=(.+)/, '$1="$2"')); + } + + return `${classes.join(' ')}" ` + + `${id ? `id="${id}"` : ''} ` + + `${styles.length ? `style="${styles.join(' ')}"` : ''} ` + + `${attributes.length ? attributes.join(' ') : ''}`; }; module.exports = {