Feature #43259
openReplace jsToolBar with a server-rendered wiki toolbar handled by a Stimulus controller
Added by Takashi Kato about 1 year ago. Updated about 1 hour ago.
Description
This patch is based on a branch from #43165, with minor modifications.
- Converting the entire library to ES modules eliminates the risk of variable name collisions.
- Refactored
jstoolbarfrom the old prototype-based syntax to a more readable class syntax. - Switched DOM element creation from JavaScript to ERB, which makes preparing and cloning DOM elements easier by using the
<template>element. - Moved all
jstoolbarlocales toconfig/localesto simplify i18n. * Added the missingtasklistlocale for bothjaanden. - Integrated the
list-autofillcontroller intojstoolbaras both controllers are used in the same places.
Applying this patch along with #42521 enables the implementation of #40310.
This patch can be applied to r24014
Files
Related issues
Updated by Marius BĂLTEANU about 1 year ago
- Assignee set to Marius BĂLTEANU
- Target version set to 7.0.0
I'm assigning this 7.0.0 in order to review the changes.
Updated by Marius BĂLTEANU 8 months ago
- File 0001-wip.patch added
Takashi Kato, I started to work on rewriting the toolbar in order to render most of the elements on the backend and connect to Stimulus JS for the actions. Here is a prof of concept only for testing purposes, it still need some work.
Any feedback is welcome!
Updated by Marius BĂLTEANU 8 months ago
- File 0001-wip.patch 0001-wip.patch added
Updated by Marius BĂLTEANU 8 months ago
- Related to Patch #37559: Use meta element instead of javascript object added
Updated by Takashi Kato 8 months ago
I applied the patch. I think the new toolbar design is simpler and better than before.
- Toolbar generation is now separated into its own class
- This has the benefit of allowing shorter method names
- Memoization speeds up rendering on subsequent runs.
- Key binding configuration has been moved from JavaScript to the data-action attribute in Stimulus.
- Added configuration for a hotkey to toggle the preview.
Updated by Takashi Kato 8 months ago
I confirmed that subsequent renderings within the same request become faster with code like the following.
require 'test_helper'
require 'benchmark/ips'
class ViewPerformanceTest < ActionDispatch::IntegrationTest
def setup
@controller = ApplicationController.new
@controller.request = ActionDispatch::TestRequest.create
@view_context = @controller.view_context
end
def test_view_benchmarks
puts "\n--- Benchmarking Render Methods ---"
Benchmark.ips do |x|
x.report('Helper (Cold Start)') do
controller = ApplicationController.new
controller.request = ActionDispatch::TestRequest.create
view_context = controller.view_context
view_context.wikitoolbar(preview_url: "/users/1"){'<textarea></textarea>'}
end
# Execute it once beforehand to memoize it.
@view_context.wikitoolbar(preview_url: "/users/1"){'<textarea></textarea>'}
x.report("Helper (Memoized)") do
@view_context.wikitoolbar(preview_url: "/users/1"){'<textarea></textarea>'}
end
x.compare!
end
end
end
--- Benchmarking Render Methods --- ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux] Warming up -------------------------------------- Helper (Cold Start) 40.000 i/100ms Helper (Memoized) 439.000 i/100ms Calculating ------------------------------------- Helper (Cold Start) 401.374 (±12.7%) i/s (2.49 ms/i) - 2.000k in 5.073074s Helper (Memoized) 5.138k (±11.7%) i/s (194.61 μs/i) - 25.462k in 5.033269s Comparison: Helper (Memoized): 5138.4 i/s Helper (Cold Start): 401.4 i/s - 12.80x slower
Updated by Marius BĂLTEANU 4 months ago
- Target version changed from 7.0.0 to 7.1.0
Updated by Marius BĂLTEANU 2 days ago
- Tracker changed from Patch to Feature
- Subject changed from Convert jstoolbar to ES modules and class syntax. to Replace jsToolBar with a server-rendered wiki toolbar handled by a Stimulus controller
I've committed a combined patch built on the work of Takashi Kato and me. It's the first in a series of changes I'd like to commit before finishing the refactoring of the wiki toolbar.
Changes made in r25352:Redmine::WikiToolbarrenders the toolbar: the edit/preview tabs, the buttons and the menus (code highlighting languages, table generator). Each text formatter (Textile, CommonMark) describes its buttons in Ruby.- One Stimulus controller handles the buttons, the menus (keyboard navigation, Escape and outside click), the keyboard shortcuts (Ctrl/Cmd+B/I/U, Ctrl/Cmd+Shift+P to toggle preview) and the preview. The preview sends the attachments and the data-preview-param fields.
- The toolbar translations move from the
jstoolbar-*.jslanguage files toconfig/locales(label_wiki_toolbar_*). - Removed: jsToolBar (jstoolbar.js, textile.js, common_mark.js), the 49 language files and the jQuery preview handler.
wikitoolbar_for(field_id, preview_url)is unchanged, so views and plugins that call it keep working.- The markup and CSS classes (jstBlock, jstTabs, jstEditor, jstElements, jstb_*, wiki-preview) are unchanged, so themes keep working.
- define the markup inserted by the buttons in JavaScript, per text formatter;
- render the toolbar around its textarea with partials and a form builder method (wiki_textarea), deprecating wikitoolbar_for;
This change breaks plugins that use the jsToolBar JavaScript object directly (for example, to add buttons) and they need to be updated. Please expect a few days to finish this.
Updated by Marius BĂLTEANU 2 days ago
- File 0001-Define-the-wiki-toolbar-markup-in-JavaScript-for-eac.patch 0001-Define-the-wiki-toolbar-markup-in-JavaScript-for-eac.patch added
Next changes in the series:
- define the markup inserted by the buttons in JavaScript, per text formatter;
Attached the patch that moves the markup of toolbar buttons from Ruby action parameters to app/javascript/wiki_formatting/<format>.js. Redmine::WikiToolbar will only describes the layout of the buttons.
Please let me know what do you think about this approach.
Updated by Florian Walchshofer about 1 hour ago
- File 0001-wiki-toolbar-keep-textarea-focus.patch 0001-wiki-toolbar-keep-textarea-focus.patch added
- File 0002-wiki-toolbar-keep-menus-in-viewport.patch 0002-wiki-toolbar-keep-menus-in-viewport.patch added
- File 0003-wiki-toolbar-return-focus-after-escape.patch 0003-wiki-toolbar-return-focus-after-escape.patch added
- File 0004-wiki-toolbar-allow-plugins-to-add-buttons.patch 0004-wiki-toolbar-allow-plugins-to-add-buttons.patch added
I tested r25355 and 0001-Define-the-wiki-toolbar-markup-in-JavaScript-for-eac.patch in the browser and compared them with the version before r25352.
I think moving the markup to JavaScript is a good approach: the inserted text and the cursor position are identical for all buttons with Textile and CommonMark.
I found two regressions from r25352. The attached patches apply on top of 0001-Define-the-wiki-toolbar-markup-in-JavaScript-for-eac.patch, the changed lines are the same for the current trunk:
- 0001-wiki-toolbar-keep-textarea-focus.patch: when editing a note, the textarea loses the focus (#40556), because it is moved after
edit.js.erbhas focused it. - 0002-wiki-toolbar-keep-menus-in-viewport.patch: on narrow screens, the table and code menus are cut off on the right, as they are now inside the toolbar and no longer positioned with
.position().
Two additions:
- 0003-wiki-toolbar-return-focus-after-escape.patch: after closing a menu with Esc, the focus is lost. It now returns to the button.
- 0004-wiki-toolbar-allow-plugins-to-add-buttons.patch: with the markup patch, a plugin cannot add a button anymore, as
LABELS.fetchraises aKeyErrorfor an unknown name. This patch adds the methodslabelsandshortcuts, which plugins can extend, and awiki-toolbar:buttonevent for buttons that the text formatter does not know.
Plugins can use it without the importmap:
document.addEventListener('wiki-toolbar:button', ({ detail: { button, editor } }) => {
if (button === 'mark') editor.wrap('%{background:yellow}', '%')
})
With the patches applied, the unit, integration and system tests of the toolbar pass.