This commit is contained in:
0
lib/assets/.keep
Normal file
0
lib/assets/.keep
Normal file
33
lib/markdown_renderer.rb
Normal file
33
lib/markdown_renderer.rb
Normal 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
|
||||
40
lib/rails_ext/action_text_has_markdown.rb
Normal file
40
lib/rails_ext/action_text_has_markdown.rb
Normal 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
|
||||
42
lib/rails_ext/action_text_markdown.rb
Normal file
42
lib/rails_ext/action_text_markdown.rb
Normal 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
|
||||
39
lib/rails_ext/action_text_tag_helper.rb
Normal file
39
lib/rails_ext/action_text_tag_helper.rb
Normal 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
|
||||
32
lib/rails_ext/active_storage_sluggable.rb
Normal file
32
lib/rails_ext/active_storage_sluggable.rb
Normal 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
0
lib/tasks/.keep
Normal file
Reference in New Issue
Block a user