v0.2.92
This commit is contained in:
1 parent
5cb6960b04
commit
0d7ffea17a
13 files changed
+17
-135
No files matched your search
+1
-3
@@ -253,8 +253,6 @@
|
||||
</form>
|
||||
</dialog>
|
||||
<script>
|
||||
// If initial account scripts/network never finish, offer a local retry rather
|
||||
// than leaving the footer placeholder indefinitely (without blocking home).
|
||||
setTimeout(() => {
|
||||
const slot = document.getElementById("footer-account-slot");
|
||||
if (slot?.dataset.state !== "loading") return;
|
||||
@@ -262,7 +260,7 @@
|
||||
slot.setAttribute("aria-busy", "false");
|
||||
const retry = document.getElementById("footer-account-retry");
|
||||
if (retry) retry.hidden = false;
|
||||
}, 15000);
|
||||
}, 10000);
|
||||
</script>
|
||||
<div id="toast" class="toast-region" aria-live="polite" aria-label="Notifications" aria-relevant="additions removals">
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
* See LICENSE.md for terms.
|
||||
*/
|
||||
|
||||
// Preserve existing nodes. Remove stale entries first: otherwise deleting a
|
||||
// user near the start of a 1000-person list would move every following node.
|
||||
// `desired` must contain each node at most once.
|
||||
export function reconcileChildren(container, desired) {
|
||||
const retained = new Set(desired);
|
||||
for (const node of [...container.childNodes]) {
|
||||
|
||||
@@ -7,7 +7,5 @@
|
||||
* See LICENSE file in repository root for details.
|
||||
*/
|
||||
|
||||
// Generated from Unicode Emoji 17.0 emoji-test.txt.
|
||||
// Native glyphs use the platform emoji font (Apple style on Apple devices).
|
||||
export { EMOJI_GROUPS } from "@rustpad/emoji-groups";
|
||||
export { EMOJI_SHORTCODES } from "@rustpad/emoji-shortcodes";
|
||||
@@ -13,8 +13,6 @@ const MAX_RESULTS = 8;
|
||||
const MENTION_SUFFIX = /[\p{L}\p{M}\p{N}_.+-]{0,64}$/u;
|
||||
const MENTION_BOUNDARY = /[\p{L}\p{N}_@]/u;
|
||||
|
||||
// A suggestion is offered only for an @word being typed at a collapsed caret.
|
||||
// Do not interpret addresses such as john@example.org as mentions.
|
||||
export function mentionAtCaret(value, caret) {
|
||||
if (caret < 1 || caret > value.length) return null;
|
||||
const lineStart = value.lastIndexOf("\n", caret - 1) + 1;
|
||||
@@ -69,8 +67,6 @@ export function createMentionAutocomplete(editor) {
|
||||
menu.hidden = true;
|
||||
shell.append(menu);
|
||||
|
||||
// A single-line offscreen mirror measures the caret's horizontal position,
|
||||
// including proportional fonts and tabs, without relying on text estimates.
|
||||
const mirror = document.createElement("div");
|
||||
mirror.className = "mention-caret-mirror";
|
||||
mirror.setAttribute("aria-hidden", "true");
|
||||
@@ -158,7 +154,6 @@ export function createMentionAutocomplete(editor) {
|
||||
editor.focus();
|
||||
const inserted = `@${user.nickname}${separator}`;
|
||||
editor.setRangeText(inserted, start, end, "end");
|
||||
// Use the normal input pipeline: live collaboration, authorship and undo/redo.
|
||||
editor.dispatchEvent(new InputEvent("input", { bubbles: true, inputType: "insertReplacementText", data: inserted }));
|
||||
}
|
||||
|
||||
@@ -189,7 +184,6 @@ export function createMentionAutocomplete(editor) {
|
||||
const label = document.createElement("span");
|
||||
label.textContent = `@${user.nickname}`;
|
||||
button.append(dot, label);
|
||||
// Keep textarea selection intact while clicking with a mouse.
|
||||
button.addEventListener("mousedown", event => event.preventDefault());
|
||||
button.addEventListener("click", () => accept(index));
|
||||
menu.append(button);
|
||||
|
||||
@@ -11,10 +11,6 @@ import { t } from "@rustpad/i18n";
|
||||
import { normalizeMentionUsers } from "@rustpad/mention-autocomplete";
|
||||
|
||||
function escapeRegex(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }
|
||||
|
||||
// Find real @mentions in the source, not arbitrary text that resembles an email
|
||||
// address or an @username inside a code fence, inline code, link or URL.
|
||||
// Offsets use UTF-16 code units, just like textarea.setSelectionRange().
|
||||
export function collectMentionOccurrences(source, authorizedUsers, { markdown = true } = {}) {
|
||||
const members = normalizeMentionUsers(authorizedUsers);
|
||||
if (!members.length) return [];
|
||||
@@ -39,7 +35,6 @@ export function collectMentionOccurrences(source, authorizedUsers, { markdown =
|
||||
|
||||
const excluded = [];
|
||||
if (markdown) {
|
||||
// The Markdown renderer stashes these constructs before highlighting mentions.
|
||||
const hidden = [
|
||||
/`[^`]+`/g,
|
||||
/!?\[[^\]]*\]\([^\s)]+(?:\s+["'][^"']*["'])?\)/g,
|
||||
@@ -90,8 +85,6 @@ export function createMentionNavigator({ container, list, previewContainer, prev
|
||||
if (!entries.has(mention.key)) entries.set(mention.key, []);
|
||||
entries.get(mention.key).push(mention);
|
||||
}
|
||||
// Keep a reference to each visible mention, so the jump can target the
|
||||
// exact chip even if several mentions are on the same source line.
|
||||
if (markdown) {
|
||||
const visible = new Map();
|
||||
for (const node of preview.querySelectorAll(".markdown-mention")) {
|
||||
@@ -174,7 +167,6 @@ export function createMentionNavigator({ container, list, previewContainer, prev
|
||||
}
|
||||
if (view !== "edit") {
|
||||
navigatePreview(mention);
|
||||
// Split view scroll synchronization may run after the textarea scroll event.
|
||||
if (view === "split") requestAnimationFrame(() => {
|
||||
if (lastJump.get(key) === mention.start) navigatePreview(mention);
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ export function startNoteEditor(adapter) {
|
||||
if (!bootLoading || bootFinishing) return;
|
||||
bootFinishing = true;
|
||||
bootLoading.complete("access");
|
||||
bootLoading.skip("files"); // Identity/password dialog is ready to use.
|
||||
bootLoading.skip("files");
|
||||
bootLoading.ready();
|
||||
}
|
||||
let accessToken = shareToken || getAccessToken(adapter.access.kind, adapter.access.key), password = "", nickname = getNickname(), info, socket, saveTimer, applyingRemote = false, applyingHistory = false, resourceUnlocked = false, uiState = readEditorState(), authorship = parseAuthorship("", "[]"), previousContent = "", globalColor = "", noteColor = "", presenceUsers = [], authorshipMode = "simple", authorshipColorsEnabled = true, lastRevealedLineHash = "", lastRevealedHeadingHash = "", flushRequested = false, accountSession = null;
|
||||
@@ -291,8 +291,7 @@ export function startNoteEditor(adapter) {
|
||||
setMarkdownMentions([]);
|
||||
mentionAutocomplete.setUsers([]);
|
||||
mentionNavigator.setUsers([]);
|
||||
// Session validation can finish before loadNoteInfo(); avoid a premature
|
||||
// request (and a second request when note info becomes available).
|
||||
|
||||
if (!accountSession || !info) { render(); return; }
|
||||
try {
|
||||
const params = new URLSearchParams({ kind: adapter.access.kind, slug: adapter.access.key });
|
||||
|
||||
@@ -35,7 +35,7 @@ export function clearResourceAccessState() {
|
||||
if (key?.startsWith("rustpad:access:")) localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
// Remove plaintext passwords saved by the previous frontend version.
|
||||
|
||||
for (let i = localStorage.length - 1; i >= 0; i--) {
|
||||
const key = localStorage.key(i);
|
||||
if (key?.startsWith("rustpad:workspace:") && key.endsWith(":password")) localStorage.removeItem(key);
|
||||
@@ -43,8 +43,7 @@ for (let i = localStorage.length - 1; i >= 0; i--) {
|
||||
|
||||
const NICKNAME_KEY = "rustpad:nickname";
|
||||
const NICKNAME_COOKIE = "rustpad_nickname";
|
||||
// A session cookie is shared by tabs, but disappears when the browser session
|
||||
// ends. The nickname is not an authentication secret.
|
||||
|
||||
function getCookie(name) {
|
||||
const prefix = `${name}=`;
|
||||
const item = document.cookie.split("; ").find(value => value.startsWith(prefix));
|
||||
@@ -79,7 +78,6 @@ export function getGuestId() {
|
||||
}
|
||||
|
||||
const AUTH_STATE_KEY = "rustpad:auth-state";
|
||||
// Remove browser-readable account tokens created by older frontend versions.
|
||||
localStorage.removeItem("rustpad:auth-token");
|
||||
sessionStorage.removeItem("rustpad:auth-token");
|
||||
export function getAuthToken() { return localStorage.getItem(AUTH_STATE_KEY) ? "cookie" : ""; }
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@
|
||||
<a class="text-button" href="/">Back to home</a>
|
||||
</form>
|
||||
</dialog>
|
||||
<div id="toast" class="toast-region" aria-live="polite" aria-label="Notifications" aria-relevant="additions removals"></div>
|
||||
<div id="toast" class="toast-region" aria-live="polite" aria-label="Notifications" aria-relevant="additions removals">
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in new issue
Block a user