+
Save current
diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx
index bbbf663ec..76cab5292 100644
--- a/client/homebrew/pages/newPage/newPage.jsx
+++ b/client/homebrew/pages/newPage/newPage.jsx
@@ -69,16 +69,15 @@ const NewPage = createClass({
const brewStorage = localStorage.getItem(BREWKEY);
const styleStorage = localStorage.getItem(STYLEKEY);
+ const brew = this.state.brew;
+
if(!this.props.brew.text || !this.props.brew.style){
- this.setState({
- brew : {
- text : this.props.brew.text || (brewStorage ?? ''),
- style : this.props.brew.style || (styleStorage ?? undefined)
- }
- });
+ brew.text = this.props.brew.text || (brewStorage ?? '');
+ brew.style = this.props.brew.style || (styleStorage ?? undefined);
}
this.setState((prevState)=>({
+ brew : brew,
htmlErrors : Markdown.validate(prevState.brew.text)
}));
diff --git a/package-lock.json b/package-lock.json
index 140fd0a27..4cb47f5c0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
{
"name": "homebrewery",
- "version": "2.13.1",
+ "version": "2.13.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "version": "2.13.1",
+ "version": "2.13.2",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -30,7 +30,7 @@
"marked": "2.1.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.29.1",
- "mongoose": "^5.13.3",
+ "mongoose": "^5.13.4",
"nanoid": "3.1.23",
"nconf": "^0.11.3",
"prop-types": "15.7.2",
@@ -6376,9 +6376,9 @@
}
},
"node_modules/mongoose": {
- "version": "5.13.3",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.3.tgz",
- "integrity": "sha512-q+zX6kqHAvwxf5speMWhq6qF4vdj+x6/kfD5RSKdZKNm52yGmaUygN+zgrtQjBZPFEzG0B3vF6GP0PoAGadE+w==",
+ "version": "5.13.4",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.4.tgz",
+ "integrity": "sha512-D1yVHAOa+G8iQZsC/nNzZe+CI1FCYu6Qk384s1vSyaSfKCu/alKeyL78BA73SsxeRKT9zmswSIueLbGBURjrKg==",
"dependencies": {
"@types/mongodb": "^3.5.27",
"@types/node": "14.x || 15.x",
@@ -6389,6 +6389,7 @@
"mpath": "0.8.3",
"mquery": "3.2.5",
"ms": "2.1.2",
+ "optional-require": "1.0.x",
"regexp-clone": "1.0.0",
"safe-buffer": "5.2.1",
"sift": "13.5.2",
@@ -14455,9 +14456,9 @@
}
},
"mongoose": {
- "version": "5.13.3",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.3.tgz",
- "integrity": "sha512-q+zX6kqHAvwxf5speMWhq6qF4vdj+x6/kfD5RSKdZKNm52yGmaUygN+zgrtQjBZPFEzG0B3vF6GP0PoAGadE+w==",
+ "version": "5.13.4",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.4.tgz",
+ "integrity": "sha512-D1yVHAOa+G8iQZsC/nNzZe+CI1FCYu6Qk384s1vSyaSfKCu/alKeyL78BA73SsxeRKT9zmswSIueLbGBURjrKg==",
"requires": {
"@types/mongodb": "^3.5.27",
"@types/node": "14.x || 15.x",
@@ -14468,6 +14469,7 @@
"mpath": "0.8.3",
"mquery": "3.2.5",
"ms": "2.1.2",
+ "optional-require": "1.0.x",
"regexp-clone": "1.0.0",
"safe-buffer": "5.2.1",
"sift": "13.5.2",
diff --git a/package.json b/package.json
index e31d91cea..b002c1965 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "homebrewery",
"description": "Create authentic looking D&D homebrews using only markdown",
- "version": "2.13.1",
+ "version": "2.13.2",
"engines": {
"node": "14.15.x"
},
@@ -61,7 +61,7 @@
"marked": "2.1.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.29.1",
- "mongoose": "^5.13.3",
+ "mongoose": "^5.13.4",
"nanoid": "3.1.23",
"nconf": "^0.11.3",
"prop-types": "15.7.2",
diff --git a/server.js b/server.js
index 45e073065..ce4ee046e 100644
--- a/server.js
+++ b/server.js
@@ -105,6 +105,25 @@ app.get('/robots.txt', (req, res)=>{
return res.sendFile(`${__dirname}/robots.txt`);
});
+//Home page
+app.get('/', async (req, res, next)=>{
+ const brew = {
+ text : welcomeText
+ };
+ req.brew = brew;
+ return next();
+});
+
+//Changelog page
+app.get('/changelog', async (req, res, next)=>{
+ const brew = {
+ title : 'Changelog',
+ text : changelogText
+ };
+ req.brew = brew;
+ return next();
+});
+
//Source page
app.get('/source/:id', asyncHandler(async (req, res)=>{
const brew = await getBrewFromId(req.params.id, 'raw');
@@ -170,6 +189,7 @@ app.get('/edit/:id', asyncHandler(async (req, res, next)=>{
//New Page
app.get('/new/:id', asyncHandler(async (req, res, next)=>{
const brew = await getBrewFromId(req.params.id, 'share');
+ brew.title = `CLONE - ${brew.title}`;
req.brew = brew;
return next();
}));
@@ -204,8 +224,6 @@ app.use((req, res)=>{
const props = {
version : require('./package.json').version,
url : req.originalUrl,
- welcomeText : welcomeText,
- changelog : changelogText,
brew : req.brew,
brews : req.brews,
googleBrews : req.googleBrews,
diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js
index 580ba5b5a..9ae71214a 100644
--- a/shared/naturalcrit/markdown.js
+++ b/shared/naturalcrit/markdown.js
@@ -31,30 +31,34 @@ const mustacheSpans = {
start(src) { return src.match(/{{[^{]/)?.index; }, // Hint to Marked.js to stop and check for a match
tokenizer(src, tokens) {
const completeSpan = /^{{[^\n]*}}/; // Regex for the complete token
- const inlineRegex = /{{(?:="[\w,\-(). ]*"|[^"'{}\s])*\s*|}}/g;
+ const inlineRegex = /{{(?::(?:"[\w,\-()#%. ]*"|[\w\,\-()#%.]*)|[^"'{}\s])*\s*|}}/g;
const match = completeSpan.exec(src);
if(match) {
//Find closing delimiter
let blockCount = 0;
let tags = '';
- let endIndex = 0;
+ let endTags = 0;
+ let endToken = 0;
let delim;
while (delim = inlineRegex.exec(match[0])) {
+ if(!tags) {
+ tags = ` ${processStyleTags(delim[0].substring(2))}`;
+ endTags = delim[0].length;
+ }
if(delim[0].startsWith('{{')) {
- tags = tags || ` ${processStyleTags(delim[0].substring(2))}`;
blockCount++;
} else if(delim[0] == '}}' && blockCount !== 0) {
blockCount--;
if(blockCount == 0) {
- endIndex = inlineRegex.lastIndex;
+ endToken = inlineRegex.lastIndex;
break;
}
}
}
- if(endIndex) {
- const raw = src.slice(0, endIndex);
- const text = raw.slice((raw.indexOf(' ')+1) || -2, -2);
+ if(endToken) {
+ const raw = src.slice(0, endToken);
+ const text = raw.slice(endTags || -2, -2);
return { // Token to generate
type : 'mustacheSpans', // Should match "name" above
@@ -74,33 +78,37 @@ const mustacheSpans = {
const mustacheDivs = {
name : 'mustacheDivs',
level : 'block',
- start(src) { return src.match(/^ *{{[^{]/m)?.index; }, // Hint to Marked.js to stop and check for a match
+ start(src) { return src.match(/\n *{{[^{]/m)?.index; }, // Hint to Marked.js to stop and check for a match
tokenizer(src, tokens) {
- const completeBlock = /^ *{{.*\n *}}/s; // Regex for the complete token
- const blockRegex = /^ *{{(?:="[\w,\-(). ]*"|[^"'{}\s])*$|^ *}}$/gm;
+ const completeBlock = /^ *{{[^\n}]* *\n.*\n *}}/s; // Regex for the complete token
+ const blockRegex = /^ *{{(?::(?:"[\w,\-()#%. ]*"|[\w\,\-()#%.]*)|[^"'{}\s])* *$|^ *}}$/gm;
const match = completeBlock.exec(src);
if(match) {
//Find closing delimiter
let blockCount = 0;
let tags = '';
- let endIndex = 0;
+ let endTags = 0;
+ let endToken = 0;
let delim;
while (delim = blockRegex.exec(match[0])?.[0].trim()) {
+ if(!tags) {
+ tags = ` ${processStyleTags(delim.substring(2))}`;
+ endTags = delim.length;
+ }
if(delim.startsWith('{{')) {
- tags = tags || ` ${processStyleTags(delim.substring(2))}`;
blockCount++;
} else if(delim == '}}' && blockCount !== 0) {
blockCount--;
if(blockCount == 0) {
- endIndex = blockRegex.lastIndex;
+ endToken = blockRegex.lastIndex;
break;
}
}
}
- if(endIndex) {
- const raw = src.slice(0, endIndex);
- const text = raw.slice((raw.indexOf('\n')+1) || -2, -2);
+ if(endToken) {
+ const raw = src.slice(0, endToken);
+ const text = raw.slice(endTags || -2, -2);
return { // Token to generate
type : 'mustacheDivs', // Should match "name" above
raw : raw, // Text to consume from the source
@@ -121,7 +129,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,\-(). ]*"|[^"'{}\s])*)}/g;
+ const inlineRegex = /^ *{((?::(?:"[\w,\-()#%. ]*"|[\w\,\-()#%.]*)|[^"'{}\s])*)}/g;
const match = inlineRegex.exec(src);
if(match) {
const lastToken = tokens[tokens.length - 1];
@@ -154,9 +162,9 @@ const mustacheInjectBlock = {
extensions : [{
name : 'mustacheInjectBlock',
level : 'block',
- start(src) { return src.match(/^ *{[^{\n]/m)?.index; }, // Hint to Marked.js to stop and check for a match
+ 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,\-(). ]*"|[^"'{}\s])*)}/ym;
+ const inlineRegex = /^ *{((?::(?:"[\w,\-()#%. ]*"|[\w\,\-()#%.]*)|[^"'{}\s])*)}/ym;
const match = inlineRegex.exec(src);
if(match) {
const lastToken = tokens[tokens.length - 1];
@@ -313,13 +321,15 @@ const tagRegex = new RegExp(`(${
}).join('|')})`, 'g');
const processStyleTags = (string)=>{
- const tags = string.match(/(?:[^, "=]+|="[^"]*")+/g);
+ //split tags up. quotes can only occur right after colons.
+ //TODO: can we simplify to just split on commas?
+ 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;'));
+ 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(' ')}"` : ''}`;
};
diff --git a/themes/5ePhb.style.less b/themes/5ePhb.style.less
index a1395554d..a5a3b6aa5 100644
--- a/themes/5ePhb.style.less
+++ b/themes/5ePhb.style.less
@@ -385,13 +385,14 @@ body {
}
}
.pageNumber{
- position : absolute;
- right : 2px;
- bottom : 22px;
- width : 50px;
- font-size : 0.9em;
- color : #c9ad6a;
- text-align : center;
+ position : absolute;
+ right : 2px;
+ bottom : 22px;
+ width : 50px;
+ font-size : 0.9em;
+ color : #c9ad6a;
+ text-align : center;
+ text-indent : 0;
&.auto::after {
content : counter(phb-page-numbers);
}
@@ -602,9 +603,10 @@ body {
break-inside : avoid;
-webkit-transform : translateZ(0); //Prevents shadows from breaking across columns
}
- .inline {
+ .inline-block {
display : inline-block;
text-indent : initial;
+ line-height : 1.3em;
}
div {
column-gap : 0.5cm; //Default spacing if a div uses multicolumns