mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-09-20 16:42:58 +00:00
Merge branch 'master' into Accessible-Dropdowns
This commit is contained in:
@@ -308,7 +308,7 @@ const CodeEditor = forwardRef(
|
||||
view.dispatch({
|
||||
effects : themeCompartment.reconfigure(themeExtension),
|
||||
});
|
||||
}, [editorTheme]);
|
||||
}, [editorTheme, tab]);
|
||||
|
||||
useEffect(()=>{
|
||||
//rebuild syntax highlight when changing tab or renderer
|
||||
|
||||
@@ -32,12 +32,12 @@ function safeHTML(htmlString) {
|
||||
return;
|
||||
}
|
||||
// Check remaining elements for blacklisted attributes
|
||||
for (const attribute of element.attributes){
|
||||
[...element.attributes].forEach((attribute)=>{
|
||||
if(blacklistAttrs.some((test)=>{return test(attribute);})) {
|
||||
element.removeAttribute(attribute.localName);
|
||||
break;
|
||||
element.removeAttribute(attribute.name);
|
||||
return;
|
||||
};
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return div.innerHTML;
|
||||
|
||||
@@ -99,11 +99,16 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
return (
|
||||
<div id='preview-toolbar' className={`toolBar ${toolsVisible ? 'visible' : 'hidden'}`} role='toolbar'>
|
||||
<div className='toggleButton'>
|
||||
<button data-tooltip-right={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`} onClick={()=>{
|
||||
setToolsVisible(!toolsVisible);
|
||||
localStorage.setItem(TOOLBAR_VISIBILITY, !toolsVisible);
|
||||
}}><i className='fas fa-glasses' /></button>
|
||||
<button data-tooltip-right={`${headerState ? 'Hide' : 'Show'} Header Navigation`} onClick={()=>{setHeaderState(!headerState);}}><i className='fas fa-rectangle-list' /></button>
|
||||
<button data-tooltip-right={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
|
||||
aria-label={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
|
||||
onClick={()=>{ setToolsVisible(!toolsVisible); localStorage.setItem(TOOLBAR_VISIBILITY, !toolsVisible); }}>
|
||||
<i aria-hidden='true' className='fas fa-glasses' />
|
||||
</button>
|
||||
<button data-tooltip-right={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
|
||||
aria-label={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
|
||||
onClick={()=>{setHeaderState(!headerState);}}>
|
||||
<i aria-hidden='true' className='fas fa-rectangle-list' />
|
||||
</button>
|
||||
</div>
|
||||
{/*v=====----------------------< Zoom Controls >---------------------=====v*/}
|
||||
<div className='group' role='group' aria-label='Zoom' aria-hidden={!toolsVisible}>
|
||||
@@ -111,17 +116,19 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
id='fill-width'
|
||||
className='tool'
|
||||
data-tooltip-bottom='Set zoom to fill preview with one page'
|
||||
aria-label='Set zoom to fill preview with one page'
|
||||
onClick={()=>handleZoomButton(displayOptions.zoomLevel + calculateChange('fill'))}
|
||||
>
|
||||
<i className='fac fit-width' />
|
||||
<i aria-hidden='true' className='fac fit-width' />
|
||||
</button>
|
||||
<button
|
||||
id='zoom-to-fit'
|
||||
className='tool'
|
||||
data-tooltip-bottom='Set zoom to fit entire page in preview'
|
||||
aria-label='Set zoom to fit entire page in preview'
|
||||
onClick={()=>handleZoomButton(displayOptions.zoomLevel + calculateChange('fit'))}
|
||||
>
|
||||
<i className='fac zoom-to-fit' />
|
||||
<i aria-hidden='true' className='fac zoom-to-fit' />
|
||||
</button>
|
||||
<button
|
||||
id='zoom-out'
|
||||
@@ -129,8 +136,9 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
onClick={()=>handleZoomButton(displayOptions.zoomLevel - 20)}
|
||||
disabled={displayOptions.zoomLevel <= MIN_ZOOM}
|
||||
data-tooltip-bottom='Zoom Out'
|
||||
aria-label='Zoom Out'
|
||||
>
|
||||
<i className='fas fa-magnifying-glass-minus' />
|
||||
<i aria-hidden='true' className='fas fa-magnifying-glass-minus' />
|
||||
</button>
|
||||
<input
|
||||
id='zoom-slider'
|
||||
@@ -138,6 +146,7 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
type='range'
|
||||
name='zoom'
|
||||
list='zoomLevels'
|
||||
aria-label='Zoom Amount'
|
||||
min={MIN_ZOOM}
|
||||
max={MAX_ZOOM}
|
||||
step='1'
|
||||
@@ -154,8 +163,9 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
onClick={()=>handleZoomButton(displayOptions.zoomLevel + 20)}
|
||||
disabled={displayOptions.zoomLevel >= MAX_ZOOM}
|
||||
data-tooltip-bottom='Zoom In'
|
||||
aria-label='Zoom In'
|
||||
>
|
||||
<i className='fas fa-magnifying-glass-plus' />
|
||||
<i aria-hidden='true' className='fas fa-magnifying-glass-plus' />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -166,27 +176,32 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
id='single-spread'
|
||||
className='tool'
|
||||
data-tooltip-bottom='Single Page'
|
||||
aria-label='Single Page Spread'
|
||||
onClick={()=>{handleOptionChange('spread', 'single');}}
|
||||
aria-checked={displayOptions.spread === 'single'}
|
||||
><i className='fac single-spread' /></button>
|
||||
><i aria-hidden='true' className='fac single-spread' /></button>
|
||||
<button role='radio'
|
||||
id='facing-spread'
|
||||
className='tool'
|
||||
data-tooltip-bottom='Facing Pages'
|
||||
aria-label='Facing Pages Spread'
|
||||
onClick={()=>{handleOptionChange('spread', 'facing');}}
|
||||
aria-checked={displayOptions.spread === 'facing'}
|
||||
><i className='fac facing-spread' /></button>
|
||||
><i aria-hidden='true' className='fac facing-spread' /></button>
|
||||
<button role='radio'
|
||||
id='flow-spread'
|
||||
className='tool'
|
||||
data-tooltip-bottom='Flow Pages'
|
||||
aria-label='Flow Pages Spread'
|
||||
onClick={()=>{handleOptionChange('spread', 'flow');}}
|
||||
aria-checked={displayOptions.spread === 'flow'}
|
||||
><i className='fac flow-spread' /></button>
|
||||
><i aria-hidden='true' className='fac flow-spread' /></button>
|
||||
|
||||
</div>
|
||||
<Anchored>
|
||||
<AnchoredTrigger id='spread-settings' className='tool' data-tooltip-bottom='Spread options'><i className='fas fa-gear' /></AnchoredTrigger>
|
||||
<AnchoredTrigger id='spread-settings' className='tool' aria-label='Spread options' data-tooltip-bottom='Spread options'>
|
||||
<i aria-hidden='true' className='fas fa-gear' />
|
||||
</AnchoredTrigger>
|
||||
<AnchoredBox>
|
||||
<h1>Options</h1>
|
||||
<label data-tooltip-left='Modify the horizontal space between pages.'>
|
||||
@@ -217,10 +232,11 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
className='previousPage tool'
|
||||
type='button'
|
||||
data-tooltip-bottom='Previous Page(s)'
|
||||
aria-label='Previous Page'
|
||||
onClick={()=>scrollToPage(_.min(visiblePages) - visiblePages.length)}
|
||||
disabled={visiblePages.includes(1)}
|
||||
>
|
||||
<i className='fas fa-arrow-left'></i>
|
||||
<i aria-hidden='true' className='fas fa-arrow-left'></i>
|
||||
</button>
|
||||
|
||||
<div className='tool'>
|
||||
@@ -230,6 +246,7 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
type='text'
|
||||
name='page'
|
||||
data-tooltip-bottom='Current page(s) in view'
|
||||
aria-label='Current page in view'
|
||||
inputMode='numeric'
|
||||
pattern='[0-9]'
|
||||
value={pageNum}
|
||||
@@ -239,7 +256,7 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
onKeyDown={(e)=>e.key == 'Enter' && scrollToPage(pageNum)}
|
||||
style={{ width: `${pageNum.length}ch` }}
|
||||
/>
|
||||
<span id='page-count' data-tooltip-bottom='Total Page Count'>/ {totalPages}</span>
|
||||
<span id='page-count' aria-label={`${totalPages} Total Pages`} data-tooltip-bottom='Total Page Count'><span aria-hidden='true'>/ {totalPages}</span></span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
@@ -247,10 +264,11 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
|
||||
className='tool'
|
||||
type='button'
|
||||
data-tooltip-bottom='Next Page(s)'
|
||||
aria-label='Next Page'
|
||||
onClick={()=>scrollToPage(_.max(visiblePages) + 1)}
|
||||
disabled={visiblePages.includes(totalPages)}
|
||||
>
|
||||
<i className='fas fa-arrow-right'></i>
|
||||
<i aria-hidden='true' className='fas fa-arrow-right'></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,9 +39,9 @@ const BrewItem = ({
|
||||
if(!brew.editId) return null;
|
||||
|
||||
return (
|
||||
<a className='deleteLink' onClick={deleteBrew}>
|
||||
<i className='fas fa-trash-alt' title='Delete' />
|
||||
</a>
|
||||
<button aria-label={`Delete ${brew.title}`} className='deleteLink' onClick={deleteBrew}>
|
||||
<i className='fas fa-trash-alt' aria-hidden='true' title='Delete' />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ const BrewItem = ({
|
||||
if(brew.googleId && !brew.stubbed) editLink = brew.googleId + editLink;
|
||||
|
||||
return (
|
||||
<a className='editLink' href={`/edit/${editLink}`} target='_blank' rel='noopener noreferrer'>
|
||||
<a className='editLink' href={`/edit/${editLink}`} aria-label={`Edit ${brew.title}`} target='_blank' rel='noopener noreferrer'>
|
||||
<i className='fas fa-pencil-alt' title='Edit' />
|
||||
</a>
|
||||
);
|
||||
@@ -67,7 +67,7 @@ const BrewItem = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<a className='shareLink' href={`/share/${shareLink}`} target='_blank' rel='noopener noreferrer'>
|
||||
<a className='shareLink' href={`/share/${shareLink}`} aria-label={`Share ${brew.title}`} target='_blank' rel='noopener noreferrer'>
|
||||
<i className='fas fa-share-alt' title='Share' />
|
||||
</a>
|
||||
);
|
||||
@@ -82,7 +82,7 @@ const BrewItem = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<a className='downloadLink' href={`/download/${shareLink}`}>
|
||||
<a className='downloadLink' aria-label={`Download ${brew.title}`} href={`/download/${shareLink}`}>
|
||||
<i className='fas fa-download' title='Download' />
|
||||
</a>
|
||||
);
|
||||
@@ -94,7 +94,7 @@ const BrewItem = ({
|
||||
return (
|
||||
<span title={brew.webViewLink ? 'Your Google Drive Storage' : 'Another User\'s Google Drive Storage'}>
|
||||
<a href={brew.webViewLink} target='_blank'>
|
||||
<img className='googleDriveIcon' src={googleDriveIcon} alt='googleDriveIcon' />
|
||||
<img className='googleDriveIcon' src={googleDriveIcon} alt='Google Drive Storage' />
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
@@ -102,7 +102,7 @@ const BrewItem = ({
|
||||
|
||||
return (
|
||||
<span title='Homebrewery Storage'>
|
||||
<img className='homebreweryIcon' src={homebreweryIcon} alt='homebreweryIcon' />
|
||||
<img className='homebreweryIcon' src={homebreweryIcon} alt='Homebrewery Storage' />
|
||||
</span>
|
||||
);
|
||||
};
|
||||
@@ -148,19 +148,20 @@ const BrewItem = ({
|
||||
))}
|
||||
</span>
|
||||
<br />
|
||||
<span title={`Last viewed: ${moment(brew.lastViewed).local().format(dateFormatString)}`}>
|
||||
<i className='fas fa-eye' /> {brew.views}
|
||||
<span aria-label={`Viewed ${brew.views} times`} title={`Last viewed: ${moment(brew.lastViewed).local().format(dateFormatString)}`}>
|
||||
<span aria-hidden='true'><i className='fas fa-eye' /> {brew.views}</span>
|
||||
</span>
|
||||
{brew.pageCount && (
|
||||
<span title={`Page count: ${brew.pageCount}`}>
|
||||
<i className='far fa-file' /> {brew.pageCount}
|
||||
<span aria-label={`${brew.pageCount} pages`} title={`Page count: ${brew.pageCount}`}>
|
||||
<span aria-hidden='true'><i className='far fa-file' /> {brew.pageCount}</span>
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
aria-label={`Last updated ${moment(brew.updatedAt).fromNow()}`}
|
||||
title={dedent` Created: ${moment(brew.createdAt).local().format(dateFormatString)}
|
||||
Last updated: ${moment(brew.updatedAt).local().format(dateFormatString)}`}
|
||||
>
|
||||
<i className='fas fa-sync-alt' /> {moment(brew.updatedAt).fromNow()}
|
||||
<span aria-hidden='true'><i className='fas fa-sync-alt' /> {moment(brew.updatedAt).fromNow()}</span>
|
||||
</span>
|
||||
{renderStorageIcon()}
|
||||
</div>
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
&::before { content : '\f518'; }
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
&:hover, &:focus-within {
|
||||
.links { opacity : 1; }
|
||||
}
|
||||
&:nth-child(2n + 1) { margin-right : 0px; }
|
||||
@@ -103,7 +103,7 @@
|
||||
text-align : center;
|
||||
background-color : fade(black, 60%);
|
||||
opacity : 0;
|
||||
a {
|
||||
a, button {
|
||||
.animate(opacity);
|
||||
display : block;
|
||||
margin : 8px 0px;
|
||||
@@ -111,6 +111,7 @@
|
||||
color : white;
|
||||
text-decoration : unset;
|
||||
opacity : 0.6;
|
||||
width : 100%;
|
||||
&:hover { opacity : 1; }
|
||||
i { cursor : pointer; }
|
||||
}
|
||||
|
||||
Generated
+3166
-3287
File diff suppressed because it is too large
Load Diff
+20
-19
@@ -86,33 +86,33 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.29.7",
|
||||
"@babel/plugin-transform-runtime": "^7.29.7",
|
||||
"@babel/preset-env": "^7.29.5",
|
||||
"@babel/preset-react": "^7.29.7",
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@babel/core": "^8.0.1",
|
||||
"@babel/plugin-transform-runtime": "^8.0.1",
|
||||
"@babel/preset-env": "^8.0.2",
|
||||
"@babel/preset-react": "^8.0.1",
|
||||
"@babel/runtime": "^8.0.0",
|
||||
"@codemirror/autocomplete": "^6.20.3",
|
||||
"@codemirror/commands": "^6.10.3",
|
||||
"@codemirror/highlight": "^0.19.8",
|
||||
"@codemirror/lang-css": "^6.3.1",
|
||||
"@codemirror/lang-javascript": "^6.2.5",
|
||||
"@codemirror/lang-markdown": "^6.5.0",
|
||||
"@codemirror/lang-markdown": "^6.5.2",
|
||||
"@codemirror/language": "^6.12.2",
|
||||
"@codemirror/language-data": "^6.5.2",
|
||||
"@codemirror/search": "^6.6.0",
|
||||
"@codemirror/state": "^6.6.0",
|
||||
"@codemirror/view": "^6.43.1",
|
||||
"@codemirror/view": "^6.43.8",
|
||||
"@dmsnell/diff-match-patch": "^1.1.0",
|
||||
"@googleapis/drive": "^20.2.0",
|
||||
"@lezer/highlight": "^1.2.3",
|
||||
"@oddbird/css-anchor-positioning": "^0.10.1",
|
||||
"@sanity/diff-match-patch": "^3.2.0",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"body-parser": "^2.2.0",
|
||||
"@vitejs/plugin-react": "^6.0.5",
|
||||
"body-parser": "^2.3.0",
|
||||
"classnames": "^2.5.1",
|
||||
"codemirror-5-themes": "^1.5.1",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"core-js": "^3.49.0",
|
||||
"core-js": "^3.50.0",
|
||||
"cors": "^2.8.5",
|
||||
"create-react-class": "^15.7.0",
|
||||
"dedent": "^1.7.2",
|
||||
@@ -123,13 +123,14 @@
|
||||
"fs-extra": "^11.3.5",
|
||||
"hash-wasm": "^4.12.0",
|
||||
"idb-keyval": "^6.2.5",
|
||||
"js-yaml": "^4.2.0",
|
||||
"js-yaml": "^5.3.0",
|
||||
"jwt-simple": "^0.5.6",
|
||||
"less": "^4.6.4",
|
||||
"less": "^4.8.1",
|
||||
"lodash": "^4.18.1",
|
||||
"marked": "15.0.12",
|
||||
"marked-alignment-paragraphs": "^1.0.0",
|
||||
"marked-definition-lists": "^1.0.1",
|
||||
"marked-diagrams-markdeep": "^1.0.1",
|
||||
"marked-emoji": "^2.0.3",
|
||||
"marked-extended-tables": "^2.0.1",
|
||||
"marked-gfm-heading-id": "^4.1.4",
|
||||
@@ -139,10 +140,10 @@
|
||||
"marked-variables": "^1.0.5",
|
||||
"markedLegacy": "npm:marked@^0.3.19",
|
||||
"moment": "^2.30.1",
|
||||
"mongoose": "^9.7.0",
|
||||
"nanoid": "5.1.11",
|
||||
"mongoose": "^9.9.2",
|
||||
"nanoid": "6.0.1",
|
||||
"nconf": "^0.13.0",
|
||||
"node": "^25.9.0",
|
||||
"node": "^26.7.0",
|
||||
"react": "^19.2.7",
|
||||
"react-dom": "^19.2.7",
|
||||
"react-frame-component": "^5.3.2",
|
||||
@@ -151,22 +152,22 @@
|
||||
"superagent": "^10.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@stylistic/stylelint-plugin": "^5.0.1",
|
||||
"@stylistic/stylelint-plugin": "^5.3.0",
|
||||
"babel-jest": "^30.4.1",
|
||||
"babel-plugin-transform-import-meta": "^2.3.3",
|
||||
"babel-plugin-transform-import-meta": "^3.0.0",
|
||||
"eslint": "9.7",
|
||||
"eslint-plugin-jest": "^29.15.1",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"globals": "^16.4.0",
|
||||
"jest": "^30.4.2",
|
||||
"jest-expect-message": "^1.1.3",
|
||||
"jsdom": "^28.1.0",
|
||||
"jsdom": "^30.0.1",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"postcss-less": "^6.0.0",
|
||||
"stylelint": "^17.11.1",
|
||||
"stylelint-config-recess-order": "^7.7.0",
|
||||
"stylelint-config-recommended": "^18.0.0",
|
||||
"supertest": "^7.1.4",
|
||||
"vite": "^8.1.5"
|
||||
"vite": "^8.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import express from 'express';
|
||||
import zlib from 'zlib';
|
||||
import GoogleActions from './googleActions.js';
|
||||
import Markdown from '../shared/markdown.js';
|
||||
import yaml from 'js-yaml';
|
||||
import * as yaml from 'js-yaml';
|
||||
import asyncHandler from 'express-async-handler';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { makePatches, applyPatches, stringifyPatches, parsePatch } from '@sanity/diff-match-patch';
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import _ from 'lodash';
|
||||
import yaml from 'js-yaml';
|
||||
import * as yaml from 'js-yaml';
|
||||
import request from '../client/homebrew/utils/request-middleware.js';
|
||||
|
||||
// Convert the templates from a brew to a Snippets Structure.
|
||||
|
||||
@@ -14,6 +14,8 @@ import { markedVariables,
|
||||
import { markedSmartypantsLite as MarkedSmartypantsLite } from 'marked-smartypants-lite';
|
||||
import { gfmHeadingId as MarkedGFMHeadingId, resetHeadings as MarkedGFMResetHeadingIDs } from 'marked-gfm-heading-id';
|
||||
import { markedEmoji as MarkedEmojis } from 'marked-emoji';
|
||||
import MarkedDiagramsMarkdeep from 'marked-diagrams-markdeep';
|
||||
|
||||
|
||||
//Icon fonts included so they can appear in emoji autosuggest dropdown
|
||||
import diceFont from '../themes/fonts/iconFonts/diceFont.js';
|
||||
@@ -353,7 +355,10 @@ const tableTerminators = [
|
||||
` *{{[^{\n]*\n.*?\n}}` // mustacheDiv
|
||||
];
|
||||
|
||||
const markdeepOptions = { langs: ['asciiArt'] };
|
||||
|
||||
Marked.use(markedVariables());
|
||||
Marked.use(MarkedDiagramsMarkdeep(markdeepOptions));
|
||||
Marked.use(MarkedDefinitionLists());
|
||||
Marked.use({ extensions: [forcedParagraphBreaks, mustacheSpans, mustacheDivs, mustacheInjectInline] });
|
||||
Marked.use(mustacheInjectBlock);
|
||||
|
||||
@@ -43,6 +43,12 @@ test('Javascript via inline event handler - onMouseOver', function() {
|
||||
expect(rendered).toBe('<div>Hover over me</div>');
|
||||
});
|
||||
|
||||
test('Javascript via multiple inline event handlers - onClick + onMouseOver', function() {
|
||||
const source = `<div onclick="alert('This is a JavaScript injection via inline event handler')" onmouseover="alert('This is a JavaScript injection via inline event handler')">Hover over or Click me</div>`;
|
||||
const rendered = safeHTML(source);
|
||||
expect(rendered).toBe('<div>Hover over or Click me</div>');
|
||||
});
|
||||
|
||||
test('Javascript via data attribute', function() {
|
||||
const source = `<div data-code="javascript:alert('This is a JavaScript injection via data attribute')">Test</div>`;
|
||||
const rendered = safeHTML(source);
|
||||
|
||||
@@ -9,7 +9,7 @@ String.prototype.trimReturns = function(){
|
||||
return this.replace(/\r?\n|\r/g, '').trim();
|
||||
};
|
||||
|
||||
renderAllPages = function(pages){
|
||||
const renderAllPages = function(pages){
|
||||
const outputs = [];
|
||||
pages.forEach((page, index)=>{
|
||||
const output = Markdown.render(page, index);
|
||||
|
||||
Reference in New Issue
Block a user