简体   繁体   中英

How to customize the Trix toolbar in Rails 7 when using importmaps?

I've recently upgraded an app to Rails 7 and I'm using importmap-rails for all of my javascript. Previously the app used Webpacker and I have all of the javascript working via importmaps except customizing the Trix toolbar to add an Underline button to the Trix Toolbar. To do this with Webpacker, I had used this JS file to customize the Trix toolbar:

trix_extensions.js :

var Trix  = require("trix")
Trix.config.textAttributes.underline = {
  tagName: 'u'
}
const {lang} = Trix.config;

Trix.config.toolbar = {
  getDefaultHTML() { return `
    <div class="trix-button-row">
     <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
       <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">#{lang.bold}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-underline" data-trix-attribute="underline" data-trix-key="u" title="underline" tabindex="-1">${lang.underline}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
     </span>
     <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
       <button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="${lang.heading1}" tabindex="-1">${lang.heading1}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1">${lang.quote}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1">${lang.bullets}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1">${lang.numbers}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1">${lang.outdent}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1">${lang.indent}</button>
     </span>
     <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
       <button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1">${lang.attachFiles}</button>
     </span>
     <span class="trix-button-group-spacer"></span>
     <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
       <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1">${lang.undo}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1">${lang.redo}</button>
     </span>
   </div>
   <div class="trix-dialogs" data-trix-dialogs>
     <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
       <div class="trix-dialog__link-fields">
         <input type="url" name="href" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input>
         <div class="trix-button-group">
           <input type="button" class="trix-button trix-button--dialog" value="${lang.link}" data-trix-method="setAttribute">
           <input type="button" class="trix-button trix-button--dialog" value="${lang.unlink}" data-trix-method="removeAttribute">
         </div>
       </div>
     </div>
   </div>
`; }
};

But I can't get this JS to work via importmaps. I tried switching the var Trix = require("trix") to import Trix from "trix"; as well as just dropping all of that directly into a tag in the HTML header just to see if I could get it working at all, but no luck.

How can I customize the Trix toolbar in Rails 7 with importmap-rails ? Do I also need to add import "@rails/actiontext" ?

FYI - I'm loading all other vanilla, non-stimulus JS in config/importmap.rb and then importing it in javascript/application.js with lines like this import "custom/trix_extensions.js" etc.

My trix_extensions.js appears to be loading correctly via my import map because I'm getting a ReferenceError: Can't find variable: require in the console. So it tells me the issue is with how I'm importing Trix into my trix_extensions.js file. Also, the default Trix toolbar is loading properly and works as expected. I'm just not seeing my customizations.

So the problem appears to be with how to extend Trix when importing it with importmaps.

Here's my full config/importmap.rb file:

pin "@rails/activestorage", to: "activestorage.esm.js"

pin "application", preload: true

pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "https://ga.jspm.io/npm:@hotwired/stimulus@3.0.1/dist/stimulus.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true

pin_all_from "app/javascript/controllers", under: "controllers"

pin "alpinejs", to: "https://unpkg.com/alpinejs@3.8.1/dist/module.esm.js", preload: true
pin "@rails/ujs", to: "https://ga.jspm.io/npm:@rails/ujs@6.1.5/lib/assets/compiled/rails-ujs.js"
pin "@rails/request.js", to: "https://ga.jspm.io/npm:@rails/request.js@0.0.6/src/index.js", preload: true

pin "trix", to: "https://ga.jspm.io/npm:trix@2.0.0-alpha.1/dist/trix.js"
pin "@rails/actiontext", to: "actiontext.js"

pin "sortablejs", to: "https://ga.jspm.io/npm:sortablejs@1.14.0/modular/sortable.esm.js"
pin "tailwindcss-stimulus-components", to: "https://ga.jspm.io/npm:tailwindcss-stimulus-components@3.0.4/dist/tailwindcss-stimulus-components.modern.js"

pin_all_from "app/javascript/custom", under: "custom"

And my javascript/application.js file:

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "@rails/activestorage"
import "controllers"
import "trix"
import "@rails/actiontext"

import "custom/direct_uploads"
import "custom/stripe_payments"
import "custom/table_sort"
import "custom/trix_extensions"

FYI - I got this working with the following in my javascript/custom/trix_extensions.js file:

// Modified from this: https://github.com/ParamagicDev/exploring-trix/blob/part01-changing-the-default-toolbar/main.js

import Trix from 'trix';

window.Trix = Trix; // Don't need to bind to the window, but useful for debugging.
Trix.config.toolbar.getDefaultHTML = toolbarDefaultHTML;

// trix-before-initialize runs too early.
// We only need to do this once. Everything after initialize will get the
// defaultHTML() call automatically.
document.addEventListener('trix-initialize', updateToolbars, { once: true });

function updateToolbars(event) {
  const toolbars = document.querySelectorAll('trix-toolbar');
  const html = Trix.config.toolbar.getDefaultHTML();
  toolbars.forEach((toolbar) => (toolbar.innerHTML = html));
}

Trix.config.textAttributes.underline = {
  tagName: 'u'
}
const {lang} = Trix.config;
/**
 * This is the default Trix toolbar. Feel free to change / manipulate it how you would like.
 * see https://github.com/basecamp/trix/blob/main/src/trix/config/toolbar.coffee
 */
function toolbarDefaultHTML() {
  const {lang} = Trix.config;
  return `
  <div class="trix-button-row">
     <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
       <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">#{lang.bold}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-underline" data-trix-attribute="underline" data-trix-key="u" title="underline" tabindex="-1">${lang.underline}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
     </span>
     <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
       <button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="${lang.heading1}" tabindex="-1">${lang.heading1}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1">${lang.quote}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1">${lang.bullets}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1">${lang.numbers}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1">${lang.outdent}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1">${lang.indent}</button>
     </span>
     <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
       <button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1">${lang.attachFiles}</button>
     </span>
     <span class="trix-button-group-spacer"></span>
     <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
       <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1">${lang.undo}</button>
       <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1">${lang.redo}</button>
     </span>
   </div>
   <div class="trix-dialogs" data-trix-dialogs>
     <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
       <div class="trix-dialog__link-fields">
         <input type="url" name="href" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input>
         <div class="trix-button-group">
           <input type="button" class="trix-button trix-button--dialog" value="${lang.link}" data-trix-method="setAttribute">
           <input type="button" class="trix-button trix-button--dialog" value="${lang.unlink}" data-trix-method="removeAttribute">
         </div>
       </div>
     </div>
   </div>
`;
}

I think the key line I was missing was document.addEventListener('trix-initialize', updateToolbars, { once: true });

Thanks to https://github.com/ParamagicDev/ for sharing this here:

https://github.com/ParamagicDev/exploring-trix/blob/part01-changing-the-default-toolbar/main.js

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM