feat(freelancer-directory): 5-axis focus profile, 3 numeric languages, OCA from the link; drop odoo_versions

The user's spec (2026-11-03): "remove the ODOO versions. people are lying anyways";
"15 points to distribute between functional system modules integration ai"; "the
languages should be self assessed with 0 can not speak and 5 native. we have the
languages english german and spanish"; "lets limit the focus on the form to 70 chars";
"lets remove the member OCA question … use the OCA link to determine if someone is a
member … show the oca link on top of all links and make it apart with a color, also
dont show the link itself just a button or a chip"; "the only quality signal we can give
and verify is how many projects the freelancer brought to our platform"; "no sorting we
keep the no rank policy"; "get the sort on the page out."

REMOVED (both forms + the filter + the hints):
- `odoo_versions` — the webhook never carried it, so every value was silently dropped
  (re-verified: the payload has no `odoo_versions` field).
- `specialities` — replaced by the focus profile.
- the OCA-member question — membership is now DERIVED from `OCA_link`.

ADDED:
- Five focus sliders (functional, system, modules, integration, ai), each 0-5, from ONE
  constant (`FOCUS_AXES`), on both forms. Live running total ("12 of 15 points"); the
  submit is BLOCKED with an inline warning unless the five total exactly 15. The 15-point
  budget of a possible 25 is what stops anyone claiming maximum everywhere, and the form
  says so. No-JS: a `<noscript>` block swaps the sliders for five number inputs.
- Three language sliders (English, German, Spanish), each 0-5 (0 = cannot speak,
  5 = native), as SEPARATE numeric wire fields — no CSV, no 114-name ISO dataset, no
  free text. Preset to 0 (the user's decision, stated): an untouched slider records
  "cannot speak" rather than a blank.
- `Focus` capped at 70 characters on both forms with a live counter; the render path
  truncates a longer legacy value to 70 with a visible ellipsis.
- The card, in the user's order: photo+name · "N clients on ODOO4projects" (once, with
  weight) · Focus · the freelancer's own words · the focus-profile chart (one row per
  axis the payload carries, five squares) · the language line ("English 4 · German 5") ·
  the links, with the OCA profile chip FIRST and APART (a label, never the raw URL;
  "(as declared)") · the anonymous-contact button (JS-only — dark).
- The anonymous-contact modal: sends `{freelancers:[{id,name}], brief, email}` for the
  one card, opens only when `ODOO_EXPERTS_QUOTE_WEBHOOK` is set (still empty — ships
  dark), and says plainly that the email goes to us, never to the freelancer.
- OCA membership from `OCA_link`, matched on host + PATH PREFIX
  (`https://apps.odoo-community.org/community/`), never the bare domain.

ORDER: the client-side `Name` sort is gone from BOTH renderers — the endpoint's order is
rendered as received, so cards reshuffle between loads (the server randomises on purpose).
Nothing is ever ordered by the client count.

Also: the count is rendered ONCE (the payload has one field for it — "clients" and
"projects" are the same number here), `0` renders (a fact) while absent/null renders
nothing, and the legacy `languages`/`specialities` fields are left in the payload but no
longer read.

QC: verify-html.py 0 · check-inline-js OK · test-directory-render.py PASS · competitor QC
exit 3, 74 site-wide pre-existing, 0 in our files · impeccable detect --no-advisory
dir 14 (0 added) / admin 7 (0 added) · 375 px 0 overflow · no form submitted by hand.
This commit is contained in:
webmaster committed 2026-11-03 13:26:26 +00:00
1 parent 5ce14ea666
commit 99245764a9
2 files changed
+1129 -674

No files matched your search

