Hi, I have question for trix community. Is possible to add attach icon into toolbar?
I can add support for drag file to textarea (even image with caption), but I can't find how to add icon into toolbar for attach file.

JavaScript
var buttonHTML, fileInputHTML;
buttonHTML = "<button type=\"button\" class=\"attach\" data-action=\"x-attach\">Attach Files</button>";
fileInputHTML = "<input type=\"file\" multiple>";
$(Trix.config.toolbar.content).find(".button_group.block_tools").append(buttonHTML);
CoffeeScript
buttonHTML = """<button type="button" class="attach" data-action="x-attach">Attach Files</button>"""
fileInputHTML = """<input type="file" multiple>"""
$(Trix.config.toolbar.content).find(".button_group.block_tools").append(buttonHTML)
https://gist.github.com/javan/20e574f1cae443ba6c59#file-attachment_tool-coffee-L1
CSS
button.attach::before {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA%2FPjxzdmcgaGVpZ2h0PSIxNnB4IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyNCAxNiIgd2lkdGg9IjI0cHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6c2tldGNoPSJodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2gvbnMiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48dGl0bGUvPjxkZXNjLz48ZGVmcy8%2BPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSI%2BPGcgZmlsbD0iIzAwMDAwMCIgaWQ9IkNvcmUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xMjYuMDAwMDAwLCAtNDYuMDAwMDAwKSI%2BPGcgaWQ9ImJhY2t1cCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI2LjAwMDAwMCwgNDYuMDAwMDAwKSI%2BPHBhdGggZD0iTTE5LjQsNiBDMTguNywyLjYgMTUuNywwIDEyLDAgQzkuMSwwIDYuNiwxLjYgNS40LDQgQzIuMyw0LjQgMCw2LjkgMCwxMCBDMCwxMy4zIDIuNywxNiA2LDE2IEwxOSwxNiBDMjEuOCwxNiAyNCwxMy44IDI0LDExIEMyNCw4LjQgMjEuOSw2LjIgMTkuNCw2IEwxOS40LDYgWiBNMTQsOSBMMTQsMTMgTDEwLDEzIEwxMCw5IEw3LDkgTDEyLDQgTDE3LDkgTDE0LDkgTDE0LDkgWiIgaWQ9IlNoYXBlIi8%2BPC9nPjwvZz48L2c%2BPC9zdmc%2B);
}
https://github.com/tanin47/trix/pull/1/files#diff-5415e2a6f4eeb577a9ac3212c8cdc99dR115
buttonHTML should be:
buttonHTML = "<button type=\"button\" class=\"attach\" data-trix-action=\"x-attach\">Attach Files</button>";
Thanks @step1profit and @chrise86@ That's the best solution for now and is more-or-less what we do to add a file upload button in Basecamp.
Should this work out of the box with data-trix-action="x-attach" ?
What do you do with fileInputHTML ?
Just posted a functional gist i'm using to do exactly this in the app i'm working on : https://gist.github.com/pmhoudry/a0dc6905872a41a316135d42a5537ddb
Add css, an actual url to talk to and maybe csrf protection and you're good to go !
There's also a few warnings if the file is empty, or too big, or if the user tries to quit the page when an upload is pending.
What could cause upload to fail? Here is the message:"Upload failed. Try to reload the page
I got HTML and UI for attach file in toolbar of editor.
But I m not getting that how to be done it work functional.
means click attach file and Images uploaded to editor..
Thanks in Advace
Here's what will work in trix as of today:
buttonHTML = """<button type="button" class="icon attach" data-trix-action="x-attach" title="Attach Files">Attach Files</button>"""
$(Trix.config.toolbar.content).find(".button_group.block_tools").append(buttonHTML)
$(document).on "trix-action-invoke", (event) ->
if event.originalEvent.actionName is "x-attach"
editorElement = event.target
fileInput = $("""<input type="file" multiple>""")
fileInput.on "change", ->
for file in this.files
editorElement.editor.insertFile(file)
fileInput.click()
And here's the cloud upload icon encoded using the trix build process.
trix-toolbar {
button.attach::before {
background-image: url(data:image/svg+xml,%3Csvg%20height%3D%2224%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3Cpath%20d%3D%22M19.4%2010a7.5%207.5%200%200%200-14-2A6%206%200%200%200%206%2020h13a5%205%200%201%200%20.4-10zM14%2013v4h-4v-4H7l5-5%205%205h-3z%22%2F%3E%3C%2Fsvg%3E);
}
}
@javan, since this is such a simple enhancement, would you consider adding it to the project proper?
馃憤 To add this safely, even when we have multiple trix-editors in the same view.
@danielmcoelho, at a cursory glance, I think this would be safe for multiple editors given I think trix shares the toolbar config and the action-invoke works with the events target editor.
To follow this up Firefox does't allow the triggering of the file selection 'popup' via a non-click event. trie-action-invoke is triggered in this case by the mousedown event. I ended up doing this:
# Custom Attach Files button
buttonHTML = """<button type="button" class="icon attach" data-trix-action="x-attach" title="Attach Files">Attach Files</button>"""
fileInput = $("""<input type="file" multiple>""")
$(Trix.config.toolbar.content).find(".button_group.block_tools").append(buttonHTML)
$(document).on "click", 'button[data-trix-action=x-attach]', (event) ->
editorElement = document.querySelector("trix-editor")
fileInput.on "change", ->
for file in this.files
editorElement.editor.insertFile(file)
fileInput.click()
It's not as nice because I couldn't figure out a cleaner way of linking the button clicked to the editor it belongs to. @javan is there a way to do this from the toolbar element. I suppose I could find the closest toolbar element to the button, then query its siblings for the editor element?
coffee script
editorElement = $(this).closest('trix-toolbar').siblings('trix-editor')[0]
It's easier to use _trix-initialize_ event to attach the button to the toolbar and add an event listener on that button at the same time. You may look at my code posted earlier, I use a variant of it in production. You just have to adapt it to your needs and figure out the server side.
document.addEventListener('trix-initialize', function(e){
trix = e.target;
toolBar = trix.toolbarElement;
button = document.createElement("button");
button.setAttribute("type", "button");
button.setAttribute("class", "attach");
button.setAttribute("data-trix-action", "x-attach");
button.setAttribute("title", "Attach a file");
button.setAttribute("tabindex", "-1");
button.innerText = "Attach a file";
uploadButton = toolBar.querySelector('.button_group.block_tools').appendChild(button);
uploadButton.addEventListener('click', function() { ... }
}
Thanks @pmhoudry, that's a great help :) I'll look into modifying things in that way.
Here's the final working version using @pmhoudry's idea:
$(document).on 'trix-initialize', (event) ->
editorElement = event.target
toolbarElement = $(editorElement.toolbarElement);
attachButton = $("""<button type="button" class="icon attach" data-trix-action="x-attach" title="Attach Files">Attach Files</button>""")
toolbarElement.find('.button_group.block_tools').append(attachButton)
fileInput = $("""<input type="file" multiple>""").on 'change', ->
for file in this.files
editorElement.editor.insertFile(file)
attachButton.on 'click', (event) ->
fileInput.click()
We found that calling .click() on an <input type="file"> doesn't work on iOS unless it's attached to the DOM. Here's an approximation of what we do in Basecamp:
buttonAction = "x-attach"
buttonSelector = "button[data-trix-action='#{buttonAction}']"
buttonHTML = """<button type="button" class="attach" data-trix-action="#{buttonAction}">Attach Files</button>"""
$(Trix.config.toolbar.content).find(".button_group.block_tools").append(buttonHTML)
$(document).on "trix-initialize", ($event) ->
editorElement = $event.target
{toolbarElement} = editorElement
$(toolbarElement).find(buttonSelector).on "click", ->
editorElement.focus()
pickFiles (files) ->
for file in files
editorElement.editor.insertFile(file)
false
pickFiles = (callback) ->
$fileInput = $("""<input type="file" multiple>""")
$fileInput.hide().appendTo("body")
uninstall = ->
if $fileInput
$fileInput.remove()
$fileInput = null
$fileInput.on "change", (event) ->
callback(@files)
uninstall()
$fileInput.click()
requestAnimationFrame ->
$(document).one("click", uninstall)
Thanks @javan, I've not noticed that myself. Do you remember what version of iOS Safari it was happening on?
I don't recall. I fixed the problem in Basecamp on Jul 28, 2016 and was able to reproduce it then so probably whatever iOS version was current then.
Guys, I've been trying all solutions that you've posted but none work, the Trix.config.toolbar.contentobject doesn't exist so I can't even add the so called button and if it did the css classes used in the toolbar are different from .find(".button_group.block_tools")
Has anyone been able to add a "File attachment button" in the toolbar in this 2017 version of Trix?
Thanks
Ok, managed to work around the new changes for v0.11.1.
Here is a new gist based on everyone's contribution on the issue:
https://gist.github.com/goncalvesjoao/3c51fe09c04e29f613145d42858a0a9c
Hope this helps someone.
PS: This code is expecting your CRUD attachment controller to return a json response with an ID in it, so that we can later destroy it when we remove it from the Trix editor.
I figured I would quickly pitch in some of what we're doing now in v1.0.0 to make this work in our React app in case anyone is stuck trying to do this currently.
Despite the last comment being a year ago for v0.11.1, this thread was super helpful (stole a ton of inspiration from @goncalvesjoao gist)
We initialize everything in a function using the onEditorReady prop, which adds the button to the toolbar and adds the event listeners.
trixOnEditorReady = (trix) => {
this.trixEditor = trix
this.trixAddAttachmentButtonToToolbar()
document.addEventListener("trix-file-accept", this.trixFileAcceptEvent)
document.addEventListener("trix-attachment-add", this.trixAddAttachmentEvent)
document.addEventListener("trix-attachment-remove", this.trixRemoveAttachmentEvent)
}
trixAddAttachmentButtonToToolbar = () => {
let trixBlockButtons = document.querySelector(".trix-button-group--block-tools")
const buttonHTML = `
<button
type="button"
class="trix-button trix-button--icon trix-button--icon-attach-files"
data-trix-action="x-attach" title="Attach Files"
tabindex="-1"
>Attach Files</button>
`
trixBlockButtons.innerHTML += buttonHTML
document.querySelector(".trix-button--icon-attach-files")
.addEventListener("click", this.trixAddAttachment)
}
trixAddAttachment = () => {
const fileInput = document.createElement("input")
fileInput.setAttribute("type", "file")
fileInput.setAttribute("accept", ".jpg, .png, .gif")
fileInput.setAttribute("multiple", "")
fileInput.addEventListener("change", () => {
const { files } = fileInput
Array.from(files).forEach(this.insertAttachment)
})
fileInput.click()
}
insertAttachment = (file) => {
this.trixEditor.insertFile(file)
}
trixFileAcceptEvent = ({ file: { name }}) => {
const [extension] = name.split('.').slice(-1)
if (['png', 'jpg', 'gif'].indexOf(extension.toLowerCase()) === -1) {
e.preventDefault()
}
}
trixAddAttachmentEvent = (e) => {
this.uploadAttachment(e.attachment)
}
// the uploadAttachment function is a custom ajax request that sets the following
// .on('progress', ({ percent }) => {
// attachment.setUploadProgress(Math.floor(percent))
// })
// .end((error) => {
// if (!error) {
// attachment.setAttributes({
// url: fileURL
// })
// }
Button CSS:
.trix-button--icon-attach-files::before {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA%2FPjxzdmcgaGVpZ2h0PSIxNnB4IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyNCAxNiIgd2lkdGg9IjI0cHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6c2tldGNoPSJodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2gvbnMiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48dGl0bGUvPjxkZXNjLz48ZGVmcy8%2BPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSI%2BPGcgZmlsbD0iIzAwMDAwMCIgaWQ9IkNvcmUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xMjYuMDAwMDAwLCAtNDYuMDAwMDAwKSI%2BPGcgaWQ9ImJhY2t1cCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI2LjAwMDAwMCwgNDYuMDAwMDAwKSI%2BPHBhdGggZD0iTTE5LjQsNiBDMTguNywyLjYgMTUuNywwIDEyLDAgQzkuMSwwIDYuNiwxLjYgNS40LDQgQzIuMyw0LjQgMCw2LjkgMCwxMCBDMCwxMy4zIDIuNywxNiA2LDE2IEwxOSwxNiBDMjEuOCwxNiAyNCwxMy44IDI0LDExIEMyNCw4LjQgMjEuOSw2LjIgMTkuNCw2IEwxOS40LDYgWiBNMTQsOSBMMTQsMTMgTDEwLDEzIEwxMCw5IEw3LDkgTDEyLDQgTDE3LDkgTDE0LDkgTDE0LDkgWiIgaWQ9IlNoYXBlIi8%2BPC9nPjwvZz48L2c%2BPC9zdmc%2B);
}
Cheers!
Just find this solution for Rails, thanks to @lucaswjohnson
Please note that this solution is only tested on Rails 6.0.0.beta1. Use it at your own risk.
// In your custom js file, for example:
// /app/javascript/utils/trix.js
export const trixOnEditorReady = () => {
trixAddAttachmentButtonToToolbar();
};
const trixAddAttachmentButtonToToolbar = () => {
let trixBlockButtons = document.querySelector(".trix-button-group--block-tools");
const buttonHTML = `
<button
type="button"
class="trix-button trix-button--icon trix-button--icon-attach-files"
data-trix-action="x-attach" title="Attach Files"
tabindex="-1"
>Attach Files</button>
`;
trixBlockButtons.innerHTML += buttonHTML;
document.querySelector(".trix-button--icon-attach-files")
.addEventListener("click", trixAddAttachment)
};
const trixAddAttachment = () => {
const fileInput = document.createElement("input");
fileInput.setAttribute("type", "file");
fileInput.setAttribute("accept", ".jpg, .png, .gif");
fileInput.setAttribute("multiple", "");
fileInput.addEventListener("change", () => {
const {files} = fileInput;
Array.from(files).forEach(insertAttachment)
});
fileInput.click()
};
const insertAttachment = (file) => {
const trixEditor = document.querySelector("trix-editor").editor;
trixEditor.insertFile(file);
};
After that, we should invoke trixOnEditorReady on document ready. Please be careful when you use Torbolinks:
// For example, in app/javascript/packs/application.js
// import {trixOnEditorReady} from "../utils/trix";
export function onReady(fn) {
if (window.Turbolinks) {
$(document).on('turbolinks:load', function () {
fn();
});
} else {
$(document).ready(function () {
fn();
});
}
}
onReady(() => {
trixOnEditorReady();
}
It would be great that Trix has APIs to customise the toolbar easily or just add an image insertion button on demand because it is not easy to dray-and-drop on mobile devices.
Most helpful comment
JavaScript
CoffeeScript
https://gist.github.com/javan/20e574f1cae443ba6c59#file-attachment_tool-coffee-L1
CSS
https://github.com/tanin47/trix/pull/1/files#diff-5415e2a6f4eeb577a9ac3212c8cdc99dR115