diff --git a/AGENTS.md b/AGENTS.md index 1a17c25..b963d9b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -219,7 +219,9 @@ Using a context manager is always safe, even when not strictly required. - Built-in filters: `| to(n)` (decimal places), `| fmtnum(pre=, post=, places=, sep=, decsep=)` (rounds half up; `uproot.fmtnum(value, {pre, post, places, sep, decsep})` in JavaScript gives identical output) - All Python builtins available in templates (`sum()`, `max()`, `min()`, `len()`, `range()`, `enumerate()`, `zip()`) - `{% set buttons = False %}` to hide navigation buttons -- Base template disable switches: `disable_bootstrap`, `disable_uproot_fonts`, `disable_tabular_numbers`, `disable_terms`, `disable_auto_start`, `disable_connection_lost_modal` +- Base template disable switches: `disable_bootstrap`, `disable_alpinejs`, `disable_uproot_fonts`, `disable_tabular_numbers`, `disable_terms`, `disable_auto_start`, `disable_connection_lost_modal` +- `upd.TEMPLATE_DEFAULTS` — project-wide defaults for the template switches; change single values in `main.py`, since invalid or missing entries stop the server at startup +- `disable_auto_start` and `disable_bootstrap` are effectively internal: warn against them, and do not present them as normal options or document workarounds. `disable_auto_start` is for pages outside an experiment (`RoomFull.html`, `RoomHello.html`, `JustPOST.html`); on experiment pages, **Next** silently fails, and set project-wide, participants never reach the first page. `disable_bootstrap` leaves modal text visible on every page and breaks pop-ups and sliders unless Bootstrap 5 is loaded another way - Admin template disable switch: `disable_navigation` - `player.along("round")` — iterate all rounds as `(round_number, data)` tuples - `player.within(round=n)` — access data from a specific round diff --git a/docs/building/alpinejs.md b/docs/building/alpinejs.md index 1e7a54a..4bfcf98 100644 --- a/docs/building/alpinejs.md +++ b/docs/building/alpinejs.md @@ -1,5 +1,5 @@ --- -description: 'Add interactivity to templates with the built-in Alpine.js: essentials, global stores, constants in JavaScript, and combining Alpine with live methods.' +description: 'Add interactivity to templates with the built-in Alpine.js: essentials, global stores, constants in JavaScript, combining Alpine with live methods, and disabling it.' --- # Using Alpine.js @@ -100,6 +100,17 @@ function submit() { [:material-github: counter_alpine example](https://github.com/mrpg/uproot-examples/tree/main/counter_alpine) · [sumhunt example](https://github.com/mrpg/uproot-examples/tree/main/sumhunt) · [encryption_task example](https://github.com/mrpg/uproot-examples/tree/main/encryption_task) +## Disabling Alpine.js + +If your study does not use Alpine.js, you can stop loading it: + +```html+jinja +{% extends "Base.html" %} +{% set disable_alpinejs = True %} +``` + +uproot’s built-in participant pages work without it. To disable it on every page, see [Changing a switch for the whole project](pages.md#changing-a-switch-for-the-whole-project). + ## Quick reference | Directive | Purpose | Example | diff --git a/docs/building/pages.md b/docs/building/pages.md index 7ae0e9a..2aa9bb4 100644 --- a/docs/building/pages.md +++ b/docs/building/pages.md @@ -1,5 +1,5 @@ --- -description: Define pages as Python classes, write Jinja2 or Markdown templates, pass variables, show pages conditionally, and use NoshowPage and lifecycle methods. +description: Define pages as Python classes, write Jinja2 or Markdown templates, pass variables, show pages conditionally, use NoshowPage and lifecycle methods, and change template switches for a whole project. --- # Pages and templates @@ -119,14 +119,22 @@ The built-in templates also read a few optional Jinja variables. Set them near t |----------|---------|---------------------------| | `buttons` | `True` | Set to `False` to hide the default Back/Next buttons | | `disable_bootstrap` | `False` | Do not load uproot’s bundled Bootstrap CSS and JavaScript | +| `disable_alpinejs` | `False` | Do not load [Alpine.js](alpinejs.md); uproot’s built-in participant pages work without it | | `disable_uproot_fonts` | `False` | Do not load uproot’s bundled web fonts | -| `disable_tabular_numbers` | `False` | Do not load the tabular-number font stylesheet | -| `disable_terms` | `False` | Do not load the terms script | +| `disable_tabular_numbers` | `False` | Do not load the tabular-number stylesheet, which makes all digits the same width | +| `disable_terms` | `False` | Do not load the [translations](#translations) for JavaScript | | `disable_auto_start` | `False` | Do not run the default `uproot.init()` and WebSocket startup hook | | `disable_connection_lost_modal`{ .text-nowrap } | `False` | Do not show or enable the connection-lost modal | For admin templates that extend the built-in admin layout, `disable_navigation = True` hides the admin navigation bar. +To change a switch on every page at once, see [Changing a switch for the whole project](#changing-a-switch-for-the-whole-project). + +!!! warning "Two switches can break your study" + `disable_auto_start` is for pages outside an experiment, such as uproot’s own “No more spots available” page. Do not use it on experiment pages: **Next** stops working, without an error, and so do [live methods](live-methods.md) and [chat](../multiplayer/chat.md). + + `disable_bootstrap` also removes what uproot itself needs. The text of pop-up windows, such as “Connection lost,” appears on the page, pop-up windows do not open, and [slider fields](forms.md#scales-and-sliders) cause a JavaScript error. Use it only if you load [Bootstrap 5](https://getbootstrap.com/docs/5.3/) yourself. + ### Adding a form To collect data, include form fields in your template: @@ -375,7 +383,7 @@ A file per language is named after its language code, such as `locales/fr.yml`. : "Cliquez sur « Suivant » lorsque vous êtes prêt(e)." ``` -Your files can also translate uproot’s built-in strings, such as `Next` or `Please wait`. This lets you run studies in a language that uproot does not ship. The built-in strings are listed in [uproot’s `en.yml`](https://github.com/mrpg/uproot/blob/main/src/uproot/default/locales/en.yml). +Your files can also translate uproot’s built-in strings, such as `Next` or `Please wait`. This lets you run studies in a language that uproot does not ship. It also lets you replace uproot’s wording in any language, including English. The built-in strings are listed in [uproot’s `en.yml`](https://github.com/mrpg/uproot/blob/main/src/uproot/default/locales/en.yml). !!! warning "Keys must match exactly" uproot finds a translation only if the key matches the phrase in your template exactly, apart from whitespace. Straight quotes (`"Next"`) and typographical quotes (`“Next”`) are different keys. If no translation matches, uproot silently shows the phrase itself, usually in English. @@ -512,6 +520,50 @@ const maxTrades = uproot.vars.max_trades; ``` +## Changing a switch for the whole project + +A [switch](#base-template-switches) set in a template applies to that template only. Sometimes you want the same value everywhere, for example because your study uses its own fonts. Set it once in `main.py` with `upd.TEMPLATE_DEFAULTS`, a [dictionary](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) of default values: + +```python +upd.TEMPLATE_DEFAULTS["disable_uproot_fonts"] = True +upd.TEMPLATE_DEFAULTS["disable_alpinejs"] = True +``` + +These defaults apply to every participant page, including built-in pages such as wait pages. Admin pages ignore them, apart from `buddy_sender`. Choose project-wide values with care: with `buttons` set to `False`, for example, every page needs its own way forward. + +!!! warning "Take care with two switches" + Do not set `disable_auto_start` here. Participants would stay on a blank page and never reach your first page, with no error. If you set `disable_bootstrap` here, load Bootstrap 5 in [`ProjectHead.html`](#project-wide-static-files). + +A single page can still differ from the default. uproot uses the first value it finds, in this order: + +1. `{% set %}` in the template; +2. a variable of the same name returned by [`templatevars`](#the-templatevars-method); +3. `upd.TEMPLATE_DEFAULTS`. + +So this template loads Alpine.js even though the example above disables it for the project: + +```html+jinja +{% extends "Base.html" %} +{% set disable_alpinejs = False %} +``` + +`upd.TEMPLATE_DEFAULTS` also has three switches for the admin chat. They hold text rather than `True` or `False`. The default, `None`, keeps uproot’s built-in text or image. See [Changing how the experimenter appears](../running/admin.md#changing-how-the-experimenter-appears) for examples. + +| Variable | Default | Effect when set | +|----------|---------|-----------------| +| `buddy_label` | `None` | Replaces the text on the chat button and the title of the chat window | +| `buddy_sender` | `None` | Replaces the name on the experimenter’s chat messages | +| `buddy_image` | `None` | Replaces the image on the chat button; give the name of a file in `_static/` | + +!!! warning "Mistakes stop the server" + uproot checks `upd.TEMPLATE_DEFAULTS` when the server starts. It stops with the error `Invalid TEMPLATE_DEFAULTS` and lists the valid names if: + + - a name is wrong, for example `disable_uproot_font`; + - a value has the wrong type, for example `"yes"` or `1` instead of `True`; + - a switch is missing. + + So change single values, as shown above. Do not assign a new dictionary containing only some of the switches. A typo in a `{% set %}` line is not caught: the switch simply has no effect. + ## Complete example Here is a complete page with context, conditional display, and form handling: diff --git a/docs/getting-started/project-structure.md b/docs/getting-started/project-structure.md index 26da3da..b6616da 100644 --- a/docs/getting-started/project-structure.md +++ b/docs/getting-started/project-structure.md @@ -110,6 +110,14 @@ upd.DEFAULT_ROOMS.append( Rooms defined this way are created automatically when the server starts. +### Template defaults + +```python +upd.TEMPLATE_DEFAULTS["disable_uproot_fonts"] = True +``` + +`upd.TEMPLATE_DEFAULTS` changes the [template switches](../building/pages.md#changing-a-switch-for-the-whole-project) for every participant page in your project. It also controls [how the experimenter appears](../running/admin.md#changing-how-the-experimenter-appears) in the admin chat. + ## App module Each app is a Python package (a directory with `__init__.py`). The `__init__.py` defines the experiment logic. diff --git a/docs/running/admin.md b/docs/running/admin.md index 88c335f..4027ccd 100644 --- a/docs/running/admin.md +++ b/docs/running/admin.md @@ -199,11 +199,37 @@ Features: - **Participant-side widget:** A floating chat button appears on the participant’s screen when the admin sends a message. - **Real-time updates:** Messages appear instantly on both sides via WebSocket. -Participants see a small button in the bottom-right corner. Messages from the experimenter appear in a pop-up chat window. Whether the participant can reply is controlled by the toggle in the admin view. +Participants see a small button in the bottom-left corner. Messages from the experimenter appear in a pop-up chat window. Whether the participant can reply is controlled by the toggle in the admin view. !!! note Admin chat channels are created automatically the first time the admin sends a message to a participant. No setup is required in your app code. +### Changing how the experimenter appears + +By default, the chat button and the title of the chat window say “Chat with Research Coordinator.” Your messages appear under the name “Research Coordinator.” Your lab may use another name, such as “Lab assistants.” To change both, add these lines to `main.py`: + +```python +upd.TEMPLATE_DEFAULTS["buddy_label"] = "Chat with the lab assistants" +upd.TEMPLATE_DEFAULTS["buddy_sender"] = "Lab assistants" +``` + +`buddy_label` replaces the text on the chat button and the title of the chat window. `buddy_sender` replaces the name on your messages, both for participants and in the admin chat. Both are part of [`upd.TEMPLATE_DEFAULTS`](../building/pages.md#changing-a-switch-for-the-whole-project). + +!!! warning "Set both" + The two switches are independent. If you set only `buddy_sender`, the button still says “Chat with Research Coordinator.” + +Set `buddy_sender` in `main.py`, not with `{% set %}` in a template. The admin chat reads only the value from `main.py`, so participants would see a different name from the one you see. + +`buddy_label` and `buddy_sender` show the same text to all participants, whatever their language. If your study runs in several languages, leave both unset and [translate](../building/pages.md#translations) uproot’s phrases “Research Coordinator” and “Chat with Research Coordinator” instead. The name on messages is translated in the browser, so keep [`disable_terms`](../building/pages.md#base-template-switches) at `False`. + +To replace the image on the chat button, put a file in the [`_static/` folder at your project root](../building/pages.md#project-wide-static-files) and give its name: + +```python +upd.TEMPLATE_DEFAULTS["buddy_image"] = "lab-logo.png" +``` + +uproot shows the image at its original size, so use a small one. The built-in image is 80 × 80 pixels. uproot does not check that the file exists: if the name is wrong, participants see a broken image. + ## App testing uproot supports automated page interactions via a `simulate.js` file in each app. When a session is created with the **Simulate responses** option enabled, `simulate.js` runs on every player page load.