feat(toolbarSelect): DRY up the toolbar <select>-change boilerplate#17
Merged
Conversation
Three Etherpad plugins (ep_font_color, ep_font_size, ep_headings2) all
implement the same toolbar-select boilerplate by hand:
hs.on('change', function () {
const value = $(this).val();
const intValue = parseInt(value, 10);
if (!isNaN(intValue)) {
context.ace.callWithAce((ace) => ace.ace_doX(intValue), 'op', true);
hs.val('dummy');
context.ace.focus();
}
});
This commit adds a shared `toolbarSelect({selector, context, invoke})`
helper that handles all four steps — value coercion, callWithAce wrap,
sentinel reset, and (most importantly for a11y) editor-focus restore so
the next keystroke doesn't get swallowed by the toolbar control.
Focus restoration runs unconditionally, even when the coerced value is
unusable, so an accidental pick on a non-numeric option still leaves
the user typing back in the pad rather than stuck on the select. This
preserves the WCAG-relevant property that the per-plugin .focus() calls
already provided — see ether/etherpad#7255 for the broader context.
Client-only module — imported via the sub-path
`ep_plugin_helpers/toolbar-select`, not via the package root, so
esbuild doesn't pull any server-only deps into the pad bundle (same
pattern as pad-toggle / pad-select).
12 new mocha tests cover config validation, int/number/string/identity
and custom-function coercers, custom resetValue, onAfterChange callback
invocation, and the focus-runs-on-failure guarantee.
Bumps minor version 0.5.3 → 0.6.0 because it's a new public API
surface; no behavior change for existing helpers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
This was referenced May 15, 2026
JohnMcLear
added a commit
to ether/ep_font_size
that referenced
this pull request
May 15, 2026
…elect (#142) Replaces the hand-rolled change handler with the shared `toolbarSelect` helper that newly ships in ep_plugin_helpers 0.6.0. Behavior is preserved: int coercion, callWithAce wrap with the same `insertsize` op label, `'dummy'` sentinel reset, and editor-focus restore after the edit so the next keystroke doesn't get swallowed by the toolbar control. The helper restores focus unconditionally (even when the picked value fails to coerce). For this plugin that means a slight behavioral improvement: previously, picking the dummy/blank entry left focus sitting on the <select>; now it always lands back in the pad. This matches the (already unconditional) behavior in ep_headings2 and is the WCAG-friendly default. Depends on ep_plugin_helpers >= 0.6.0 (ether/ep_plugin_helpers#17). Refs ether/etherpad#7255 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JohnMcLear
added a commit
to ether/ep_headings2
that referenced
this pull request
May 15, 2026
…elect (#184) Replaces the hand-rolled change handler with the shared `toolbarSelect` helper that newly ships in ep_plugin_helpers 0.6.0. Behavior is fully preserved including the unconditional focus restore from #130 (the helper guarantees focus runs regardless of whether the coerced value was usable, matching what the original code already did). Depends on ep_plugin_helpers >= 0.6.0 (ether/ep_plugin_helpers#17). Refs ether/etherpad#7255 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JohnMcLear
added a commit
to ether/ep_font_color
that referenced
this pull request
May 15, 2026
* feat: migrate toolbar <select> handler to ep_plugin_helpers/toolbar-select Replaces the hand-rolled change handler with the shared `toolbarSelect` helper that newly ships in ep_plugin_helpers 0.6.0. Behavior is preserved: int coercion, callWithAce wrap with the same `insertColor` op label, `'dummy'` sentinel reset, and editor-focus restore after the edit so the next keystroke doesn't get swallowed by the toolbar control. The helper restores focus unconditionally (even when the picked value fails to coerce). For this plugin that means a slight behavioral improvement: previously, picking the dummy/blank entry left focus sitting on the <select>; now it always lands back in the pad. This matches the (already unconditional) behavior in ep_headings2 and is the WCAG-friendly default. Depends on ep_plugin_helpers >= 0.6.0 (ether/ep_plugin_helpers#17). Refs ether/etherpad#7255 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(deps): bump ep_plugin_helpers range to ^0.6.1 (the published version) Etherpad's plugin installer (live-plugin-manager-backed) resolves the dependency's lower-bound version literally — `^0.6.0` makes it ask npm for `ep_plugin_helpers@0.6.0`, which was never published (the auto publish workflow bumped straight to `0.6.1`). Anchor to the actual published version so the install resolves. Same fix being applied to ep_font_size and ep_headings2. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Three core-adjacent plugins —
ep_font_color,ep_font_size,ep_headings2— all implement the same toolbar<select>change handler by hand:This PR adds a shared
toolbarSelect({selector, context, invoke})helper that handles the four steps — value coercion,callWithAcewrap, sentinel reset, and editor-focus restore — so each plugin can drop the boilerplate.Why focus restoration matters
The
context.ace.focus()call in each plugin is intentional and load-bearing: without it, picking from the toolbar leaves focus stuck on the<select>(or its nice-select wrapper), and the next keystroke goes there instead of the pad. The existingselect_focus_restore.spec.tstest in core covers this for ep_headings2.This helper restores focus unconditionally — even when the coerced value is unusable — so an accidental pick on a non-numeric option still leaves the user typing back in the pad. That preserves the WCAG-relevant property that the per-plugin
.focus()calls already provided (context: ether/etherpad#7255).API
selector<select>.contextpostAceInitcontext — must exposecontext.ace.callWithAceandcontext.ace.focus.invoke(ace, coercedValue) => void. Runs insidecallWithAceso the edit joins the undo stack.op'toolbarSelect'callWithAcelabel.coerce'int''int' | 'number' | 'string' | 'identity'or a custom(raw) => coerced | null. Returningnullskips the edit but still restores focus.resetValue'dummy'onAfterChange(coercedValue) => void, called after focus restoration. Errors swallowed and logged.Client-only — imported via the sub-path
ep_plugin_helpers/toolbar-select, not via the package root, so esbuild doesn't pull any server-only deps into the pad bundle (same pattern as pad-toggle / pad-select).Tests
12 new mocha tests cover:
nullresetValueonAfterChangeinvocation + error swallowingAll 103 tests pass (12 new + 91 existing).
Version bump
0.5.3 → 0.6.0— new public API surface, no behavior change for existing helpers.Follow-up PRs
Once this merges and ships to npm:
toolbarSelecttoolbarSelecttoolbarSelect🤖 Generated with Claude Code