feat: Adresszeile folgt dem Dokument, Live-Sitzung ebenso (D80)

Wer bei offenem `?live=` umschaltet, behielt die alte Adresse — optisch
falsch, und ein Neuladen holte das falsche Dokument zurück. Der Parameter
gehört jetzt zum aktiven Dokument, für `?live=` wie für `?sourceUrl=`;
`?etherpad=` wird nur noch weggeräumt. Fremde Parameter (`?server=`)
bleiben wörtlich stehen, damit die URL lesbar bleibt.

Dabei gefunden: Die Live-Sitzung lief weiter, während ein anderes Dokument
vorn stand — `setLiveText()` schrieb fremde Änderungen in dessen Text. Die
Sitzung gehört jetzt dem sichtbaren Dokument: Umschalten beendet sie,
Umschalten auf ein Server-Dokument nimmt sie auf. Was noch im Debounce
steckt, geht vorher raus, und `pushLive()` hält seine Sitzung fest statt
anzunehmen, dass sich über ein `await` hinweg nichts ändert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-26 21:19:29 +02:00
co-authored by Claude Opus 5
parent 627f6feca8
commit fdca934cf0
8 changed files with 313 additions and 20 deletions
+82
View File
@@ -0,0 +1,82 @@
import { describe, it, expect } from 'vitest';
import { docParam, docSearch, LIVE_PARAM, SOURCE_PARAM } from '../src/docurl.js';
const LIVE = 'live:https://werkbaum.example/api/v1/documents/44753df1';
const URLDOC = 'url:https://example.org/plan.werkbaum';
describe('docParam — welcher Parameter öffnet dieses Dokument wieder?', () => {
it('ein Server-Dokument wird über ?live= adressiert', () => {
expect(docParam(LIVE)).toEqual(
{name: LIVE_PARAM, value: 'https://werkbaum.example/api/v1/documents/44753df1'});
});
it('ein geholtes Dokument über ?sourceUrl=', () => {
expect(docParam(URLDOC)).toEqual(
{name: SOURCE_PARAM, value: 'https://example.org/plan.werkbaum'});
});
it('eigene, mitgelieferte und aus Dateien geöffnete Dokumente haben keine Adresse', () => {
expect(docParam('example')).toBe(null);
expect(docParam('werkbaum')).toBe(null);
expect(docParam('k3f9x1')).toBe(null);
expect(docParam(null)).toBe(null);
expect(docParam(undefined)).toBe(null);
});
});
describe('docSearch — die Adresszeile folgt dem aktiven Dokument', () => {
it('setzt den Parameter des Server-Dokuments', () => {
expect(docSearch('', LIVE))
.toBe('?live=https://werkbaum.example/api/v1/documents/44753df1');
});
it('räumt ihn weg, sobald ein lokales Dokument vorn ist', () => {
expect(docSearch('?live=https://werkbaum.example/api/v1/documents/44753df1', 'example'))
.toBe('');
});
it('tauscht ihn beim Wechsel auf ein anderes Server-Dokument', () => {
expect(docSearch('?live=https://werkbaum.example/api/v1/documents/aaa',
'live:https://werkbaum.example/api/v1/documents/bbb'))
.toBe('?live=https://werkbaum.example/api/v1/documents/bbb');
});
it('tauscht auch zwischen den beiden Eingängen', () => {
expect(docSearch('?sourceUrl=https://example.org/plan.werkbaum', LIVE))
.toBe('?live=https://werkbaum.example/api/v1/documents/44753df1');
expect(docSearch('?live=https://werkbaum.example/api/v1/documents/44753df1', URLDOC))
.toBe('?sourceUrl=https://example.org/plan.werkbaum');
});
it('räumt den ausgebauten ?etherpad= mit weg (D78)', () => {
expect(docSearch('?etherpad=https://pad.example/p/plan', 'example')).toBe('');
});
it('lässt fremde Parameter wörtlich stehen — auch ihre Schreibweise', () => {
expect(docSearch('?server=http://localhost:8080&live=https://a/x', 'example'))
.toBe('?server=http://localhost:8080');
expect(docSearch('?server=http://localhost:8080', LIVE))
.toBe('?server=http://localhost:8080&live=https://werkbaum.example/api/v1/documents/44753df1');
});
it('schreibt die URL unmaskiert — lesbar ist der Zweck', () => {
expect(docSearch('', LIVE)).toContain('https://werkbaum.example/api/v1/documents/44753df1');
});
it('maskiert nur, was den Query-String zerrisse', () => {
expect(docSearch('', 'url:https://example.org/p?a=1&b=2#tail'))
.toBe('?sourceUrl=https://example.org/p?a=1%26b=2%23tail');
});
it('nimmt den Query-String mit und ohne führendes Fragezeichen', () => {
expect(docSearch('server=x', 'example')).toBe('?server=x');
expect(docSearch('?server=x', 'example')).toBe('?server=x');
expect(docSearch(undefined, 'example')).toBe('');
});
it('ändert nichts, wenn schon das Richtige dasteht', () => {
const s = '?live=https://werkbaum.example/api/v1/documents/44753df1';
expect(docSearch(s, LIVE)).toBe(s);
expect(docSearch('', 'example')).toBe('');
});
});