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:
@@ -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,
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user