richer_text 0.7.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/helpers/richer_text/tag_helper.rb +37 -0
- data/app/models/richer_text/json_text.rb +25 -2
- data/app/models/richer_text/rich_text.rb +6 -0
- data/lib/richer_text/content.rb +6 -0
- data/lib/richer_text/html_visitor.rb +33 -0
- data/lib/richer_text/node.rb +2 -2
- data/lib/richer_text/nodes/attachment_figure.rb +17 -0
- data/lib/richer_text/nodes/attachment_gallery.rb +6 -0
- data/lib/richer_text/nodes/mention.rb +30 -0
- data/lib/richer_text/version.rb +1 -1
- data/lib/richer_text.rb +4 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03e9732ed2320f56a2c30cbcd6af7614b6840b601aab70d790c96e6e8412babf
|
4
|
+
data.tar.gz: 4413b9240e46d0153dff22c7b4dd7161a555f572ada62b69159f0c267ae7b0b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39f20dfc3cecd2f74f4cc4d01b396d9678ceeed635ff4dc2a35bc62ba0dc8f6361f882dfe1df67b9286d63b1c86fbd6b7e73b729175e8fd3948435eb041a7ade
|
7
|
+
data.tar.gz: 4718871930d84edd4de392d9ea2d321f6a04782e5f0c774906e468e8c70ecac6ea9c78fb4ed92dcf7aa8598fea600dea3d13a117beef8287d5b709a8547d2318
|
@@ -17,16 +17,40 @@ module ActionView::Helpers
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
class Tags::RhinoEditor < Tags::Base
|
21
|
+
include Tags::Placeholderable
|
22
|
+
|
23
|
+
delegate :dom_id, to: ActionView::RecordIdentifier
|
24
|
+
|
25
|
+
def render
|
26
|
+
options = @options.stringify_keys
|
27
|
+
add_default_name_and_id(options)
|
28
|
+
options["input"] ||= dom_id(object, [options["id"], :rhino_text_input].compact.join("_")) if object
|
29
|
+
options["value"] = options.fetch("value") { value&.to_editor_format }
|
30
|
+
options["serializer"] = options.fetch("serializer") { "html"}
|
31
|
+
|
32
|
+
@template_object.rhino_text_area_tag(options.delete("name"), options["value"], options.except("value"))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
20
36
|
module FormHelper
|
21
37
|
def richer_text_area(object_name, method, options = {})
|
22
38
|
Tags::Editor.new(object_name, method, self, options).render
|
23
39
|
end
|
40
|
+
|
41
|
+
def rhino_text_area(object_name, method, options = {})
|
42
|
+
Tags::RhinoEditor.new(object_name, method, self, options).render
|
43
|
+
end
|
24
44
|
end
|
25
45
|
|
26
46
|
class FormBuilder
|
27
47
|
def richer_text_area(method, options = {})
|
28
48
|
@template.richer_text_area(@object_name, method, objectify_options(options))
|
29
49
|
end
|
50
|
+
|
51
|
+
def rhino_text_area(method, options = {})
|
52
|
+
@template.rhino_text_area(@object_name, method, objectify_options(options))
|
53
|
+
end
|
30
54
|
end
|
31
55
|
end
|
32
56
|
|
@@ -49,5 +73,18 @@ module RicherText
|
|
49
73
|
|
50
74
|
input_tag + editor_tag
|
51
75
|
end
|
76
|
+
|
77
|
+
def rhino_text_area_tag(name, value = nil, options = {})
|
78
|
+
options = options.symbolize_keys
|
79
|
+
options[:input] ||= "rhino_text_input_#{RicherText::TagHelper.id += 1}"
|
80
|
+
|
81
|
+
# So we can choose the serializer to use, e.g. "html" or "json"
|
82
|
+
options[:serializer] ||= "html"
|
83
|
+
|
84
|
+
input_tag = hidden_field_tag(name, value, id: options[:input])
|
85
|
+
editor_tag = tag("rhino-editor", { input: options[:input], serializer: "json", data: { "blob-url-template": rails_service_blob_url(":signed_id", ":filename"), "direct-upload-url": rails_direct_uploads_url }}.merge(options))
|
86
|
+
|
87
|
+
input_tag + editor_tag
|
88
|
+
end
|
52
89
|
end
|
53
90
|
end
|
@@ -7,8 +7,9 @@ module RicherText
|
|
7
7
|
serialize :body, JSON, default: DEFAULT_BODY.to_json
|
8
8
|
|
9
9
|
has_many_attached :images
|
10
|
+
has_many_attached :rhino_attachments # For handling attachments in the Rhino Editor
|
10
11
|
|
11
|
-
before_save :
|
12
|
+
before_save :update_attachments
|
12
13
|
|
13
14
|
def to_editor_format
|
14
15
|
body
|
@@ -18,18 +19,40 @@ module RicherText
|
|
18
19
|
RicherText.default_renderer.visit(document)
|
19
20
|
end
|
20
21
|
|
22
|
+
def mentionees
|
23
|
+
gids = mention_nodes.map(&:id).compact_blank
|
24
|
+
|
25
|
+
GlobalID::Locator.locate_many(gids).uniq # Only return unique records
|
26
|
+
end
|
27
|
+
|
21
28
|
private
|
22
29
|
|
23
|
-
def
|
30
|
+
def update_attachments
|
24
31
|
self.images = image_nodes.map(&:signed_id)
|
32
|
+
self.rhino_attachments = rhino_attachment_records.map(&:signed_id)
|
25
33
|
end
|
26
34
|
|
27
35
|
def image_nodes
|
28
36
|
find_nodes_of_type(RicherText::Nodes::Image).flatten.compact_blank
|
29
37
|
end
|
30
38
|
|
39
|
+
def mention_nodes
|
40
|
+
find_nodes_of_type(RicherText::Nodes::Mention).flatten.compact_blank
|
41
|
+
end
|
42
|
+
|
43
|
+
def rhino_attachment_nodes
|
44
|
+
find_nodes_of_type(RicherText::Nodes::AttachmentFigure).flatten.compact_blank
|
45
|
+
end
|
46
|
+
|
47
|
+
def rhino_attachment_records
|
48
|
+
sgids = rhino_attachment_nodes.map(&:sgid).compact_blank
|
49
|
+
GlobalID::Locator.locate_many_signed(sgids, for: "attachable")
|
50
|
+
end
|
51
|
+
|
31
52
|
def find_nodes_of_type(type, node = document)
|
32
53
|
if node.children.any?
|
54
|
+
return node if node.is_a?(type)
|
55
|
+
|
33
56
|
node.children.map { |child| find_nodes_of_type(type, child) }
|
34
57
|
else
|
35
58
|
node.is_a?(type) ? node : nil
|
data/lib/richer_text/content.rb
CHANGED
@@ -28,6 +28,12 @@ module RicherText
|
|
28
28
|
end.uniq
|
29
29
|
end
|
30
30
|
|
31
|
+
def mentionees_global_ids
|
32
|
+
global_ids = fragment.find_all("span[data-type=mention]").map do |span|
|
33
|
+
span.attributes["data-id"].value
|
34
|
+
end.uniq
|
35
|
+
end
|
36
|
+
|
31
37
|
def image_blobs
|
32
38
|
image_blob_ids.map { |id| ActiveStorage::Blob.find_signed(id) }
|
33
39
|
end
|
@@ -6,6 +6,18 @@ module RicherText
|
|
6
6
|
node.accept(self)
|
7
7
|
end
|
8
8
|
|
9
|
+
def visit_attachment_figure(node)
|
10
|
+
"<figure sgid=#{node.attrs["sgid"]}>
|
11
|
+
#{node_previewable?(node) ? "<img src=#{node.url} />" : "<a href=#{node.url} target='_blank'>"}
|
12
|
+
<figcaption class='attachment__caption'>#{visit_children(node).join}</figcaption>
|
13
|
+
#{node_previewable?(node) ? "" : "</a>"}
|
14
|
+
</figure>"
|
15
|
+
end
|
16
|
+
|
17
|
+
def visit_attachment_gallery(node)
|
18
|
+
"<div class='attachment-gallery'>#{visit_children(node).join}</div>"
|
19
|
+
end
|
20
|
+
|
9
21
|
def visit_blockquote(node)
|
10
22
|
"<blockquote>#{visit_children(node).join}</blockquote>"
|
11
23
|
end
|
@@ -30,6 +42,17 @@ module RicherText
|
|
30
42
|
"<div class='richer-text'>#{visit_children(node).join("\n")}</div>".html_safe
|
31
43
|
end
|
32
44
|
|
45
|
+
def visit_mention(node, marks)
|
46
|
+
if marks.any?
|
47
|
+
content_tag(marks[0].tag, visit_mention(node, marks[1..]), marks[0].attrs)
|
48
|
+
else
|
49
|
+
tag.span(
|
50
|
+
tag.img(src: node.avatar_url, class: "richer-text--mention-img") +
|
51
|
+
tag.span(node.name, class: "richer-text--mention-label"),
|
52
|
+
class: "richer-text--mention")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
33
56
|
def visit_paragraph(node)
|
34
57
|
"<p style='#{node.style}'>#{visit_children(node).join}</p>"
|
35
58
|
end
|
@@ -81,5 +104,15 @@ module RicherText
|
|
81
104
|
def visit_table_header(node)
|
82
105
|
"<th>#{visit_children(node).join}</th>"
|
83
106
|
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def previewable_regex
|
111
|
+
/^image(\/(gif|png|jpe?g)|$)/
|
112
|
+
end
|
113
|
+
|
114
|
+
def node_previewable?(node)
|
115
|
+
node.attrs["contentType"].match(previewable_regex)
|
116
|
+
end
|
84
117
|
end
|
85
118
|
end
|
data/lib/richer_text/node.rb
CHANGED
@@ -8,8 +8,8 @@ module RicherText
|
|
8
8
|
|
9
9
|
def self.build(json)
|
10
10
|
node = json.is_a?(String) ? JSON.parse(json) : json
|
11
|
-
klass = "RicherText::Nodes::#{node["type"].underscore.classify}".
|
12
|
-
klass.new(node)
|
11
|
+
klass = "RicherText::Nodes::#{node["type"].underscore.classify}".constantize
|
12
|
+
klass.new(node) if klass
|
13
13
|
end
|
14
14
|
|
15
15
|
def initialize(json)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RicherText
|
2
|
+
module Nodes
|
3
|
+
class AttachmentFigure < ::RicherText::Node
|
4
|
+
def previewable?
|
5
|
+
@attrs["previewable"]
|
6
|
+
end
|
7
|
+
|
8
|
+
def url
|
9
|
+
@attrs["url"].presence || @attrs["src"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def sgid
|
13
|
+
@attrs["sgid"]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module RicherText
|
2
|
+
module Nodes
|
3
|
+
class Mention < ::RicherText::Node
|
4
|
+
def initialize(json)
|
5
|
+
@marks = json.fetch("marks", []).map { |mark| RicherText::Mark.new(mark) }
|
6
|
+
super(json)
|
7
|
+
end
|
8
|
+
|
9
|
+
def accept(visitor)
|
10
|
+
visitor.visit_mention(self, @marks)
|
11
|
+
end
|
12
|
+
|
13
|
+
def user
|
14
|
+
@user ||= GlobalID::Locator.locate(@attrs["id"])
|
15
|
+
end
|
16
|
+
|
17
|
+
def id
|
18
|
+
@attrs["id"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def name
|
22
|
+
@user.respond_to?(:name) ? @user.name : @attrs["label"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def avatar_url
|
26
|
+
@user.respond_to?(:avatar_url) ? @user.avatar_url : @attrs["avatarUrl"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/richer_text/version.rb
CHANGED
data/lib/richer_text.rb
CHANGED
@@ -21,6 +21,8 @@ module RicherText
|
|
21
21
|
module Nodes
|
22
22
|
extend ActiveSupport::Autoload
|
23
23
|
|
24
|
+
autoload :AttachmentFigure # For Rhino Editor support
|
25
|
+
autoload :AttachmentGallery # For Rhino Editor support
|
24
26
|
autoload :Blockquote
|
25
27
|
autoload :BulletList
|
26
28
|
autoload :Callout
|
@@ -31,8 +33,9 @@ module RicherText
|
|
31
33
|
autoload :HorizontalRule
|
32
34
|
autoload :Image
|
33
35
|
autoload :ListItem
|
34
|
-
autoload :
|
36
|
+
autoload :Mention
|
35
37
|
autoload :OrderedList
|
38
|
+
autoload :Paragraph
|
36
39
|
autoload :Text
|
37
40
|
autoload :Table
|
38
41
|
autoload :TableCell
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: richer_text
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrea Fomera
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-09-
|
11
|
+
date: 2023-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -59,6 +59,8 @@ files:
|
|
59
59
|
- lib/richer_text/html_visitor.rb
|
60
60
|
- lib/richer_text/mark.rb
|
61
61
|
- lib/richer_text/node.rb
|
62
|
+
- lib/richer_text/nodes/attachment_figure.rb
|
63
|
+
- lib/richer_text/nodes/attachment_gallery.rb
|
62
64
|
- lib/richer_text/nodes/blockquote.rb
|
63
65
|
- lib/richer_text/nodes/bullet_list.rb
|
64
66
|
- lib/richer_text/nodes/callout.rb
|
@@ -69,6 +71,7 @@ files:
|
|
69
71
|
- lib/richer_text/nodes/horizontal_rule.rb
|
70
72
|
- lib/richer_text/nodes/image.rb
|
71
73
|
- lib/richer_text/nodes/list_item.rb
|
74
|
+
- lib/richer_text/nodes/mention.rb
|
72
75
|
- lib/richer_text/nodes/ordered_list.rb
|
73
76
|
- lib/richer_text/nodes/paragraph.rb
|
74
77
|
- lib/richer_text/nodes/table.rb
|