Feature #43259 » 0004-wiki-toolbar-allow-plugins-to-add-buttons.patch
| app/javascript/controllers/wiki_toolbar_controller.js | ||
|---|---|---|
| 13 | 13 |
// textarea's position on connect, so that existing views only need to call |
| 14 | 14 |
// wikitoolbar_for. The markup inserted by each button is defined by the text |
| 15 | 15 |
// formatter in app/javascript/wiki_formatting/<format>.js, which is loaded on |
| 16 |
// connect. |
|
| 16 |
// connect. Buttons added by plugins are handled by listening to the |
|
| 17 |
// wiki-toolbar:button event. |
|
| 17 | 18 |
export default class extends Controller {
|
| 18 | 19 |
static targets = ['editor', 'preview', 'editTab', 'previewTab', 'toolbar', 'precodeMenu', 'tableMenu'] |
| 19 | 20 |
static values = {
|
| ... | ... | |
| 52 | 53 | |
| 53 | 54 |
async apply({ params: { button } }) {
|
| 54 | 55 |
await this.syntaxLoaded |
| 55 |
this.syntax?.[button]?.(this) |
|
| 56 |
const action = this.syntax?.[button] |
|
| 57 |
if (action) {
|
|
| 58 |
action(this) |
|
| 59 |
} else {
|
|
| 60 |
this.dispatch('button', { detail: { button, editor: this } })
|
|
| 61 |
} |
|
| 56 | 62 |
} |
| 57 | 63 | |
| 58 | 64 |
async insertPrecode({ params: { lang } }) {
|
| lib/redmine/wiki_toolbar.rb | ||
|---|---|---|
| 23 | 23 |
# The toolbar only describes the layout: which buttons are displayed and in |
| 24 | 24 |
# which groups. What each button inserts in the text is defined for each text |
| 25 | 25 |
# formatter in app/javascript/wiki_formatting/<format>.js. |
| 26 |
# |
|
| 27 |
# Plugins can add a button by extending #button_groups and #labels (and |
|
| 28 |
# #shortcuts) of a text formatter toolbar. The button is handled in JavaScript |
|
| 29 |
# by listening to the wiki-toolbar:button event, which gives the name of the |
|
| 30 |
# button and the editor: |
|
| 31 |
# |
|
| 32 |
# document.addEventListener('wiki-toolbar:button', ({ detail: { button, editor } }) => {
|
|
| 33 |
# if (button === 'mark') editor.wrap('%{background:yellow}', '%')
|
|
| 34 |
# }) |
|
| 26 | 35 |
class WikiToolbar |
| 27 | 36 |
LABELS = {
|
| 28 | 37 |
'strong' => :label_wiki_toolbar_strong, |
| ... | ... | |
| 85 | 94 |
raise NotImplementedError |
| 86 | 95 |
end |
| 87 | 96 | |
| 97 |
# Labels of the buttons |
|
| 98 |
def labels |
|
| 99 |
LABELS |
|
| 100 |
end |
|
| 101 | ||
| 102 |
# Keys used with Ctrl (Cmd on macOS) to run the buttons |
|
| 103 |
def shortcuts |
|
| 104 |
SHORTCUTS |
|
| 105 |
end |
|
| 106 | ||
| 88 | 107 |
def render(field_id, preview_url) |
| 89 | 108 |
tag.div(class: 'jstBlock', hidden: true, |
| 90 | 109 |
data: {
|
| ... | ... | |
| 140 | 159 |
end |
| 141 | 160 | |
| 142 | 161 |
def render_button(name) |
| 143 |
title = l(LABELS.fetch(name))
|
|
| 162 |
title = l(labels.fetch(name))
|
|
| 144 | 163 |
data = |
| 145 | 164 |
if MENUS.include?(name) |
| 146 | 165 |
{action: 'wiki-toolbar#toggleMenu', wiki_toolbar_menu_param: name}
|
| ... | ... | |
| 149 | 168 |
else |
| 150 | 169 |
{action: 'wiki-toolbar#apply', wiki_toolbar_button_param: name}
|
| 151 | 170 |
end |
| 152 |
data[:wiki_toolbar_shortcut] = SHORTCUTS[name] if SHORTCUTS[name]
|
|
| 171 |
data[:wiki_toolbar_shortcut] = shortcuts[name] if shortcuts[name]
|
|
| 153 | 172 | |
| 154 | 173 |
tag.button(tag.span(title), type: 'button', class: "jstb_#{name}", title: title, tabindex: 200, data: data)
|
| 155 | 174 |
end |
| test/system/wiki_toolbar_test.rb | ||
|---|---|---|
| 75 | 75 |
end |
| 76 | 76 |
end |
| 77 | 77 | |
| 78 |
def test_button_added_by_a_plugin_should_trigger_an_event |
|
| 79 |
log_user('jsmith', 'jsmith')
|
|
| 80 |
visit '/projects/ecookbook/issues/new' |
|
| 81 | ||
| 82 |
within 'div.jstBlock' do |
|
| 83 |
assert_selector 'button.jstb_strong' |
|
| 84 |
end |
|
| 85 |
page.execute_script(<<~JS) |
|
| 86 |
document.addEventListener('wiki-toolbar:button', ({ detail: { button, editor } }) => {
|
|
| 87 |
if (button === 'mark') editor.wrap('[', ']')
|
|
| 88 |
}) |
|
| 89 |
const button = document.querySelector('.jstb_strong').cloneNode(true)
|
|
| 90 |
button.className = 'jstb_mark' |
|
| 91 |
button.dataset.wikiToolbarButtonParam = 'mark' |
|
| 92 |
document.querySelector('.jstElements').append(button)
|
|
| 93 |
JS |
|
| 94 |
fill_in 'Description', :with => 'text' |
|
| 95 |
select_text('issue_description', 0, 4)
|
|
| 96 |
find('button.jstb_mark').click
|
|
| 97 | ||
| 98 |
assert_equal '[text]', find('#issue_description').value
|
|
| 99 |
end |
|
| 100 | ||
| 78 | 101 |
def test_insert_table_using_common_mark |
| 79 | 102 |
with_settings :text_formatting => 'common_mark' do |
| 80 | 103 |
log_user('jsmith', 'jsmith')
|
| test/unit/lib/redmine/wiki_toolbar_test.rb | ||
|---|---|---|
| 64 | 64 |
end |
| 65 | 65 |
end |
| 66 | 66 | |
| 67 |
def test_button_added_by_a_plugin |
|
| 68 |
toolbar_class = Class.new(Redmine::WikiFormatting::Textile::WikiToolbar) do |
|
| 69 |
def button_groups |
|
| 70 |
super + [%w[mark]] |
|
| 71 |
end |
|
| 72 | ||
| 73 |
def labels |
|
| 74 |
super.merge('mark' => :button_add)
|
|
| 75 |
end |
|
| 76 | ||
| 77 |
def shortcuts |
|
| 78 |
super.merge('mark' => 'm')
|
|
| 79 |
end |
|
| 80 |
end |
|
| 81 | ||
| 82 |
html = toolbar_class.new(self).render('issue_description', '/preview')
|
|
| 83 | ||
| 84 |
assert_select_in html, 'button.jstb_mark[title=Add][data-action=?][data-wiki-toolbar-button-param=mark][data-wiki-toolbar-shortcut=m]', |
|
| 85 |
'wiki-toolbar#apply' |
|
| 86 |
end |
|
| 87 | ||
| 67 | 88 |
def test_textile_buttons |
| 68 | 89 |
with_settings :text_formatting => 'textile' do |
| 69 | 90 |
html = wikitoolbar_for('issue_description')
|
- « Previous
- 1
- …
- 6
- 7
- 8
- Next »