跳至主要内容

[Rails] Action Text Overview

keywords:action text

Action Text @ Edge RailsGuides

安裝

$ rails action_text:install

使用

Model

# app/models/message.rb
class Message < ApplicationRecord
has_rich_text :content
end

Controller

class MessagesController < ApplicationController
def create
message = Message.create! params.require(:message).permit(:title, :content)
redirect_to message
end
end

View

<%# app/views/messages/_form.html.erb %>
<%= form_with(model: message) do |form| %>
<div class="field">
<%= form.label :content %>
<%= form.rich_text_area :content %>
</div>
<% end %>
<%# app/views/messages/show.html.erb %>
<%= @message.content %>

客製化

新增一顆 h2 的按鈕

建立一支 trix_init.js

// ./app/javascript/packs/trix_init.js
const trixInit = (e) => {
const trix = e.target;

addSubHeadingButton(trix);

return;
};

function addSubHeadingButton(trix) {
const toolBar = trix.toolbarElement;

// Creation of the sub-heading button
const subHeadingButton = document.createElement('button');
subHeadingButton.innerText = 'h2';
setAttributes(subHeadingButton, {
type: 'button',
class: 'trix-button trix-button--icon trix-button--icon-heading-2',
title: 'subHeading',
tabindex: '-1',
'data-trix-attribute': 'subHeading',
});

// Attachment of the sub-heading button to the toolBar
const headingButton = toolBar.querySelector('[data-trix-attribute="heading1"]');
headingButton.insertAdjacentElement('afterend', subHeadingButton);

// When the sub-heading button is clicked
subHeadingButton.addEventListener('click', () => {
if (trix.editor.attributeIsActive('subHeading')) {
headingButton.setAttribute('disabled', '');
} else {
headingButton.removeAttribute('disabled');
}
});
}

function setAttributes(element, attributes) {
if (!element || !attributes) {
console.warn('Element or attributes is not existed in setAttributes function');
return;
}
Object.entries(attributes).forEach(([key, value]) => {
element.setAttribute(key, value);
});
}

module.exports = trixInit;

接著在 application.js 中去載入 trix_init.js 這支檔案:

// app/javascript/packs/application.js
require('@rails/actiontext');
const Trix = require('trix');
const trixInit = require('./trix_init.js');

// 告訴 Trix 當 attribute 是 subHeading 時,要產生 <h2> 的標籤
Trix.config.textAttributes.subHeading = {
inheritable: true,
tagName: 'h2',
};

// trix-initialize 時執行 trixInit
document.addEventListener('turbolinks:load', function () {
document.addEventListener('trix-initialize', trixInit, false);
});

樣式

trix-toolbar {
// REMOVE:
max-width: 730px;
margin: 0 auto;

.trix-button--icon-heading-1::before {
background-image: url('...');
}

.trix-button--icon-heading-2::before {
background-image: url('...');
}

.trix-button-group,
.trix-button,
.trix-button:not(:first-child) {
border: 0;
}

.trix-button::before {
background-size: 60%;
}
}

.trix-content {
color: #333333;

// REMOVE:
max-width: 730px;
margin: 0 auto;

> div {
font-size: 16px;
line-height: 24px;
letter-spacing: -0.003em;
margin-bottom: 16px;
}

h2 {
font-size: 18px;
margin-bottom: 1rem;
}

ul,
ol {
margin-bottom: 1rem;
padding-left: 40px;
}

a {
color: #007bff;
text-decoration: none;
}

blockquote {
margin-bottom: 2rem;
margin-top: 2rem;
font-style: italic;
color: #7f8c8d;
font-size: 22px;
line-height: 1.5;
}

.attachment {
margin-bottom: 1rem;
}

.attachment-gallery {
> action-text-attachment,
> .attachment {
flex: 1 0 33%;
padding: 0 0.5em;
max-width: 33%;
}

&.attachment-gallery--2,
&.attachment-gallery--4 {
> action-text-attachment,
> .attachment {
flex-basis: 50%;
max-width: 50%;
}
}
}

action-text-attachment {
.attachment {
padding: 0 !important;
max-width: 100% !important;
}
}
}

參考