fix(client): quote breaking tooltips (fixes #1003)

This commit is contained in:
Elian Doran 2025-01-28 21:03:39 +02:00
parent a2b6504d9d
commit 5c31a0afeb
No known key found for this signature in database
5 changed files with 35 additions and 29 deletions

View File

@ -124,6 +124,10 @@ function escapeHtml(str: string) {
return str.replace(/[&<>"'`=\/]/g, (s) => entityMap[s]); return str.replace(/[&<>"'`=\/]/g, (s) => entityMap[s]);
} }
export function escapeQuotes(value: string) {
return value.replaceAll("\"", "&quot;");
}
function formatSize(size: number) { function formatSize(size: number) {
size = Math.max(Math.round(size / 1024), 1); size = Math.max(Math.round(size / 1024), 1);

View File

@ -14,6 +14,7 @@ import type AttributeDetailWidget from "./attribute_detail.js";
import type { CommandData, EventData, EventListener, FilteredCommandNames } from "../../components/app_context.js"; import type { CommandData, EventData, EventListener, FilteredCommandNames } from "../../components/app_context.js";
import type { default as FAttribute, AttributeType } from "../../entities/fattribute.js"; import type { default as FAttribute, AttributeType } from "../../entities/fattribute.js";
import type FNote from "../../entities/fnote.js"; import type FNote from "../../entities/fnote.js";
import { escapeQuotes } from "../../services/utils.js";
const HELP_TEXT = ` const HELP_TEXT = `
<p>${t("attribute_editor.help_text_body1")}</p> <p>${t("attribute_editor.help_text_body1")}</p>
@ -76,8 +77,8 @@ const TPL = `
<div class="attribute-list-editor" tabindex="200"></div> <div class="attribute-list-editor" tabindex="200"></div>
<div class="bx bx-save save-attributes-button" title="${t("attribute_editor.save_attributes")}"></div> <div class="bx bx-save save-attributes-button" title="${escapeQuotes(t("attribute_editor.save_attributes"))}"></div>
<div class="bx bx-plus add-new-attribute-button" title="${t("attribute_editor.add_a_new_attribute")}"></div> <div class="bx bx-plus add-new-attribute-button" title="${escapeQuotes(t("attribute_editor.add_a_new_attribute"))}"></div>
<div class="attribute-errors" style="display: none;"></div> <div class="attribute-errors" style="display: none;"></div>
</div> </div>

View File

@ -1,4 +1,4 @@
import utils from "../../services/utils.js"; import utils, { escapeQuotes } from "../../services/utils.js";
import treeService from "../../services/tree.js"; import treeService from "../../services/tree.js";
import importService from "../../services/import.js"; import importService from "../../services/import.js";
import options from "../../services/options.js"; import options from "../../services/options.js";
@ -27,21 +27,21 @@ const TPL = `
<strong>${t("import.options")}:</strong> <strong>${t("import.options")}:</strong>
<div class="checkbox"> <div class="checkbox">
<label data-bs-toggle="tooltip" title="${t("import.safeImportTooltip")}"> <label data-bs-toggle="tooltip" title="${escapeQuotes(t("import.safeImportTooltip"))}">
<input class="safe-import-checkbox" value="1" type="checkbox" checked> <input class="safe-import-checkbox" value="1" type="checkbox" checked>
<span>${t("import.safeImport")}</span> <span>${t("import.safeImport")}</span>
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label data-bs-toggle="tooltip" title="${t("import.explodeArchivesTooltip")}"> <label data-bs-toggle="tooltip" title="${escapeQuotes(t("import.explodeArchivesTooltip"))}">
<input class="explode-archives-checkbox" value="1" type="checkbox" checked> <input class="explode-archives-checkbox" value="1" type="checkbox" checked>
<span>${t("import.explodeArchives")}</span> <span>${t("import.explodeArchives")}</span>
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label data-bs-toggle="tooltip" title="${t("import.shrinkImagesTooltip")}"> <label data-bs-toggle="tooltip" title="${escapeQuotes(t("import.shrinkImagesTooltip"))}">
<input class="shrink-images-checkbox" value="1" type="checkbox" checked> <span>${t("import.shrinkImages")}</span> <input class="shrink-images-checkbox" value="1" type="checkbox" checked> <span>${t("import.shrinkImages")}</span>
</label> </label>
</div> </div>

View File

@ -1,5 +1,5 @@
import { t } from "../../services/i18n.js"; import { t } from "../../services/i18n.js";
import utils from "../../services/utils.js"; import utils, { escapeQuotes } from "../../services/utils.js";
import treeService from "../../services/tree.js"; import treeService from "../../services/tree.js";
import importService from "../../services/import.js"; import importService from "../../services/import.js";
import options from "../../services/options.js"; import options from "../../services/options.js";
@ -24,7 +24,7 @@ const TPL = `
<div class="form-group"> <div class="form-group">
<strong>${t("upload_attachments.options")}:</strong> <strong>${t("upload_attachments.options")}:</strong>
<div class="checkbox"> <div class="checkbox">
<label data-bs-toggle="tooltip" title="${t("upload_attachments.tooltip")}"> <label data-bs-toggle="tooltip" title="${escapeQuotes(t("upload_attachments.tooltip"))}">
<input class="shrink-images-checkbox form-check-input" value="1" type="checkbox" checked> <span>${t("upload_attachments.shrink_images")}</span> <input class="shrink-images-checkbox form-check-input" value="1" type="checkbox" checked> <span>${t("upload_attachments.shrink_images")}</span>
</label> </label>
</div> </div>

View File

@ -3,35 +3,36 @@ import BasicWidget from "./basic_widget.js";
import ws from "../services/ws.js"; import ws from "../services/ws.js";
import options from "../services/options.js"; import options from "../services/options.js";
import syncService from "../services/sync.js"; import syncService from "../services/sync.js";
import { escapeQuotes } from "../services/utils.js";
const TPL = ` const TPL = `
<div class="sync-status-widget launcher-button"> <div class="sync-status-widget launcher-button">
<style> <style>
.sync-status-widget { .sync-status-widget {
} }
.sync-status { .sync-status {
box-sizing: border-box; box-sizing: border-box;
} }
.sync-status .sync-status-icon { .sync-status .sync-status-icon {
display: inline-block; display: inline-block;
position: relative; position: relative;
top: -5px; top: -5px;
font-size: 110%; font-size: 110%;
} }
.sync-status .sync-status-sub-icon { .sync-status .sync-status-sub-icon {
font-size: 40%; font-size: 40%;
position: absolute; position: absolute;
left: 0; left: 0;
top: 16px; top: 16px;
} }
.sync-status .sync-status-icon span { .sync-status .sync-status-icon span {
border: none !important; border: none !important;
} }
.sync-status-icon:not(.sync-status-in-progress):hover { .sync-status-icon:not(.sync-status-in-progress):hover {
background-color: var(--hover-item-background-color); background-color: var(--hover-item-background-color);
cursor: pointer; cursor: pointer;
@ -39,31 +40,31 @@ const TPL = `
</style> </style>
<div class="sync-status"> <div class="sync-status">
<span class="sync-status-icon sync-status-unknown bx bx-time" <span class="sync-status-icon sync-status-unknown bx bx-time"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
title="${t("sync_status.unknown")}"> title="${escapeQuotes(t("sync_status.unknown"))}">
</span> </span>
<span class="sync-status-icon sync-status-connected-with-changes bx bx-wifi" <span class="sync-status-icon sync-status-connected-with-changes bx bx-wifi"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
title="${t("sync_status.connected_with_changes")}"> title="${escapeQuotes(t("sync_status.connected_with_changes"))}">
<span class="bx bxs-star sync-status-sub-icon"></span> <span class="bx bxs-star sync-status-sub-icon"></span>
</span> </span>
<span class="sync-status-icon sync-status-connected-no-changes bx bx-wifi" <span class="sync-status-icon sync-status-connected-no-changes bx bx-wifi"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
title="${t("sync_status.connected_no_changes")}"> title="${escapeQuotes(t("sync_status.connected_no_changes"))}">
</span> </span>
<span class="sync-status-icon sync-status-disconnected-with-changes bx bx-wifi-off" <span class="sync-status-icon sync-status-disconnected-with-changes bx bx-wifi-off"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
title="${t("sync_status.disconnected_with_changes")}"> title="${escapeQuotes(t("sync_status.disconnected_with_changes"))}">
<span class="bx bxs-star sync-status-sub-icon"></span> <span class="bx bxs-star sync-status-sub-icon"></span>
</span> </span>
<span class="sync-status-icon sync-status-disconnected-no-changes bx bx-wifi-off" <span class="sync-status-icon sync-status-disconnected-no-changes bx bx-wifi-off"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
title="${t("sync_status.disconnected_no_changes")}"> title="${escapeQuotes(t("sync_status.disconnected_no_changes"))}">
</span> </span>
<span class="sync-status-icon sync-status-in-progress bx bx-analyse bx-spin" <span class="sync-status-icon sync-status-in-progress bx bx-analyse bx-spin"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
title="${t("sync_status.in_progress")}"> title="${escapeQuotes(t("sync_status.in_progress"))}">
</span> </span>
</div> </div>
</div> </div>