From c48bc8a76ef9c4c6bf1275249863a4b396e073fe Mon Sep 17 00:00:00 2001 From: valadaptive Date: Sat, 9 Dec 2023 21:29:36 -0500 Subject: [PATCH 1/3] Cache compiled Handlebars templates Since we already have a template cache, it makes sense to store the templates in it *after* compiling them, to avoid the overhead of re-compiling them every time we call renderTemplate. I've also changed the cache from an object to a Map--it's more semantically correct, and avoids weird edge cases like a template named "hasOwnProperty" or some other function that exists as an object property. --- public/script.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/public/script.js b/public/script.js index 64cb41752..ee236f448 100644 --- a/public/script.js +++ b/public/script.js @@ -526,14 +526,17 @@ function getUrlSync(url, cache = true) { }).responseText; } -const templateCache = {}; +const templateCache = new Map(); export function renderTemplate(templateId, templateData = {}, sanitize = true, localize = true, fullPath = false) { try { const pathToTemplate = fullPath ? templateId : `/scripts/templates/${templateId}.html`; - const templateContent = (pathToTemplate in templateCache) ? templateCache[pathToTemplate] : getUrlSync(pathToTemplate); - templateCache[pathToTemplate] = templateContent; - const template = Handlebars.compile(templateContent); + let template = templateCache.get(pathToTemplate); + if (!template) { + const templateContent = getUrlSync(pathToTemplate); + template = Handlebars.compile(templateContent); + templateCache.set(pathToTemplate, template); + } let result = template(templateData); if (sanitize) { From 0fce475a95750e00e539737c3000ad7c0249ad4a Mon Sep 17 00:00:00 2001 From: valadaptive Date: Sat, 9 Dec 2023 22:37:49 -0500 Subject: [PATCH 2/3] Implement random sort with a shuffle Sorting with a random comparator doesn't actually shuffle an array. Depending on the sorting algorithm used, there will be a bias to the shuffle (see https://bost.ocks.org/mike/shuffle/compare.html). If you open that link in Firefox, the bias will be especially bad. Instead of implementing "random" character sort using a random sort comparator, use the shuffle function instead. --- public/scripts/power-user.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 21806cb99..75f22581d 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -35,7 +35,7 @@ import { registerSlashCommand } from './slash-commands.js'; import { tags } from './tags.js'; import { tokenizers } from './tokenizers.js'; -import { countOccurrences, debounce, delay, isOdd, resetScrollHeight, sortMoments, stringToRange, timestampToMoment } from './utils.js'; +import { countOccurrences, debounce, delay, isOdd, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js'; export { loadPowerUserSettings, @@ -1818,10 +1818,6 @@ export function renderStoryString(params) { const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a); const compareFunc = (first, second) => { - if (power_user.sort_order == 'random') { - return Math.random() > 0.5 ? 1 : -1; - } - const a = first[power_user.sort_field]; const b = second[power_user.sort_field]; @@ -1853,6 +1849,11 @@ function sortEntitiesList(entities) { return; } + if (power_user.sort_order === 'random') { + shuffle(entities); + return; + } + entities.sort((a, b) => { if (a.type === 'tag' && b.type !== 'tag') { return -1; From 5f1683f43a750f3eea1c21fa93eb82b48b2557d9 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sun, 10 Dec 2023 15:07:39 +0200 Subject: [PATCH 3/3] More input padding and stricter sanitation --- public/script.js | 2 +- public/scripts/RossAscends-mods.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/script.js b/public/script.js index 64cb41752..aac06febd 100644 --- a/public/script.js +++ b/public/script.js @@ -1494,7 +1494,7 @@ function messageFormatting(mes, ch_name, isSystem, isUser) { mes = mes.replace(new RegExp(`(^|\n)${ch_name}:`, 'g'), '$1'); } - mes = DOMPurify.sanitize(mes); + mes = DOMPurify.sanitize(mes, { FORBID_TAGS: ['style'] }); return mes; } diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js index a565502eb..eb70341ba 100644 --- a/public/scripts/RossAscends-mods.js +++ b/public/scripts/RossAscends-mods.js @@ -902,7 +902,7 @@ export function initRossMods() { const chatBlock = $('#chat'); const originalScrollBottom = chatBlock[0].scrollHeight - (chatBlock.scrollTop() + chatBlock.outerHeight()); this.style.height = window.getComputedStyle(this).getPropertyValue('min-height'); - this.style.height = this.scrollHeight + 0.1 + 'px'; + this.style.height = this.scrollHeight + 0.3 + 'px'; if (!isFirefox) { const newScrollTop = Math.round(chatBlock[0].scrollHeight - (chatBlock.outerHeight() + originalScrollBottom));