Trix editor define custom attachment styles
Asked Answered
S

1

7

I added an image to the Trix editor, generating the following code:

<figure 
    data-trix-attachment="{lots of data}" 
    data-trix-content-type="image/jpeg"
    data-trix-attributes="{'presentation':'gallery'}" 
    class="attachment attachment--preview attachment--jpg">
    <img src="http://myhost/myimage.jpg" width="5731" height="3821">
    <figcaption class="attachment__caption">
        <span class="attachment__name">cool.jpg</span> <span class="attachment__size">4.1 MB</span>
    </figcaption>
</figure>

When I display the generated HTML from the editor on my Bootstrap-based page, the image obviously extends the screen (see the width and height) and I'd like to remove these props and also assign the img-fluid class to it.

So basically I thought to use the config:

Trix.config.css.attachment = 'img-fluid'

But that does a) not change the attachment class to img-fluid and it also would not apply the changes to the image but the figure.

I would like to avoid using jQuery each time I display the content and traverse all figures and then manipulate the image's properties at runtime.

Isn't there a solution to define these styles when adding the attachment?

Spurt answered 15/3, 2019 at 14:13 Comment(0)
W
10

Trix does not have any kind of support to change the image element inside the attachment. One way to do it is by using MutationObserver to check for mutations inside Trix editor that apply to attributes, childList and subtree.

If we have a width or height attributes mutation to an img target node with a figure parent node, then we remove those attributes and we can apply the class img-fluid to the first attribute mutation, for example width.

Run code snippet and try to add some image attachments to see or inspect the HTML

Please read inline comments

// Listen to trix-attachment-add event so we'll get rid of the progress bar just for this demo
// Here we should upload the attachment and handle progress properly
document.addEventListener("trix-attachment-add", event => {
  const { attachment } = event.attachment;
 
  // Get rid of the progress bar
  attachment.setUploadProgress(100)
});


// Get the Trix editor
const editor = document.querySelector('trix-editor');

// Instantiating an observer
const observer = new MutationObserver(function (mutations) {
  mutations.forEach(({ type, target, attributeName }) => {
    
    // If the parent is a figure with an img target
    if (target.parentNode.tagName === 'FIGURE' && 
        target.nodeName === 'IMG')
    {
      if (type === 'attributes') {
        switch(attributeName) {

          // If we have attribute width
          case 'width':
            // Remove attribute width
            target.removeAttribute('width');
            // Add img-fluid only once
            target.classList.add('img-fluid');
            break;

          // If we have attribute height
          case 'height':
            // Remove attribute height
            target.removeAttribute('height');
            break;
        }
      }

      // Render images HTML code
      renderHtmlOutput();
    }

  });
});

// Observing Trix Editor
observer.observe(editor, {
  attributes: true,
  childList: true,
  subtree: true
});

// Function to render every figure > img HTML code
function renderHtmlOutput() {
  const images = editor.querySelectorAll('figure > img');
  let output = '';

  for(const image of images) {
    output += image.outerHTML.replace(/ /g, "\n  ") + "\n";
  }

  document.getElementById('output-html').textContent = output;
}
body {
  height: 100vh;
  margin: 0;
  flex-direction: column;
  display: flex;
}
#main {
  display: flex;
  flex-direction: row;
  flex: 1;
  margin: 10px;
}

#editor-container {
  flex: 3;
}

#output-container {
  flex: 2;
  margin-left: 20px;
  border-left: 1px solid lightgray;
  overflow: auto;
}

#output-html {
  margin: 0;
  padding: 10px;
  font-size: small;
  color: blue;
}

/* Hide some Trix buttons to free horizontal space */
.trix-button--icon-increase-nesting-level,
.trix-button--icon-decrease-nesting-level,
.trix-button--icon-bullet-list,
.trix-button--icon-number-list { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/trix/1.2.1/trix.js" integrity="sha256-2D+ZJyeHHlEMmtuQTVtXt1gl0zRLKr51OCxyFfmFIBM=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/trix/1.2.1/trix.css" integrity="sha256-yebzx8LjuetQ3l4hhQ5eNaOxVLgqaY1y8JcrXuJrAOg=" crossorigin="anonymous"/>

<section id="main">
  <div id="editor-container">
    <form>
      <input id="editor" value="Editor content goes here" type="hidden" name="content">
      <trix-editor input="editor"></trix-editor>
    </form>
  </div>
  <div id="output-container">
    <pre id="output-html"></pre>
  </div>
</section>
Wittgenstein answered 21/3, 2020 at 23:10 Comment(4)
can you possibly explain this using react? @christoslytrasPhilia
@Philia there is nothing special using MutationObserver in React, you just do it by using refs made with useRef hook. If you want to make things easier, there is a hook you can use for MutationObserver itself and you can find details about installation and usage here @rooks/use-mutation-observer.Wittgenstein
why does your code adds img-fluid to only first added attachment? @christoslytrasPhilia
@Philia it doesn't add it on the first attachment, it adds it on one of the attributes of each attachment found, don't you see what purpose the switch/case is there for? It's for attributes, it writes switch(attributeName) so it's obviously for the image attributes; so, we only add the class img-fluid to the width attribute because we want to add it just once and don't waste CPU cycles on adding twice a class that already exists.Wittgenstein

© 2022 - 2024 — McMap. All rights reserved.