Replace House with lexical-powered actiontext

This commit is contained in:
Jorge Manrubia
2025-05-23 11:41:08 +02:00
parent 99797ca856
commit 10b2aad647
33 changed files with 737 additions and 382 deletions
-81
View File
@@ -1,81 +0,0 @@
require "rouge/plugins/redcarpet"
class MarkdownRenderer < Redcarpet::Render::HTML
include Rouge::Plugins::Redcarpet
def self.build
Redcarpet::Markdown.new MarkdownRenderer.new(filter_html: false),
autolink: true, highlight: true, no_intra_emphasis: true,
fenced_code_blocks: true, lax_spacing: true, strikethrough: true, tables: true
end
def initialize(...)
super
@id_counts = Hash.new 0
end
def header(text, header_level)
unique_id(text).then do |id|
<<~HTML.chomp
<h#{header_level} id="#{id}">
#{text} <a href="##{id}" class="heading__link" aria-hidden="true">#</a>
</h#{header_level}>
HTML
end
end
def image(url, title, alt_text)
<<~HTML.chomp
<a title="#{title}" href="#{url}" data-action="lightbox#open:prevent" data-lightbox-target="image" data-lightbox-url-value="#{url}?disposition=attachment">
<img src="#{url}" alt="#{alt_text}">
</a>
HTML
end
def code_block(code, language)
block_code(code, language) # call Rouge Redcarpet plugin
end
def link(url, title, content)
return video_tag(url, title) if video_url?(url)
attributes = { href: url }
attributes[:title] = title if title
attributes["data-turbo-frame"] = "_top"
"<a #{html_attributes(attributes)}>#{content}</a>"
end
def autolink(url, link_type)
attributes = { href: url }
attributes["data-turbo-frame"] = "_top"
"<a #{html_attributes(attributes)}>#{url}</a>"
end
private
attr_reader :id_counts
def html_attributes(attributes)
attributes.map { |key, value| %Q(#{key}="#{value}") }.join(" ")
end
def unique_id(text)
text.parameterize.then do |base_id|
id_counts[base_id] += 1
id_counts[base_id] > 1 ? "#{base_id}-#{id_counts[base_id]}" : base_id
end
end
def video_url?(url)
File.extname(url).downcase.match?(/\.(mp4|webm|ogg|mov|avi|mkv)/)
end
def video_tag(url, title)
<<~HTML.chomp
<video controls title="#{title}" width="1024">
<source src="#{url}" type="video/#{File.extname(url).delete('.')}">
</video>
HTML
end
end
-47
View File
@@ -1,47 +0,0 @@
module ActionText
module HasMarkdown
extend ActiveSupport::Concern
class_methods do
def has_markdown(name, strict_loading: strict_loading_by_default)
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}
markdown_#{name} || build_markdown_#{name}
end
def #{name}_html
#{name}.to_html
end
def #{name}_plain_text
#{name}.to_plain_text
end
def #{name}?
markdown_#{name}.present?
end
def #{name}=(content)
self.#{name}.content = content
end
CODE
has_one :"markdown_#{name}", -> { where(name: name) },
class_name: "ActionText::Markdown", as: :record, inverse_of: :record, autosave: true, dependent: :destroy,
strict_loading: strict_loading
scope :"with_markdown_#{name}", -> { includes("markdown_#{name}") }
end
end
def safe_markdown_attribute(name)
if self.class.reflect_on_association("markdown_#{name}")&.klass == ActionText::Markdown
public_send(name)
end
end
end
end
ActiveSupport.on_load :active_record do
include ActionText::HasMarkdown
end
-44
View File
@@ -1,44 +0,0 @@
module ActionText
class Markdown < Record
mattr_accessor :html_renderer
mattr_accessor :plain_text_renderer
belongs_to :record, polymorphic: true, touch: true
def to_html
to_unsafe_html.html_safe
end
def to_unsafe_html
if html_renderer.respond_to? :call
html_renderer.call content
else
html_renderer.render content
end
end
def to_plain_text
if plain_text_renderer.respond_to? :call
plain_text_renderer.call content
else
plain_text_renderer.render content
end
end
end
end
module ActionText::Markdown::Uploads
extend ActiveSupport::Concern
included do
has_many_attached :uploads, dependent: :destroy
end
end
ActiveSupport.on_load :active_storage_attachment do
class ActionText::Markdown
include ActionText::Markdown::Uploads
end
end
ActiveSupport.run_load_hooks :action_text_markdown, ActionText::Markdown
-36
View File
@@ -1,36 +0,0 @@
module ActionText
module TagHelper
def markdown_area(record, name, value: nil, data: {}, **options)
field_name = "#{record.class.model_name.param_key}[#{name}]"
value = record.safe_markdown_attribute(name).content.to_s if value.nil?
data = data.reverse_merge! uploads_url: uploads_url(format: "json")
tag.house_md value, name: field_name, data: data, **options
end
def house_toolbar(**options, &block)
tag.house_md_toolbar(**options, &block)
end
def house_toolbar_button(action, **options, &block)
tag.button title: action.to_s.humanize, data: { "house-md-action": action }, **options, &block
end
def house_toolbar_file_upload_button(name: "upload", title: "Upload File", **options, &block)
tag.label title: title, **options do
safe_join [
file_field_tag(name, data: { "house-md-toolbar-file-picker": true }, style: "display: none;"),
capture(&block)
]
end
end
end
end
module ActionView::Helpers
class FormBuilder
def markdown_area(method, **options)
@template.markdown_area(@object, method, **options)
end
end
end
-32
View File
@@ -1,32 +0,0 @@
module ActiveStorage::Sluggable
extend ActiveSupport::Concern
included do
before_create :set_slug
end
def slug_url(host: ActiveStorage::Current.url_options[:host], port: ActiveStorage::Current.url_options[:port])
Rails.application.routes.url_helpers.upload_url(slug, host: host, port: port)
end
private
def set_slug
self.slug = "#{slug_basename}-#{SecureRandom.alphanumeric(6)}.#{slug_extension}"
end
def slug_basename
File.basename(slug_filename, ".*").parameterize
end
def slug_extension
File.extname(slug_filename).delete(".").parameterize
end
def slug_filename
slug.presence || filename.to_s
end
end
ActiveSupport.on_load :active_storage_attachment do
ActiveStorage::Attachment.include ActiveStorage::Sluggable
end