0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-24 20:42:43 +00:00

Merge branch 'naturalcrit:master' into v3-Artist-Snippet

This commit is contained in:
Gazook89
2021-08-04 09:39:02 -05:00
committed by GitHub
2 changed files with 184 additions and 2 deletions

View File

@@ -42,7 +42,7 @@ const UserPage = createClass({
renderBrews : function(brews){
if(!brews || !brews.length) return <div className='noBrews'>No Brews.</div>;
const sortedBrews = this.sortBrews(brews, this.state.sortType);
const sortedBrews = this.sortBrews(brews);
return _.map(sortedBrews, (brew, idx)=>{
return <BrewItem brew={brew} key={idx}/>;
@@ -50,6 +50,7 @@ const UserPage = createClass({
},
sortBrewOrder : function(brew){
if(!brew.title){brew.title = 'No Title';};
const mapping = {
'alpha' : _.deburr(brew.title.toLowerCase()),
'created' : brew.createdAt,

View File

@@ -234,7 +234,188 @@ const definitionLists = {
}
};
Markdown.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists] });
const spanTable = {
name : 'spanTable',
level : 'block', // Is this a block-level or inline-level tokenizer?
start(src) { return src.match(/^\n *([^\n ].*\|.*)\n/)?.index; }, // Hint to Marked.js to stop and check for a match
tokenizer(src, tokens) {
//const regex = this.tokenizer.rules.block.table;
const regex = new RegExp('^ *([^\\n ].*\\|.*\\n(?:.*?[^\\s].*\\n)*?)' // Header
+ ' {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)\\|?' // Align
+ '(?:\\n *((?:(?!\\n| {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})' // Cells
+ '(?:\\n+|$)| {0,3}#{1,6} | {0,3}>| {4}[^\\n]| {0,3}(?:`{3,}'
+ '(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n| {0,3}(?:[*+-]|1[.)]) |'
+ '<\\/?(?:address|article|aside|base|basefont|blockquote|body|'
+ 'caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)(?: +|\\n|\\/?>)|<(?:script|pre|style|textarea|!--)).*(?:\\n|$))*)\\n*|$)'); // Cells
const cap = regex.exec(src);
if(cap) {
const item = {
type : 'spanTable',
header : cap[1].replace(/\n$/, '').split('\n'),
align : cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
rows : cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
};
// Get first header row to determine how many columns
item.header[0] = splitCells(item.header[0]);
const colCount = item.header[0].reduce((length, header)=>{
return length + header.colspan;
}, 0);
if(colCount === item.align.length) {
item.raw = cap[0];
let i, j, k, row;
// Get alignment row (:---:)
let l = item.align.length;
for (i = 0; i < l; i++) {
if(/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if(/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if(/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
}
}
// Get any remaining header rows
l = item.header.length;
for (i = 1; i < l; i++) {
item.header[i] = splitCells(item.header[i], colCount);
}
// Get main table cells
l = item.rows.length;
for (i = 0; i < l; i++) {
item.rows[i] = splitCells(item.rows[i], colCount);
}
// header child tokens
l = item.header.length;
for (j = 0; j < l; j++) {
row = item.header[j];
for (k = 0; k < row.length; k++) {
row[k].tokens = [];
this.inlineTokens(row[k].text, row[k].tokens);
}
}
// cell child tokens
l = item.rows.length;
for (j = 0; j < l; j++) {
row = item.rows[j];
for (k = 0; k < row.length; k++) {
row[k].tokens = [];
this.inlineTokens(row[k].text, row[k].tokens);
}
}
return item;
}
}
},
renderer(token) {
let i, j, row, cell, col, text;
let output = `<table>`;
output += `<thead>`;
for (i = 0; i < token.header.length; i++) {
row = token.header[i];
let col = 0;
output += `<tr>`;
for (j = 0; j < row.length; j++) {
cell = row[j];
text = this.parseInline(cell.tokens);
output += getTableCell(text, cell.colspan, 'th', token.align[col]);
col += cell.colspan;
}
output += `</tr>`;
}
output += `</thead>`;
if(token.rows.length) {
output += `<tbody>`;
for (i = 0; i < token.rows.length; i++) {
row = token.rows[i];
col = 0;
output += `<tr>`;
for (j = 0; j < row.length; j++) {
cell = row[j];
text = this.parseInline(cell.tokens);
output += getTableCell(text, cell.colspan, 'td', token.align[col]);
col += cell.colspan;
}
output += `</tr>`;
}
output += `</tbody>`;
}
output += `</table>`;
return output;
}
};
const getTableCell = (text, colspan, type, align)=>{
const tag = `<${type}`
+ `${colspan > 1 ? ` colspan=${colspan}` : ''}`
+ `${align ? ` align=${align}` : ''}>`;
return `${tag + text}</${type}>\n`;
};
const splitCells = (tableRow, count)=>{
// ensure that every cell-delimiting pipe has a space
// before it to distinguish it from an escaped pipe
const row = tableRow.replace(/(\|+)/g, (match, p1, offset, str)=>{
let escaped = false,
curr = offset;
while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
if(escaped) {
// odd number of slashes means | is escaped
// so we leave it and the slashes alone
return p1;
} else {
// add space before unescaped |
return ` ${p1}`;
}
});
const cells = row.split(/(?: \||(?<=\|)\|)(?=[^\|]|$)/g);
let i = 0;
// First/last cell in a row cannot be empty if it has no leading/trailing pipe
if(!cells[0].trim()) { cells.shift(); }
if(!cells[cells.length - 1].trim()) { cells.pop(); }
let numCols = 0;
for (; i < cells.length; i++) {
const trimmedCell = cells[i].split(/(?<!\\)\|+$/)[0];
cells[i] = {
colspan : 1 + cells[i].length - trimmedCell.length,
text : trimmedCell.trim().replace(/\\\|/g, '|')
// leading or trailing whitespace is ignored per the gfm spec
};
numCols += cells[i].colspan;
}
// Force main cell rows to match header column count
if(numCols > count) {
cells.splice(count);
} else {
while (numCols < count) {
cells.push({
colspan : 1,
text : ''
});
numCols += 1;
}
}
return cells;
};
Markdown.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists, spanTable] });
Markdown.use(mustacheInjectBlock);
Markdown.use({ smartypants: true });