Covers the ES5/no-flexbox browser constraints, the flow-data.js content shape (node/option/step, function-valued fields), the device-filter and auto-select mechanisms, the index.php server-side menu-nav fetch, and the git branch layout (old-version preserves the pre-rewrite docs site history) -- enough for someone else to pick this up cold.
7.9 KiB
webOS Archive Docs / Help Flow
An interactive, progressive-disclosure help site for setting up, activating, and using legacy Palm/HP webOS devices. It's the primary help entry point for webOS Archive, replacing an older flat mkdocs documentation site.
Live at https://docs.webosarchive.org. Repo: webOSArchive/webos-docs.
Git branches
main— this site (what you're looking at).old-version— the complete history of the previous mkdocs-based docs site, preserved unchanged. If content here seems thinner than before, or you need to recover exact old wording/links/images, check that branch — it's the source of truth for pre-rewrite content. Some things were deliberately cut or restructured (the old site was flat per-topic pages; this one is a step-by-step wizard), so a diff isn't automatically a bug.main's history also hasold-version's tip as a merge-commit ancestor (the cutover was done as a history-preserving merge, not a squash), so the old commits are reachable frommaintoo, not just via the branch.
Hard constraints — read before touching JS/CSS
This has to run correctly on real 2010-2011-era webOS browsers (TouchPad at 1024x768, Pre3 at 480x800) as well as modern desktop/phone browsers. That means:
- JS: plain ES5 only. No arrow functions,
let/const, template literals, classes, or newerArray/Objectmethods. - CSS: no flexbox, no grid, no custom properties, no
remunits. Layout is done with floats +overflow:hiddenclearfix tricks (see.site-header-text,.header-actionsinstyle.cssfor the pattern). - No build step, no bundler, no npm dependencies. Everything is loaded as
plain
<script>/<link>tags. - Prefer relative links for anything on this site. For links to
webosarchive.orgresources, always use plainhttp://, neverhttps://— legacy devices can't do modern TLS, and we never want to force a protocol upgrade on them. Third-party links keep whatever scheme they require. - When adding an icon/image that gets displayed small (buttons, favicons), pre-scale it close to its CSS display size rather than relying on the browser to downscale a large source image — old WebKit's scaler produces visible aliasing on a large ratio (e.g. a 320px source shown at 36px). A clean rule of thumb: ship at ~2x the CSS display size.
File layout
index.php— the only HTML entry point. Also does one server-side job: fetches the shared webOS Archive top nav (www.webosarchive.org/menu.php) over the same protocol the request arrived on and inlines it directly into the page. This is server-side specifically becausewww.webosarchive.orgsends no CORS headers, so a client-side fetch from a different origin would be blocked by the browser — inlining via PHP sidesteps that entirely. Requires a PHP-enabled host. Local dev:php -S 127.0.0.1:PORTfrom the repo root — NOTpython3 -m http.server, which can't execute.phpfiles (it'll just serve the raw source).flow-data.js— all step/question/answer content. No rendering logic.app.js— the rendering/state engine. No content. See "Content model" below for the shape it expects fromflow-data.js.style.css— site styling.css/wosa-menu.css— positions the injected top-nav bar (fixed, 45px tall) and reserves page space for it, only whenindex.php's server-side fetch actually succeeded (graceful degradation — a failed fetch leaves no empty gap).images/— content images, icons, favicons.DeviceIcons/— the four device-category icons used in Steps 3 and 6 (order must matchDEVICE_CATEGORY_ICONSinflow-data.js).
Content model (flow-data.js)
- A node is one question:
{ q, code, info, options }. - An option is one answer:
{ label, content, next }—contentis HTML shown once picked;nextis an optional nested node for a follow-up question. - A step is a top-level numbered row:
{ id, title, node }, collected in theFLOWarray in step order. q,info, andoptionscan each be either a plain value/array, or a function evaluated fresh on every render (e.g. reading the device filter). SeewosaResolveField/wosaResolveOptionsinapp.js. Use this when a question's wording or choices need to depend on state already collected elsewhere in the flow.- Steps 7 and 8 don't use the question/option wizard shape at all — they're
{ topics: [{label, content}, ...], after }, rendered bywosaRenderTopicsas a continuous flowing document (like the old docs pages), not a click-to-expand list.
Device filter
Steps 3 and 6 (FILTER_STEP_IDS) both ask the same top-level "which
device?" question (DEVICE_CATEGORY_LABELS/_SHORT/_ICONS, a shared
4-entry array: Older Phone, Later Phone, TouchPad 10", TouchPad Go).
Answering it anywhere seeds wosaState.deviceFilter and carries the answer
into whichever of the two hasn't been asked yet, so the user is never asked
twice.
FILTER_DEPENDENT_STEP_IDS (currently [4, 5]) lists steps whose own
options function reads that filter to narrow its choices (e.g. Step 4's
recovery-mode procedure differs by device). Any answer change within a
filter step (not just the top-level device pick — e.g. Step 3's nested
"upgrade to Community Edition" sub-answer) invalidates those steps' stored
answers via wosaInvalidateFilterDependents(), so a stale option index can
never silently point at the wrong choice once the filtered list reshuffles.
When a filter-dependent node's options function resolves to exactly one
real choice, wosaRenderNode auto-selects it — no point making someone tap
the only available answer. This never applies to a node that's naturally
single-option by design (a plain array, e.g. the "confirm deviceTool
finished" checkpoint), which still requires a deliberate tap since it's
confirming a real-world action, not narrowing a question.
wosaIsCEUpgrade() in flow-data.js is a further example of this pattern:
it derives (purely from Step 3's own path — TouchPad 10" filter plus its
"Upgrade to webOS 3.1.0 Community Edition" sub-answer) whether Steps 4 and
5 should skip their normal instructions in favor of a short "already
handled by the CE Doctor" message.
Rendering / state
- State lives in
localStorage(wosaHelpFlowState2):{ path, deviceFilter, collapsedSteps }.wosaReset()clears it back to defaults (step 1 expanded, everything else collapsed). - Every state change triggers a full re-render (
wosaRender()rebuilds the entire#appinnerHTML fromFLOW) — there's no incremental DOM patching. - Because of that, entrance animations are scoped via a transient,
non-persisted global,
wosaAnimateFrom = {stepId, level}, set right before a re-render so only the genuinely-new content (deeper than the level that was just answered) gets the reveal animation — otherwise already-visible content would replay its animation on every unrelated re-render. - Options stay visible after being answered (highlighted green, others dimmed) rather than collapsing away — changing an answer is just clicking a different visible option.
Testing pattern used during development
- Headless smoke tests: fake minimal
document/windowobjects in a Node one-liner,evalflow-data.jsthenapp.js, callwosaChoose/wosaGotodirectly, and inspect the generatedinnerHTMLstring for expected classes/content. Fast, no browser needed, good for verifying render-tree logic (auto-select, filter narrowing, CE-upgrade branches). - Live browser verification: needed for anything visual (layout,
animation, icon rendering) or to catch caching gotchas — the browser
caches
app.js/flow-data.jsseparately fromindex.php, so a cache-busting query string on the page alone won't bust the script cache; a real hard reload is needed after editing JS. - Always reset state (
wosaReset()) before ending a test session so the next visitor doesn't inherit leftover test state from localStorage.