diff --git a/README.md b/README.md index 0133f94a3..2645b79cd 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,75 @@ Place an empty `` tag on the page. Trix will automati Like an HTML ``, `` accepts `autofocus` and `placeholder` attributes. Unlike a ``, `` automatically expands vertically to fit its contents. +## Creating a Toolbar + +Trix automatically will create a toolbar for you and attach it right before the `` element. If you'd like to place the toolbar in a different place you can use the `toolbar` attribute: + +```html + + + + + +``` + +To change the toolbar without modifying Trix, you can overwrite the `Trix.config.toolbar.getDefaultHTML()` function. The default toolbar HTML is in `config/toolbar.js`. Trix uses data attributes to determine how to respond to a toolbar button click. + +**Toggle Attribute** + +With `data-trix-attribute=""`, you can add an attribute to the current selection. +For example, to apply bold styling to the selected text the button is: + +``` html + +``` + +Trix will determine that a range of text is selected and will apply the formatting defined in `Trix.config.textAttributes` (found in `config/text_attributes.js`). + +`data-trix-key="b"` tells Trix that this attribute should be applied when you use meta+b + +If the attribute is defined in `Trix.config.blockAttributes`, Trix will apply the attribute to the current block of text. + +``` html + +``` + +Clicking the quote button toggles whether the block should be rendered with ``. + +## Invoking Internal Trix Actions + +Internal actions are defined in `controllers/editor_controller.js` and consist of: + +* undo +* redo +* link +* increaseBlockLevel +* decreaseBlockLevel + +``` html + +``` + +## Invoking External Custom Actions + +If you want to add a button to the toolbar and have it invoke an external action, you can prefix your action name with `x-`. For example, if I want to print a log statement any time my new button is clicked, I would set by button's data attribute to be `data-trix-action="x-log"` + +``` html + +``` + +To respond to the action, listen for `trix-action-invoke`. The event's `target` property returns a reference to the `` element, its `invokingElement` property returns a reference to the `` element, and its `actionName` property returns the value of the `[data-trix-action]` attribute. Use the value of the `actionName` property to detect which external action was invoked. + +```javascript +document.addEventListener("trix-action-invoke", function(event) { + const { target, invokingElement, actionName } = event + + if (actionName === "x-log") { + console.log(`Custom ${actionName} invoked from ${invokingElement.id} button on ${target.id} trix-editor`) + } +}) +``` + ## Integrating With Forms To submit the contents of a `` with a form, first define a hidden input field in the form and assign it an `id`. Then reference that `id` in the editor’s `input` attribute. @@ -371,6 +440,8 @@ The `` element emits several events which you can use to observe an * `trix-attachment-remove` fires when an attachment is removed from the document. You can access the Trix attachment object through the `attachment` property on the event. You may wish to use this event to clean up remotely stored files. +* `trix-action-invoke` fires when a Trix action is invoked. You can access the `` element through the event's `target` property, the element responsible for invoking the action through the `invokingElement` property, and the action's name through the `actionName` property. The `trix-action-invoke` event will only fire for [custom](#invoking-external-custom-actions) actions and not for [built-in](#invoking-internal-trix-actions). + # Contributing to Trix Trix is open-source software, freely distributable under the terms of an [MIT-style license](LICENSE). The [source code is hosted on GitHub](https://github.com/basecamp/trix). diff --git a/src/test/system/custom_element_test.js b/src/test/system/custom_element_test.js index 2e77e3fc4..00b2f2250 100644 --- a/src/test/system/custom_element_test.js +++ b/src/test/system/custom_element_test.js @@ -133,6 +133,30 @@ testGroup("Custom element API", { template: "editor_empty" }, () => { assert.equal(eventCount, 5) }) + test("invoking internal actions does not dispatch a trix-action-invoke event", async () => { + let event = null + + addEventListener("trix-action-invoke", (ev) => event = ev, { once: true }) + await clickToolbarButton({ action: "link" }) + + assert.equal(null, event) + }) + + test("invoking external actions dispatches a trix-action-invoke event", async () => { + let event = null + const editor = getEditorElement() + editor.toolbarElement.insertAdjacentHTML("beforeend", ` + + `) + + addEventListener("trix-action-invoke", (ev) => event = ev, { once: true }) + await clickToolbarButton({ action: "x-test" }) + + assert.equal(editor, event.target) + assert.equal("x-test", event.actionName) + assert.equal(document.getElementById("test-action"), event.invokingElement) + }) + test("element triggers trix-change event after toggling attributes", async () => { const element = getEditorElement() const { editor } = element
`. + +## Invoking Internal Trix Actions + +Internal actions are defined in `controllers/editor_controller.js` and consist of: + +* undo +* redo +* link +* increaseBlockLevel +* decreaseBlockLevel + +``` html + +``` + +## Invoking External Custom Actions + +If you want to add a button to the toolbar and have it invoke an external action, you can prefix your action name with `x-`. For example, if I want to print a log statement any time my new button is clicked, I would set by button's data attribute to be `data-trix-action="x-log"` + +``` html + +``` + +To respond to the action, listen for `trix-action-invoke`. The event's `target` property returns a reference to the `` element, its `invokingElement` property returns a reference to the `` element, and its `actionName` property returns the value of the `[data-trix-action]` attribute. Use the value of the `actionName` property to detect which external action was invoked. + +```javascript +document.addEventListener("trix-action-invoke", function(event) { + const { target, invokingElement, actionName } = event + + if (actionName === "x-log") { + console.log(`Custom ${actionName} invoked from ${invokingElement.id} button on ${target.id} trix-editor`) + } +}) +``` + ## Integrating With Forms To submit the contents of a `` with a form, first define a hidden input field in the form and assign it an `id`. Then reference that `id` in the editor’s `input` attribute. @@ -371,6 +440,8 @@ The `` element emits several events which you can use to observe an * `trix-attachment-remove` fires when an attachment is removed from the document. You can access the Trix attachment object through the `attachment` property on the event. You may wish to use this event to clean up remotely stored files. +* `trix-action-invoke` fires when a Trix action is invoked. You can access the `` element through the event's `target` property, the element responsible for invoking the action through the `invokingElement` property, and the action's name through the `actionName` property. The `trix-action-invoke` event will only fire for [custom](#invoking-external-custom-actions) actions and not for [built-in](#invoking-internal-trix-actions). + # Contributing to Trix Trix is open-source software, freely distributable under the terms of an [MIT-style license](LICENSE). The [source code is hosted on GitHub](https://github.com/basecamp/trix). diff --git a/src/test/system/custom_element_test.js b/src/test/system/custom_element_test.js index 2e77e3fc4..00b2f2250 100644 --- a/src/test/system/custom_element_test.js +++ b/src/test/system/custom_element_test.js @@ -133,6 +133,30 @@ testGroup("Custom element API", { template: "editor_empty" }, () => { assert.equal(eventCount, 5) }) + test("invoking internal actions does not dispatch a trix-action-invoke event", async () => { + let event = null + + addEventListener("trix-action-invoke", (ev) => event = ev, { once: true }) + await clickToolbarButton({ action: "link" }) + + assert.equal(null, event) + }) + + test("invoking external actions dispatches a trix-action-invoke event", async () => { + let event = null + const editor = getEditorElement() + editor.toolbarElement.insertAdjacentHTML("beforeend", ` + + `) + + addEventListener("trix-action-invoke", (ev) => event = ev, { once: true }) + await clickToolbarButton({ action: "x-test" }) + + assert.equal(editor, event.target) + assert.equal("x-test", event.actionName) + assert.equal(document.getElementById("test-action"), event.invokingElement) + }) + test("element triggers trix-change event after toggling attributes", async () => { const element = getEditorElement() const { editor } = element