+239 -250
View File
@@ -228,10 +228,75 @@
border-radius: var(--radius); border-radius: var(--radius);
} }
/* ---- Focus + language sliders (2026-11-03n) ---- */
.focus-field {
min-width: 0;
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 0.85rem 0.9rem 0.7rem;
}
.focus-field legend {
font-size: 0.8rem;
font-weight: 600;
color: var(--midnight);
padding: 0 0.35rem;
}
.focus-axis {
display: grid;
grid-template-columns: 6.5rem 1fr 2.2rem;
align-items: center;
gap: 0.6rem;
margin: 0.3rem 0;
}
.focus-axis label {
font-size: 0.85rem;
font-weight: 500;
color: var(--ink);
}
.focus-axis input[type="range"] {
width: 100%;
accent-color: var(--brass-deep);
}
.focus-axis output {
font-variant-numeric: tabular-nums;
font-size: 0.9rem;
text-align: right;
color: var(--ink);
}
.focus-total {
margin: 0.6rem 0 0;
font-size: 0.85rem;
font-weight: 600;
color: var(--midnight);
}
.focus-scale {
margin: 0.45rem 0 0;
font-size: 0.76rem;
line-height: 1.55;
color: var(--ink-soft);
}
.focus-warn {
margin: 0.55rem 0 0;
font-size: 0.85rem;
color: #b3452f;
min-height: 1.1em;
}
.focus-counter {
font-size: 0.78rem;
color: var(--ink-soft);
}
.focus-counter[data-over="1"] {
color: #b3452f;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.form-grid { .form-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.focus-axis {
grid-template-columns: 5.2rem 1fr 1.7rem;
gap: 0.4rem;
}
} }
</style> </style>
</head> </head>
@@ -280,8 +345,9 @@
<span class="hint">A number we record ourselves — not the freelancer's, not a rating.</span> <span class="hint">A number we record ourselves — not the freelancer's, not a rating.</span>
</div> </div>
<div class="form-field"> <div class="form-field">
<label for="adFocus">Focus</label> <label for="adFocus">Focus <span class="hint">(one line, at most 70 characters)</span></label>
<input id="adFocus" name="Focus" type="text" /> <input id="adFocus" name="Focus" type="text" maxlength="70" aria-describedby="adFocusCount" />
<span class="focus-counter" id="adFocusCount" aria-live="polite">0 / 70</span>
</div> </div>
<div class="form-field full"> <div class="form-field full">
<label for="adDescription">Description</label> <label for="adDescription">Description</label>
@@ -545,145 +611,64 @@
</select> </select>
<span class="hint">Stored as the ISO code (e.g. DE).</span> <span class="hint">Stored as the ISO code (e.g. DE).</span>
</div> </div>
<div class="form-field"> <fieldset class="form-field full focus-field">
<label for="adVersions">Odoo versions</label> <legend>Focus profile — five numbers, 0 to 5, totalling 15</legend>
<input id="adVersions" name="odoo_versions" type="text" /> <div class="focus-axis">
<span class="hint">Separate with commas.</span> <label for="ad-axis-functional">Functional</label>
</div> <input type="range" id="ad-axis-functional" name="functional" min="0" max="5" step="1" value="0" />
<fieldset class="form-field full lang-field"> <output for="ad-axis-functional">0</output>
<legend>Languages</legend>
<div class="lang-list" id="adLanguages">
<!-- LANGUAGE-OPTIONS-START -->
<span class="lang-pick"><input type="checkbox" id="ad-lang-afrikaans" name="languages" value="Afrikaans" /><label for="ad-lang-afrikaans">Afrikaans</label><select class="lang-level" name="language_level" data-language="Afrikaans" aria-label="Level in Afrikaans"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-amharic" name="languages" value="Amharic" /><label for="ad-lang-amharic">Amharic</label><select class="lang-level" name="language_level" data-language="Amharic" aria-label="Level in Amharic"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-arabic" name="languages" value="Arabic" /><label for="ad-lang-arabic">Arabic</label><select class="lang-level" name="language_level" data-language="Arabic" aria-label="Level in Arabic"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-aymara" name="languages" value="Aymara" /><label for="ad-lang-aymara">Aymara</label><select class="lang-level" name="language_level" data-language="Aymara" aria-label="Level in Aymara"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-azerbaijani" name="languages" value="Azerbaijani" /><label for="ad-lang-azerbaijani">Azerbaijani</label><select class="lang-level" name="language_level" data-language="Azerbaijani" aria-label="Level in Azerbaijani"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-belarusian" name="languages" value="Belarusian" /><label for="ad-lang-belarusian">Belarusian</label><select class="lang-level" name="language_level" data-language="Belarusian" aria-label="Level in Belarusian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-bulgarian" name="languages" value="Bulgarian" /><label for="ad-lang-bulgarian">Bulgarian</label><select class="lang-level" name="language_level" data-language="Bulgarian" aria-label="Level in Bulgarian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-bislama" name="languages" value="Bislama" /><label for="ad-lang-bislama">Bislama</label><select class="lang-level" name="language_level" data-language="Bislama" aria-label="Level in Bislama"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-bengali" name="languages" value="Bengali" /><label for="ad-lang-bengali">Bengali</label><select class="lang-level" name="language_level" data-language="Bengali" aria-label="Level in Bengali"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-bosnian" name="languages" value="Bosnian" /><label for="ad-lang-bosnian">Bosnian</label><select class="lang-level" name="language_level" data-language="Bosnian" aria-label="Level in Bosnian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-catalan" name="languages" value="Catalan" /><label for="ad-lang-catalan">Catalan</label><select class="lang-level" name="language_level" data-language="Catalan" aria-label="Level in Catalan"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-chamorro" name="languages" value="Chamorro" /><label for="ad-lang-chamorro">Chamorro</label><select class="lang-level" name="language_level" data-language="Chamorro" aria-label="Level in Chamorro"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-czech" name="languages" value="Czech" /><label for="ad-lang-czech">Czech</label><select class="lang-level" name="language_level" data-language="Czech" aria-label="Level in Czech"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-danish" name="languages" value="Danish" /><label for="ad-lang-danish">Danish</label><select class="lang-level" name="language_level" data-language="Danish" aria-label="Level in Danish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-german" name="languages" value="German" /><label for="ad-lang-german">German</label><select class="lang-level" name="language_level" data-language="German" aria-label="Level in German"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-divehi" name="languages" value="Divehi" /><label for="ad-lang-divehi">Divehi</label><select class="lang-level" name="language_level" data-language="Divehi" aria-label="Level in Divehi"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-dzongkha" name="languages" value="Dzongkha" /><label for="ad-lang-dzongkha">Dzongkha</label><select class="lang-level" name="language_level" data-language="Dzongkha" aria-label="Level in Dzongkha"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-greek" name="languages" value="Greek" /><label for="ad-lang-greek">Greek</label><select class="lang-level" name="language_level" data-language="Greek" aria-label="Level in Greek"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-english" name="languages" value="English" /><label for="ad-lang-english">English</label><select class="lang-level" name="language_level" data-language="English" aria-label="Level in English"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-spanish" name="languages" value="Spanish" /><label for="ad-lang-spanish">Spanish</label><select class="lang-level" name="language_level" data-language="Spanish" aria-label="Level in Spanish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-estonian" name="languages" value="Estonian" /><label for="ad-lang-estonian">Estonian</label><select class="lang-level" name="language_level" data-language="Estonian" aria-label="Level in Estonian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-basque" name="languages" value="Basque" /><label for="ad-lang-basque">Basque</label><select class="lang-level" name="language_level" data-language="Basque" aria-label="Level in Basque"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-persian" name="languages" value="Persian" /><label for="ad-lang-persian">Persian</label><select class="lang-level" name="language_level" data-language="Persian" aria-label="Level in Persian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-peul" name="languages" value="Peul" /><label for="ad-lang-peul">Peul</label><select class="lang-level" name="language_level" data-language="Peul" aria-label="Level in Peul"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-finnish" name="languages" value="Finnish" /><label for="ad-lang-finnish">Finnish</label><select class="lang-level" name="language_level" data-language="Finnish" aria-label="Level in Finnish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-fijian" name="languages" value="Fijian" /><label for="ad-lang-fijian">Fijian</label><select class="lang-level" name="language_level" data-language="Fijian" aria-label="Level in Fijian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-faroese" name="languages" value="Faroese" /><label for="ad-lang-faroese">Faroese</label><select class="lang-level" name="language_level" data-language="Faroese" aria-label="Level in Faroese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-french" name="languages" value="French" /><label for="ad-lang-french">French</label><select class="lang-level" name="language_level" data-language="French" aria-label="Level in French"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-irish" name="languages" value="Irish" /><label for="ad-lang-irish">Irish</label><select class="lang-level" name="language_level" data-language="Irish" aria-label="Level in Irish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-galician" name="languages" value="Galician" /><label for="ad-lang-galician">Galician</label><select class="lang-level" name="language_level" data-language="Galician" aria-label="Level in Galician"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-guarani" name="languages" value="Guarani" /><label for="ad-lang-guarani">Guarani</label><select class="lang-level" name="language_level" data-language="Guarani" aria-label="Level in Guarani"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-manx" name="languages" value="Manx" /><label for="ad-lang-manx">Manx</label><select class="lang-level" name="language_level" data-language="Manx" aria-label="Level in Manx"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-hebrew" name="languages" value="Hebrew" /><label for="ad-lang-hebrew">Hebrew</label><select class="lang-level" name="language_level" data-language="Hebrew" aria-label="Level in Hebrew"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-hindi" name="languages" value="Hindi" /><label for="ad-lang-hindi">Hindi</label><select class="lang-level" name="language_level" data-language="Hindi" aria-label="Level in Hindi"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-croatian" name="languages" value="Croatian" /><label for="ad-lang-croatian">Croatian</label><select class="lang-level" name="language_level" data-language="Croatian" aria-label="Level in Croatian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-haitian" name="languages" value="Haitian" /><label for="ad-lang-haitian">Haitian</label><select class="lang-level" name="language_level" data-language="Haitian" aria-label="Level in Haitian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-hungarian" name="languages" value="Hungarian" /><label for="ad-lang-hungarian">Hungarian</label><select class="lang-level" name="language_level" data-language="Hungarian" aria-label="Level in Hungarian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-armenian" name="languages" value="Armenian" /><label for="ad-lang-armenian">Armenian</label><select class="lang-level" name="language_level" data-language="Armenian" aria-label="Level in Armenian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-indonesian" name="languages" value="Indonesian" /><label for="ad-lang-indonesian">Indonesian</label><select class="lang-level" name="language_level" data-language="Indonesian" aria-label="Level in Indonesian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-icelandic" name="languages" value="Icelandic" /><label for="ad-lang-icelandic">Icelandic</label><select class="lang-level" name="language_level" data-language="Icelandic" aria-label="Level in Icelandic"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-italian" name="languages" value="Italian" /><label for="ad-lang-italian">Italian</label><select class="lang-level" name="language_level" data-language="Italian" aria-label="Level in Italian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-japanese" name="languages" value="Japanese" /><label for="ad-lang-japanese">Japanese</label><select class="lang-level" name="language_level" data-language="Japanese" aria-label="Level in Japanese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-georgian" name="languages" value="Georgian" /><label for="ad-lang-georgian">Georgian</label><select class="lang-level" name="language_level" data-language="Georgian" aria-label="Level in Georgian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-kongo" name="languages" value="Kongo" /><label for="ad-lang-kongo">Kongo</label><select class="lang-level" name="language_level" data-language="Kongo" aria-label="Level in Kongo"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-kazakh" name="languages" value="Kazakh" /><label for="ad-lang-kazakh">Kazakh</label><select class="lang-level" name="language_level" data-language="Kazakh" aria-label="Level in Kazakh"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-greenlandic" name="languages" value="Greenlandic" /><label for="ad-lang-greenlandic">Greenlandic</label><select class="lang-level" name="language_level" data-language="Greenlandic" aria-label="Level in Greenlandic"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-cambodian" name="languages" value="Cambodian" /><label for="ad-lang-cambodian">Cambodian</label><select class="lang-level" name="language_level" data-language="Cambodian" aria-label="Level in Cambodian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-korean" name="languages" value="Korean" /><label for="ad-lang-korean">Korean</label><select class="lang-level" name="language_level" data-language="Korean" aria-label="Level in Korean"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-kurdish" name="languages" value="Kurdish" /><label for="ad-lang-kurdish">Kurdish</label><select class="lang-level" name="language_level" data-language="Kurdish" aria-label="Level in Kurdish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-kyrgyz" name="languages" value="Kyrgyz" /><label for="ad-lang-kyrgyz">Kyrgyz</label><select class="lang-level" name="language_level" data-language="Kyrgyz" aria-label="Level in Kyrgyz"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-latin" name="languages" value="Latin" /><label for="ad-lang-latin">Latin</label><select class="lang-level" name="language_level" data-language="Latin" aria-label="Level in Latin"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-luxembourgish" name="languages" value="Luxembourgish" /><label for="ad-lang-luxembourgish">Luxembourgish</label><select class="lang-level" name="language_level" data-language="Luxembourgish" aria-label="Level in Luxembourgish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-lingala" name="languages" value="Lingala" /><label for="ad-lang-lingala">Lingala</label><select class="lang-level" name="language_level" data-language="Lingala" aria-label="Level in Lingala"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-laotian" name="languages" value="Laotian" /><label for="ad-lang-laotian">Laotian</label><select class="lang-level" name="language_level" data-language="Laotian" aria-label="Level in Laotian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-lithuanian" name="languages" value="Lithuanian" /><label for="ad-lang-lithuanian">Lithuanian</label><select class="lang-level" name="language_level" data-language="Lithuanian" aria-label="Level in Lithuanian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-luba-katanga" name="languages" value="Luba-Katanga" /><label for="ad-lang-luba-katanga">Luba-Katanga</label><select class="lang-level" name="language_level" data-language="Luba-Katanga" aria-label="Level in Luba-Katanga"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-latvian" name="languages" value="Latvian" /><label for="ad-lang-latvian">Latvian</label><select class="lang-level" name="language_level" data-language="Latvian" aria-label="Level in Latvian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-malagasy" name="languages" value="Malagasy" /><label for="ad-lang-malagasy">Malagasy</label><select class="lang-level" name="language_level" data-language="Malagasy" aria-label="Level in Malagasy"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-marshallese" name="languages" value="Marshallese" /><label for="ad-lang-marshallese">Marshallese</label><select class="lang-level" name="language_level" data-language="Marshallese" aria-label="Level in Marshallese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-maori" name="languages" value="Maori" /><label for="ad-lang-maori">Maori</label><select class="lang-level" name="language_level" data-language="Maori" aria-label="Level in Maori"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-macedonian" name="languages" value="Macedonian" /><label for="ad-lang-macedonian">Macedonian</label><select class="lang-level" name="language_level" data-language="Macedonian" aria-label="Level in Macedonian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-mongolian" name="languages" value="Mongolian" /><label for="ad-lang-mongolian">Mongolian</label><select class="lang-level" name="language_level" data-language="Mongolian" aria-label="Level in Mongolian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-malay" name="languages" value="Malay" /><label for="ad-lang-malay">Malay</label><select class="lang-level" name="language_level" data-language="Malay" aria-label="Level in Malay"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-maltese" name="languages" value="Maltese" /><label for="ad-lang-maltese">Maltese</label><select class="lang-level" name="language_level" data-language="Maltese" aria-label="Level in Maltese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-burmese" name="languages" value="Burmese" /><label for="ad-lang-burmese">Burmese</label><select class="lang-level" name="language_level" data-language="Burmese" aria-label="Level in Burmese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-nauruan" name="languages" value="Nauruan" /><label for="ad-lang-nauruan">Nauruan</label><select class="lang-level" name="language_level" data-language="Nauruan" aria-label="Level in Nauruan"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-norwegian-bokmål" name="languages" value="Norwegian Bokmål" /><label for="ad-lang-norwegian-bokmål">Norwegian Bokmål</label><select class="lang-level" name="language_level" data-language="Norwegian Bokmål" aria-label="Level in Norwegian Bokmål"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-north-ndebele" name="languages" value="North Ndebele" /><label for="ad-lang-north-ndebele">North Ndebele</label><select class="lang-level" name="language_level" data-language="North Ndebele" aria-label="Level in North Ndebele"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-nepali" name="languages" value="Nepali" /><label for="ad-lang-nepali">Nepali</label><select class="lang-level" name="language_level" data-language="Nepali" aria-label="Level in Nepali"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-dutch" name="languages" value="Dutch" /><label for="ad-lang-dutch">Dutch</label><select class="lang-level" name="language_level" data-language="Dutch" aria-label="Level in Dutch"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-norwegian-nynorsk" name="languages" value="Norwegian Nynorsk" /><label for="ad-lang-norwegian-nynorsk">Norwegian Nynorsk</label><select class="lang-level" name="language_level" data-language="Norwegian Nynorsk" aria-label="Level in Norwegian Nynorsk"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-norwegian" name="languages" value="Norwegian" /><label for="ad-lang-norwegian">Norwegian</label><select class="lang-level" name="language_level" data-language="Norwegian" aria-label="Level in Norwegian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-south-ndebele" name="languages" value="South Ndebele" /><label for="ad-lang-south-ndebele">South Ndebele</label><select class="lang-level" name="language_level" data-language="South Ndebele" aria-label="Level in South Ndebele"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-chichewa" name="languages" value="Chichewa" /><label for="ad-lang-chichewa">Chichewa</label><select class="lang-level" name="language_level" data-language="Chichewa" aria-label="Level in Chichewa"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-occitan" name="languages" value="Occitan" /><label for="ad-lang-occitan">Occitan</label><select class="lang-level" name="language_level" data-language="Occitan" aria-label="Level in Occitan"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-panjabi-/-punjabi" name="languages" value="Panjabi / Punjabi" /><label for="ad-lang-panjabi-/-punjabi">Panjabi / Punjabi</label><select class="lang-level" name="language_level" data-language="Panjabi / Punjabi" aria-label="Level in Panjabi / Punjabi"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-polish" name="languages" value="Polish" /><label for="ad-lang-polish">Polish</label><select class="lang-level" name="language_level" data-language="Polish" aria-label="Level in Polish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-pashto" name="languages" value="Pashto" /><label for="ad-lang-pashto">Pashto</label><select class="lang-level" name="language_level" data-language="Pashto" aria-label="Level in Pashto"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-portuguese" name="languages" value="Portuguese" /><label for="ad-lang-portuguese">Portuguese</label><select class="lang-level" name="language_level" data-language="Portuguese" aria-label="Level in Portuguese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-quechua" name="languages" value="Quechua" /><label for="ad-lang-quechua">Quechua</label><select class="lang-level" name="language_level" data-language="Quechua" aria-label="Level in Quechua"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-kirundi" name="languages" value="Kirundi" /><label for="ad-lang-kirundi">Kirundi</label><select class="lang-level" name="language_level" data-language="Kirundi" aria-label="Level in Kirundi"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-romanian" name="languages" value="Romanian" /><label for="ad-lang-romanian">Romanian</label><select class="lang-level" name="language_level" data-language="Romanian" aria-label="Level in Romanian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-russian" name="languages" value="Russian" /><label for="ad-lang-russian">Russian</label><select class="lang-level" name="language_level" data-language="Russian" aria-label="Level in Russian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-rwandi" name="languages" value="Rwandi" /><label for="ad-lang-rwandi">Rwandi</label><select class="lang-level" name="language_level" data-language="Rwandi" aria-label="Level in Rwandi"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-sango" name="languages" value="Sango" /><label for="ad-lang-sango">Sango</label><select class="lang-level" name="language_level" data-language="Sango" aria-label="Level in Sango"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-sinhalese" name="languages" value="Sinhalese" /><label for="ad-lang-sinhalese">Sinhalese</label><select class="lang-level" name="language_level" data-language="Sinhalese" aria-label="Level in Sinhalese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-slovak" name="languages" value="Slovak" /><label for="ad-lang-slovak">Slovak</label><select class="lang-level" name="language_level" data-language="Slovak" aria-label="Level in Slovak"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-slovenian" name="languages" value="Slovenian" /><label for="ad-lang-slovenian">Slovenian</label><select class="lang-level" name="language_level" data-language="Slovenian" aria-label="Level in Slovenian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-samoan" name="languages" value="Samoan" /><label for="ad-lang-samoan">Samoan</label><select class="lang-level" name="language_level" data-language="Samoan" aria-label="Level in Samoan"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-shona" name="languages" value="Shona" /><label for="ad-lang-shona">Shona</label><select class="lang-level" name="language_level" data-language="Shona" aria-label="Level in Shona"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-somalia" name="languages" value="Somalia" /><label for="ad-lang-somalia">Somalia</label><select class="lang-level" name="language_level" data-language="Somalia" aria-label="Level in Somalia"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-albanian" name="languages" value="Albanian" /><label for="ad-lang-albanian">Albanian</label><select class="lang-level" name="language_level" data-language="Albanian" aria-label="Level in Albanian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-serbian" name="languages" value="Serbian" /><label for="ad-lang-serbian">Serbian</label><select class="lang-level" name="language_level" data-language="Serbian" aria-label="Level in Serbian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-swati" name="languages" value="Swati" /><label for="ad-lang-swati">Swati</label><select class="lang-level" name="language_level" data-language="Swati" aria-label="Level in Swati"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-southern-sotho" name="languages" value="Southern Sotho" /><label for="ad-lang-southern-sotho">Southern Sotho</label><select class="lang-level" name="language_level" data-language="Southern Sotho" aria-label="Level in Southern Sotho"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-swedish" name="languages" value="Swedish" /><label for="ad-lang-swedish">Swedish</label><select class="lang-level" name="language_level" data-language="Swedish" aria-label="Level in Swedish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-swahili" name="languages" value="Swahili" /><label for="ad-lang-swahili">Swahili</label><select class="lang-level" name="language_level" data-language="Swahili" aria-label="Level in Swahili"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-tamil" name="languages" value="Tamil" /><label for="ad-lang-tamil">Tamil</label><select class="lang-level" name="language_level" data-language="Tamil" aria-label="Level in Tamil"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-tajik" name="languages" value="Tajik" /><label for="ad-lang-tajik">Tajik</label><select class="lang-level" name="language_level" data-language="Tajik" aria-label="Level in Tajik"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-thai" name="languages" value="Thai" /><label for="ad-lang-thai">Thai</label><select class="lang-level" name="language_level" data-language="Thai" aria-label="Level in Thai"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-tigrinya" name="languages" value="Tigrinya" /><label for="ad-lang-tigrinya">Tigrinya</label><select class="lang-level" name="language_level" data-language="Tigrinya" aria-label="Level in Tigrinya"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-turkmen" name="languages" value="Turkmen" /><label for="ad-lang-turkmen">Turkmen</label><select class="lang-level" name="language_level" data-language="Turkmen" aria-label="Level in Turkmen"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-tswana" name="languages" value="Tswana" /><label for="ad-lang-tswana">Tswana</label><select class="lang-level" name="language_level" data-language="Tswana" aria-label="Level in Tswana"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-tonga" name="languages" value="Tonga" /><label for="ad-lang-tonga">Tonga</label><select class="lang-level" name="language_level" data-language="Tonga" aria-label="Level in Tonga"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-turkish" name="languages" value="Turkish" /><label for="ad-lang-turkish">Turkish</label><select class="lang-level" name="language_level" data-language="Turkish" aria-label="Level in Turkish"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-tsonga" name="languages" value="Tsonga" /><label for="ad-lang-tsonga">Tsonga</label><select class="lang-level" name="language_level" data-language="Tsonga" aria-label="Level in Tsonga"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-ukrainian" name="languages" value="Ukrainian" /><label for="ad-lang-ukrainian">Ukrainian</label><select class="lang-level" name="language_level" data-language="Ukrainian" aria-label="Level in Ukrainian"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-urdu" name="languages" value="Urdu" /><label for="ad-lang-urdu">Urdu</label><select class="lang-level" name="language_level" data-language="Urdu" aria-label="Level in Urdu"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-uzbek" name="languages" value="Uzbek" /><label for="ad-lang-uzbek">Uzbek</label><select class="lang-level" name="language_level" data-language="Uzbek" aria-label="Level in Uzbek"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-venda" name="languages" value="Venda" /><label for="ad-lang-venda">Venda</label><select class="lang-level" name="language_level" data-language="Venda" aria-label="Level in Venda"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-vietnamese" name="languages" value="Vietnamese" /><label for="ad-lang-vietnamese">Vietnamese</label><select class="lang-level" name="language_level" data-language="Vietnamese" aria-label="Level in Vietnamese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-xhosa" name="languages" value="Xhosa" /><label for="ad-lang-xhosa">Xhosa</label><select class="lang-level" name="language_level" data-language="Xhosa" aria-label="Level in Xhosa"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-chinese" name="languages" value="Chinese" /><label for="ad-lang-chinese">Chinese</label><select class="lang-level" name="language_level" data-language="Chinese" aria-label="Level in Chinese"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<span class="lang-pick"><input type="checkbox" id="ad-lang-zulu" name="languages" value="Zulu" /><label for="ad-lang-zulu">Zulu</label><select class="lang-level" name="language_level" data-language="Zulu" aria-label="Level in Zulu"><option value="">—</option><option value="native">native</option><option value="fluent">fluent</option><option value="advanced">advanced</option><option value="intermediate">intermediate</option><option value="beginner">beginner</option></select></span>
<!-- LANGUAGE-OPTIONS-END -->
</div> </div>
<span class="hint">Each language is stored by its standard name, so the directory filter never gets a name like “Spanish - beginners”. A level is optional.</span> <div class="focus-axis">
<label for="ad-axis-system">System</label>
<input type="range" id="ad-axis-system" name="system" min="0" max="5" step="1" value="0" />
<output for="ad-axis-system">0</output>
</div>
<div class="focus-axis">
<label for="ad-axis-modules">Modules</label>
<input type="range" id="ad-axis-modules" name="modules" min="0" max="5" step="1" value="0" />
<output for="ad-axis-modules">0</output>
</div>
<div class="focus-axis">
<label for="ad-axis-integration">Integration</label>
<input type="range" id="ad-axis-integration" name="integration" min="0" max="5" step="1" value="0" />
<output for="ad-axis-integration">0</output>
</div>
<div class="focus-axis">
<label for="ad-axis-ai">AI</label>
<input type="range" id="ad-axis-ai" name="ai" min="0" max="5" step="1" value="0" />
<output for="ad-axis-ai">0</output>
</div>
<p class="focus-total" id="adFocusTotal" aria-live="polite">0 of 15 points</p>
<p class="focus-warn" id="adFocusWarn" role="alert"></p>
<p class="focus-scale">How much of the freelancer's work each area is — 0 to 5, totalling 15. Leave all five at 0 to leave the profile untouched (a save then keeps the record's current numbers); any other value must total exactly 15.</p>
</fieldset>
<fieldset class="form-field full lang-field">
<legend>Languages — 0 to 5, same scale as the public form</legend>
<div class="focus-axis">
<label for="ad-lang-english">English</label>
<input type="range" id="ad-lang-english" name="english" min="0" max="5" step="1" value="0" />
<output for="ad-lang-english">0</output>
</div>
<div class="focus-axis">
<label for="ad-lang-german">German</label>
<input type="range" id="ad-lang-german" name="german" min="0" max="5" step="1" value="0" />
<output for="ad-lang-german">0</output>
</div>
<div class="focus-axis">
<label for="ad-lang-spanish">Spanish</label>
<input type="range" id="ad-lang-spanish" name="spanish" min="0" max="5" step="1" value="0" />
<output for="ad-lang-spanish">0</output>
</div>
<p class="focus-scale">0 means “cannot speak it”; 5 means “native”. The applicant's own assessment.</p>
</fieldset> </fieldset>
<div class="form-field">
<label for="adSpecialities">Specialities</label>
<input id="adSpecialities" name="specialities" type="text" />
<span class="hint">Separate with commas.</span>
</div>
<div class="form-field"> <div class="form-field">
<label for="adGithub">GitHub URL</label> <label for="adGithub">GitHub URL</label>
<input id="adGithub" name="github" type="text" inputmode="url" /> <input id="adGithub" name="github" type="text" inputmode="url" />
</div> </div>
<div class="form-field"> <div class="form-field">
<label for="adOca">OCA profile URL</label> <label for="adOca">OCA profile URL</label>
<input id="adOca" name="oca_profile" type="text" inputmode="url" /> <input id="adOca" name="OCA_link" type="text" inputmode="url" />
<span class="hint">The OCA member profile link. A chip leads to it from the card when the host is apps.odoo-community.org and the path is /community/…</span>
</div> </div>
<div class="form-field"> <div class="form-field">
<label for="adLinkedin">LinkedIn URL</label> <label for="adLinkedin">LinkedIn URL</label>
@@ -702,10 +687,6 @@
<input id="adImage" name="Image" type="text" inputmode="url" /> <input id="adImage" name="Image" type="text" inputmode="url" />
<span class="hint">A link (https://…). A photo shows on the card only when this is a link — an inline/base64 image is not displayed.</span> <span class="hint">A link (https://…). A photo shows on the card only when this is a link — an inline/base64 image is not displayed.</span>
</div> </div>
<label class="form-check">
<input type="checkbox" name="OCA_member" value="1" />
<span>OCA member.</span>
</label>
<label class="form-check"> <label class="form-check">
<input type="checkbox" name="is_individual" value="1" /> <input type="checkbox" name="is_individual" value="1" />
<span>Works as an individual.</span> <span>Works as an individual.</span>
@@ -731,30 +712,33 @@
POST without an id → CREATE a new record POST without an id → CREATE a new record
Email confirmation applies to both paths. Email confirmation applies to both paths.
READ-MODIFY-WRITE (the reason this page loads the record first): a boolean the READ-MODIFY-WRITE (the reason this page loads the record first): a value the
owner did not touch must keep the record's CURRENT value. Loading the record owner did not touch must keep the record's CURRENT value. Loading the record
syncs the checkboxes to it, so an untouched box sends what the record already syncs every control to it, so an untouched control sends what the record already
holds instead of flipping it to false. An edit is refused until the record has holds. An edit is refused until the record has been loaded and confirmed.
been loaded and confirmed — a bare numeric id can no longer edit the wrong person.
The focus block: left all-zero it is simply NOT sent (an unrelated correction
must stay savable); any other value must total exactly 15.
============================================================================ */ ============================================================================ */
var ODOO_EXPERTS_WEBHOOK = var ODOO_EXPERTS_WEBHOOK =
"https://n8n.odoo4projects.com/webhook/ODOO4projects/odoo_experts"; "https://n8n.odoo4projects.com/webhook/ODOO4projects/odoo_experts";
var MULTI_FIELDS = ["odoo_versions"]; // comma-separated → array var FOCUS_AXES = ["functional", "system", "modules", "integration", "ai"];
// `languages` and `specialities` are COMMA-SEPARATED STRINGS on the wire var FOCUS_TOTAL = 15;
// ("English,German"), NOT arrays. `odoo_versions` stays an array. var FOCUS_MAX = 5;
var CSV_STRING_FIELDS = ["languages", "specialities"]; var FOCUS_MAX_CHARS = 70;
var BOOL_FIELDS = ["OCA_member", "is_individual"]; var LANG_FIELDS = [["english", "English"], ["german", "German"], ["spanish", "Spanish"]];
var NUM_FIELDS = ["odoo4projects_clients"];
// Country VALUE FORMAT — what the Country select sends to the webhook. // Country VALUE FORMAT — what the Country select sends to the webhook.
// "code" → the ISO 3166-1 alpha-2 code, e.g. "DE" (default; stable, exact-matchable) // "code" → the ISO 3166-1 alpha-2 code, e.g. "DE" (default)
// "name" → the full English name, e.g. "Germany" (switch to this line if the // "name" → the full English name, e.g. "Germany"
// workflow expects names instead of codes)
// The select always DISPLAYS the English name; this only changes the SUBMITTED value.
var COUNTRY_VALUE_FORMAT = "code"; var COUNTRY_VALUE_FORMAT = "code";
var BOOL_FIELDS = ["is_individual"];
var NUM_FIELDS = ["odoo4projects_clients"].concat(FOCUS_AXES).concat(
LANG_FIELDS.map(function (p) { return p[0]; })
);
var TEXT_FIELDS = [ var TEXT_FIELDS = [
"Name", "email", "Focus", "description", "Country", "Name", "email", "Focus", "description", "Country",
"Linkedin", "upwork", "fiverr", "github", "oca_profile", "Image" "Linkedin", "upwork", "fiverr", "github", "OCA_link", "Image"
]; ];
var loadedRecord = null; var loadedRecord = null;
@@ -765,7 +749,6 @@
); );
} }
/* Lower-case and strip accents ("Zürich" -> "zurich"). */
function fold(text) { function fold(text) {
return String(text == null ? "" : text) return String(text == null ? "" : text)
.normalize("NFD") .normalize("NFD")
@@ -773,22 +756,13 @@
.toLowerCase(); .toLowerCase();
} }
/* Comma-separated tokens from any shape of field: a text box split on commas, or the function intOr(value, fallback) {
`languages` checklist read as its checked values. One wire shape either way. */ var n = parseInt(value, 10);
function collectCsvTokens(els) { return isNaN(n) ? fallback : n;
var out = [];
els.forEach(function (el) {
if (el.type === "checkbox" || el.type === "radio") {
if (el.checked && el.value) out.push(el.value.trim());
} else {
(el.value || "").split(",").forEach(function (part) { out.push(part.trim()); });
}
});
return out.filter(Boolean);
} }
/* The Country value to submit: the ISO code by default, the English name when function clamp05(n) { return Math.max(0, Math.min(FOCUS_MAX, n)); }
COUNTRY_VALUE_FORMAT is "name". Empty until the owner picks a country. */
function countryValue(form) { function countryValue(form) {
var sel = form.querySelector('select[name="Country"]'); var sel = form.querySelector('select[name="Country"]');
if (!sel || !sel.value) return ""; if (!sel || !sel.value) return "";
@@ -806,17 +780,59 @@
else el.removeAttribute("data-state"); else el.removeAttribute("data-state");
} }
/* The webhook casing is inconsistent; read a field's value by its known names. */
function recordField(rec, name) { function recordField(rec, name) {
if (rec[name] !== undefined) return rec[name]; if (rec[name] !== undefined) return rec[name];
if (name === "Country" && rec.country !== undefined) return rec.country; if (name === "Country" && rec.country !== undefined) return rec.country;
return undefined; return undefined;
} }
function joinMulti(value) { function focusSum(form) {
if (value == null) return ""; return FOCUS_AXES.reduce(function (s, axis) {
if (Array.isArray(value)) return value.join(", "); var el = form.querySelector('[name="' + axis + '"]');
return String(value); return s + (el ? intOr(el.value, 0) : 0);
}, 0);
}
function focusError(form, required) {
var sum = focusSum(form);
if (sum === 0) {
return required ? "Distribute all 15 points across the five areas." : "";
}
if (sum !== FOCUS_TOTAL) {
return "The five focus numbers total " + sum + ". They must total exactly " +
FOCUS_TOTAL + " (or all be 0 to leave the profile untouched).";
}
return "";
}
function refreshFocus(form) {
var sum = 0;
FOCUS_AXES.forEach(function (axis) {
var el = form.querySelector('[name="' + axis + '"]');
if (!el) return;
var n = clamp05(intOr(el.value, 0));
el.value = String(n);
sum += n;
var out = el.parentNode ? el.parentNode.querySelector("output") : null;
if (out) out.textContent = String(n);
el.setAttribute("aria-valuetext", n + " of " + FOCUS_MAX);
});
var langs = form.querySelectorAll(".lang-field input[type=range]");
Array.prototype.forEach.call(langs, function (el) {
var n = clamp05(intOr(el.value, 0));
el.value = String(n);
var out = el.parentNode ? el.parentNode.querySelector("output") : null;
if (out) out.textContent = String(n);
el.setAttribute("aria-valuetext", n + " of " + FOCUS_MAX);
});
var total = document.getElementById("adFocusTotal");
if (total) total.textContent = sum + " of " + FOCUS_TOTAL + " points";
var warn = document.getElementById("adFocusWarn");
if (warn) {
warn.textContent = (sum === 0 || sum === FOCUS_TOTAL)
? ""
: "You have " + sum + " of 15. The five must total exactly 15, or all be 0 to leave the profile untouched.";
}
} }
/* Copy a loaded record into the form, so an untouched field carries the record's /* Copy a loaded record into the form, so an untouched field carries the record's
@@ -829,10 +845,6 @@
var v = recordField(rec, name); var v = recordField(rec, name);
el.value = v == null ? "" : String(v); el.value = v == null ? "" : String(v);
}); });
MULTI_FIELDS.forEach(function (name) {
var el = form.querySelector('[name="' + name + '"]');
if (el) el.value = joinMulti(recordField(rec, name));
});
var clients = form.querySelector('[name="odoo4projects_clients"]'); var clients = form.querySelector('[name="odoo4projects_clients"]');
if (clients) { if (clients) {
var n = rec.odoo4projects_clients; var n = rec.odoo4projects_clients;
@@ -845,27 +857,23 @@
box.checked = val; box.checked = val;
box.dataset.loaded = val ? "true" : "false"; box.dataset.loaded = val ? "true" : "false";
}); });
// Languages: the standardised checklist. A stored token ticks a box when it IS a // The five focus axes and the three languages — plain numbers, read off the
// standard name or begins with one ("Spanish - beginners" -> Spanish); its level, // record. A field the record does not carry stays 0 (and the block is left
// where `language_levels` records one, goes in the level select beside it. // unsent unless it totals 15).
var langs = String(recordField(rec, "languages") || "").split(",") FOCUS_AXES.forEach(function (axis) {
.map(function (s) { return s.trim(); }).filter(Boolean); var el = form.querySelector('[name="' + axis + '"]');
var levels = {}; if (el) el.value = String(clamp05(intOr(rec[axis], 0)));
String(recordField(rec, "language_levels") || "").split(",").forEach(function (pair) {
var bits = pair.split(":");
if (bits.length === 2) levels[fold(bits[0])] = bits[1].trim();
}); });
Array.prototype.forEach.call(form.querySelectorAll('input[name="languages"]'), function (box) { LANG_FIELDS.forEach(function (p) {
var fb = fold(box.value); var el = form.querySelector('[name="' + p[0] + '"]');
var on = langs.some(function (t) { if (el) el.value = String(clamp05(intOr(rec[p[0]], 0)));
var ft = fold(t);
return ft === fb || ft.indexOf(fb + " ") === 0 || ft.indexOf(fb + "-") === 0 || ft.indexOf(fb + "(") === 0;
});
box.checked = on;
var row = box.closest(".lang-pick");
var sel = row ? row.querySelector("select") : null;
if (sel) sel.value = on && levels[fb] ? levels[fb] : "";
}); });
refreshFocus(form);
var focusInput = document.getElementById("adFocus");
var focusCount = document.getElementById("adFocusCount");
if (focusInput && focusCount) {
focusCount.textContent = focusInput.value.length + " / " + FOCUS_MAX_CHARS;
}
} }
function loadRecord() { function loadRecord() {
@@ -879,9 +887,7 @@
} }
setStatus(info, "Loading record " + idRaw + "…", null); setStatus(info, "Loading record " + idRaw + "…", null);
fetch(ODOO_EXPERTS_WEBHOOK, { method: "GET" }) fetch(ODOO_EXPERTS_WEBHOOK, { method: "GET" })
.then(function (r) { .then(function (r) { return r.json(); })
return r.json();
})
.then(function (payload) { .then(function (payload) {
var list = Array.isArray(payload) ? payload : (payload && payload.data) || []; var list = Array.isArray(payload) ? payload : (payload && payload.data) || [];
var rec = null; var rec = null;
@@ -930,47 +936,9 @@
return; return;
} }
if (MULTI_FIELDS.indexOf(name) !== -1) {
var text = els[0].value || "";
var list = text
.split(",")
.map(function (s) {
return s.trim();
})
.filter(Boolean);
if (list.length) payload[name] = list; // an empty box must not wipe the field
return;
}
if (name === "language_level") {
// Proficiency is a SEPARATE AXIS: a level rides in `language_levels`
// ("Spanish:beginner"), never inside a language name.
var pairs = [];
Array.prototype.forEach.call(
form.querySelectorAll('input[name="languages"]:checked'),
function (box) {
var row = box.closest(".lang-pick");
var sel = row ? row.querySelector("select") : null;
if (sel && sel.value) pairs.push(box.value + ":" + sel.value);
}
);
if (pairs.length) payload.language_levels = pairs.join(",");
return;
}
if (CSV_STRING_FIELDS.indexOf(name) !== -1) {
// Normalise to the wire shape: trim each entry, drop blanks, re-join. A text
// box is split on commas; the `languages` checklist is read as its checked
// values. Nothing selected → the field is omitted, so a save cannot wipe it.
var norm = collectCsvTokens(els).join(",");
if (norm) payload[name] = norm;
return;
}
if (BOOL_FIELDS.indexOf(name) !== -1) { if (BOOL_FIELDS.indexOf(name) !== -1) {
var box = els[0]; var box = els[0];
if (withId && box.dataset.loaded !== undefined) { if (withId && box.dataset.loaded !== undefined) {
// READ-MODIFY-WRITE: an untouched box keeps the record's current value.
var original = box.dataset.loaded === "true"; var original = box.dataset.loaded === "true";
var now = !!box.checked; var now = !!box.checked;
payload[name] = now === original ? original : now; payload[name] = now === original ? original : now;
@@ -981,8 +949,11 @@
} }
if (NUM_FIELDS.indexOf(name) !== -1) { if (NUM_FIELDS.indexOf(name) !== -1) {
var n = els[0].value.trim(); // A focus block that is not a valid 15 is left unsent, so an update cannot
if (n !== "") payload[name] = Number(n); // wipe it (the gate already refused a half-set block).
if (FOCUS_AXES.indexOf(name) !== -1 && focusSum(form) !== FOCUS_TOTAL) return;
var nv = els[0].value.trim();
if (nv !== "") payload[name] = Number(nv);
return; return;
} }
@@ -1009,7 +980,6 @@
document.getElementById("adLoadBtn").addEventListener("click", loadRecord); document.getElementById("adLoadBtn").addEventListener("click", loadRecord);
// Changing the id after a load invalidates the confirmation.
form.querySelector('[name="id"]').addEventListener("input", function () { form.querySelector('[name="id"]').addEventListener("input", function () {
if (loadedRecord && String(loadedRecord.id) !== this.value.trim()) { if (loadedRecord && String(loadedRecord.id) !== this.value.trim()) {
loadedRecord = null; loadedRecord = null;
@@ -1017,6 +987,22 @@
} }
}); });
Array.prototype.forEach.call(form.querySelectorAll(".focus-field input, .lang-field input"),
function (el) { el.addEventListener("input", function () { refreshFocus(form); }); });
var focusInput = document.getElementById("adFocus");
var focusCount = document.getElementById("adFocusCount");
if (focusInput && focusCount) {
var refreshCount = function () {
var n = focusInput.value.length;
focusCount.textContent = n + " / " + FOCUS_MAX_CHARS;
focusCount.setAttribute("data-over", n > FOCUS_MAX_CHARS ? "1" : "0");
};
focusInput.addEventListener("input", refreshCount);
refreshCount();
}
refreshFocus(form);
form.addEventListener("submit", function (event) { form.addEventListener("submit", function (event) {
event.preventDefault(); event.preventDefault();
if (!form.reportValidity()) return; if (!form.reportValidity()) return;
@@ -1024,11 +1010,17 @@
var hasId = !!idRaw; var hasId = !!idRaw;
if (hasId && (!loadedRecord || String(loadedRecord.id) !== idRaw)) { if (hasId && (!loadedRecord || String(loadedRecord.id) !== idRaw)) {
setStatus( setStatus(status,
status,
"Load the record first (Load this record) and confirm it is the right person. Nothing was saved.", "Load the record first (Load this record) and confirm it is the right person. Nothing was saved.",
"err" "err");
); return;
}
var focusMsg = focusError(form, false);
if (focusMsg) {
setStatus(status, focusMsg, "err");
var warn = document.getElementById("adFocusWarn");
if (warn) warn.textContent = focusMsg;
return; return;
} }
@@ -1038,22 +1030,19 @@
postToWebhook(buildPayload(form, true)) postToWebhook(buildPayload(form, true))
.then(function () { .then(function () {
setStatus( setStatus(status,
status,
hasId hasId
? "Saved. Check your inbox to confirm the change before it is applied." ? "Saved. Check your inbox to confirm the change before it is applied."
: "New record sent. Check your inbox to confirm it before it goes live.", : "New record sent. Check your inbox to confirm it before it goes live.",
"ok" "ok");
);
}) })
.catch(function () { .catch(function () {
setStatus(status, "That did not save. Please try again.", "err"); setStatus(status, "That did not save. Please try again.", "err");
}) })
.then(function () { .then(function () { submit.disabled = false; });
submit.disabled = false;
});
}); });
})(); })();
</script> </script>
</body> </body>
</html> </html>
File diff suppressed because it is too large. Load diff