action-text

Action Text

Action Text adds rich-text content to a model. Content is stored as sanitized HTML against an allowlist, edited through a Trix editor, rendered with safe-buffer output, and can embed Active Storage attachments.

Rich-text content

A MVC::Keayl::ActionText::Content wraps a fragment of rich-text HTML. Content.from-html sanitizes the input, keeping the rich-text allowlist of tags and attributes and dropping everything else (scripts, event handlers, unknown tags):

use MVC::Keayl::ActionText;

my $content = MVC::Keayl::ActionText::Content.from-html(
  '<h1>Title</h1><script>evil()</script>'
);

$content.to-trix-html;   # '<h1>Title</h1>' as a safe string, for editing
$content.to-html;        # rendered html (attachments expanded), a safe string
$content.to-plain-text;  # 'Title'
$content.is-empty;       # False

sanitize-rich-text($html) runs the same allowlist on its own.

Attaching rich text to a record

A model includes MVC::Keayl::ActionText::RichTextable and declares its rich-text fields with has-rich-text:

use MVC::Keayl::ActionText::RichTextable;

class Article does RichTextable {
  has $.id;
}
Article.has-rich-text('content');

Each declared name returns a proxy backed by a rich-text record:

$article.content.assign('<h1>Hello</h1>');   # sanitizes and stores
$article.content.is-present;                  # True
$article.content.to-html;                     # the rendered html
$article.content.to-plain-text;               # 'Hello'

Records persist through a repository. MVC::Keayl::ActionText::Repository defines the interface and MemoryRepository is the in-process implementation. Configure an ORM-backed repository at boot:

set-rich-text-repository(MemoryRepository.new);

Editing

rich-text-area on the form builder emits the Trix editor markup: a hidden input that carries the value plus a <trix-editor> bound to it.

use MVC::Keayl::Helpers::Form;

FormBuilder.new(object-name => 'post').rich-text-area('body');
<input type="hidden" id="post_body_trix_input" name="post[body]" value="...">
<trix-editor input="post_body_trix_input" class="trix-content"></trix-editor>

rich-text-area-tag(name, value?, %options) renders the same markup without a form builder.

Rendering

The rich-text helper renders content for a view with safe-buffer output. It accepts a Content, a rich-text proxy, or a raw HTML string (which it sanitizes):

rich-text($article.content);
rich-text('<p>hello</p>');

Embedded attachments

An Active Storage blob can be embedded in the document as an <action-text-attachment> element carrying a signed blob id. embed-tag($blob) builds one:

my $tag = embed-tag($blob);
# <action-text-attachment sgid="..." content-type="image/png" filename="photo.png"></action-text-attachment>

When the content renders, each attachment resolves its signed id to a blob and expands into a <figure>. An image becomes a preview pointing at the proxy serving path; any other file becomes a download link. An attachment whose signed id no longer resolves is dropped.

<figure class="attachment attachment--preview attachment--png">
  <img src="/keayl/blobs/proxy/..." alt="photo.png">
</figure>

content.attachment-sgids lists the signed ids embedded in a document.

MVC::Keayl v0.9.1

Model-View-Controller web framework

Authors

  • Greg Donald

License

Artistic-2.0

Dependencies

Cro::HTTPCrypt::RandomDigest::HMACDigest::SHA1::NativeOpenSSLMIME::Base64YAMLishORM::ActiveRecord:auth<zef:gdonald>Template::HAML:auth<zef:gdonald>

