feat(padToggle): native-style User + Pad Wide settings helper#8
Merged
JohnMcLear merged 4 commits intomainfrom May 7, 2026
Merged
feat(padToggle): native-style User + Pad Wide settings helper#8JohnMcLear merged 4 commits intomainfrom
JohnMcLear merged 4 commits intomainfrom
Conversation
Plugins built on toggle() get only a User Settings checkbox stored in a per-user cookie — they never appear in the Pad Wide Settings panel and can't ride enforceSettings. That's the wrong half of Etherpad's native model: every core toggle (sticky chat, line numbers, etc.) renders in both panels and broadcasts pad-wide changes to every connected client. padToggle emits parallel checkboxes in both panels with one config object, stashes the pad-wide value at pad.padOptions[pluginName] so it rides the existing padoptions COLLABROOM rail, and honors enforce by locking the user-side checkbox when the pad creator turns it on. Capability-detects the ep_* passthrough patch via PluginCapabilities; on older cores the pad-wide block silently no-ops and the user-side cookie toggle keeps working, so plugins built on padToggle are backward-compatible. i18n is mandatory (no hardcoded English labels) — the helper requires an l10nId and emits only data-l10n-id, leaving translations to the plugin's own locales/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Top-level requires of ep_etherpad-lite/node/* in pad-toggle.js were getting
crawled by esbuild when plugin authors imported the helper from client code,
even though the requires were inside try/catch and the chain only reached
leaf modules. The bundler resolves the package and pulls in everything
along the way. The existing convention (attributes.js client / attributes-
server.js server) handles this cleanly — adopt the same split:
- pad-toggle-server.js — server hooks (loadSettings, clientVars,
eejsBlock_mySettings, eejsBlock_padSettings) + capability detection via
PluginCapabilities.
- pad-toggle.js — client hooks (init, handleClientMessage_CLIENT_MESSAGE)
with no top-level node-only requires.
Plugin authors:
// server (index.js)
const {padToggle} = require('ep_plugin_helpers/pad-toggle-server');
// client (static/js/postAceInit.js)
const {padToggle} = require('ep_plugin_helpers/pad-toggle');
The top-level `padToggle` getter on ep_plugin_helpers' index.js still
returns the server factory for callers who already use the index entry.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The empty <label data-l10n-id="..."></label> meant screen readers had nothing to announce while html10n was still loading or if a translation failed to fetch. Native Etherpad's templates always render English text inside the label tag for exactly this reason; the helper was missing that safety net. Make defaultLabel a required config field. Helper now renders <label data-l10n-id="..." for="...">Default text</label> with both the defaultLabel and l10nId HTML-escaped to prevent injection. html10n still overwrites the text the moment it loads in the user's locale. Validate on both server and client factories so a misconfigured plugin fails loudly on import rather than silently shipping a nameless checkbox. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one. |
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
padTogglehelper that emits parallel checkboxes in both the User Settings and Pad Wide Settings panels, matching how native Etherpad toggles (sticky chat, line numbers, dark mode, …) work.padoptionsCOLLABROOM rail — broadcast to every connected client, persisted with the pad, honored byenforceSettings— so the helper carries no parallel transport.ep_etherpad-lite/node/utils/PluginCapabilities(added by the etherpad-lite passthrough patch). On older cores the pad-wide block silently no-ops and the user-side cookie toggle keeps working — plugins built on this helper are backward-compatible.loadSettings,clientVars,eejsBlock_mySettings,eejsBlock_padSettings. Client side:init({onChange}),handleClientMessage_CLIENT_MESSAGE. Split acrosspad-toggle-server.jsandpad-toggle.jsfollowing the existingattributes-server.js/attributes.jsconvention so the client bundle stays clean.i18n + a11y
l10nIdis required (i18n is mandatory) — emitsdata-l10n-idon every<label>.defaultLabelis required (a11y fallback) — rendered inside the<label>so screen readers announce something before html10n loads. html10n overwrites at runtime in the user's locale.Companion patches
applyPadSettings(separate PR — capability flag lives there).eejsBlock_mySettingstopadToggle(separate PR).Test plan
🤖 Generated with Claude Code