-
Notifications
You must be signed in to change notification settings - Fork 122
Open
Description
Error code
ERRW:0.7:SJ0.7:AS
Were you logged in?
Yes
Your username (if logged in)
silnavi
Your HTML
<h1>QR Dynamic Parameter POC</h1>
<div class="grid">
<!-- Left: Show your QR so people can scan it -->
<div class="card">
<h2>1) Show your QR</h2>
<p class="small">Upload your QR image (e.g., the one you attached) so testers can scan it from their phones.</p>
<input id="file" type="file" accept="image/*" />
<div id="qrWrap" style="margin-top: 1rem;">
<img id="qrImg" alt="QR will appear here" />
</div>
<p class="muted small">Note: Scanning opens whatever URL is encoded in the QR. To test dynamic parameters, the QR should point to this page (your JSFiddle URL), optionally with <span class="mono">?go=1</span> and/or <span class="mono">&to=...</span>.</p>
</div>
<!-- Right: Landing/redirect logic -->
<div class="card">
<h2>2) Dynamic redirect</h2>
<p class="small">This acts as the “landing” that appends dynamic parameters at scan time and forwards to your destination.</p>
<label for="dest">Destination URL (final target)</label>
<input id="dest" type="text" placeholder="https://example.com/landing" />
<div style="margin: 0.5rem 0;">
<label><input id="preserveAll" type="checkbox" checked /> Preserve all incoming query params</label><br/>
<label><input id="auto" type="checkbox" /> Auto‑redirect now</label>
</div>
<div class="row">
<button id="build">Build URL</button>
<button id="go">Redirect now</button>
<button id="copy">Copy built URL</button>
</div>
<details open>
<summary class="small">Built URL</summary>
<div id="out" class="mono small break"></div>
</details>
<p class="small muted">
How it works:
<span class="pill">Copies incoming params (if enabled)</span>
<span class="pill">Adds src=qr</span>
<span class="pill">Adds ts=UNIXms</span>
<span class="pill">Adds rid=random</span>
</p>
<details>
<summary class="small">Tips</summary>
<ul class="small">
<li>Pass <span class="mono">?go=1</span> in the URL to auto‑redirect on page load.</li>
<li>Pass <span class="mono">?to=https://your-target</span> to set the destination from the URL.</li>
<li>Any other params sent to this page (e.g., <span class="mono">?campaign=Q1&id=42</span>) will be preserved if the checkbox is on.</li>
</ul>
</details>
</div>
</div>Your JavaScript
// --- QR display (upload your attached image) ---
const fileInput = document.getElementById('file');
const qrImg = document.getElementById('qrImg');
fileInput.addEventListener('change', (e) => {
const f = e.target.files?.[0];
if (!f) return;
const reader = new FileReader();
reader.onload = () => { qrImg.src = reader.result; };
reader.readAsDataURL(f);
});
// --- Dynamic parameter landing/redirect ---
const params = new URLSearchParams(location.search);
const UI = {
dest: document.getElementById('dest'),
auto: document.getElementById('auto'),
out: document.getElementById('out'),
preserveAll: document.getElementById('preserveAll'),
build: document.getElementById('build'),
go: document.getElementById('go'),
copy: document.getElementById('copy'),
};
// Initialize fields from URL (optional)
UI.dest.value = params.get('to') || '';
UI.auto.checked = params.has('go') || params.get('auto') === '1';
function randId(len = 8) {
const alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789';
let s = '';
crypto.getRandomValues(new Uint8Array(len)).forEach(v => s += alphabet[v % alphabet.length]);
return s;
}
function buildRedirectURL() {
const base = UI.dest.value.trim() || 'https://example.com/landing';
let dest;
try {
dest = new URL(base);
} catch {
alert('Destination URL is invalid.');
return null;
}
// Copy incoming query params (except control keys)
if (UI.preserveAll.checked) {
for (const [k, v] of params.entries()) {
if (['to', 'go', 'auto'].includes(k)) continue; // control keys
dest.searchParams.set(k, v);
}
}
// Add dynamic params
dest.searchParams.set('src', 'qr');
dest.searchParams.set('ts', Date.now().toString());
dest.searchParams.set('rid', randId());
return dest.toString();
}
function refreshOut() {
const url = buildRedirectURL();
UI.out.textContent = url || '';
}
UI.build.addEventListener('click', refreshOut);
UI.go.addEventListener('click', () => {
const url = buildRedirectURL();
if (url) location.href = url;
});
UI.copy.addEventListener('click', async () => {
const url = buildRedirectURL();
if (!url) return;
try {
await navigator.clipboard.writeText(url);
UI.copy.textContent = 'Copied!';
setTimeout(() => (UI.copy.textContent = 'Copy built URL'), 800);
} catch {
prompt('Copy the URL:', url);
}
});
// On load: build output
refreshOut();
// Auto-redirect if requested
if (UI.auto.checked) {
const url = buildRedirectURL();
if (url) location.replace(url);
}Your CSS
:root { color-scheme: light dark; }
body { font-family: system-ui, Arial, sans-serif; margin: 2rem; line-height: 1.45; }
h1 { font-size: 1.25rem; margin: 0 0 1rem; }
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; align-items: start; }
.card { border: 1px solid #ccc; border-radius: 8px; padding: 1rem; }
label { display: block; margin: 0.5rem 0 0.25rem; font-weight: 600; }
input[type="text"] { width: 100%; padding: 0.5rem; }
button { padding: 0.5rem 0.75rem; margin-right: 0.5rem; }
code, .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.muted { color: #666; }
img { max-width: 100%; height: auto; }
.row { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.small { font-size: 0.9rem; }
.pill { display: inline-block; border: 1px solid #ccc; border-radius: 999px; padding: 0.1rem 0.5rem; margin: 0.1rem; }
.good { color: #065f46; }
.warn { color: #92400e; }
details { margin-top: 0.5rem; }
.break { overflow-wrap: anywhere; }Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels