See Our Compatibility

Upload both surveys before exporting.

Category Partner A Match % Partner B
Unanswered Categories (0 or blank) Partner A Partner B
function tkNormalizeOverrides(raw){ // Accept a mapping {id:name} or array of {id,name}/{code,label} if (!raw) return {}; if (Array.isArray(raw)){ const map = {}; for (const r of raw){ const id = r.id || r.code || r.key; const nm = r.name || r.label || r.title; if (id && nm) map[id] = nm; } return map; } if (typeof raw === 'object') return raw; return {}; } async function tkFetchJSON(url){ const r = await fetch(url, {cache:'no-store'}); if (!r.ok) throw new Error(`${url} ${r.status}`); return r.json(); } /* ----------------------------- robust loader ------------------------------ */ async function tkLoadKinkData(){ if (window.__TK_DATA) return window.__TK_DATA; const now = Date.now(); const candidates = [ `/data/kinks.json?v=${now}`, `/data/categories.json?v=${now}`, // optional fallback ]; let items = []; let lastErr; for (const url of candidates){ try{ const raw = await tkFetchJSON(url); items = tkNormalizeItems(raw); if (items && items.length) { tkLog(`loaded ${items.length} raw items from`, url); break; } }catch(e){ lastErr = e; } } if (!items || !items.length){ tkLog('no items available', lastErr || ''); items = []; // continue gracefully } // Overrides (optional) let overridesMap = {}; try{ const rawOver = await tkFetchJSON(`/data/labels-overrides.json?v=${now}`); overridesMap = tkNormalizeOverrides(rawOver); }catch{} // Build labels map const labelsMap = {}; for (const it of items){ const id = it?.id ?? it?.code ?? it?.key ?? null; if (!id) continue; const baseName = it?.name ?? it?.label ?? it?.title ?? id; labelsMap[id] = (overridesMap[id] || baseName).toString().trim(); } window.__TK_DATA = { items, labelsMap }; window.__TK_LABELS = labelsMap; // expose for PDF return window.__TK_DATA; } /* ------------------------ modal + “Start Survey” wiring ------------------- */ (function tkSurveyInit(){ const $ = (s,r=document)=>r.querySelector(s); const $$ = (s,r=document)=>Array.from(r.querySelectorAll(s)); const panel = $('#categorySurveyPanel'); const list = $('#categoryChecklist'); const badge = $('#selectedCountBadge'); const btnClose = $('#btnClosePanel'); const btnAll = $('#btnSelectAll'); const btnNone = $('#btnDeselectAll'); const btnGo = $('#beginSurveyFromPanel'); if (!panel || !list || !btnGo){ console.warn('[TK] panel skeleton missing'); return; } let ALL_IDS = []; let selected = new Set(); const nameFor = id => (window.__TK_LABELS && window.__TK_LABELS[id]) || id; function updateBadge(){ badge.textContent = `${selected.size} selected / ${ALL_IDS.length} total`; } function open(){ panel.classList.add('visible'); panel.setAttribute('aria-hidden','false'); (btnClose||panel).focus({preventScroll:true}); } function close(){ panel.classList.remove('visible'); panel.setAttribute('aria-hidden','true'); } function render(){ const f = document.createDocumentFragment(); if (!ALL_IDS.length){ const p = document.createElement('p'); p.style.opacity = .8; p.textContent = 'Dataset unavailable. Please try again shortly.'; f.append(p); }else{ for (const id of ALL_IDS){ const L = document.createElement('label'); const cb = document.createElement('input'); cb.type='checkbox'; cb.value=id; cb.checked=selected.has(id); cb.addEventListener('change',()=>{ cb.checked?selected.add(id):selected.delete(id); updateBadge(); }); const t = document.createElement('span'); t.textContent = nameFor(id); L.append(cb,t); f.append(L); } } list.replaceChildren(f); list.setAttribute('aria-busy','false'); updateBadge(); } async function prepareAndOpen(){ try{ list.setAttribute('aria-busy','true'); const { items } = await tkLoadKinkData(); // never throws fatally ALL_IDS = (items||[]).map(it=>it.id||it.code||it.key).filter(Boolean); const saved = JSON.parse(localStorage.getItem('__TK_SELECTED_CATEGORIES')||'[]'); selected = new Set(saved.length ? saved : ALL_IDS); // default to all when present render(); open(); }catch(e){ console.error('[TK] data load failed', e); ALL_IDS = []; selected = new Set(); render(); open(); } } // Wire explicit IDs/attributes first function wireKnown(){ let n = 0; for (const el of $$('#startSurveyBtn, [data-tk-start-survey]')){ if (el.__tkWired) continue; el.__tkWired = true; el.addEventListener('click', (ev)=>{ ev.preventDefault(); ev.stopPropagation(); prepareAndOpen(); }, {capture:true}); n++; } return n; } // Heuristic wiring (text/href) function wireHeuristic(){ let n = 0; for (const el of $$('a,button')){ if (el.__tkWired) continue; const txt = (el.textContent||'').trim().toLowerCase(); const href = (el.getAttribute('href')||'').toLowerCase(); if (/start\s*survey/.test(txt) || /\/kinksurvey\/?$/.test(href)){ el.__tkWired = true; el.addEventListener('click', (ev)=>{ ev.preventDefault(); ev.stopPropagation(); prepareAndOpen(); }, {capture:true}); n++; } } return n; } // Global capture guard so nested elements can’t swallow the click document.addEventListener('click', (ev)=>{ const t = ev.target.closest('a,button,[role="button"]'); if (!t || t.__tkWired) return; const txt = (t.textContent||'').toLowerCase(); const href = (t.getAttribute('href')||'').toLowerCase(); if (/start\s*survey/.test(txt) || /\/kinksurvey\/?$/.test(href)){ ev.preventDefault(); ev.stopPropagation(); prepareAndOpen(); } }, true); // Wire now + after small delay for late UI const wired0 = wireKnown() + wireHeuristic(); setTimeout(()=>{ wireKnown(); wireHeuristic(); }, 250); // Panel controls btnClose && btnClose.addEventListener('click', close); btnAll && btnAll.addEventListener('click', ()=>{ selected = new Set(ALL_IDS); render(); }); btnNone && btnNone.addEventListener('click', ()=>{ selected = new Set(); render(); }); btnGo.addEventListener('click', ()=>{ const choice = Array.from(selected); localStorage.setItem('__TK_SELECTED_CATEGORIES', JSON.stringify(choice)); const evt = new CustomEvent('tk:start-survey', { detail: { includeCategories: choice }}); document.dispatchEvent(evt); // If your runner sets this to true we won’t navigate setTimeout(()=>{ if (!window.__TK_SURVEY_STARTED){ const qs = new URLSearchParams({ run:'1', cats: choice.join(',') }); location.href = `/kinksurvey/?${qs}`; } }, 120); }); // Auto-open if hinted via URL or if no button was wired if (/[#?](survey|start=1)/i.test(location.href) || wired0 === 0){ setTimeout(prepareAndOpen, 60); } })(); /* ---------------------------- PDF name helper ------------------------------ Anywhere on the compatibility/PDF page, call: const nameFor = id => (window.__TK_LABELS||{})[id] || id; If __TK_LABELS isn’t ready yet on that page, preload: (async()=>{ if(!window.__TK_LABELS){ const d=await tkLoadKinkData(); window.__TK_LABELS=d.labelsMap; }})(); ---------------------------------------------------------------------------- */