This commit is contained in:
2025-11-07 13:34:32 -08:00
commit 7578ff95dd
437 changed files with 11000 additions and 0 deletions

0
lib/assets/.keep Normal file
View File

33
lib/markdown_renderer.rb Normal file
View File

@@ -0,0 +1,33 @@
require "rouge/plugins/redcarpet"
class MarkdownRenderer < Redcarpet::Render::HTML
include Rouge::Plugins::Redcarpet
def self.build
renderer = MarkdownRenderer.new(ActionText::Markdown::DEFAULT_RENDERER_OPTIONS)
Redcarpet::Markdown.new(renderer, ActionText::Markdown::DEFAULT_MARKDOWN_EXTENSIONS)
end
def initialize(*args)
super
@id_counts = Hash.new(0)
end
def header(text, header_level)
unique_id(text).then do |id|
"<h#{header_level} id='#{id}'>#{text} <a href='##{id}' class='heading__link' aria-hidden='true'>#</a></h#{header_level}>"
end
end
def image(url, title, alt_text)
%(<a title="#{title}" data-action="lightbox#open:prevent" data-lightbox-target="image" data-lightbox-url-value="#{url}?disposition=attachment" href="#{url}"><img src="#{url}" alt="#{alt_text}"></a>)
end
private
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
end

View File

@@ -0,0 +1,40 @@
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}?
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}") }
scope :"with_markdown_#{name}_and_embeds", -> { includes("markdown_#{name}": { embeds_attachments: :blob }) }
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

View File

@@ -0,0 +1,42 @@
module ActionText
class Markdown < Record
DEFAULT_RENDERER_OPTIONS = {
filter_html: false
}
DEFAULT_MARKDOWN_EXTENSIONS = {
autolink: true,
highlight: true,
no_intra_emphasis: true,
fenced_code_blocks: true,
lax_spacing: true,
strikethrough: true,
tables: true
}
mattr_accessor :renderer, default: Redcarpet::Markdown.new(
Redcarpet::Render::HTML.new(DEFAULT_RENDERER_OPTIONS), DEFAULT_MARKDOWN_EXTENSIONS)
belongs_to :record, polymorphic: true, touch: true
def to_html
(renderer.try(:call) || renderer).render(content).html_safe
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

View File

@@ -0,0 +1,39 @@
module ActionText
module TagHelper
def markdown_area(record, name, value: nil, **options)
field_name = "#{record.class.model_name.param_key}[#{name}]"
value = record.safe_markdown_attribute(name).content.to_s if value.nil?
data = options.delete(:data) || {}
data.reverse_merge! \
uploads_url: action_text_markdown_uploads_url(record_gid: record.to_signed_global_id.to_s, attribute_name: name, 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

View File

@@ -0,0 +1,32 @@
module ActiveStorage::Sluggable
extend ActiveSupport::Concern
included do
before_create :set_slug
end
def slug_url(host: ActiveStorage::Current.host)
Rails.application.routes.url_helpers.action_text_markdown_upload_url(slug, host: host)
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

0
lib/tasks/.keep Normal file
View File