Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

About:Pharmacopedia.ext: Difference between revisions

From Pharmacopedia
[checked revision][checked revision]
Bump to 0.9.4: add research_id (stable opaque per-user identifier for research)
Doc update for v0.9.5: birthday->Born! sync, DatePicker range separators, ObservationParser range/age/custom-trait, MW reserved-param lesson
Line 1: Line 1:
= Pharmacopedia extension specification =
= Pharmacopedia extension specification =


'''Version:''' 0.9.4 · '''Requires:''' MediaWiki >= 1.46.0 · PHP >= 8.5
'''Version:''' 0.9.5 · '''Requires:''' MediaWiki >= 1.46.0 · PHP >= 8.5
'''Author:''' MDElliottMD · '''License:''' GPL-2.0-or-later
'''Author:''' MDElliottMD · '''License:''' GPL-2.0-or-later
'''Source:''' <code>/var/www/mediawiki/extensions/Pharmacopedia/</code>
'''Source:''' <code>/var/www/mediawiki/extensions/Pharmacopedia/</code>
Line 181: Line 181:
All categorical demographics use the chip-picker widget (single or multi, with optional primary marker, optional custom free-text). All quantitative demographics use numeric inputs or structured composite widgets.
All categorical demographics use the chip-picker widget (single or multi, with optional primary marker, optional custom free-text). All quantitative demographics use numeric inputs or structured composite widgets.


* '''Birthday''' DatePicker (single / range / possibility-mix)
* '''Birthday''' DatePicker (single / range / possibility-mix). Setting (or changing) the birthday auto-syncs a TYPE_STORY life event tagged <code>auto-birth</code> titled 'Born!' on the life-story timeline. Subsequent birthday edits move ONLY the event's date; user edits to title, body, tags, images are preserved.
* '''Sex assigned at birth''' single-select (clinical category)
* '''Sex assigned at birth''' single-select (clinical category)
* '''Gender identity''' multi-select chip-picker, 27 common terms + custom
* '''Gender identity''' multi-select chip-picker, 27 common terms + custom
Line 295: Line 295:
*# Global ICD diagnosis abbreviations (<code>pcp_diagnosis_abbreviations</code>)
*# Global ICD diagnosis abbreviations (<code>pcp_diagnosis_abbreviations</code>)
*# Free-text fallback (stored as type='free' for later upgrade)
*# Free-text fallback (stored as type='free' for later upgrade)
* '''Auto-promote unrecognized subjects to custom-trait keyframes''': when the subject doesn't match an existing entity but the input has BOTH a numeric value AND a date (e.g. <code>my neuroticism was 5 at 10yo</code>), the subject is treated as a NEW custom trait (<code>namespace='custom'</code>, key derived from subject text). Creates a TYPE_KEYFRAME event with the value + a trajectory point. Future inputs with the same subject auto-append to that series.
* '''Flexible range separators''': <code>X to Y</code>, <code>X through Y</code>, <code>X thru Y</code>, <code>X until Y</code>, <code>X till Y</code>, em-dash, en-dash, flexible-whitespace hyphens (digit-aware so <code>2026-05-31</code> ISO dates aren't split), <code>..</code> / <code>...</code> ellipsis.
* '''Age-range phrases without literal "ages"''': <code>when I was 11-13</code>, <code>from 11 to 13</code>, <code>between ages 5 and 12</code>, <code>aged 10 to 14</code>. Negative lookahead prevents false matches on dosages (<code>10-20 mg</code>), durations (<code>5-10 years ago</code>), measurements (<code>cm/mm/ft/lb/etc</code>).
* '''Episode-shape detection''': "manic episode" → type=mood, subtype=manic; "psychotic break", "panic attack", "anxiety attack", "trauma response" all route to <code>addEpisode</code> instead of <code>addObservation</code>. A date RANGE alone is enough to force <code>is_episode=true</code>.
* '''Episode-shape detection''': "manic episode" → type=mood, subtype=manic; "psychotic break", "panic attack", "anxiety attack", "trauma response" all route to <code>addEpisode</code> instead of <code>addObservation</code>. A date RANGE alone is enough to force <code>is_episode=true</code>.


Line 595: Line 598:


== Notable lessons learned ==
== Notable lessons learned ==
* '''Synthetic Event needs bubbles:true to trigger delegated listeners.''' <code>new Event('input')</code> defaults to <code>bubbles:false</code>, so listeners on parent wrappers never see programmatic dispatches. Native input/change events bubble by default; only JS-fired ones don't. Pass <code>{ bubbles: true }</code> explicitly. Bit DatePicker calendar-cell clicks 2026-05-18 — typing in the text field autosaved fine, but picking a date from the calendar didn't, because blocksave's wrapper listener never received the event.
* '''MediaWiki form-field names collide with reserved URL params.''' A form <code>&lt;input name="title"&gt;</code> or <code>name="action"&gt;</code> with user-controlled value silently HIJACKS MW's dispatch when POSTed (body param overrides URL param). Symptom: form submits but lands on a wiki article named whatever the user typed, with URL bar still showing the special page. Bit the episode form 2026-05-18 (user typed 'Fake one' as title → got a 404 'create article: Fake one' page). Fix: prefix ALL custom form inputs with <code>pcp_</code> (both the input <code>name="..."</code> AND the matching <code>$request->getVal('...', ...)</code> read). Self-referential hidden inputs (<code>name="title" value="&lt;getPageTitle()&gt;"</code>) are safe.


* '''Cargo string fields cap at ~300 chars.''' <code>structure</code> and <code>mechanism</code> on MedTemplate are short VARCHARs; long prose goes in MEDIUMBLOB sections. Overruns silently lose Cargo data (MySQL Error 1406).
* '''Cargo string fields cap at ~300 chars.''' <code>structure</code> and <code>mechanism</code> on MedTemplate are short VARCHARs; long prose goes in MEDIUMBLOB sections. Overruns silently lose Cargo data (MySQL Error 1406).