Provides

  • MVC::Keayl
  • MVC::Keayl::APIController
  • MVC::Keayl::ActionText
  • MVC::Keayl::ActionText::Repository
  • MVC::Keayl::ActionText::RichTextable
  • MVC::Keayl::Adapter
  • MVC::Keayl::Adapter::Cro
  • MVC::Keayl::Adapter::Test
  • MVC::Keayl::Application
  • MVC::Keayl::Assets
  • MVC::Keayl::Assets::Serving
  • MVC::Keayl::CLI
  • MVC::Keayl::CSRF
  • MVC::Keayl::Cable::Broadcasting
  • MVC::Keayl::Cable::Channel
  • MVC::Keayl::Cable::Connection
  • MVC::Keayl::Cable::PubSub
  • MVC::Keayl::Cable::PubSub::External
  • MVC::Keayl::Cable::PubSub::InMemory
  • MVC::Keayl::Cache
  • MVC::Keayl::Caching
  • MVC::Keayl::Config
  • MVC::Keayl::Controller
  • MVC::Keayl::Cookies
  • MVC::Keayl::Credentials
  • MVC::Keayl::Dispatcher
  • MVC::Keayl::Endpoint
  • MVC::Keayl::Engine
  • MVC::Keayl::ErrorReporter
  • MVC::Keayl::ErrorReporting
  • MVC::Keayl::Errors
  • MVC::Keayl::ExceptionPage
  • MVC::Keayl::Flash
  • MVC::Keayl::HealthController
  • MVC::Keayl::Helpers::Asset
  • MVC::Keayl::Helpers::DateTime
  • MVC::Keayl::Helpers::Form
  • MVC::Keayl::Helpers::Number
  • MVC::Keayl::Helpers::Options
  • MVC::Keayl::Helpers::Tag
  • MVC::Keayl::Helpers::Text
  • MVC::Keayl::Helpers::Url
  • MVC::Keayl::HttpAuthentication
  • MVC::Keayl::I18n
  • MVC::Keayl::I18n::Locale
  • MVC::Keayl::I18n::Pluralization
  • MVC::Keayl::Job
  • MVC::Keayl::Job::GlobalID
  • MVC::Keayl::Job::QueueAdapter
  • MVC::Keayl::Job::QueueAdapter::Async
  • MVC::Keayl::Job::QueueAdapter::Database
  • MVC::Keayl::Job::QueueAdapter::Inline
  • MVC::Keayl::Job::QueueAdapter::Test
  • MVC::Keayl::Live
  • MVC::Keayl::LogEvent
  • MVC::Keayl::Logger
  • MVC::Keayl::Mail
  • MVC::Keayl::Mailbox
  • MVC::Keayl::Mailbox::Ingress
  • MVC::Keayl::Mailbox::Router
  • MVC::Keayl::Mailer
  • MVC::Keayl::Mailer::Delivery
  • MVC::Keayl::Mailer::Delivery::File
  • MVC::Keayl::Mailer::Delivery::SMTP
  • MVC::Keayl::Mailer::Delivery::Test
  • MVC::Keayl::Mailer::DeliveryJob
  • MVC::Keayl::Mailer::Preview
  • MVC::Keayl::Middleware
  • MVC::Keayl::Middleware::Database
  • MVC::Keayl::Middleware::HostAuthorization
  • MVC::Keayl::Middleware::Logger
  • MVC::Keayl::Middleware::RequestId
  • MVC::Keayl::Middleware::SSL
  • MVC::Keayl::Middleware::SecureHeaders
  • MVC::Keayl::Middleware::Static
  • MVC::Keayl::MiddlewareStack
  • MVC::Keayl::Mime
  • MVC::Keayl::Notifications
  • MVC::Keayl::PWAController
  • MVC::Keayl::ParameterFilter
  • MVC::Keayl::Parameters
  • MVC::Keayl::Params
  • MVC::Keayl::Request
  • MVC::Keayl::Response
  • MVC::Keayl::Router
  • MVC::Keayl::Routing
  • MVC::Keayl::Routing::Mount
  • MVC::Keayl::Routing::PathPattern
  • MVC::Keayl::Routing::Redirect
  • MVC::Keayl::Routing::Resources
  • MVC::Keayl::Routing::Route
  • MVC::Keayl::Routing::RouteMatch
  • MVC::Keayl::Routing::UrlHelpers
  • MVC::Keayl::SafeString
  • MVC::Keayl::Secrets
  • MVC::Keayl::Session
  • MVC::Keayl::Storage
  • MVC::Keayl::Storage::Attached
  • MVC::Keayl::Storage::Repository
  • MVC::Keayl::Storage::Service
  • MVC::Keayl::Storage::Serving
  • MVC::Keayl::Storage::Variant
  • MVC::Keayl::TestSupport
  • MVC::Keayl::View
  • MVC::Keayl::View::Context
  • MVC::Keayl::View::Handler
  • MVC::Keayl::View::Handler::HAML

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.