Commit 9acf1bb8 by PLN (Algolia)

Finish Clarté persistence + offline, and the couple subsite engine

parent 8aac0fb3
......@@ -161,6 +161,49 @@ const state = {
};
// ============================================
// PERSISTENCE (localStorage shim)
// Survive reloads: answers and current section are saved locally,
// restored before first render. Silent no-op in private mode.
// ============================================
const STORAGE_KEY = 'clarte:v1';
function saveState() {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify({
responses: state.responses,
currentSection: state.currentSection
}));
} catch (e) { /* storage unavailable (private mode, quota): skip */ }
}
function clearSavedState() {
try {
localStorage.removeItem(STORAGE_KEY);
} catch (e) { /* storage unavailable: nothing to clear */ }
}
// Merge saved answers into state before first render, so question
// rendering (which reads state.responses) shows restored answers.
// Returns the saved section to resume at, or null.
function restoreState() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
const saved = JSON.parse(raw);
if (saved && typeof saved === 'object') {
if (saved.responses && typeof saved.responses === 'object') {
Object.assign(state.responses, saved.responses);
}
if (sections.includes(saved.currentSection)) {
return saved.currentSection;
}
}
} catch (e) { /* corrupt or unavailable storage: start fresh */ }
return null;
}
// ============================================
// NAVIGATION
// ============================================
......@@ -177,6 +220,7 @@ function showSection(sectionId) {
state.currentSection = sectionId;
updateProgress();
window.scrollTo(0, 0);
saveState();
}
}
......@@ -336,6 +380,7 @@ function attachOptionHandlers(container) {
container.querySelectorAll('input[type="radio"]').forEach(input => {
input.addEventListener('change', (e) => {
state.responses[e.target.name] = parseInt(e.target.value);
saveState();
const question = e.target.closest('.question');
if (question) question.classList.add('answered');
});
......@@ -789,6 +834,9 @@ function validateSection(section) {
// ============================================
function init() {
// Restore saved answers BEFORE first render so radios render checked
const savedSection = restoreState();
// Render all questionnaires
renderASRS();
renderDIVA();
......@@ -833,6 +881,7 @@ function init() {
document.getElementById('restart').addEventListener('click', () => {
state.responses = {};
state.results = null;
clearSavedState();
renderASRS();
renderDIVA();
renderExecutive();
......@@ -841,6 +890,14 @@ function init() {
// Initialize
showSection('home');
// Resume where the user left off (after showSection('home') above)
if (savedSection && savedSection !== 'home') {
if (savedSection === 'results') {
renderResults(); // recomputes purely from state.responses
}
showSection(savedSection);
}
}
// Start app when DOM is ready
......
......@@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Auto-évaluation scientifique du TDAH chez l'adulte. Outils validés: ASRS (OMS), critères DSM-5, fonctions exécutives.">
<meta name="theme-color" content="#5B8A8A">
<link rel="manifest" href="manifest.webmanifest">
<!-- Open Graph / Social -->
<meta property="og:type" content="website">
......@@ -247,5 +248,10 @@
</footer>
<script src="app.js"></script>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js').catch(function () {});
}
</script>
</body>
</html>
{
"name": "Clarté — Auto-Évaluation TDAH",
"short_name": "Clarté TDAH",
"lang": "fr",
"start_url": ".",
"display": "standalone",
"background_color": "#FAF8F5",
"theme_color": "#5B8A8A"
}
/* Cache-first: la page et ses données chargent hors réseau; les réponses
vivent dans localStorage et ne passent jamais par le réseau. */
var CACHE = 'clarte-v1';
var ASSETS = ['./', './index.html', './style.css', './app.js', './jspdf.min.js',
'./manifest.webmanifest',
'./fonts/AtkinsonHyperlegible-Regular.woff2',
'./fonts/AtkinsonHyperlegible-Bold.woff2',
'./fonts/AtkinsonHyperlegible-Italic.woff2'];
self.addEventListener('install', function (e) {
e.waitUntil(caches.open(CACHE).then(function (c) { return c.addAll(ASSETS); }));
});
self.addEventListener('activate', function (e) {
e.waitUntil(caches.keys().then(function (keys) {
return Promise.all(keys.filter(function (k) { return k !== CACHE; })
.map(function (k) { return caches.delete(k); }));
}));
});
self.addEventListener('fetch', function (e) {
if (e.request.method !== 'GET') return;
e.respondWith(caches.match(e.request, { ignoreSearch: true })
.then(function (hit) { return hit || fetch(e.request); }));
});
/* Clarté couple — moteur de questionnaires, 100% local.
Les réponses sont sauvées à chaque sélection dans localStorage :
fermer, recharger ou couper le réseau ne perd jamais un effort.
Score partiel à chaque instant : on note ce qui est répondu. */
(function () {
'use strict';
var DATA = window.COUPLE_DATA;
var SCALES = DATA.scale_library;
var LS = 'couple:v1:';
var app = document.getElementById('app');
var prog = document.getElementById('progress');
var el = function (tag, cls, text) {
var n = document.createElement(tag);
if (cls) n.className = cls;
if (text != null) n.textContent = text;
return n;
};
var store = {
get: function (qid) {
var v = null;
try { v = JSON.parse(localStorage.getItem(LS + 'q:' + qid)); } catch (e) { return null; }
if (!v || typeof v !== 'object' || !v.answers || typeof v.answers !== 'object') return null;
return v;
},
set: function (qid, st) { try { localStorage.setItem(LS + 'q:' + qid, JSON.stringify(st)); } catch (e) {} }
};
/* ---------- session : qui répond ----------
Base d'identité locale, posée pour le « à deux » et les futurs
échanges de réponses. Les clés de réponses ne bougent pas :
`index` reste la clé de stockage, `source_label` n'est que l'affichage. */
function session() {
var s = null;
try { s = JSON.parse(localStorage.getItem(LS + 'session')); } catch (e) { s = null; }
if (!s || typeof s !== 'object') s = { created: new Date().toISOString(), respondent_label: 'moi' };
if (typeof s.created !== 'string') s.created = new Date().toISOString();
if (typeof s.respondent_label !== 'string' || !s.respondent_label) s.respondent_label = 'moi';
return s;
}
function saveSession(s) { try { localStorage.setItem(LS + 'session', JSON.stringify(s)); } catch (e) {} }
/* Options hors échelle : valeur sentinelle distincte de « non répondu »,
jamais comptée dans les totaux (les scores n'additionnent que des nombres). */
var OPT = 'optout:';
function optValue(k) { return OPT + k; }
/* ---------- sérialisation (pour de futurs liens de partage) ----------
Modules purs, sans UI ni réseau : à quoi ressemblerait ce qu'on
raconterait de ses réponses. Rien n'est expédié aujourd'hui.
TODO(partage): ce contenu est sensible (sexualité, couple). Tout
lien de partage devra être CHIFFRÉ avant de quitter l'appareil —
l'encryption se branche ici, entre serializeAnswers et l'URL. */
function computeScore(q, st) {
var sc = q.scoring || {};
if (sc.method !== 'sum_all_items') return null;
var sum = 0, maxSum = 0, n = 0;
allItems(q).forEach(function (r) {
var v = st.answers[r.key];
if (v === undefined || typeof v !== 'number') return; // hors échelle : exclu des totaux
n++; sum += v; maxSum += 4;
});
return maxSum > 0 ? { n: n, pct: Math.round((sum / maxSum) * 100) } : null;
}
function optionLabel(q, section, v) {
if (typeof v === 'string' && v.lastIndexOf(OPT, 0) === 0) {
var o = (DATA.opt_out_options || {})[v.slice(OPT.length)];
return o ? o.label : '';
}
var s = resolveScale(section, q);
if (!s) return '';
for (var i = 0; i < s.options.length; i++) if (s.options[i].value === v) return s.options[i].label;
return '';
}
function serializeAnswers(qid) {
var q = null;
DATA.questionnaires.forEach(function (x) { if (x.id === qid) q = x; });
if (!q) return null;
var st = store.get(qid);
var out = { qid: qid, title: q.title, respondent: session().respondent_label, answered: [] };
if (st) {
allItems(q).forEach(function (r) {
var v = st.answers[r.key];
if (v === undefined) return;
out.answered.push({ i: r.key, v: v, l: optionLabel(q, r.section, v) });
});
var sc = computeScore(q, st);
if (sc) out.pct = sc.pct;
}
return out;
}
function answersToBase64url(obj) {
var bytes = new TextEncoder().encode(JSON.stringify(obj));
var bin = '';
for (var i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
function allItems(q) {
// Clé de stockage = item.index (contrat). Deux instruments réutilisent
// la numérotation d'origine section par section (pensees_negatives,
// inhibiteurs_excitateurs) : là, un index nu écraserait une réponse
// d'une autre section — les répétitions sont préfixées `s<si>:`.
var out = [], seen = {};
(q.sections || []).forEach(function (s, si) {
(s.items || []).forEach(function (it) {
var key = seen[it.index] === undefined ? String(it.index) : 's' + si + ':' + it.index;
seen[it.index] = true;
out.push({ item: it, section: s, key: key });
});
});
return out;
}
function resolveScale(section, q) {
var key = (section && section.scale) || q.default_scale;
var s = typeof key === 'string' ? SCALES[key] : (key || null);
return s && s.options && s.options.length ? s : null;
}
function answeredCount(q, st) {
var n = 0;
allItems(q).forEach(function (r) { if (st.answers[r.key] !== undefined) n++; });
return n;
}
/* ---------- clavier ----------
keymap est posé par la vue active (question, récapitulatif) et remis
à null par les autres ; un seul écouteur pour toute la vie de la page. */
var keymap = null;
document.addEventListener('keydown', function (e) {
if (!keymap || e.ctrlKey || e.metaKey || e.altKey) return;
var tag = e.target && e.target.tagName;
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;
if (/^[1-9]$/.test(e.key) && keymap.digit && +e.key <= keymap.digit) { e.preventDefault(); keymap.pick(+e.key); return; }
if (e.key === 'ArrowRight' && keymap.right) { e.preventDefault(); keymap.right(); return; }
if (e.key === 'ArrowLeft' && keymap.left) { e.preventDefault(); keymap.left(); return; }
if (e.key === 'Enter' && keymap.enter) { e.preventDefault(); keymap.enter(); }
});
/* ---------- progress header ---------- */
function showProgress(text, frac) {
prog.hidden = false;
prog.innerHTML = '';
var line = el('div', null, text);
var fill = el('div', 'fill');
var bar = el('i');
bar.style.width = Math.round(frac * 100) + '%';
fill.appendChild(bar);
prog.appendChild(line); prog.appendChild(fill);
}
function hideProgress() { prog.hidden = true; prog.innerHTML = ''; }
/* ---------- views ---------- */
function home() {
keymap = null;
hideProgress();
app.innerHTML = '';
app.appendChild(el('h1', null, 'Espace couple'));
app.appendChild(el('p', 'muted',
'Des questionnaires pour mettre des mots, à deux, sur ce qui se passe entre vous. ' +
'Répondez librement, à votre rythme — tout reste sur cet appareil, rien n\'est envoyé nulle part.'));
var list = el('ul', 'cardlist');
DATA.questionnaires.forEach(function (q) {
var total = allItems(q).length;
var st = store.get(q.id);
var li = el('li');
var b = el('button', 'cardbtn');
var left = el('span', null, q.title);
var right = el('span', 'meta', total + ' questions');
if (st) {
var n = answeredCount(q, st);
if (n >= total) { right = el('span', 'state', 'Terminé — voir mes réponses'); }
else if (n > 0) { right = el('span', 'state', 'En cours — ' + n + ' sur ' + total); }
}
b.appendChild(left); b.appendChild(right);
b.addEventListener('click', function () { intro(q); });
li.appendChild(b); list.appendChild(li);
});
app.appendChild(list);
var who = session();
var w = el('div', 'who');
var lbl = el('label', 'muted', 'Je réponds en tant que');
lbl.setAttribute('for', 'respondent-label');
var inp = el('input');
inp.id = 'respondent-label';
inp.maxLength = 40;
inp.value = who.respondent_label;
inp.addEventListener('input', function () {
who.respondent_label = inp.value.trim() || 'moi';
saveSession(who);
});
w.appendChild(lbl); w.appendChild(inp);
app.appendChild(w);
app.appendChild(el('p', 'muted',
'Ces questionnaires ne sont pas un jugement ni un diagnostic : ils servent de support à la discussion. ' +
'Un score bas n\'est pas un échec — c\'est une information, et souvent le début de quelque chose de meilleur.'));
var foot = el('footer', 'pagefoot', 'Vos réponses ne quittent jamais cet appareil.');
app.appendChild(foot);
}
function intro(q) {
keymap = null;
hideProgress();
app.innerHTML = '';
app.appendChild(el('h1', null, q.title));
if (q.intro) app.appendChild(el('p', null, q.intro));
if (q.instructions) app.appendChild(el('p', null, q.instructions));
var total = allItems(q).length;
app.appendChild(el('p', 'muted', total + ' questions · quelques minutes · vous pouvez arrêter et reprendre quand vous voulez.'));
var nav = el('div', 'nav');
var back = el('button', null, 'Retour');
back.addEventListener('click', home);
var st = store.get(q.id);
var start = el('button', 'cta', st ? 'Reprendre' : 'Commencer');
start.addEventListener('click', function () { quiz(q, st && st.pos ? st.pos : 0); });
nav.appendChild(back); nav.appendChild(start);
app.appendChild(nav);
}
function quiz(q, pos) {
var items = allItems(q);
var total = items.length;
var st = store.get(q.id) || { answers: {}, pos: 0 };
pos = Math.max(0, Math.min(pos, total)); // pos == total → récapitulatif
st.pos = pos; store.set(q.id, st);
if (pos >= total) { recap(q); return; }
var cur = items[pos];
var scale = resolveScale(cur.section, q);
var answered = answeredCount(q, st);
showProgress(answered + ' sur ' + total + ' répondues', answered / total);
app.innerHTML = '';
app.appendChild(el('p', 'muted', 'Question ' + (pos + 1) + ' sur ' + total));
var t = el('p', 'item-text', cur.item.text);
t.setAttribute('tabindex', '-1');
app.appendChild(t);
var box = el('div', 'scale');
box.setAttribute('role', 'group');
var pick = function (value) {
return function () {
st.answers[cur.key] = value;
st.pos = pos + 1;
store.set(q.id, st);
quiz(q, pos + 1);
};
};
if (scale) {
scale.options.forEach(function (o) {
var b = el('button', null, o.label);
b.setAttribute('aria-pressed', st.answers[cur.key] === o.value ? 'true' : 'false');
b.addEventListener('click', pick(o.value));
box.appendChild(b);
});
} else {
// échelle absente ou sans options (réponse libre) : on n'invente rien.
app.appendChild(el('p', 'muted',
'Cette partie ne se coche pas : elle est faite pour être parlée. Passez à la suite quand vous voulez.'));
}
(cur.item.extra_options || []).forEach(function (k) {
var o = (DATA.opt_out_options || {})[k];
if (!o) return;
var b = el('button', 'optout', o.label);
b.setAttribute('aria-pressed', st.answers[cur.key] === optValue(k) ? 'true' : 'false');
b.addEventListener('click', pick(optValue(k)));
box.appendChild(b);
});
app.appendChild(box);
var goNext = function () { st.pos = pos + 1; store.set(q.id, st); quiz(q, pos + 1); };
var nav = el('div', 'nav');
var prev = el('button', null, 'Précédente');
prev.addEventListener('click', function () { quiz(q, pos - 1); });
var next = el('button', null, pos + 1 < total ? 'Passer' : 'Voir le récapitulatif');
next.addEventListener('click', goNext);
nav.appendChild(prev); nav.appendChild(next);
app.appendChild(nav);
keymap = {
digit: scale ? scale.options.length : 0,
pick: function (n) { var b = box.children[n - 1]; if (b) b.click(); },
right: goNext,
left: function () { quiz(q, pos - 1); }
};
t.focus();
}
/* ---------- résultats : score partiel à chaque instant ---------- */
function recap(q) {
var items = allItems(q);
var total = items.length;
var st = store.get(q.id) || { answers: {}, pos: 0 };
var n = answeredCount(q, st);
showProgress(n + ' sur ' + total + ' répondues', n / total);
app.innerHTML = '';
app.appendChild(el('h1', null, q.title));
app.appendChild(el('p', null,
'Merci d\'avoir pris ce temps. Voici où vous en êtes — ce n\'est ni une note ni un verdict.'));
var sc = computeScore(q, st);
if (sc) {
var pct = sc.pct;
var band = null;
((q.scoring || {}).bands || []).forEach(function (b) { if (pct >= b.min && pct <= b.max) band = b; });
var box = el('div', 'result-band');
box.appendChild(el('div', 'score', pct + ' %'));
var sub = el('p', null,
n === total
? 'Score complet, sur les ' + total + ' questions.'
: 'Score provisoire : ' + n + ' questions répondues sur ' + total +
'. Il évolue à chaque réponse — rien n\'est figé.');
box.appendChild(sub);
if (band) {
box.appendChild(el('p', null, 'Lecture du support d\'origine : ' + band.label));
}
box.appendChild(el('p', 'muted',
'Ce chiffre décrit un moment, pas une personne ni un couple. S\'il vous surprend ou vous pèse, ' +
'c\'est exactement le genre de chose à apporter en séance — pas à porter en silence.'));
app.appendChild(box);
if (q.scoring && q.scoring.source_instruction) {
var q2 = el('blockquote', 'orig', q.scoring.source_instruction);
app.appendChild(q2);
}
} else if (n === 0) {
app.appendChild(el('p', null,
'Aucune réponse pour l\'instant — le questionnaire sera là quand vous serez prêt·e.'));
} else {
app.appendChild(el('p', null,
'Vous avez répondu à ' + n + ' questions sur ' + total +
'. Ce questionnaire ne se calcule pas : vos réponses valent par elles-mêmes, comme matière à réflexion ou à discussion.'));
}
var details = el('details');
var summary = el('summary', null, 'Revoir mes réponses');
details.appendChild(summary);
var table = el('table', 'recap');
items.forEach(function (r) {
var v = st.answers[r.key];
if (v === undefined) return;
var tr = el('tr');
tr.appendChild(el('td', null, r.item.text));
tr.appendChild(el('td', null, optionLabel(q, r.section, v)));
table.appendChild(tr);
});
details.appendChild(table);
app.appendChild(details);
var nav = el('div', 'nav');
var back = el('button', null, 'Retour à l\'accueil');
back.addEventListener('click', home);
var again = el('button', 'cta', n < total ? 'Continuer' : 'Recommencer');
again.addEventListener('click', function () {
if (n < total) {
var resume = st.pos || 0;
if (resume >= total) { // on avait déjà atteint le bout : reprendre à la 1re question sans réponse
resume = 0;
for (var i = 0; i < items.length; i++) {
if (st.answers[items[i].key] === undefined) { resume = i; break; }
}
}
quiz(q, resume);
return;
}
if (window.confirm('Recommencer ce questionnaire ? Vos réponses actuelles seront effacées.')) {
store.set(q.id, { answers: {}, pos: 0 });
quiz(q, 0);
}
});
nav.appendChild(back); nav.appendChild(again);
app.appendChild(nav);
// Entrée = continuer, mais seulement quand rien n'est à risque :
// questionnaire complet, Entrée ne déclenche jamais la remise à zéro.
keymap = n < total ? { enter: function () { again.click(); } } : null;
}
home();
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js').catch(function () {});
}
})();
window.COUPLE_DATA =
{
"schema_version": "1.0.0",
"language": "fr",
"generated_at": "2026-09-21",
"fidelity": {
"policy": "Les champs `text`, `title`, `instructions`, `intro`, `source_label` et les `label` d'options sont VERBATIM (orthographe, typos et numérotation d'origine conservées). Tout champ sous `annotations` ou `anomalies` est une observation ajoutée, PAS une donnée source.",
"extraction": "pdftotext -layout, relu page par page. Les ligatures perdues à l'extraction (ffi, fl, fi, ff) ont été restaurées : difficile, conflit, afin, affectif, suffisamment, finances, diversifiées, différentes.",
"total_items": 190
},
"scale_library": {
"satisfaction_0_4": {
"type": "likert",
"values_in_source": true,
"options": [
{
"value": 0,
"ordinal": 0,
"label": "Très insatisfait"
},
{
"value": 1,
"ordinal": 1,
"label": "Peu satisfait"
},
{
"value": 2,
"ordinal": 2,
"label": "Neutre"
},
{
"value": 3,
"ordinal": 3,
"label": "Satisfait"
},
{
"value": 4,
"ordinal": 4,
"label": "Très satisfait"
}
]
},
"frequence_pensees_0_5": {
"type": "likert",
"values_in_source": true,
"options": [
{
"value": 0,
"ordinal": 0,
"label": "Jamais"
},
{
"value": 1,
"ordinal": 1,
"label": "Rarement"
},
{
"value": 2,
"ordinal": 2,
"label": "Occasionnellement"
},
{
"value": 3,
"ordinal": 3,
"label": "Fréquemment"
},
{
"value": 4,
"ordinal": 4,
"label": "La plupart du temps"
},
{
"value": 5,
"ordinal": 5,
"label": "Toujours"
}
]
},
"communication_1_9": {
"type": "numeric_range",
"values_in_source": true,
"min": 1,
"max": 9,
"step": 1,
"anchors": {
"1": "Jamais",
"9": "Très souvent"
},
"note_source": "« 1 correspond à « Jamais », le 9 à « Très souvent » et les autres se situent entre « Jamais » et « Très souvent ». »"
},
"ressemblance_0_4": {
"type": "likert",
"values_in_source": true,
"options": [
{
"value": 0,
"ordinal": 0,
"label": "pas du tout"
},
{
"value": 1,
"ordinal": 1,
"label": "pas vraiment"
},
{
"value": 2,
"ordinal": 2,
"label": "à peu près"
},
{
"value": 3,
"ordinal": 3,
"label": "beaucoup"
},
{
"value": 4,
"ordinal": 4,
"label": "complètement"
}
]
},
"frequence_jamais_toujours": {
"type": "likert",
"values_in_source": false,
"note": "Aucune valeur numérique n'est imprimée dans le PDF. `ordinal` = position dans le document uniquement ; le mapping ordinal → score n'est pas fourni par la source.",
"options": [
{
"value": null,
"ordinal": 0,
"label": "Jamais"
},
{
"value": null,
"ordinal": 1,
"label": "Rarement"
},
{
"value": null,
"ordinal": 2,
"label": "Quelquefois"
},
{
"value": null,
"ordinal": 3,
"label": "Souvent"
},
{
"value": null,
"ordinal": 4,
"label": "Toujours"
}
]
},
"accord_5": {
"type": "likert",
"values_in_source": false,
"options": [
{
"value": null,
"ordinal": 0,
"label": "Complètement en désaccord"
},
{
"value": null,
"ordinal": 1,
"label": "Plutôt en désaccord"
},
{
"value": null,
"ordinal": 2,
"label": "Ni d'accord ni en désaccord"
},
{
"value": null,
"ordinal": 3,
"label": "Plutôt d'accord"
},
{
"value": null,
"ordinal": 4,
"label": "Complètement en accord"
}
]
},
"exploration_5": {
"type": "likert",
"values_in_source": false,
"options": [
{
"value": null,
"ordinal": 0,
"label": "Pas du tout"
},
{
"value": null,
"ordinal": 1,
"label": "Peu"
},
{
"value": null,
"ordinal": 2,
"label": "Moyennement"
},
{
"value": null,
"ordinal": 3,
"label": "Beaucoup"
},
{
"value": null,
"ordinal": 4,
"label": "Pleinement"
}
]
},
"frequence_6_mois": {
"type": "single_choice",
"values_in_source": false,
"options": [
{
"value": null,
"ordinal": 0,
"label": "Jamais"
},
{
"value": null,
"ordinal": 1,
"label": "2 fois ou moins par mois"
},
{
"value": null,
"ordinal": 2,
"label": "3 à 5 fois par mois"
},
{
"value": null,
"ordinal": 3,
"label": "8 à 12 fois par mois"
},
{
"value": null,
"ordinal": 4,
"label": "4 fois et plus par semaine"
}
],
"anomaly": "Trou dans les bornes : rien ne couvre 6-7 fois par mois (entre « 3 à 5 » et « 8 à 12 »). Défaut présent dans le PDF d'origine."
},
"texte_libre": {
"type": "free_text",
"values_in_source": false,
"options": []
}
},
"opt_out_options": {
"partenaire_ne_propose_pas": {
"label": "Mon (ma) partenaire ne me propose pas d'activité sexuelle.",
"scored": false,
"note": "Option supplémentaire hors échelle, imprimée sous la ligne de réponses."
},
"pas_activite_avec_partenaire": {
"label": "Je n'ai pas d'activité sexuelle avec mon (ma) partenaire",
"scored": false,
"note": "Option supplémentaire hors échelle."
}
},
"questionnaires": [
{
"id": "bonheur_conjugal",
"title": "TEST DU BONHEUR CONJUGAL",
"source_file": "Test_bonheur_conjugal_AV.pdf",
"pdf_title_metadata": "Test_bonheur_conjugal",
"author_attribution": null,
"last_updated_in_source": "14 janvier 2023",
"item_count": 25,
"default_scale": "satisfaction_0_4",
"header_fields": [],
"intro": "Malgré toutes les difficultés de la vie à deux, le couple apparaît encore aujourd'hui comme le meilleur style de vie et la meilleure garantie de bonheur. Tous sont heureux le temps de la séduction et de la lune de miel, soit de quelques mois à deux ou trois ans ; certains savent le rester à plus long terme parce qu'ils ont surmonté les crises et les conflits conjugaux inévitables.\n\nPourquoi certains couples réussissent-ils là où la majorité échoue ? Les psychologues ont observé, écouté, analysé ces couples et ont découvert qu'ils manifestent des attitudes et des aptitudes qui font défaut aux couples malheureux. Ils ont aussi constaté que les couples heureux évitent les pièges dans lesquels se retrouvent les couples qui divorcent. Chaque couple heureux possède sa propre histoire, sa propre culture conjugale. À l'amour et la bonne foi du début, les partenaires heureux ont su acquérir les connaissances et faire les efforts nécessaires pour transformer leur relation en lieu de croissance personnelle, conjugale et familiale. Le bonheur s'apprend et se construit. On peut choisir d'être heureux ou malheureux en amour.",
"instructions": "Évaluez votre degré de satisfaction à propos des vingt-cinq items ci-dessous à partir de l'échelle suivante :",
"sections": [
{
"id": "items",
"title": null,
"scale": "satisfaction_0_4",
"items": [
{
"id": "bc_01",
"index": 1,
"source_label": "1.",
"text": "Notre confiance et respect réciproques"
},
{
"id": "bc_02",
"index": 2,
"source_label": "2.",
"text": "Le respect de mon territoire et de mes habitudes"
},
{
"id": "bc_03",
"index": 3,
"source_label": "3.",
"text": "Sentiment d'admiration pour mon partenaire"
},
{
"id": "bc_04",
"index": 4,
"source_label": "4.",
"text": "Sentiment que mon partenaire m'admire"
},
{
"id": "bc_05",
"index": 5,
"source_label": "5.",
"text": "Sentiment de complicité avec mon partenaire"
},
{
"id": "bc_06",
"index": 6,
"source_label": "6.",
"text": "Notre entente sur nos projets à court, moyen et long terme"
},
{
"id": "bc_07",
"index": 7,
"source_label": "7.",
"text": "La communication verbale émotive"
},
{
"id": "bc_08",
"index": 8,
"source_label": "8.",
"text": "La fréquence de nos rapports sexuels"
},
{
"id": "bc_09",
"index": 9,
"source_label": "9.",
"text": "La qualité de nos rapports sexuels"
},
{
"id": "bc_10",
"index": 10,
"source_label": "10.",
"text": "Nos moments de tendresse, hors sexualité"
},
{
"id": "bc_11",
"index": 11,
"source_label": "11.",
"text": "L'éducation de nos enfants (actuels ou à venir)"
},
{
"id": "bc_12",
"index": 12,
"source_label": "12.",
"text": "Notre entente financière"
},
{
"id": "bc_13",
"index": 13,
"source_label": "13.",
"text": "Le partage des tâches ménagères"
},
{
"id": "bc_14",
"index": 14,
"source_label": "14.",
"text": "Mes liens avec la belle-famille"
},
{
"id": "bc_15",
"index": 15,
"source_label": "15.",
"text": "Les activités de loisirs"
},
{
"id": "bc_16",
"index": 16,
"source_label": "16.",
"text": "La vie au jour le jour"
},
{
"id": "bc_17",
"index": 17,
"source_label": "17.",
"text": "La prise de décision"
},
{
"id": "bc_18",
"index": 18,
"source_label": "18.",
"text": "La résolution de nos conflits"
},
{
"id": "bc_19",
"index": 19,
"source_label": "19.",
"text": "La quantité de temps passé ensemble"
},
{
"id": "bc_20",
"index": 20,
"source_label": "20.",
"text": "La qualité de temps passé ensemble"
},
{
"id": "bc_21",
"index": 21,
"source_label": "21.",
"text": "Le support obtenu lors de moments difficiles"
},
{
"id": "bc_22",
"index": 22,
"source_label": "22.",
"text": "Les relations avec nos couples amis ou nos amis personnels réciproques"
},
{
"id": "bc_23",
"index": 23,
"source_label": "23.",
"text": "Nos périodes de vacances en couples ou seul, sans la famille"
},
{
"id": "bc_24",
"index": 24,
"source_label": "24.",
"text": "Notre engagement réciproque et notre partage du pouvoir"
},
{
"id": "bc_25",
"index": 25,
"source_label": "25.",
"text": "Mon sentiment de liberté dans mon couple"
}
]
}
],
"scoring": {
"method": "sum_all_items",
"min": 0,
"max": 100,
"unit": "percent",
"source_instruction": "Faites le total de chaque colonne et inscrivez le total des cinq (5) colonnes ici = _______ %. Le chiffre obtenu vous donne votre taux de satisfaction conjugale en pourcentage. Plus celui-ci est élevé et plus vous vivez en couple depuis longtemps, plus vous êtes susceptible d'être amoureux et heureux.",
"bands": [
{
"min": 75,
"max": 100,
"label": "Couple très heureux, surtout si vous approchez 100 %."
},
{
"min": 51,
"max": 75,
"label": "Couple heureux avec des hauts et des bas, mais attention si vous approchez 51 %."
},
{
"min": 25,
"max": 50,
"label": "Couple malheureux et qui risque de l'être de plus en plus si vous ne réagissez pas immédiatement."
},
{
"min": 0,
"max": 25,
"label": "L'un de vous deux, sinon les deux, songe sérieusement à la séparation ou à une aventure. Pensez à une thérapie conjugale et/ou personnelle."
}
],
"benchmark": "Les couples heureux à long terme cotent autour de 80 %.",
"debrief": "Pour une meilleure perception de votre situation conjugale, nous vous suggérons de demander à votre partenaire de répondre lui aussi à ce questionnaire et de discuter ensemble de votre degré de satisfaction et des points sur lesquels tous deux êtes satisfaits. Évitez de discuter des 0, 1 et 2, mais prenez-les en note afin d'adapter votre comportement en conséquence. Prenez la responsabilité de vos insatisfactions et de celles de votre partenaire et voyez ce que vous pouvez faire pour les diminuer. Ne cherchez surtout pas un « coupable » ou à savoir qui a raison ou tort, cela ne ferait qu'augmenter votre tension conjugale et votre taux d'insatisfaction. Le couple est une coréalisation où chacun des deux partenaires est responsable à 100 % de son bout de la relation, tant dans ses actions que dans ses réactions. Pour paraphraser John F. Kennedy, demandez-vous ce que vous pouvez faire pour votre couple et non l'inverse."
},
"anomalies": [
"Bandes d'interprétation chevauchantes/trouées : 75 apparaît dans deux bandes (51-75 et 75-100) et rien ne couvre l'intervalle 50-51. Décider d'une règle de départage côté app (p. ex. bornes basses inclusives, hautes exclusives sauf la dernière).",
"Le total brut (0-100) est traité comme un pourcentage : c'est arithmétiquement exact seulement parce que 25 items × 4 = 100."
]
},
{
"id": "satisfaction_sexuelle",
"title": "Test de satisfaction sexuelle",
"source_file": "Test_de_satisfaction_sexuelle_AV.pdf",
"pdf_title_metadata": "Test_de_satisfaction_sexuelle.pdf",
"author_attribution": null,
"item_count": 25,
"default_scale": "satisfaction_0_4",
"header_fields": [],
"instructions": "Le test de satisfaction sexuelle consiste à évaluer votre degré de satisfaction à propos de 25 items à l'aide de l'échelle suivante :",
"sections": [
{
"id": "items",
"title": null,
"scale": "satisfaction_0_4",
"items": [
{
"id": "ss_01",
"index": 1,
"source_label": "1.",
"text": "Mon partenaire est suffisamment tendre et affectueux lors de nos rapports intimes."
},
{
"id": "ss_02",
"index": 2,
"source_label": "2.",
"text": "Mon partenaire est suffisamment attentif à mes envies et à mes besoins lors de nos relations sexuelles."
},
{
"id": "ss_03",
"index": 3,
"source_label": "3.",
"text": "En dehors de nos relations sexuelles, nous prenons toujours du temps pour parler de nos rapports sexuels."
},
{
"id": "ss_04",
"index": 4,
"source_label": "4.",
"text": "Je suis capable de dire ce que j'aime et ce que je n'aime pas chez mon partenaire au sujet de nos rapports sexuels."
},
{
"id": "ss_05",
"index": 5,
"source_label": "5.",
"text": "Je suis satisfait(e) de la fréquence de nos rapports sexuels."
},
{
"id": "ss_06",
"index": 6,
"source_label": "6.",
"text": "Je suis satisfait(e) de la qualité de nos rapports sexuels."
},
{
"id": "ss_07",
"index": 7,
"source_label": "7.",
"text": "Je suis satisfait(e) de nos moments de tendresse hors sexualité."
},
{
"id": "ss_08",
"index": 8,
"source_label": "8.",
"text": "Lorsque nous sommes en vacances, nous privilégions davantage la sexualité."
},
{
"id": "ss_09",
"index": 9,
"source_label": "9.",
"text": "Lors de nos rapports sexuels, nous consacrons beaucoup d'importance aux préliminaires",
"note_source": "Pas de point final dans le PDF."
},
{
"id": "ss_10",
"index": 10,
"source_label": "10.",
"text": "Lors de nos rapports intimes, nous essayons de varier les positions sexuelles."
},
{
"id": "ss_11",
"index": 11,
"source_label": "11.",
"text": "Mon partenaire est capable de comprendre ce qui me fait plaisir durant l'acte sexuel."
},
{
"id": "ss_12",
"index": 12,
"source_label": "12.",
"text": "Je suis capable de comprendre les envies, les besoins et les désirs de mon partenaire lors de nos relations sexuelles."
},
{
"id": "ss_13",
"index": 13,
"source_label": "13.",
"text": "Je suis ouvert(e) aux fantaisies sexuelles."
},
{
"id": "ss_14",
"index": 14,
"source_label": "14.",
"text": "Mon partenaire est ouvert(e) aux fantaisies sexuelles."
},
{
"id": "ss_15",
"index": 15,
"source_label": "15.",
"text": "J'aime voir mon partenaire nu(e)."
},
{
"id": "ss_16",
"index": 16,
"source_label": "16.",
"text": "Je suis suffisamment motivé(e) pour travailler sur ma sexualité, seul(e) et avec mon partenaire."
},
{
"id": "ss_17",
"index": 17,
"source_label": "17.",
"text": "Lors de nos rapports sexuels, il nous arrive de nous masturber l'un l'autre."
},
{
"id": "ss_18",
"index": 18,
"source_label": "18.",
"text": "Dans une relation de couple, j'estime que la sexualité doit avoir une place importante."
},
{
"id": "ss_19",
"index": 19,
"source_label": "19.",
"text": "Lors de nos rapports sexuels, je suis capable de partager et de réaliser mes fantasmes."
},
{
"id": "ss_20",
"index": 20,
"source_label": "20.",
"text": "Lors de nos rapports sexuels, mon partenaire est capable de partager ses fantasmes."
},
{
"id": "ss_21",
"index": 21,
"source_label": "21.",
"text": "D'une façon générale, dans notre couple, le climat est suffisamment érotique."
},
{
"id": "ss_22",
"index": 22,
"source_label": "22.",
"text": "Lors de nos relations sexuelles, je suis capable de lâcher prise et de m'abandonner à mon partenaire."
},
{
"id": "ss_23",
"index": 23,
"source_label": "23.",
"text": "Pour moi, la sexualité, « ça s'apprend, ça se comprend et ça se travaille »."
},
{
"id": "ss_24",
"index": 24,
"source_label": "24.",
"text": "Je sais que les relations sexuelles ne peuvent pas toujours être de la même qualité et de la même intensité."
},
{
"id": "ss_25",
"index": 25,
"source_label": "25.",
"text": "Nous nous endormons rarement sans un geste d'amour ou d'affection."
}
]
}
],
"scoring": {
"method": "sum_all_items",
"min": 0,
"max": 100,
"unit": "percent",
"source_instruction": "Faites le total = ___ %. Le chiffre obtenu vous donne votre taux de satisfaction sexuelle en pourcentage. Plus celui-ci est élevé et plus vous vivez en couple depuis longtemps, plus vous êtes satisfaits de votre sexualité en couple.",
"bands": [
{
"min": 76,
"max": 100,
"label": "couple très satisfait de sa sexualité, surtout si près de 100%."
},
{
"min": 51,
"max": 75,
"label": "couple satisfait de sa sexualité, avec des hauts et des bas, mais attention si près de 51 %."
},
{
"min": 25,
"max": 50,
"label": "couple peu satisfait de sa sexualité et qui risque de l'être de plus en plus."
},
{
"min": 0,
"max": 25,
"label": "couple très peu satisfait de sa sexualité. Soit cette dernière est rare, voire inexistante, soit elle est devenue une corvée."
}
]
},
"anomalies": [
"Trous dans les bandes : rien ne couvre 50-51 ni 75-76. Bandes 25-50 et 0-25 se chevauchent à 25.",
"Item 23 et item 24 mesurent une croyance/attitude, pas une satisfaction : l'échelle « Très insatisfait → Très satisfait » s'y applique mal. Défaut de l'instrument d'origine, conservé tel quel."
]
},
{
"id": "pensees_negatives",
"title": "Questionnaire sur les pensées négatives et inquiétudes durant les rapports sexuels.",
"source_file": "Questionnaire_sur_les_pense_es_ne_gatives_et_inquie_tudes.pdf",
"pdf_title_metadata": "Questionnaire sur les pensées négatives et inquiétudes",
"author_attribution": "Alexandra Vatimbella — sexologue, sophrologue (logo en en-tête)",
"item_count": 59,
"default_scale": "frequence_pensees_0_5",
"header_fields": [
{
"id": "nom",
"label": "NOM",
"type": "text"
},
{
"id": "statut_social",
"label": "Statut social",
"type": "text"
}
],
"instructions": "Lisez chacun des énoncés ci-dessous et indiquez la fréquence de ces pensées durant vos rapports sexuels en utilisant les réponses suivantes :",
"sections": [
{
"id": "s1_soi",
"title": "1- Inquiétudes face à moi-même",
"scale": "frequence_pensees_0_5",
"items": [
{
"id": "pn_1_01",
"index": 1,
"source_label": "1-",
"text": "Certaines parties de mon corps ne sont pas attirantes."
},
{
"id": "pn_1_02",
"index": 2,
"source_label": "2-",
"text": "Je ne suis pas assez bon(ne)."
},
{
"id": "pn_1_03",
"index": 3,
"source_label": "3-",
"text": "Mon corps n'est pas assez « sexy »."
},
{
"id": "pn_1_04",
"index": 4,
"source_label": "4-",
"text": "Je n'atteindrai pas l'orgasme."
},
{
"id": "pn_1_05",
"index": 5,
"source_label": "5-",
"text": "Je ne satisferai pas mon / ma partenaire."
},
{
"id": "pn_1_06",
"index": 6,
"source_label": "6-",
"text": "Je ne parviendrai pas à être excité(e) sexuellement."
},
{
"id": "pn_1_07",
"index": 7,
"source_label": "7-",
"text": "Je suis anxieux(se)"
},
{
"id": "pn_1_08",
"index": 8,
"source_label": "8-",
"text": "J'ai honte."
},
{
"id": "pn_1_09",
"index": 9,
"source_label": "9-",
"text": "Je me sens coupable."
},
{
"id": "pn_1_10",
"index": 10,
"source_label": "10-",
"text": "Je me sens un « objet sexuel »"
}
]
},
{
"id": "s2_partenaire",
"title": "2- Inquiétudes face à mon / ma partenaire",
"scale": "frequence_pensees_0_5",
"items": [
{
"id": "pn_2_01",
"index": 1,
"source_label": "1-",
"text": "Tu es trop pressé(é)."
},
{
"id": "pn_2_02",
"index": 2,
"source_label": "2-",
"text": "Tu es trop mécanique."
},
{
"id": "pn_2_03",
"index": 3,
"source_label": "3-",
"text": "Tu n'es intéressé(e) que par ton propre plaisir.."
},
{
"id": "pn_2_04",
"index": 4,
"source_label": "4-",
"text": "Je me demande à qui tu penses."
},
{
"id": "pn_2_05",
"index": 5,
"source_label": "5-",
"text": "Je m'inquiète de ta réaction si on arrête."
},
{
"id": "pn_2_06",
"index": 6,
"source_label": "6-",
"text": "J'ai peur de te décevoir."
},
{
"id": "pn_2_07",
"index": 7,
"source_label": "7-",
"text": "Combien de temps ça va prendre."
},
{
"id": "pn_2_08",
"index": 8,
"source_label": "8-",
"text": "C'est tout ce qui t'intéresse."
},
{
"id": "pn_2_09",
"index": 9,
"source_label": "9-",
"text": "Ce n'est pas agréable mais j'ai peur de te le dire."
},
{
"id": "pn_2_10",
"index": 10,
"source_label": "10-",
"text": "J'aimerais que tu te relaxes."
},
{
"id": "pn_2_11",
"index": 11,
"source_label": "11-",
"text": "J'ai peur que tu n'atteignes pas l'orgasme."
},
{
"id": "pn_2_12",
"index": 12,
"source_label": "12-",
"text": "Tu essayes trop fort."
},
{
"id": "pn_2_13",
"index": 13,
"source_label": "13-",
"text": "J'aimerais que tu aies plus de plaisir."
},
{
"id": "pn_2_14",
"index": 14,
"source_label": "14-",
"text": "Tu parles trop."
},
{
"id": "pn_2_15",
"index": 15,
"source_label": "15-",
"text": "Si seulement ce n'était pas si important."
},
{
"id": "pn_2_16",
"index": 16,
"source_label": "16-",
"text": "Je n'ai pas vraiment de plaisir."
},
{
"id": "pn_2_17",
"index": 17,
"source_label": "17-",
"text": "Si ce n'est pas parfait, tu vas me laisser."
},
{
"id": "pn_2_18",
"index": 18,
"source_label": "18-",
"text": "Tu ne m'aimes plus."
},
{
"id": "pn_2_19",
"index": 19,
"source_label": "19-",
"text": "Tu me « presses » tu veux me « contrôler »"
},
{
"id": "pn_2_20",
"index": 20,
"source_label": "20-",
"text": "Tu ne me comprends pas."
},
{
"id": "pn_2_21",
"index": 21,
"source_label": "21-",
"text": "Tu ne sais pas communiquer."
},
{
"id": "pn_2_22",
"index": 22,
"source_label": "22-",
"text": "Tu me désires moins qu'avant."
},
{
"id": "pn_2_23",
"index": 23,
"source_label": "23-",
"text": "Tu ne me trouves pas assez attrayant(e)."
}
]
},
{
"id": "s3_relation",
"title": "3- Inquiétudes face à la relation",
"scale": "frequence_pensees_0_5",
"items": [
{
"id": "pn_3_01",
"index": 1,
"source_label": "1-",
"text": "Notre relation est ennuyeuse."
},
{
"id": "pn_3_02",
"index": 2,
"source_label": "2-",
"text": "Notre relation va se terminer par un échec."
},
{
"id": "pn_3_03",
"index": 3,
"source_label": "3-",
"text": "Tu ne veux pas t'engager."
},
{
"id": "pn_3_04",
"index": 4,
"source_label": "4-",
"text": "Nous sommes incompatibles."
},
{
"id": "pn_3_05",
"index": 5,
"source_label": "5-",
"text": "Nous ne nous aimons pas assez."
}
]
},
{
"id": "s4_injonctions",
"title": "4- Les « JE DOIS » et les « IL FAUT »",
"scale": "frequence_pensees_0_5",
"items": [
{
"id": "pn_4_01",
"index": 1,
"source_label": "1-",
"text": "Je ressens que je DOIS faire tout ce que tu veux."
},
{
"id": "pn_4_02",
"index": 2,
"source_label": "2-",
"text": "Il FAUT que je sois excité(e)."
},
{
"id": "pn_4_03",
"index": 3,
"source_label": "3-",
"text": "Nous DEVONS tous les deux réussir."
},
{
"id": "pn_4_04",
"index": 4,
"source_label": "4-",
"text": "Je DEVRAI avoir plus de plaisir."
},
{
"id": "pn_4_05",
"index": 5,
"source_label": "5-",
"text": "J'ai le sentiment que je DOIS te donner un orgasme."
},
{
"id": "pn_4_06",
"index": 6,
"source_label": "6-",
"text": "Je DOIS avoir un orgasme."
},
{
"id": "pn_4_07",
"index": 7,
"source_label": "7-",
"text": "Nous DEVONS avoir un orgasme en même temps."
},
{
"id": "pn_4_08",
"index": 8,
"source_label": "8-",
"text": "Nous DEVONS toujours avoir une activité sexuelle parfaitement réussie."
}
]
},
{
"id": "s5_autres",
"title": "5- Autre pensées négatives ou inquiétudes",
"scale": "frequence_pensees_0_5",
"items": [
{
"id": "pn_5_01",
"index": 1,
"source_label": "1-",
"text": "Je n'ai pas vraiment le goût."
},
{
"id": "pn_5_02",
"index": 2,
"source_label": "2-",
"text": "Pourquoi dois-je m'y intéresser."
},
{
"id": "pn_5_03",
"index": 3,
"source_label": "3-",
"text": "Ca ne marchera pas pour moi."
},
{
"id": "pn_5_04",
"index": 4,
"source_label": "4-",
"text": "Je devrais laisser tomber."
},
{
"id": "pn_5_05",
"index": 5,
"source_label": "5-",
"text": "Je le fais seulement pour te faire plaisir."
},
{
"id": "pn_5_06",
"index": 6,
"source_label": "6-",
"text": "C'est trop d'effort."
},
{
"id": "pn_5_07",
"index": 7,
"source_label": "7-",
"text": "Je fais ce que j'ai à faire, mais ça ne m'apporte rien."
},
{
"id": "pn_5_08",
"index": 8,
"source_label": "8-",
"text": "Je suis trop fatiguée."
},
{
"id": "pn_5_09",
"index": 9,
"source_label": "9-",
"text": "Si tu penses que tu vas réussir à me donner le goût."
},
{
"id": "pn_5_10",
"index": 10,
"source_label": "10-",
"text": "Je trouve les activités sexuelles « dégoutantes »."
},
{
"id": "pn_5_11",
"index": 11,
"source_label": "11-",
"text": "Je n'aime pas voir les organes génitaux."
},
{
"id": "pn_5_12",
"index": 12,
"source_label": "12-",
"text": "Ca va faire mal."
},
{
"id": "pn_5_13",
"index": 13,
"source_label": "13-",
"text": "Je ne suis pas satisfait(e)."
}
]
}
],
"scoring": null,
"anomalies": [
"Aucune clé de cotation ni interprétation dans le PDF : ne pas inventer de score. Au mieux, totaux par section (max : 50 / 115 / 25 / 40 / 65) à titre descriptif.",
"La numérotation repart à 1 à chaque section : les `id` sont préfixés par section pour rester uniques.",
"Typos conservées verbatim : « pressé(é) », « plaisir.. », « Autre pensées », « Ca » sans cédille (items 5-3 et 5-12), « dégoutantes », « Je suis trop fatiguée » (accord au féminin dans un questionnaire par ailleurs épicène)."
]
},
{
"id": "communication",
"title": "Questionnaire d'auto-évaluation de la communication.",
"source_file": "Questionnaire_d_auto-e_valuation_de_la_communication__.pdf",
"pdf_title_metadata": "Questionnaire d'auto-évaluation de la communication.",
"author_attribution": "Alexandra Vatimbella — sexologue, sophrologue (logo en en-tête)",
"item_count": 14,
"default_scale": "communication_1_9",
"header_fields": [
{
"id": "nom",
"label": "NOM",
"type": "text"
}
],
"instructions": "Évaluez votre propre comportement en notant le chiffre qui correspond le mieux à ce que vous faites, selon vous, particulièrement dans des situations de désaccord ou de conflit avec votre conjoint ou conjointe.\n\n1 correspond à « Jamais », le 9 à « Très souvent » et les autres se situent entre « Jamais » et « Très souvent ».\n\nPour mieux comprendre ces différents items, n'hésitez pas à consulter le texte sur les « Principes de la communication » (ci-avant).",
"sections": [
{
"id": "items",
"title": null,
"scale": "communication_1_9",
"items": [
{
"id": "co_01",
"index": 1,
"source_label": "1-",
"text": "Je dis clairement, précisément et brièvement ce que je pense et ressens."
},
{
"id": "co_02",
"index": 2,
"source_label": "2-",
"text": "J'exprime mes sentiments positifs."
},
{
"id": "co_03",
"index": 3,
"source_label": "3-",
"text": "J'exprime mes sentiments négatifs d'une façon non accusatrice, mais directe et constructive."
},
{
"id": "co_04",
"index": 4,
"source_label": "4-",
"text": "J'exprime mes demandes d'une façon constructive."
},
{
"id": "co_05",
"index": 5,
"source_label": "5-",
"text": "Je demeure dans le sujet (je ne sors pas du sujet)."
},
{
"id": "co_06",
"index": 6,
"source_label": "6-",
"text": "Je respecte l'autre: pas d'insultes, de compliments déguisés, de sarcasmes, de remarques désobligeantes sur le passé ou le présent."
},
{
"id": "co_07",
"index": 7,
"source_label": "7-",
"text": "Je laisse l'autre parler, l'écoute l'autre d'une façon active."
},
{
"id": "co_08",
"index": 8,
"source_label": "8-",
"text": "Je vérifie si j'ai bien compris ce que l'autre a dit."
},
{
"id": "co_09",
"index": 9,
"source_label": "9-",
"text": "Je vérifie si l'autre a bien compris ce que j'ai dit."
},
{
"id": "co_10",
"index": 10,
"source_label": "10-",
"text": "Je vérifie si l'autre pense ou ressent ce que je crois qu'il ou elle pense ou ressent."
},
{
"id": "co_11",
"index": 11,
"source_label": "11-",
"text": "Je vérifie les besoins de l'autre et je les respecte."
},
{
"id": "co_12",
"index": 12,
"source_label": "12-",
"text": "Je remarque le côté positif de ses comportements, de ses idées et de ses sentiments."
},
{
"id": "co_13",
"index": 13,
"source_label": "13-",
"text": "Quand je suis d'accord avec l'autre, je le dis honnêtement."
},
{
"id": "co_14",
"index": 14,
"source_label": "14-",
"text": "Quand je ne suis pas d'accord avec l'autre, je reconnais quand même que son point de vue peut avoir du sens pour lui ou pour elle."
}
]
}
],
"scoring": null,
"anomalies": [
"Aucune cotation ni interprétation dans le PDF (total brut possible : 14-126, purement descriptif).",
"Tous les items sont formulés positivement : pas d'items inversés, mais désirabilité sociale probable sur une auto-évaluation.",
"Le PDF renvoie à un texte « Principes de la communication (ci-avant) » qui n'est pas dans les fichiers fournis."
]
},
{
"id": "inhibiteurs_excitateurs",
"title": "Questionnaires sur inhibiteurs et excitateurs",
"source_file": "Questionnaires_sur_inhibiteurs_et_excitateurs.pdf",
"pdf_title_metadata": "Questionnaires sur inhibiteurs et excitateurs",
"author_attribution": "Alexandra Vatimbella — sexologue, sophrologue (logo en en-tête)",
"item_count": 10,
"default_scale": "ressemblance_0_4",
"header_fields": [],
"instructions": null,
"instructions_note": "Aucun bloc INSTRUCTIONS : la consigne est portée par chaque item (« Cela me ressemble : » / « Ça me ressemble : »).",
"sections": [
{
"id": "inhibiteurs",
"title": "QUESTIONNAIRE SUR LES INHIBITEURS",
"scale": "ressemblance_0_4",
"items": [
{
"id": "inh_01",
"index": 1,
"source_label": "1-",
"text": "Parfois, j'ai tellement de soucis que je ne parviens pas à être excité(e). Cela me ressemble :"
},
{
"id": "inh_02",
"index": 2,
"source_label": "2-",
"text": "A moins que tout soit « parfait », il m'est difficile d'être excité(e) sexuellement. Ça me ressemble :"
},
{
"id": "inh_03",
"index": 3,
"source_label": "3-",
"text": "Si je ne suis pas sûre de ce que mon partenaire ressent pour moi, il m'est plus difficile d'être excité(e). Ça me ressemble :"
},
{
"id": "inh_04",
"index": 4,
"source_label": "4-",
"text": "Si je crains de mettre trop de temps à être excité(e) ou à atteindre l'orgasme, cela peut interférer avec mon excitation. Ça me ressemble :"
},
{
"id": "inh_05",
"index": 5,
"source_label": "5-",
"text": "Parfois je me sens tellement « timide » ou gêné(e) pendant les rapports sexuels que je n'arrive pas à être pleinement excité(e). Ça me ressemble :"
}
]
},
{
"id": "excitateurs",
"title": "QUESTIONNAIRE SUR LES EXCITATEURS",
"scale": "ressemblance_0_4",
"items": [
{
"id": "exc_01",
"index": 1,
"source_label": "1-",
"text": "Voir un(e) partenaire faire quelque chose qui prouve son talent oui son intelligence, ou le/la voir interagir correctement avec les autres est susceptible de beaucoup m'exciter sexuellement. Ça me ressemble :"
},
{
"id": "exc_02",
"index": 2,
"source_label": "2-",
"text": "Lorsque je pense à quelqu'un que je trouve sexuellement attirant ou que je fantasme sur le sexe, je suis facilement excité(e) sexuellement. Ça me ressemble :"
},
{
"id": "exc_03",
"index": 3,
"source_label": "3-",
"text": "Si il y a un risque qu'on nous voie ou qu'on nous entende faire l'amour, j'ai plus de mal à être excité(e). Ça me ressemble :"
},
{
"id": "exc_04",
"index": 4,
"source_label": "4-",
"text": "Certaine odeurs particulières sont très excitantes pour moi. Ça me ressemble :"
},
{
"id": "exc_05",
"index": 5,
"source_label": "5-",
"text": "Je pense beaucoup au sexe quand je m'ennuie. Ça me ressemble :"
}
]
}
],
"scoring": null,
"anomalies": [
"Aucune cotation ni interprétation dans le PDF.",
"OBSERVATION (non-source) : exc_03 est formulé comme un inhibiteur (« j'ai plus de mal à être excité(e) ») alors qu'il figure dans la section excitateurs. Si un score de section est calculé un jour, cet item est le candidat évident à l'inversion — à confirmer avec la clinicienne, ne pas coder d'office.",
"Typos conservées : « talent oui son intelligence » (probablement « ou »), « Certaine odeurs », « sûre » accordé au féminin (inh_03), « Si il ».",
"Ces items ressemblent à des adaptations de l'échelle SIS/SES (modèle du double contrôle, Janssen & Bancroft) ; la source ne l'indique pas — hypothèse, à ne pas inscrire dans l'app comme un fait."
]
},
{
"id": "desir_relationnel_comportemental",
"title": "Questionnaire sur la baisse du désir sexuel : aspects relationnel et comportemental",
"source_file": "Questionnaire_sur_la_baisse_du_de_sir_sexuel___aspects_relationnel_et_comportemental_.pdf",
"pdf_title_metadata": "Questionnaire sur la baisse du désir sexuel : aspects relationnel et comportemental",
"author_attribution": "Alexandra Vatimbella — sexologue, sophrologue (logo en en-tête)",
"item_count": 33,
"default_scale": "frequence_jamais_toujours",
"header_fields": [
{
"id": "nom",
"label": "NOM",
"type": "text"
},
{
"id": "date",
"label": "Date",
"type": "date"
}
],
"instructions": "Pour chaque item, cochez la réponse qui correspond le mieux à votre situation depuis les 6 derniers mois.\nTout au long du questionnaire, l'expression « activités sexuelles » signifie tout comportement de nature sexuelle (pas uniquement la relation sexuelle avec pénétration)",
"sections": [
{
"id": "frequence",
"title": null,
"scale": "frequence_jamais_toujours",
"items": [
{
"id": "drc_01",
"index": 1,
"source_label": "1-",
"text": "J'accepte les avances sexuelles de mon (ma) partenaire afin de me rapprocher de lui (elle) au plan affectif.",
"emphasis": "afin de me rapprocher de lui (elle) au plan affectif.",
"extra_options": [
"partenaire_ne_propose_pas"
]
},
{
"id": "drc_02",
"index": 2,
"source_label": "2-",
"text": "J'accepte les avances sexuelles de mon (ma) partenaire par sentiment de devoir conjugal.",
"emphasis": "par sentiment de devoir conjugal.",
"extra_options": [
"partenaire_ne_propose_pas"
]
},
{
"id": "drc_03",
"index": 3,
"source_label": "3-",
"text": "J'accepte les avances sexuelles de mon (ma) partenaire pour ne pas le (la) blesser.",
"emphasis": "pour ne pas le (la) blesser.",
"extra_options": [
"partenaire_ne_propose_pas"
]
},
{
"id": "drc_04",
"index": 4,
"source_label": "4-",
"text": "J'accepte les avances sexuelles de mon (ma) partenaire pour le plaisir qu'elles mes procurent.",
"emphasis": "pour le plaisir qu'elles mes procurent.",
"extra_options": [
"partenaire_ne_propose_pas"
]
},
{
"id": "drc_05",
"index": 5,
"source_label": "5-",
"text": "J'évite certaines situations si je crois qu'elles peuvent mener à des activités sexuelles avec mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_06",
"index": 6,
"source_label": "6-",
"text": "Je fais des avances sexuelles à mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_07",
"index": 7,
"source_label": "7-",
"text": "Je refuse les avances sexuelles de mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_08",
"index": 8,
"source_label": "8-",
"text": "Les contacts oraux-génitaux (stimulations des organes génitaux par la bouche) me dégoutent.",
"extra_options": []
},
{
"id": "drc_09",
"index": 9,
"source_label": "9-",
"text": "Mes activités sexuelles avec mon (ma) partenaire sont diversifiées.",
"extra_options": []
},
{
"id": "drc_10",
"index": 10,
"source_label": "10-",
"text": "J'aime expérimenter de nouvelles activités sexuelles avec mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_11",
"index": 11,
"source_label": "11-",
"text": "Je communique (de façon verbale ou non verbale) à mon (ma) partenaire les activités sexuelles que je préfère.",
"extra_options": [
"partenaire_ne_propose_pas"
]
},
{
"id": "drc_12",
"index": 12,
"source_label": "12-",
"text": "Je communique (de façon verbale ou non verbale) à mon (ma) partenaire les activités sexuelles ce que je n'aime pas dans nos activités sexuelles.",
"extra_options": []
},
{
"id": "drc_13",
"index": 13,
"source_label": "13-",
"text": "Je suis attiré(e) physiquement par mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_14",
"index": 14,
"source_label": "14-",
"text": "Mon (ma) partenaire et moi parlons de sexualité.",
"extra_options": []
},
{
"id": "drc_15",
"index": 15,
"source_label": "15-",
"text": "Mon (ma) partenaire et moi sommes d'accord dans les domaines importants de notre relation de couple (par exemple : finances, loisirs, éducation de enfants, relations familiales, tâches ménagères, etc.)",
"extra_options": []
},
{
"id": "drc_16",
"index": 16,
"source_label": "16-",
"text": "Je suis satisfait(e) de ma relation de couple.",
"extra_options": []
},
{
"id": "drc_17",
"index": 17,
"source_label": "17-",
"text": "Mon (ma) partenaire et moi partageons plusieurs activités.",
"extra_options": []
},
{
"id": "drc_18",
"index": 18,
"source_label": "18-",
"text": "Je déteste être séparé(e) de mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_19",
"index": 19,
"source_label": "19-",
"text": "Mon (ma) partenaire me démontre suffisamment d'affection.",
"extra_options": []
},
{
"id": "drc_20",
"index": 20,
"source_label": "20-",
"text": "J'éprouve de la colère envers mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_21",
"index": 21,
"source_label": "21-",
"text": "Je suis satisfait(e) de la manière dont mon (ma) partenaire et moi communiquons.",
"extra_options": []
},
{
"id": "drc_22",
"index": 22,
"source_label": "22-",
"text": "Je suis satisfait(e) de ma capacité à écouter mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_23",
"index": 23,
"source_label": "23-",
"text": "Je suis satisfait(e) de la façon dont les conflits dans mon couple sont résolus.",
"extra_options": []
},
{
"id": "drc_24",
"index": 24,
"source_label": "24-",
"text": "Je ressens de l'amour pour mon (ma) partenaire.",
"extra_options": []
},
{
"id": "drc_25",
"index": 25,
"source_label": "25-",
"text": "Je me sens proche de mon (ma) partenaire au plan affectif.",
"extra_options": []
}
]
},
{
"id": "accord",
"title": null,
"section_instructions": "Pour les prochains items, indiquez dans quelle mesure vous êtes d'accord avec les énoncés",
"scale": "accord_5",
"items": [
{
"id": "drc_26",
"index": 26,
"source_label": "26-",
"text": "Il est facile pour mon (ma) partenaire et moi de parler de notre sexualité."
},
{
"id": "drc_27",
"index": 27,
"source_label": "27-",
"text": "Je tiens à ce que ma relation de couple se poursuive."
}
]
},
{
"id": "exploration",
"title": null,
"section_instructions": "Pour les derniers items, cochez la réponse qui correspond le mieux à votre situation",
"scale": "exploration_5",
"items": [
{
"id": "drc_28",
"index": 28,
"source_label": "28-",
"text": "J'ai exploré par le toucher les différentes parties non génitales de mon corps."
},
{
"id": "drc_29",
"index": 29,
"source_label": "29-",
"text": "J'ai exploré par le toucher les différentes parties génitales de mon corps."
},
{
"id": "drc_30",
"index": 30,
"source_label": "30-",
"text": "Je connais les parties non génitales de mon corps qui me procurent du plaisir."
},
{
"id": "drc_31",
"index": 31,
"source_label": "31-",
"text": "Je connais les parties génitales de mon corps qui me procurent du plaisir."
}
]
},
{
"id": "frequences_6_mois",
"title": null,
"scale": "frequence_6_mois",
"items": [
{
"id": "drc_32",
"index": 32,
"source_label": "32-",
"text": "Depuis les six derniers mois, j'ai eu des activités sexuelles avec mon (ma) partenaire."
},
{
"id": "drc_33",
"index": 33,
"source_label": "12-",
"text": "Depuis les six derniers mois, je me suis masturbé(e) (avec ou sans la présence de mon (ma) partenaire).",
"label_anomaly": "Numéroté « 12- » dans le PDF alors qu'il suit l'item 32 : erreur de numérotation d'origine. `index` 33 = position réelle."
}
]
}
],
"scoring": null,
"anomalies": [
"Aucune cotation ni interprétation dans le PDF.",
"Dernier item numéroté « 12- » au lieu de « 33- » (doublon avec l'item 12). Conservé en `source_label`, corrigé en `index`.",
"drc_12 : phrase bancale d'origine (« les activités sexuelles ce que je n'aime pas dans nos activités sexuelles »). Conservée verbatim ; l'app pourrait afficher la version d'origine et non une reformulation.",
"drc_11 porte l'option « Mon (ma) partenaire ne me propose pas d'activité sexuelle » alors que l'item porte sur MA communication de préférences : option sans doute copiée-collée par erreur. Conservée (fidélité), à signaler à la clinicienne.",
"drc_05 à drc_10 n'ont PAS l'option d'échappatoire alors que leur contenu la justifierait autant : incohérence d'origine.",
"Quatre échelles différentes se succèdent : le rendu mobile doit être piloté par `section.scale`, pas par un composant unique."
]
},
{
"id": "desir_individuel_cognitif",
"title": "Questionnaire sur la baisse du désir sexuel : aspects individuel et cognitif",
"source_file": "Questionnaire_sur_la_baisse_du_de_sir_sexuel___aspects_individuel_et_cognitif.pdf",
"pdf_title_metadata": "Questionnaire sur la baisse du désir sexuel : aspects individuel et cognitif",
"author_attribution": "Alexandra Vatimbella — sexologue, sophrologue (logo en en-tête)",
"item_count": 17,
"default_scale": "frequence_jamais_toujours",
"header_fields": [
{
"id": "nom",
"label": "NOM",
"type": "text"
},
{
"id": "date",
"label": "Date",
"type": "date"
}
],
"instructions": "Pour chaque item, cochez la réponse qui correspond le mieux à votre situation depuis les 6 derniers mois.\nTout au long du questionnaire, l'expression « activités sexuelles » signifie tout comportement de nature sexuelle (pas uniquement la relation sexuelle avec pénétration)",
"sections": [
{
"id": "frequence",
"title": null,
"scale": "frequence_jamais_toujours",
"items": [
{
"id": "dic_01",
"index": 1,
"source_label": "1-",
"text": "Je suis satisfait(e) de la fréquence de mes activités sexuelles avec mon(ma) partenaire",
"emphasis": "fréquence",
"extra_options": []
},
{
"id": "dic_02",
"index": 2,
"source_label": "2-",
"text": "Je suis satisfait(e) de la qualité de mes activités sexuelles avec mon(ma) partenaire",
"extra_options": []
},
{
"id": "dic_03",
"index": 3,
"source_label": "3-",
"text": "J'ai des fantasmes sexuels (idées ou images à contenu sexuel) au cours de la journée (en-dehors des activités sexuelles avec ou sans partenaire)",
"emphasis": "au cours de la journée",
"extra_options": []
},
{
"id": "dic_04",
"index": 4,
"source_label": "4-",
"text": "Durant mes relations sexuelles, je suis préoccupé(e) par ma performance sexuelles",
"extra_options": []
},
{
"id": "dic_05",
"index": 5,
"source_label": "5-",
"text": "Lors de mon enfance et de mon adolescence, mes parents (ou tuteurs) avaient une attitude négative face à la sexualité.",
"extra_options": []
},
{
"id": "dic_06",
"index": 6,
"source_label": "6-",
"text": "Je crains de m'abandonner (me laisser aller) lors des activé sexuelles avec mon (ma) partenaire.",
"extra_options": [
"pas_activite_avec_partenaire"
]
},
{
"id": "dic_07",
"index": 7,
"source_label": "7-",
"text": "Je crains l'intimité qu'impliquent les activé sexuelles avec mon (ma) partenaire.",
"extra_options": []
},
{
"id": "dic_08",
"index": 8,
"source_label": "8-",
"text": "Pendant mes relations sexuelles, je souhaite que certaines activité sexuelles plaisantes se produisent.",
"extra_options": []
}
]
},
{
"id": "accord",
"title": null,
"section_instructions": "Pour les prochains items, indiquez dans quelle mesure vous êtes d'accord avec les énoncés",
"scale": "accord_5",
"items": [
{
"id": "dic_09",
"index": 9,
"source_label": "9-",
"text": "Certains fantasmes sexuels (osées ou images à contenu sexuel) sont inaceptables."
},
{
"id": "dic_10",
"index": 10,
"source_label": "10-",
"text": "Je me trouve maladroit(e) dans mes activités sexuelles avec mon (ma) partenaire."
},
{
"id": "dic_11",
"index": 11,
"source_label": "11-",
"text": "Je me considère comme un(e) bon(ne) partenaire sexuel(le)."
},
{
"id": "dic_12",
"index": 12,
"source_label": "12-",
"text": "Avoir des activités sexuelles (avec ou sans partenaire) est quelque chose de mal."
},
{
"id": "dic_13",
"index": 13,
"source_label": "13-",
"text": "Les personnes âgées n'ont pas de désir sexuel."
},
{
"id": "dic_14",
"index": 14,
"source_label": "15-",
"text": "Les changements physiques causés par le vieillissement rendent la personne moins attirante sexuellement.",
"label_anomaly": "Le PDF saute de 13 à 15 : aucun item numéroté 14 n'existe."
},
{
"id": "dic_15",
"index": 15,
"source_label": "16-",
"text": "Les activités sexuelles entre deux personnes sont impossibles si l'homme (ou personne à penis) n'a pas d'érection."
},
{
"id": "dic_16",
"index": 16,
"source_label": "16 bis-",
"text": "Les activités sexuelles entre deux personnes sont impossibles si la femme (ou personne à clitoris) n'a pas d'érection.",
"label_anomaly": "Numéroté « 16 bis- » dans le PDF (deuxième item portant le numéro 16)."
},
{
"id": "dic_17",
"index": 17,
"source_label": "17-",
"text": "Une activité sexuelle est bonne seulement si elle mène à l'orgasme."
}
]
}
],
"scoring": null,
"anomalies": [
"Aucune cotation ni interprétation dans le PDF.",
"Numérotation d'origine défaillante : 1→13, puis 15, 16, « 16 bis », 17. Pas d'item 14. 17 étiquettes pour 17 items réels ; `index` renuméroté proprement, `source_label` conservé.",
"Typos conservées verbatim : « activé sexuelles » (×2), « performance sexuelles », « activité sexuelles », « (osées ou images à contenu sexuel) » (probablement « idées », cf. dic_03), « inaceptables », « penis » sans accent.",
"dic_16 parle d'« érection » pour « la femme (ou personne à clitoris) » — formulation volontaire ou coquille, ambiguë. Conservée telle quelle.",
"dic_11 est le seul item formulé positivement de la section « accord » : inversion probable si un score est construit un jour — à valider par la clinicienne, pas codé ici."
]
},
{
"id": "folio_vie_en_couple",
"title": "La vie en couple",
"source_file": "Folio__copie.pdf",
"pdf_title_metadata": "Folio",
"author_attribution": null,
"item_count": 7,
"default_scale": "texte_libre",
"type": "worksheet",
"header_fields": [
{
"id": "nom",
"label": "Nom",
"type": "text"
},
{
"id": "date",
"label": "Date :",
"type": "date"
}
],
"instructions": null,
"sections": [
{
"id": "quotidien",
"title": "Dans la vie de tous les jours",
"scale": "texte_libre",
"layout": "two_columns",
"items": [
{
"id": "fo_01",
"index": 1,
"source_label": null,
"text": "Ce que j'aime chez lui-elle",
"column": 1
},
{
"id": "fo_02",
"index": 2,
"source_label": null,
"text": "Ce que je n'aime pas chez lui elle",
"column": 2
}
]
},
{
"id": "sexuel",
"title": "Dans la relation sexuelle",
"scale": "texte_libre",
"layout": "two_columns",
"items": [
{
"id": "fo_03",
"index": 3,
"source_label": null,
"text": "Ce que j'aime",
"column": 1
},
{
"id": "fo_04",
"index": 4,
"source_label": null,
"text": "Ce que je n'aime pas",
"column": 2
}
]
},
{
"id": "conclusion",
"title": "Conclusion",
"scale": "texte_libre",
"layout": "single_column",
"items": [
{
"id": "fo_05",
"index": 5,
"source_label": null,
"text": "Chez moi : si je pouvais changer 3 choses en moi pour m'améliorer et améliorer notre relation, ce serait…",
"suggested_input": "3 champs libres"
},
{
"id": "fo_06",
"index": 6,
"source_label": null,
"text": "Chez elle lui : si d'un coup de baguette magique, j'étais capable de changer 3 choses en elle pour améliorer notre relation, ce serait…",
"suggested_input": "3 champs libres"
},
{
"id": "fo_07",
"index": 7,
"source_label": null,
"text": "Quelles raisons ai-je de continuer à vivre avec elle ?",
"suggested_input": "texte long"
}
]
}
],
"scoring": null,
"anomalies": [
"Document de travail à champs libres, pas un questionnaire coté.",
"Formulation genrée et incohérente : « chez lui-elle », « chez lui elle », « Chez elle lui », puis « en elle » et « avec elle » (masculin/féminin mélangés, l'original semble écrit pour un répondant hétéro masculin). Verbatim conservé ; une version épicène serait une modification éditoriale, à décider avec la clinicienne.",
"Le pied de page porte la mention « Interne » (métadonnée du modèle Pages, pas du contenu)."
]
}
],
"caveats_for_implementation": [
"Cotation : seuls 2 des 8 instruments (bonheur_conjugal, satisfaction_sexuelle) ont une clé de score et des bandes d'interprétation. Pour les 6 autres, `scoring` est null — ne pas fabriquer de score, surtout pas un « % » affiché à l'utilisateur : ce serait inventer une métrique clinique inexistante.",
"Échelles sans valeurs : `frequence_jamais_toujours`, `accord_5`, `exploration_5` et `frequence_6_mois` n'ont aucun chiffre imprimé. `ordinal` encode seulement la position à l'écran. Si un scoring est ajouté plus tard, il doit venir de la clinicienne, pas du code.",
"Items inversés : aucun n'est marqué comme tel dans les sources. Les candidats repérés (exc_03, dic_11, drc_07/08/20…) sont des observations, listées dans `anomalies`, jamais dans les données.",
"Utiliser `index` comme clé de tri/stockage et `source_label` uniquement pour l'affichage, afin que la numérotation cassée des PDF n'atteigne pas la couche de données.",
"Les `id` sont stables : à traiter comme un contrat. Toute correction future de libellé ne doit pas changer l'id (sinon les réponses déjà saisies se décrochent).",
"Chaque questionnaire mélange plusieurs échelles par section : le composant de saisie doit se résoudre via `section.scale` (fallback `questionnaire.default_scale`), jamais en dur.",
"Options hors échelle (`extra_options`) : stocker une valeur sentinelle distincte de « non répondu » et exclue de tout total.",
"Données extrêmement sensibles (sexualité, couple, potentiellement deux répondants). Local-first, chiffrement au repos, pas de télémétrie, export/suppression totale — cohérent avec l'approche privacy-first déjà adoptée ailleurs.",
"Deux répondants : prévoir dès le modèle de données un `respondent_id` et un `session_id`, puisque bonheur_conjugal recommande explicitement que le/la partenaire réponde aussi et qu'on compare les réponses.",
"Les textes proviennent des supports d'une praticienne identifiable (logo Alexandra Vatimbella sur 5 des 8 PDF). Usage personnel : sans objet. Toute diffusion de l'app au-delà de vous deux exige son accord."
]
}
;
......@@ -3,12 +3,17 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bientôt — me.nech.pl/couple/</title>
<style>
body { font-family: Georgia, serif; max-width: 30rem; margin: 20vh auto; padding: 0 1.5rem; line-height: 1.7; color: #3a3630; background: #faf8f4; }
</style>
<meta name="robots" content="noindex, nofollow">
<title>Clarté — Espace couple</title>
<meta name="description" content="Questionnaires d'auto-évaluation de couple, en privé, sur votre appareil.">
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#faf8f4">
<link rel="stylesheet" href="style.css">
</head>
<body>
<p>Une page arrive ici. Bientôt.</p>
<div id="progress" hidden></div>
<main id="app" aria-live="polite"></main>
<script src="data.js"></script>
<script src="app.js"></script>
</body>
</html>
{
"name": "Clarté — Espace couple",
"short_name": "Clarté couple",
"lang": "fr",
"start_url": ".",
"display": "standalone",
"background_color": "#faf8f4",
"theme_color": "#faf8f4"
}
/* Clarté couple — paper-like, low cognitive load */
@font-face { font-family: 'Atkinson'; src: url('fonts/AtkinsonHyperlegible-Regular.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Atkinson'; src: url('fonts/AtkinsonHyperlegible-Bold.woff2') format('woff2'); font-weight: 700; font-display: swap; }
@font-face { font-family: 'Atkinson'; src: url('fonts/AtkinsonHyperlegible-Italic.woff2') format('woff2'); font-style: italic; font-display: swap; }
:root {
--paper: #faf8f4;
--ink: #3a3630;
--ink-faint: #837d76;
--teal: #3e7d78;
--teal-soft: #e3efee;
--line: #e5e0d8;
--measure: 46ch;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0; background: var(--paper); color: var(--ink);
font-family: 'Atkinson', Georgia, serif; font-size: 1.05rem; line-height: 1.65;
}
main { max-width: 40rem; margin: 0 auto; padding: 1.5rem 1.25rem 4rem; }
header.progress {
position: sticky; top: 0; z-index: 2; background: var(--paper);
padding: .6rem 1.25rem; border-bottom: 1px solid var(--line);
font-size: .9rem; color: var(--ink-faint);
max-width: 40rem; margin: 0 auto;
}
header.progress .fill {
height: 3px; background: var(--line); border-radius: 2px; margin-top: .35rem; overflow: hidden;
}
header.progress .fill i { display: block; height: 100%; background: var(--teal); transition: width .25s ease; }
h1 { font-size: 1.5rem; line-height: 1.3; margin: 1.2rem 0 .6rem; }
h2 { font-size: 1.2rem; margin: 1.6rem 0 .4rem; }
p { margin: .6rem 0; max-width: var(--measure); }
.muted { color: var(--ink-faint); font-size: .92rem; }
small.source { display: block; margin-top: .8rem; color: var(--ink-faint); font-size: .8rem; }
button { font: inherit; cursor: pointer; }
.cardlist { list-style: none; padding: 0; margin: 1.2rem 0; }
.cardlist li { margin: 0 0 .7rem; }
.cardbtn {
width: 100%; text-align: left; background: #fff; border: 1px solid var(--line);
border-radius: 10px; padding: .85rem 1rem; display: flex; justify-content: space-between; gap: 1rem; align-items: baseline;
transition: border-color .15s ease;
}
.cardbtn:hover { border-color: var(--teal); }
.cardbtn .meta { color: var(--ink-faint); font-size: .85rem; white-space: nowrap; }
.cardbtn .state { color: var(--teal); font-size: .85rem; white-space: nowrap; }
.item-text { font-size: 1.18rem; line-height: 1.55; margin: 1.4rem 0 1.2rem; max-width: var(--measure); }
.scale { display: flex; flex-direction: column; gap: .5rem; margin: 1.2rem 0; max-width: var(--measure); }
.scale button {
text-align: left; padding: .75rem .9rem; border-radius: 9px;
border: 1px solid var(--line); background: #fff; transition: all .12s ease;
}
.scale button:hover { border-color: var(--teal); }
.scale button[aria-pressed="true"] { background: var(--teal-soft); border-color: var(--teal); font-weight: 700; }
.scale button.optout { border-style: dashed; color: var(--ink-faint); font-size: .92rem; padding: .5rem .9rem; }
.who { margin: 1.6rem 0 0; display: flex; align-items: baseline; gap: .45rem; }
.who input {
font: inherit; color: var(--ink); background: transparent;
border: none; border-bottom: 1px solid var(--line);
width: 12ch; padding: .1rem .15rem;
}
.who input:focus { outline: none; border-bottom-color: var(--teal); }
.nav { display: flex; justify-content: space-between; gap: 1rem; margin-top: 1.6rem; }
.nav button, .cta {
border: 1px solid var(--line); background: #fff; border-radius: 9px; padding: .6rem 1.1rem;
}
.cta { background: var(--teal); border-color: var(--teal); color: #fff; font-weight: 700; }
.cta:disabled { opacity: .45; cursor: default; }
.result-band {
background: var(--teal-soft); border-radius: 12px; padding: 1.1rem 1.2rem; margin: 1.2rem 0;
}
.result-band .score { font-size: 2rem; font-weight: 700; color: var(--teal); }
blockquote.orig {
border-left: 3px solid var(--line); margin: 1rem 0 0; padding: .2rem 0 .2rem 1rem;
color: var(--ink-faint); font-size: .92rem; font-style: italic;
}
.recap { width: 100%; border-collapse: collapse; font-size: .92rem; margin-top: 1rem; }
.recap td, .recap th { border-bottom: 1px solid var(--line); padding: .45rem .5rem .45rem 0; text-align: left; vertical-align: top; }
.recap td:last-child { padding-right: 0; }
details { margin-top: 1.4rem; }
summary { cursor: pointer; color: var(--ink-faint); }
footer.pagefoot { margin-top: 3rem; font-size: .85rem; color: var(--ink-faint); }
a { color: var(--teal); }
/* Cache-first: la page et ses données chargent hors réseau; les réponses
vivent dans localStorage et ne passent jamais par le réseau. */
var CACHE = 'couple-v3';
var ASSETS = ['./', './index.html', './style.css', './app.js', './data.js',
'./manifest.webmanifest',
'./fonts/AtkinsonHyperlegible-Regular.woff2',
'./fonts/AtkinsonHyperlegible-Bold.woff2',
'./fonts/AtkinsonHyperlegible-Italic.woff2'];
self.addEventListener('install', function (e) {
e.waitUntil(caches.open(CACHE).then(function (c) { return c.addAll(ASSETS); }));
});
self.addEventListener('activate', function (e) {
e.waitUntil(caches.keys().then(function (keys) {
return Promise.all(keys.filter(function (k) { return k !== CACHE; })
.map(function (k) { return caches.delete(k); }));
}));
});
self.addEventListener('fetch', function (e) {
if (e.request.method !== 'GET') return;
e.respondWith(caches.match(e.request, { ignoreSearch: true })
.then(function (hit) { return hit || fetch(e.request); }));
});
......@@ -161,6 +161,49 @@ const state = {
};
// ============================================
// PERSISTENCE (localStorage shim)
// Survive reloads: answers and current section are saved locally,
// restored before first render. Silent no-op in private mode.
// ============================================
const STORAGE_KEY = 'clarte:v1';
function saveState() {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify({
responses: state.responses,
currentSection: state.currentSection
}));
} catch (e) { /* storage unavailable (private mode, quota): skip */ }
}
function clearSavedState() {
try {
localStorage.removeItem(STORAGE_KEY);
} catch (e) { /* storage unavailable: nothing to clear */ }
}
// Merge saved answers into state before first render, so question
// rendering (which reads state.responses) shows restored answers.
// Returns the saved section to resume at, or null.
function restoreState() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
const saved = JSON.parse(raw);
if (saved && typeof saved === 'object') {
if (saved.responses && typeof saved.responses === 'object') {
Object.assign(state.responses, saved.responses);
}
if (sections.includes(saved.currentSection)) {
return saved.currentSection;
}
}
} catch (e) { /* corrupt or unavailable storage: start fresh */ }
return null;
}
// ============================================
// NAVIGATION
// ============================================
......@@ -177,6 +220,7 @@ function showSection(sectionId) {
state.currentSection = sectionId;
updateProgress();
window.scrollTo(0, 0);
saveState();
}
}
......@@ -336,6 +380,7 @@ function attachOptionHandlers(container) {
container.querySelectorAll('input[type="radio"]').forEach(input => {
input.addEventListener('change', (e) => {
state.responses[e.target.name] = parseInt(e.target.value);
saveState();
const question = e.target.closest('.question');
if (question) question.classList.add('answered');
});
......@@ -789,6 +834,9 @@ function validateSection(section) {
// ============================================
function init() {
// Restore saved answers BEFORE first render so radios render checked
const savedSection = restoreState();
// Render all questionnaires
renderASRS();
renderDIVA();
......@@ -833,6 +881,7 @@ function init() {
document.getElementById('restart').addEventListener('click', () => {
state.responses = {};
state.results = null;
clearSavedState();
renderASRS();
renderDIVA();
renderExecutive();
......@@ -841,6 +890,14 @@ function init() {
// Initialize
showSection('home');
// Resume where the user left off (after showSection('home') above)
if (savedSection && savedSection !== 'home') {
if (savedSection === 'results') {
renderResults(); // recomputes purely from state.responses
}
showSection(savedSection);
}
}
// Start app when DOM is ready
......
......@@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Auto-évaluation scientifique du TDAH chez l'adulte. Outils validés: ASRS (OMS), critères DSM-5, fonctions exécutives.">
<meta name="theme-color" content="#5B8A8A">
<link rel="manifest" href="manifest.webmanifest">
<!-- Open Graph / Social -->
<meta property="og:type" content="website">
......@@ -247,5 +248,10 @@
</footer>
<script src="app.js"></script>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js').catch(function () {});
}
</script>
</body>
</html>
{
"name": "Clarté — Auto-Évaluation TDAH",
"short_name": "Clarté TDAH",
"lang": "fr",
"start_url": ".",
"display": "standalone",
"background_color": "#FAF8F5",
"theme_color": "#5B8A8A"
}
/* Cache-first: la page et ses données chargent hors réseau; les réponses
vivent dans localStorage et ne passent jamais par le réseau. */
var CACHE = 'clarte-v1';
var ASSETS = ['./', './index.html', './style.css', './app.js', './jspdf.min.js',
'./manifest.webmanifest',
'./fonts/AtkinsonHyperlegible-Regular.woff2',
'./fonts/AtkinsonHyperlegible-Bold.woff2',
'./fonts/AtkinsonHyperlegible-Italic.woff2'];
self.addEventListener('install', function (e) {
e.waitUntil(caches.open(CACHE).then(function (c) { return c.addAll(ASSETS); }));
});
self.addEventListener('activate', function (e) {
e.waitUntil(caches.keys().then(function (keys) {
return Promise.all(keys.filter(function (k) { return k !== CACHE; })
.map(function (k) { return caches.delete(k); }));
}));
});
self.addEventListener('fetch', function (e) {
if (e.request.method !== 'GET') return;
e.respondWith(caches.match(e.request, { ignoreSearch: true })
.then(function (hit) { return hit || fetch(e.request); }));
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment