group editor code display changed
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
# Gemeinsam bearbeiten
|
||||
|
||||
In „Strecken bearbeiten“ öffnet der kleine Gruppenbutton zwischen Stift und
|
||||
Löschen einen Dialog. Dort sind die beiden Wichtel groß zu sehen: links der Vogel,
|
||||
rechts der Stein. Erst „Gemeinsamen Entwurf öffnen“ legt einen gemeinsamen
|
||||
Entwurf auf der Website an. Das Original bleibt unverändert. Bei lokalen Entwürfen
|
||||
In „Strecken bearbeiten“ öffnet der kleine Button mit zwei gezeichneten Wichteln
|
||||
zwischen Stift und
|
||||
Löschen den gemeinsamen Entwurf und zeigt anschließend den echten Code mit
|
||||
fünf Wichteln in einem großen Popup an. Eine vorgeschaltete Zwei-Wichtel-Vorschau
|
||||
gibt es nicht mehr. Das Original bleibt unverändert. Bei lokalen Entwürfen
|
||||
fragt die App vorher, ob Weg, Stationen, Bilder und Ton übertragen werden dürfen.
|
||||
Ein bereits eingesandter eigener Entwurf wird dabei zuerst aktualisiert.
|
||||
|
||||
Danach zeigt die App fünf Wichtel als Gruppencode. Andere öffnen in der
|
||||
Streckenverwaltung „Gruppencode eingeben“ und schieben die Bilder in den fünf
|
||||
Streckenverwaltung „Gruppencode eingeben“. Ein eigenes breites Popup bietet
|
||||
Platz für alle fünf Drehräder. Dort schieben sie die Bilder in den fünf
|
||||
Drehrädern nach oben oder unten. Es zählen die Wichtel in der Mitte, von links
|
||||
nach rechts. Wiederholungen sind erlaubt. Pfeiltasten und die Pfeilschaltflächen
|
||||
funktionieren ebenfalls. „Mitmachen“ öffnet den gemeinsamen Entwurf.
|
||||
|
||||
@@ -92,3 +92,14 @@ Sitzungen, Rollen owner/member, Codewechsel und Widerruf. Bedienung und Einspiel
|
||||
nicht vorhanden; bestehende Gruppenrechte gelten unverändert. Heartbeats sind
|
||||
POSTs mit eigenem Bearbeitungsschlüssel und dürfen weder fremde noch bereits
|
||||
abgelaufene Sperren übernehmen.
|
||||
|
||||
## Code-Popups
|
||||
|
||||
- Gruppenbutton zeigt unmittelbar den echten fünfstelligen Einladungscode. Keine
|
||||
vorgeschaltete Zwei-Wichtel-Vorschau wieder einführen; sie wurde mit dem Code
|
||||
verwechselt. Eine unvollständige Codeantwort nicht anzeigen.
|
||||
- Codeanzeige und Codeeingabe verwenden getrennte breite native Dialoge. Alle
|
||||
fünf Drehräder nebeneinander anordnen; Wiederholungen weiterhin zulassen.
|
||||
- Scrollschritt in groups.js und Optionshöhe/Innenabstand in editor.css müssen
|
||||
übereinstimmen (96 Pixel). Schließen der Eingabe verwirft verspätete Antworten;
|
||||
die automatische Einladungsaktualisierung darf die Eingabe nicht überdecken.
|
||||
|
||||
@@ -595,24 +595,24 @@
|
||||
.current-location-button img { width: 24px; height: 24px; vertical-align: middle; }
|
||||
|
||||
/* Shared drafts and vertically scrolling Wichtel-code wheels. */
|
||||
.group-share-pictures { display: flex; align-items: center; justify-content: center; gap: 1rem; margin: 1rem 0; }
|
||||
.group-share-pictures img { width: min(34vw, 9rem); height: 10rem; object-fit: contain; }
|
||||
.group-share-button img { display: block; width: 100%; height: 100%; object-fit: contain; pointer-events: none; }
|
||||
.group-dialog { width: min(35rem, calc(100% - 2rem)); max-height: 90dvh; box-sizing: border-box; overflow-y: auto; padding: 1.25rem; border: 1px solid #c8d3ca; border-radius: 1.25rem; background: #f8faf5; color: #1f3022; }
|
||||
.group-code-dialog { width: min(56rem, calc(100vw - 1rem)); max-height: calc(100dvh - 1rem); padding: clamp(.5rem, 2vw, 1.5rem); }
|
||||
.group-dialog::backdrop { background: rgba(20, 40, 25, .5); }
|
||||
.group-dialog-header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
|
||||
.group-dialog-header h2 { margin: 0; font-size: 1.2rem; }
|
||||
.group-dialog button { min-width: 44px; min-height: 44px; border: 1px solid #c8d3ca; border-radius: .85rem; background: white; color: #24462b; touch-action: manipulation; }
|
||||
.group-dialog button:focus-visible, .group-wheel-viewport:focus-visible { outline: 3px solid #1e6fba; outline-offset: 2px; }
|
||||
.group-wheels { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .3rem; padding: 0; border: 0; margin: 1rem 0; }
|
||||
.group-wheels { display: grid; grid-template-columns: repeat(5, minmax(44px, 1fr)); gap: .3rem; padding: 0; border: 0; margin: 1rem 0; }
|
||||
.group-code-fieldset { border: 0; padding: 0; min-width: 0; }
|
||||
.group-code-fieldset legend { margin-bottom: .5rem; font-weight: 600; }
|
||||
.group-wheel { display: grid; gap: .3rem; min-width: 0; }
|
||||
.group-wheel-viewport { height: 156px; padding: 52px 0; box-sizing: border-box; overflow-y: auto; overscroll-behavior: contain; scroll-snap-type: y mandatory; scrollbar-width: none; border-radius: .85rem; background: linear-gradient(to bottom, #edf2eb 0 33.33%, #dcebdc 33.33% 66.66%, #edf2eb 66.66%); }
|
||||
.group-wheel-viewport { height: 288px; padding: 96px 0; box-sizing: border-box; overflow-y: auto; overscroll-behavior: contain; scroll-snap-type: y mandatory; scrollbar-width: none; border-radius: .85rem; background: linear-gradient(to bottom, #edf2eb 0 33.33%, #dcebdc 33.33% 66.66%, #edf2eb 66.66%); }
|
||||
.group-wheel-viewport::-webkit-scrollbar { display: none; }
|
||||
.group-wheel-option { height: 52px; display: grid; place-items: center; scroll-snap-align: center; cursor: pointer; }
|
||||
.group-wheel-option img { width: 100%; max-width: 48px; height: 48px; object-fit: contain; pointer-events: none; }
|
||||
.group-code { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .3rem; padding: .6rem; border: 1px solid #c8d3ca; border-radius: 1rem; background: #e7f1e9; }
|
||||
.group-code img { width: 100%; height: 64px; object-fit: contain; }
|
||||
.group-wheel-option { height: 96px; display: grid; place-items: center; scroll-snap-align: center; cursor: pointer; }
|
||||
.group-wheel-option img { width: 100%; max-width: 88px; height: 88px; object-fit: contain; pointer-events: none; }
|
||||
.group-code { display: grid; grid-template-columns: repeat(5, minmax(44px, 1fr)); gap: .3rem; padding: .6rem; border: 1px solid #c8d3ca; border-radius: 1rem; background: #e7f1e9; }
|
||||
.group-code img { width: 100%; height: clamp(64px, 14vw, 128px); object-fit: contain; }
|
||||
.group-actions { max-width: min(18rem, 52vw); flex-wrap: wrap; justify-content: flex-end; }
|
||||
.group-actions .editor-secondary-button { font-size: .85rem; }
|
||||
.group-status { display: block; min-height: 1.5rem; color: #9b2c2c; }
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none" stroke="#315d3a" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M5 23 12 6Q14 2 16 6L23 23Z" fill="#e7f1e9"/>
|
||||
<path d="M7 24Q5 34 14 43 23 34 21 24" fill="#fff"/>
|
||||
<circle cx="14" cy="25" r="3" fill="#f2ca6b"/>
|
||||
<path d="M25 25 32 10Q34 6 36 10L43 25Z" fill="#f8f5eb"/>
|
||||
<path d="M27 26Q25 35 34 43 43 35 41 26" fill="#fff"/>
|
||||
<circle cx="34" cy="27" r="3" fill="#f2ca6b"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 507 B |
+13
-17
@@ -579,33 +579,29 @@
|
||||
<script src="js/user-messages.js?v=0.12.14"></script>
|
||||
<script src="js/local-routes.js?v=0.12.14"></script>
|
||||
<script src="js/route-recorder.js?v=0.12.14"></script>
|
||||
<dialog id="group-share-dialog" class="group-dialog" aria-labelledby="group-share-title">
|
||||
<dialog id="group-entry-dialog" class="group-dialog group-code-dialog" aria-labelledby="group-entry-title">
|
||||
<header class="group-dialog-header">
|
||||
<h2 id="group-share-title" data-i18n="groups.share">Gemeinsam bearbeiten</h2>
|
||||
<button id="group-share-close" type="button" data-i18n-aria-label="info.close">×</button>
|
||||
</header>
|
||||
<p id="group-share-route"></p>
|
||||
<div id="group-share-pictures" class="group-share-pictures"></div>
|
||||
<p data-i18n="groups.share-help">Mit diesen beiden Wichteln öffnest du einen gemeinsamen Entwurf. Andere können mit einem Wichtelcode mitmachen. Das Original bleibt erhalten.</p>
|
||||
<div class="editor-form-actions">
|
||||
<button id="group-share-start" type="button" data-i18n="groups.share-start">Gemeinsamen Entwurf öffnen</button>
|
||||
</div>
|
||||
</dialog>
|
||||
<dialog id="group-dialog" class="group-dialog" aria-labelledby="group-title">
|
||||
<header class="group-dialog-header">
|
||||
<h2 id="group-title" data-i18n="groups.share">Gemeinsam bearbeiten</h2>
|
||||
<button id="group-close" type="button" aria-label="Schließen" data-i18n-aria-label="info.close">×</button>
|
||||
<h2 id="group-entry-title" data-i18n="groups.join-open">Gruppencode eingeben</h2>
|
||||
<button id="group-entry-close" type="button" data-i18n-aria-label="info.close">×</button>
|
||||
</header>
|
||||
<section id="group-entry">
|
||||
<p data-i18n="groups.wheel-help">Schiebe die Wichtel nach oben oder unten. Die fünf Wichtel in der Mitte ergeben den Code. Lies von links nach rechts. Ein Wichtel darf mehrmals vorkommen.</p>
|
||||
<fieldset class="group-code-fieldset"><legend data-i18n="groups.code-label">Gruppencode</legend><div id="group-wheels" class="group-wheels"></div></fieldset>
|
||||
<button id="group-join" type="button" data-i18n="groups.join">Mitmachen</button>
|
||||
<div class="editor-form-actions"><button id="group-join" type="button" data-i18n="groups.join">Mitmachen</button></div>
|
||||
</section>
|
||||
<output id="group-entry-status" class="group-status"></output>
|
||||
</dialog>
|
||||
<dialog id="group-dialog" class="group-dialog group-code-dialog" aria-labelledby="group-title">
|
||||
<header class="group-dialog-header">
|
||||
<h2 id="group-title" data-i18n="groups.code-label">Gruppencode</h2>
|
||||
<button id="group-close" type="button" aria-label="Schließen" data-i18n-aria-label="info.close">×</button>
|
||||
</header>
|
||||
<p id="group-route"></p>
|
||||
<section id="group-invitation" hidden>
|
||||
<p data-i18n="groups.invite-help">Zeige diesen Code den anderen. Damit können sie deinen gemeinsamen Entwurf öffnen und bearbeiten. Das Original bleibt erhalten.</p>
|
||||
<div id="group-code" class="group-code" aria-label="Gruppencode" data-i18n-aria-label="groups.code-label"></div>
|
||||
<p id="group-expiry"></p>
|
||||
<button id="group-edit" type="button" data-i18n="groups.edit">Entwurf bearbeiten</button>
|
||||
<div class="editor-form-actions"><button id="group-edit" type="button" data-i18n="groups.edit">Entwurf bearbeiten</button></div>
|
||||
</section>
|
||||
<output id="group-status" class="group-status"></output>
|
||||
</dialog>
|
||||
|
||||
@@ -1652,7 +1652,6 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
if (shareInProgress) return;
|
||||
shareInProgress = true;
|
||||
try {
|
||||
if (ns.Groups.confirmShare && !await ns.Groups.confirmShare(routeName(route))) return;
|
||||
let sourceId = routeId(route);
|
||||
if (routeSource(route) === 'local') {
|
||||
if (!globalThis.confirm(ns.I18n.t('groups.upload-confirm'))) return;
|
||||
|
||||
+28
-43
@@ -6,10 +6,11 @@ globalThis.Wegwichtel ??= {};
|
||||
joinOpen: 'group-join-open', editorJoin: 'editor-group-join', list: 'editor-group-list',
|
||||
dialog: 'group-dialog', close: 'group-close', status: 'group-status', wheels: 'group-wheels',
|
||||
entry: 'group-entry', invitation: 'group-invitation', code: 'group-code', join: 'group-join',
|
||||
edit: 'group-edit', expiry: 'group-expiry'
|
||||
edit: 'group-edit', expiry: 'group-expiry',
|
||||
entryDialog: 'group-entry-dialog', entryClose: 'group-entry-close', entryStatus: 'group-entry-status'
|
||||
};
|
||||
const codeLength = 5;
|
||||
const wheelStep = 52;
|
||||
const wheelStep = 96;
|
||||
const revisions = new Map();
|
||||
let selection = [];
|
||||
let currentGroup = null;
|
||||
@@ -73,12 +74,12 @@ globalThis.Wegwichtel ??= {};
|
||||
async function guarded(action) {
|
||||
if (pending) return;
|
||||
pending = true;
|
||||
element(ids.status).textContent = '';
|
||||
const status = element(element(ids.entryDialog).open ? ids.entryStatus : ids.status);
|
||||
status.textContent = '';
|
||||
element(ids.join).disabled = true;
|
||||
try { await action(); } catch (error) {
|
||||
element(ids.status).textContent = errorMessage(error);
|
||||
if (!element(ids.dialog).open) {
|
||||
element(ids.entry).hidden = true;
|
||||
element(element(ids.entryDialog).open ? ids.entryStatus : ids.status).textContent = errorMessage(error);
|
||||
if (!element(ids.dialog).open && !element(ids.entryDialog).open) {
|
||||
element(ids.invitation).hidden = true;
|
||||
element(ids.dialog).showModal();
|
||||
}
|
||||
@@ -146,21 +147,22 @@ globalThis.Wegwichtel ??= {};
|
||||
}
|
||||
|
||||
function openEntry() {
|
||||
if (element(ids.dialog).open) element(ids.dialog).close();
|
||||
dialogGeneration += 1;
|
||||
selection = new Array(codeLength).fill(0);
|
||||
element(ids.status).textContent = '';
|
||||
element(ids.entry).hidden = false;
|
||||
element(ids.invitation).hidden = true;
|
||||
element(ids.entryStatus).textContent = '';
|
||||
const wheels = element(ids.wheels);
|
||||
wheels.replaceChildren(...selection.map((_, index) => makeWheel(index)));
|
||||
if (!element(ids.dialog).open) element(ids.dialog).showModal();
|
||||
if (!element(ids.entryDialog).open) element(ids.entryDialog).showModal();
|
||||
}
|
||||
|
||||
function showInvitation(payload) {
|
||||
if (!Array.isArray(payload.code) || payload.code.length !== codeLength) throw new Error(t('error.connection'));
|
||||
currentGroup = payload.group;
|
||||
element(ids.status).textContent = '';
|
||||
element(ids.entry).hidden = true;
|
||||
if (element(ids.entryDialog).open) element(ids.entryDialog).close();
|
||||
element(ids.invitation).hidden = false;
|
||||
element('group-route').textContent = payload.group.route.name || '';
|
||||
const motifs = payload.code.map(value => ns.GroupSymbols.get(value));
|
||||
element(ids.code).replaceChildren(...motifs.map(picture));
|
||||
const time = new Date(payload.expiresAt * 1000).toLocaleTimeString(ns.I18n.language, { hour: '2-digit', minute: '2-digit' });
|
||||
@@ -182,7 +184,8 @@ globalThis.Wegwichtel ??= {};
|
||||
finally { invitationPolling = false; }
|
||||
}
|
||||
async function edit(group) {
|
||||
element(ids.dialog).close();
|
||||
if (element(ids.dialog).open) element(ids.dialog).close();
|
||||
if (element(ids.entryDialog).open) element(ids.entryDialog).close();
|
||||
await ns.EditorUi.openGroup(group.route);
|
||||
}
|
||||
|
||||
@@ -258,34 +261,20 @@ globalThis.Wegwichtel ??= {};
|
||||
function shareButton(action) {
|
||||
const result = document.createElement('button');
|
||||
result.type = 'button';
|
||||
result.className = 'editor-icon-button';
|
||||
result.className = 'editor-icon-button group-share-button';
|
||||
result.dataset.editorAction = action;
|
||||
result.title = t('share');
|
||||
result.setAttribute('aria-label', t('share'));
|
||||
result.setAttribute('aria-haspopup', 'dialog');
|
||||
result.textContent = '👥';
|
||||
const icon = document.createElement('img');
|
||||
icon.src = '/images/icons/group-edit.svg';
|
||||
icon.alt = '';
|
||||
icon.width = 32;
|
||||
icon.height = 32;
|
||||
result.appendChild(icon);
|
||||
return result;
|
||||
}
|
||||
|
||||
let shareDecision = null;
|
||||
function confirmShare(name) {
|
||||
if (shareDecision) return Promise.resolve(false);
|
||||
const dialog = element('group-share-dialog');
|
||||
element('group-share-route').textContent = name;
|
||||
element('group-share-pictures').replaceChildren(...['🐦', '🪨'].map(value => picture(ns.GroupSymbols.get(value))));
|
||||
return new Promise(resolve => {
|
||||
shareDecision = resolve;
|
||||
dialog.showModal();
|
||||
});
|
||||
}
|
||||
|
||||
function finishShare(accepted) {
|
||||
const resolve = shareDecision;
|
||||
shareDecision = null;
|
||||
element('group-share-dialog').close();
|
||||
resolve?.(accepted);
|
||||
}
|
||||
|
||||
function headersFor(path) {
|
||||
const id = /^\/routes\/(\d+)(?:\/|$)/.exec(path)?.[1];
|
||||
return id && revisions.has(id) ? { 'If-Match': String(revisions.get(id)) } : {};
|
||||
@@ -306,31 +295,27 @@ globalThis.Wegwichtel ??= {};
|
||||
code: selection.map(index => motifs[index].unicode), creator_id: ns.LocalRoutes.creatorId()
|
||||
});
|
||||
} catch (error) {
|
||||
if (!element(ids.dialog).open || generation !== dialogGeneration) return;
|
||||
if (!element(ids.entryDialog).open || generation !== dialogGeneration) return;
|
||||
throw error;
|
||||
}
|
||||
if (!element(ids.dialog).open || generation !== dialogGeneration) return;
|
||||
if (!element(ids.entryDialog).open || generation !== dialogGeneration) return;
|
||||
await edit(payload.group);
|
||||
await refresh();
|
||||
}
|
||||
|
||||
function init() {
|
||||
globalThis.setInterval?.(() => { refreshInvitation(); }, 30_000);
|
||||
activate(element('group-share-start'), () => finishShare(true));
|
||||
activate(element('group-share-close'), () => finishShare(false));
|
||||
element('group-share-dialog').addEventListener('close', () => {
|
||||
const resolve = shareDecision; shareDecision = null; resolve?.(false);
|
||||
});
|
||||
document.addEventListener('wegwichtel:point-drafts-changed', () => { renderPending(); ns.StorageUsage?.refresh(); });
|
||||
element(ids.dialog).addEventListener('cancel', () => { dialogGeneration += 1; });
|
||||
element(ids.dialog).addEventListener('close', () => { dialogGeneration += 1; });
|
||||
element(ids.entryDialog).addEventListener('cancel', () => { dialogGeneration += 1; });
|
||||
element(ids.entryDialog).addEventListener('close', () => { dialogGeneration += 1; });
|
||||
activate(element(ids.entryClose), () => element(ids.entryDialog).close());
|
||||
for (const id of [ids.joinOpen, ids.editorJoin]) activate(element(id), openEntry);
|
||||
activate(element(ids.close), () => element(ids.dialog).close());
|
||||
activate(element(ids.join), () => guarded(joinSelectedGroup));
|
||||
activate(element(ids.edit), () => guarded(() => edit(currentGroup)));
|
||||
}
|
||||
|
||||
ns.Groups = Object.freeze({ share, shareButton, confirmShare, refresh, refreshInvitation, headersFor, observe });
|
||||
ns.Groups = Object.freeze({ share, shareButton, refresh, refreshInvitation, headersFor, observe });
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, { once: true });
|
||||
else init();
|
||||
}(globalThis.Wegwichtel));
|
||||
|
||||
@@ -135,8 +135,6 @@ globalThis.Wegwichtel ??= {};
|
||||
},
|
||||
"groups": {
|
||||
"code-wait": "In der Gruppe wird gerade eine Station bearbeitet. Ein neuer Code erscheint, sobald die Stationen wieder frei sind. Ein abgelaufener Code erlaubt keinen neuen Beitritt.",
|
||||
"share-help": "Mit diesen beiden Wichteln öffnest du einen gemeinsamen Entwurf. Andere können mit einem Wichtelcode mitmachen. Das Original bleibt erhalten.",
|
||||
"share-start": "Gemeinsamen Entwurf öffnen",
|
||||
"title": "Gemeinsame Entwürfe",
|
||||
"upload-confirm": "Dein Entwurf mit Bildern und Ton wird dafür an die Website gesendet und als gemeinsamer Entwurf kopiert. Fortfahren?",
|
||||
"share": "Gemeinsam bearbeiten",
|
||||
|
||||
@@ -135,8 +135,6 @@ globalThis.Wegwichtel ??= {};
|
||||
},
|
||||
"groups": {
|
||||
"code-wait": "Someone in the group is editing a stop. A new code will appear once the stops are free. An expired code cannot be used to join.",
|
||||
"share-help": "These two gnomes open a shared draft. Others can join using a gnome code. The original stays unchanged.",
|
||||
"share-start": "Open a shared draft",
|
||||
"title": "Shared drafts",
|
||||
"upload-confirm": "Your draft, including pictures and recordings, will be sent to the website and copied into a shared draft. Continue?",
|
||||
"share": "Edit together",
|
||||
|
||||
+34
-33
@@ -27,7 +27,7 @@ function key(node, value) {
|
||||
}
|
||||
async function harness(loading = false) {
|
||||
const ids = ['group-join-open', 'editor-group-join', 'editor-group-list', 'group-dialog', 'group-close',
|
||||
'group-share-dialog', 'group-share-route', 'group-share-pictures', 'group-share-start', 'group-share-close',
|
||||
'group-entry-dialog', 'group-entry-close', 'group-entry-status', 'group-route',
|
||||
'group-status', 'group-wheels', 'group-entry', 'group-invitation', 'group-code', 'group-join', 'group-edit', 'group-expiry'];
|
||||
const nodes = new Map(ids.map(id => [id, new Element()]));
|
||||
const document = new EventTarget();
|
||||
@@ -66,9 +66,9 @@ test('group code wheels support arrows, keyboard wrapping, scrolling and joining
|
||||
const h = await harness(true);
|
||||
h.context.document.dispatchEvent(new Event('DOMContentLoaded'));
|
||||
pointer(h.nodes.get('group-join-open'), { isPrimary: false });
|
||||
assert.equal(h.nodes.get('group-dialog').open, false);
|
||||
assert.equal(h.nodes.get('group-entry-dialog').open, false);
|
||||
pointer(h.nodes.get('group-join-open'));
|
||||
assert.equal(h.nodes.get('group-dialog').open, true);
|
||||
assert.equal(h.nodes.get('group-entry-dialog').open, true);
|
||||
const columns = h.nodes.get('group-wheels').children;
|
||||
assert.equal(columns.length, 5);
|
||||
const [up, viewport, down] = columns[0].children;
|
||||
@@ -82,7 +82,7 @@ test('group code wheels support arrows, keyboard wrapping, scrolling and joining
|
||||
key(viewport, 'Home'); key(viewport, 'ArrowDown');
|
||||
pointer(viewport.children[5]);
|
||||
assert.equal(viewport.attributes.get('aria-valuetext'), 'Vogel');
|
||||
viewport.scrollTop = 3 * 52; viewport.dispatchEvent(new Event('scroll'));
|
||||
viewport.scrollTop = 3 * 96; viewport.dispatchEvent(new Event('scroll'));
|
||||
key(h.nodes.get('group-join'), ' ');
|
||||
await tick();
|
||||
const joined = h.calls.find(call => call.url.endsWith('/join'));
|
||||
@@ -91,10 +91,10 @@ test('group code wheels support arrows, keyboard wrapping, scrolling and joining
|
||||
assert.equal(body.code[0], '🌼');
|
||||
assert.equal(body.creator_id, 'a'.repeat(64));
|
||||
assert.deepEqual(h.edits, [22]);
|
||||
assert.equal(h.nodes.get('group-dialog').open, false);
|
||||
assert.equal(h.nodes.get('group-entry-dialog').open, false);
|
||||
pointer(h.nodes.get('editor-group-join'));
|
||||
pointer(h.nodes.get('group-close'));
|
||||
assert.equal(h.nodes.get('group-dialog').open, false);
|
||||
pointer(h.nodes.get('group-entry-close'));
|
||||
assert.equal(h.nodes.get('group-entry-dialog').open, false);
|
||||
});
|
||||
|
||||
test('sharing displays five motifs and the owner can renew or close access with confirmation', async () => {
|
||||
@@ -102,11 +102,14 @@ test('sharing displays five motifs and the owner can renew or close access with
|
||||
await h.groups.share(7);
|
||||
assert.equal(JSON.parse(h.calls[0].body).routeId, 7);
|
||||
assert.equal(h.nodes.get('group-code').children.length, 5);
|
||||
assert.equal(h.nodes.get('group-entry').hidden, true);
|
||||
assert.equal(h.nodes.get('group-entry-dialog').open, false);
|
||||
assert.equal(h.nodes.get('group-dialog').open, true);
|
||||
assert.match(h.nodes.get('group-expiry').textContent, /Code gilt/);
|
||||
const shareButton = h.groups.shareButton('share-route');
|
||||
assert.equal(shareButton.dataset.editorAction, 'share-route');
|
||||
assert.equal(shareButton.textContent, '👥');
|
||||
assert.equal(shareButton.children.length, 1);
|
||||
assert.equal(shareButton.children[0].src, '/images/icons/group-edit.svg');
|
||||
assert.equal(shareButton.children[0].alt, '');
|
||||
assert.equal(shareButton.attributes.get('aria-haspopup'), 'dialog');
|
||||
pointer(h.nodes.get('group-edit')); await tick();
|
||||
assert.deepEqual(h.edits, [22]);
|
||||
@@ -140,13 +143,13 @@ test('code failures are localized and group list refresh never advances an editi
|
||||
for (const [status, text] of [[404, /Code stimmt/], [401, /nicht geöffnet/], [403, /nicht geöffnet/], [409, /inzwischen geändert/], [429, /eine Minute/], [500, /Internetverbindung/]]) {
|
||||
h.controls.error = status;
|
||||
pointer(h.nodes.get('group-join')); await tick();
|
||||
assert.match(h.nodes.get('group-status').textContent, text);
|
||||
assert.match(h.nodes.get('group-entry-status').textContent, text);
|
||||
assert.equal(h.nodes.get('group-join').disabled, false);
|
||||
}
|
||||
h.controls.error = 0; h.controls.offline = true;
|
||||
h.context.Wegwichtel.I18n.setLanguage('en', null);
|
||||
pointer(h.nodes.get('group-join')); await tick();
|
||||
assert.match(h.nodes.get('group-status').textContent, /internet connection/);
|
||||
assert.match(h.nodes.get('group-entry-status').textContent, /internet connection/);
|
||||
await h.groups.refresh();
|
||||
});
|
||||
|
||||
@@ -161,10 +164,10 @@ test('a late join response does not reopen a cancelled dialog or editor', async
|
||||
pointer(h.nodes.get('group-join-open'));
|
||||
pointer(h.nodes.get('group-join'));
|
||||
await tick();
|
||||
pointer(h.nodes.get('group-close'));
|
||||
pointer(h.nodes.get('group-entry-close'));
|
||||
release();
|
||||
await tick();
|
||||
assert.equal(h.nodes.get('group-dialog').open, false);
|
||||
assert.equal(h.nodes.get('group-entry-dialog').open, false);
|
||||
assert.deepEqual(h.edits, []);
|
||||
});
|
||||
|
||||
@@ -189,29 +192,27 @@ test('unsent station changes are listed before network access and discarded only
|
||||
assert.equal(list.children.length, 0);
|
||||
});
|
||||
|
||||
test('compact sharing button opens a large gnome preview and requires confirmation before starting', async () => {
|
||||
test('sharing opens the actual five-symbol invitation directly without a two-symbol preview', async () => {
|
||||
const h = await harness();
|
||||
const decision = h.groups.confirmShare('Blumenweg');
|
||||
const dialog = h.nodes.get('group-share-dialog');
|
||||
assert.equal(dialog.open, true);
|
||||
assert.equal(h.nodes.get('group-share-route').textContent, 'Blumenweg');
|
||||
const pictures = h.nodes.get('group-share-pictures').children;
|
||||
assert.equal(pictures.length, 2);
|
||||
assert.match(pictures[0].src, /🐦/);
|
||||
assert.match(pictures[1].src, /🪨/);
|
||||
assert.equal(h.calls.length, 0);
|
||||
assert.equal(await h.groups.confirmShare('Zweiter Weg'), false);
|
||||
pointer(h.nodes.get('group-share-close'));
|
||||
assert.equal(await decision, false);
|
||||
const accepted = h.groups.confirmShare('Blumenweg');
|
||||
key(h.nodes.get('group-share-start'), 'Enter');
|
||||
assert.equal(await accepted, true);
|
||||
assert.equal(dialog.open, false);
|
||||
const dismissed = h.groups.confirmShare('Blumenweg');
|
||||
dialog.close();
|
||||
assert.equal(await dismissed, false);
|
||||
await h.groups.share(7);
|
||||
assert.equal(h.nodes.get('group-dialog').open, true);
|
||||
assert.equal(h.nodes.get('group-entry-dialog').open, false);
|
||||
assert.equal(h.nodes.get('group-code').children.length, 5);
|
||||
assert.equal(h.nodes.get('group-route').textContent, 'Waldweg');
|
||||
pointer(h.nodes.get('group-close'));
|
||||
pointer(h.nodes.get('editor-group-join'));
|
||||
assert.equal(h.nodes.get('group-entry-dialog').open, true);
|
||||
assert.equal(h.nodes.get('group-dialog').open, false);
|
||||
assert.equal(h.nodes.get('group-wheels').children.length, 5);
|
||||
});
|
||||
|
||||
test('an incomplete invitation is never displayed as a two-symbol group code', async () => {
|
||||
const h = await harness();
|
||||
h.context.fetch = async () => ({ ok: true, json: async () => ({ group: { route: { id: 7 } }, code: ['🐦', '🪨'] }) });
|
||||
await assert.rejects(h.groups.share(7));
|
||||
assert.equal(h.nodes.get('group-dialog').open, false);
|
||||
assert.equal(h.nodes.get('group-code').children.length, 0);
|
||||
});
|
||||
|
||||
test('the open invitation refreshes its code automatically and shows a deferred renewal during station editing', async () => {
|
||||
const h = await harness();
|
||||
|
||||
Reference in New Issue
Block a user