use highlight.js for syntax highlighting in code blocks of posts

merge-requests/208/head
fatchan 5 years ago
parent ac158e44f4
commit 23c9079c03
  1. 2
      ecosystem.config.js
  2. 1
      gulp/res/css/solarized-dark.css
  3. 1
      gulp/res/css/style.css
  4. 7
      gulpfile.js
  5. 18
      helpers/posting/markdown.js
  6. 2
      helpers/posting/sanitizeoptions.js
  7. 4
      models/forms/addnews.js
  8. 4
      models/forms/changeboardsettings.js
  9. 3
      models/forms/deletepost.js
  10. 2
      models/forms/makepost.js
  11. 3
      models/forms/moveposts.js
  12. 5
      package-lock.json
  13. 1
      package.json
  14. 1
      views/includes/head.pug

@ -3,7 +3,7 @@ module.exports = {
apps : [{
name: 'build-worker',
script: 'worker.js',
instances: 1,
instances: 2,
/*
increase instances if building is getting backed up,
best to keep at numCPUs-1 to prevent server choke under high load though.

@ -0,0 +1 @@
/home/tom/jschan/node_modules/highlight.js/styles/solarized-dark.css

@ -83,7 +83,6 @@ pre {
border-color: var(--darken);
display: block;
margin: 0.5em 0;
display: flex;
overflow-x: auto;
white-space: pre;
}

@ -110,7 +110,12 @@ async function wipe() {
//update the css file
function css() {
return gulp.src(paths.styles.src)
try {
fs.symlinkSync(__dirname+'/node_modules/highlight.js/styles/solarized-dark.css', __dirname+'/gulp/res/css/solarized-dark.css', 'file');
} catch (e) {
//already exists, ignore error
}
gulp.src(paths.styles.src)
.pipe(less())
.pipe(cleanCSS())
.pipe(gulp.dest(paths.styles.dest));

@ -11,23 +11,22 @@ const greentextRegex = /^>((?!>).+)/gm
, spoilerRegex = /\|\|([\s\S]+?)\|\|/gm
, detectedRegex = /(\(\(\(.+?\)\)\))/gm
, linkRegex = /https?\:&#x2F;&#x2F;[^\s<>\[\]{}|\\^]+/g
, codeRegex = /&#x60;&#x60;&#x60;([\s\S]+?)&#x60;&#x60;&#x60;/gm
, codeRegex = /```([\s\S]+?)```/gm
, diceRegex = /##(?<numdice>\d+)d(?<numsides>\d+)(?:(?<operator>[+-])(?<modifier>\d+))?/gmi
, getDomain = (string) => string.split(/\/\/|\//)[1] //unused atm
, diceRoll = require(__dirname+'/diceroll.js');
, diceRoll = require(__dirname+'/diceroll.js')
, escape = require(__dirname+'/escape.js')
, { highlightAuto } = require('highlight.js');
module.exports = {
markdown: (text) => {
const chunks = text.split(codeRegex);
if (chunks.length === 1) {
//length of 1 means no code chunks
return module.exports.processRegularChunk(text);
}
for (let i = 0; i < chunks.length; i++) {
//every other chunk will be a code block
if (i % 2 === 0) {
const newlineFix = chunks[i].replace(/^\r?\n/,''); //fix ending newline because of codeblock
const escaped = escape(chunks[i]);
const newlineFix = escaped.replace(/^\r?\n/,''); //fix ending newline because of codeblock
chunks[i] = module.exports.processRegularChunk(newlineFix);
} else {
chunks[i] = module.exports.processCodeChunk(chunks[i]);
@ -37,8 +36,9 @@ module.exports = {
},
processCodeChunk: (text) => {
const trimFix = text.replace(/^\s*\r?\n/g, ''); //remove extra whitespace/newline at start
return `<span class='code'>${trimFix}</span>`;
const trimFix = text.replace(/^\s*(\r?\n)*|(\r?\n)*$/g, ''); //remove extra whitespace/newlines at ends
const { language, relevance, value } = highlightAuto(trimFix);
return `<span class='code'>${value}\n<small>language: ${language}, confidence: ${relevance}</small></span>`;
},
processRegularChunk: (text) => {

@ -8,7 +8,7 @@ module.exports = {
},
after: {
allowedTags: [ 'span', 'a', 'em', 'strong', 'img', 'small'],
allowedTags: [ 'span', 'a', 'img', 'small'],
allowedAttributes: {
'a': [ 'href', 'rel', 'class', 'referrerpolicy', 'target' ],
'span': [ 'class' ],

@ -5,14 +5,12 @@ const { News } = require(__dirname+'/../../db/')
, buildQueue = require(__dirname+'/../../queue.js')
, linkQuotes = require(__dirname+'/../../helpers/posting/quotes.js')
, { markdown } = require(__dirname+'/../../helpers/posting/markdown.js')
, escape = require(__dirname+'/../../helpers/posting/escape.js')
, sanitizeOptions = require(__dirname+'/../../helpers/posting/sanitizeoptions.js')
, sanitize = require('sanitize-html');
module.exports = async (req, res, next) => {
const escaped = escape(req.body.message);
const styled = markdown(escaped);
const styled = markdown(req.body.message);
const quoted = (await linkQuotes(null, styled, null)).quotedMessage;
const sanitized = sanitize(quoted, sanitizeOptions.after);

@ -7,7 +7,6 @@ const { Boards, Posts, Accounts } = require(__dirname+'/../../db/')
, deletePosts = require(__dirname+'/deletepost.js')
, linkQuotes = require(__dirname+'/../../helpers/posting/quotes.js')
, { markdown } = require(__dirname+'/../../helpers/posting/markdown.js')
, escape = require(__dirname+'/../../helpers/posting/escape.js')
, sanitizeOptions = require(__dirname+'/../../helpers/posting/sanitizeoptions.js')
, sanitize = require('sanitize-html');
@ -18,8 +17,7 @@ module.exports = async (req, res, next) => {
let markdownAnnouncement;
if (req.body.announcement !== oldSettings.announcement.raw) {
//remarkup the announcement if it changes
const escaped = escape(req.body.announcement);
const styled = markdown(escaped);
const styled = markdown(req.body.announcement);
const quoted = (await linkQuotes(req.params.board, styled, null)).quotedMessage;
const sanitized = sanitize(quoted, sanitizeOptions.after);
markdownAnnouncement = sanitized;

@ -5,7 +5,6 @@ const uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.
, Mongo = require(__dirname+'/../../db/db.js')
, { Posts, Files } = require(__dirname+'/../../db/')
, linkQuotes = require(__dirname+'/../../helpers/posting/quotes.js')
, escape = require(__dirname+'/../../helpers/posting/escape.js')
, { markdown } = require(__dirname+'/../../helpers/posting/markdown.js')
, sanitize = require('sanitize-html')
, sanitizeOptions = require(__dirname+'/../../helpers/posting/sanitizeoptions.js');
@ -114,7 +113,7 @@ module.exports = async (posts, board, all=false) => {
await Promise.all(remarkupPosts.map(async post => { //doing these all at once
if (post.nomarkup && post.nomarkup.length > 0) { //is this check even necessary? how would it have a quote with no message
//redo the markup
let message = markdown(escape(post.nomarkup));
let message = markdown(post.nomarkup);
const { quotedMessage, threadQuotes, crossQuotes } = await linkQuotes(post.board, message, post.thread);
message = sanitize(quotedMessage, sanitizeOptions.after);
bulkWrites.push({

@ -9,7 +9,6 @@ const path = require('path')
, { Stats, Posts, Boards, Files, Bans } = require(__dirname+'/../../db/')
, getTripCode = require(__dirname+'/../../helpers/posting/tripcode.js')
, linkQuotes = require(__dirname+'/../../helpers/posting/quotes.js')
, escape = require(__dirname+'/../../helpers/posting/escape.js')
, { markdown } = require(__dirname+'/../../helpers/posting/markdown.js')
, sanitizeOptions = require(__dirname+'/../../helpers/posting/sanitizeoptions.js')
, sanitize = require('sanitize-html')
@ -314,7 +313,6 @@ module.exports = async (req, res, next) => {
let quotes = [];
let crossquotes = [];
if (message && message.length > 0) {
message = escape(message);
message = markdown(message);
const { quotedMessage, threadQuotes, crossQuotes } = await linkQuotes(req.params.board, message, req.body.thread || null);
message = quotedMessage;

@ -4,7 +4,6 @@ const uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.
, { remove } = require('fs-extra')
, { Posts } = require(__dirname+'/../../db/')
, linkQuotes = require(__dirname+'/../../helpers/posting/quotes.js')
, escape = require(__dirname+'/../../helpers/posting/escape.js')
, { markdown } = require(__dirname+'/../../helpers/posting/markdown.js')
, sanitize = require('sanitize-html')
, sanitizeOptions = require(__dirname+'/../../helpers/posting/sanitizeoptions.js');
@ -113,7 +112,7 @@ module.exports = async (req, res) => {
await Promise.all(remarkupPosts.map(async post => { //doing these all at once
if (post.nomarkup && post.nomarkup.length > 0) {
//redo the markup
let message = markdown(escape(post.nomarkup));
let message = markdown(post.nomarkup);
const { quotedMessage, threadQuotes, crossQuotes } = await linkQuotes(post.board, message, req.body.move_to_thread);
message = sanitize(quotedMessage, sanitizeOptions.after);
bulkWrites.push({

5
package-lock.json generated

@ -3727,6 +3727,11 @@
}
}
},
"highlight.js": {
"version": "9.15.10",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz",
"integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw=="
},
"homedir-polyfill": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",

@ -25,6 +25,7 @@
"gulp-less": "^4.0.1",
"gulp-pug": "^4.0.1",
"gulp-uglify-es": "^1.0.4",
"highlight.js": "^9.15.10",
"ioredis": "^4.14.1",
"mongodb": "^3.3.2",
"node-fetch": "^2.6.0",

@ -1,6 +1,7 @@
meta(charset='utf-8')
meta(name='viewport', content='width=device-width, initial-scale=1')
link(rel='stylesheet' href='/css/style.css')
link(rel='stylesheet' href='/css/solarized-dark.css')
- const theme = board ? board.settings.theme : defaultTheme;
link#theme(rel='stylesheet' data-theme=theme href=`/css/themes/${theme}.css`)
noscript

Loading…
Cancel
Save