About:Pharmacopedia.ext: Difference between revisions
From Pharmacopedia
More actions
| [checked revision] | [checked revision] |
MDElliottMD (talk | contribs) Bump to 0.9.4: add research_id (stable opaque per-user identifier for research) |
MDElliottMD (talk | contribs) 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. | '''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><input name="title"></code> or <code>name="action"></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="<getPageTitle()>"</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). | ||