storyblok-richtext-renderer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +9 -0
- data/.gitignore +8 -0
- data/Gemfile +3 -0
- data/README.md +23 -0
- data/lib/storyblok/richtext.rb +2 -0
- data/lib/storyblok/richtext/html_renderer.rb +162 -0
- data/lib/storyblok/richtext/html_renderer/marks/bold.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/marks/code.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/marks/italic.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/marks/link.rb +17 -0
- data/lib/storyblok/richtext/html_renderer/marks/mark.rb +24 -0
- data/lib/storyblok/richtext/html_renderer/marks/strike.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/marks/strong.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/marks/underline.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/nodes/blockquote.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/nodes/blok.rb +22 -0
- data/lib/storyblok/richtext/html_renderer/nodes/bullet_list.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/nodes/code_block.rb +20 -0
- data/lib/storyblok/richtext/html_renderer/nodes/hard_break.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/nodes/heading.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/nodes/horizontal_rule.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/nodes/image.rb +17 -0
- data/lib/storyblok/richtext/html_renderer/nodes/list_item.rb +13 -0
- data/lib/storyblok/richtext/html_renderer/nodes/node.rb +37 -0
- data/lib/storyblok/richtext/html_renderer/nodes/ordered_list.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/nodes/paragraph.rb +14 -0
- data/lib/storyblok/richtext/html_renderer/nodes/text.rb +14 -0
- data/lib/storyblok/richtext/version.rb +6 -0
- data/storyblok.gemspec +20 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2eb892e77eebea9767d260686015cff5f8948508939f2327a1fcab0494e34e78
|
4
|
+
data.tar.gz: 9f685e352c16d6c929bddf591f0f136aa42f5296ecabe29f5603a609b5ed85b9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 73b34ed7f2421bd114e770f4ea122a19d0651602901247c90edf8bf12c3cb68f76ba9e94750ec2258f7070dff6ecb0e9f80032ee5abe8fcf8060c6bd20dcd80c
|
7
|
+
data.tar.gz: 4800002870e1b0d0807ad2a0ded413e6aa4aebf337c4fa16ecec70c75c35309d39bb0a2ea1f7b18e57c4a712e24f0e535fe31c199d1e69a4cb51634a2354ae5d
|
data/.editorconfig
ADDED
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# About
|
2
|
+
|
3
|
+
This is Storyblok's rendering service to render html from the data of the richtext field type. The renderer is also compatible with Prosemirror's json format.
|
4
|
+
|
5
|
+
## How to install
|
6
|
+
|
7
|
+
Add the gem to your Gemfile
|
8
|
+
|
9
|
+
```bash
|
10
|
+
gem 'storyblok-richtext-renderer'
|
11
|
+
```
|
12
|
+
|
13
|
+
### Rendering a richtext field
|
14
|
+
|
15
|
+
```
|
16
|
+
renderer = Storyblok::Richtext::HtmlRenderer.new
|
17
|
+
renderer.render({'type' => 'doc', 'content' => [{'type' => 'paragraph', 'content' => [{'text' => 'Good', 'type' => 'text'}]}]})
|
18
|
+
# -> <p>Good</p>
|
19
|
+
```
|
20
|
+
|
21
|
+
### License
|
22
|
+
|
23
|
+
This project is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require "cgi"
|
2
|
+
|
3
|
+
module Storyblok
|
4
|
+
module Richtext
|
5
|
+
require_relative "html_renderer/marks/mark"
|
6
|
+
require_relative "html_renderer/marks/strike"
|
7
|
+
require_relative "html_renderer/marks/underline"
|
8
|
+
require_relative "html_renderer/marks/bold"
|
9
|
+
require_relative "html_renderer/marks/strong"
|
10
|
+
require_relative "html_renderer/marks/code"
|
11
|
+
require_relative "html_renderer/marks/italic"
|
12
|
+
require_relative "html_renderer/marks/link"
|
13
|
+
require_relative "html_renderer/nodes/node"
|
14
|
+
require_relative "html_renderer/nodes/bullet_list"
|
15
|
+
require_relative "html_renderer/nodes/code_block"
|
16
|
+
require_relative "html_renderer/nodes/hard_break"
|
17
|
+
require_relative "html_renderer/nodes/heading"
|
18
|
+
require_relative "html_renderer/nodes/image"
|
19
|
+
require_relative "html_renderer/nodes/list_item"
|
20
|
+
require_relative "html_renderer/nodes/ordered_list"
|
21
|
+
require_relative "html_renderer/nodes/paragraph"
|
22
|
+
require_relative "html_renderer/nodes/text"
|
23
|
+
require_relative "html_renderer/nodes/blockquote"
|
24
|
+
require_relative "html_renderer/nodes/horizontal_rule"
|
25
|
+
require_relative "html_renderer/nodes/text"
|
26
|
+
require_relative "html_renderer/nodes/blok"
|
27
|
+
|
28
|
+
class HtmlRenderer
|
29
|
+
def initialize
|
30
|
+
@marks = [
|
31
|
+
Storyblok::Richtext::Marks::Bold,
|
32
|
+
Storyblok::Richtext::Marks::Strike,
|
33
|
+
Storyblok::Richtext::Marks::Underline,
|
34
|
+
Storyblok::Richtext::Marks::Strong,
|
35
|
+
Storyblok::Richtext::Marks::Code,
|
36
|
+
Storyblok::Richtext::Marks::Italic,
|
37
|
+
Storyblok::Richtext::Marks::Link
|
38
|
+
]
|
39
|
+
@nodes = [
|
40
|
+
Storyblok::Richtext::Nodes::HorizontalRule,
|
41
|
+
Storyblok::Richtext::Nodes::Blockquote,
|
42
|
+
Storyblok::Richtext::Nodes::BulletList,
|
43
|
+
Storyblok::Richtext::Nodes::CodeBlock,
|
44
|
+
Storyblok::Richtext::Nodes::HardBreak,
|
45
|
+
Storyblok::Richtext::Nodes::Heading,
|
46
|
+
Storyblok::Richtext::Nodes::Image,
|
47
|
+
Storyblok::Richtext::Nodes::ListItem,
|
48
|
+
Storyblok::Richtext::Nodes::OrderedList,
|
49
|
+
Storyblok::Richtext::Nodes::Paragraph,
|
50
|
+
Storyblok::Richtext::Nodes::Text,
|
51
|
+
Storyblok::Richtext::Nodes::Blok
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_component_resolver(component_resolver)
|
56
|
+
Storyblok::Richtext::Nodes::Blok.define_method :component_resolver, component_resolver
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_node(node)
|
60
|
+
@nodes.push(node)
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_mark(mark)
|
64
|
+
@marks.push(mark)
|
65
|
+
end
|
66
|
+
|
67
|
+
def render(data)
|
68
|
+
html = ""
|
69
|
+
data['content'].each do |node|
|
70
|
+
html += render_node(node)
|
71
|
+
end
|
72
|
+
|
73
|
+
html
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def render_node(item)
|
79
|
+
html = []
|
80
|
+
if item['marks']
|
81
|
+
item['marks'].each do |m|
|
82
|
+
mark = get_matching_mark(m)
|
83
|
+
html.push(render_opening_tag(mark.tag)) if mark
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
node = get_matching_node(item)
|
88
|
+
html.push(render_opening_tag(node.tag)) if node and node.tag
|
89
|
+
|
90
|
+
if item['content']
|
91
|
+
item['content'].each do |content|
|
92
|
+
html.push(render_node(content))
|
93
|
+
end
|
94
|
+
elsif node and node.text
|
95
|
+
html.push(CGI.escapeHTML(node.text))
|
96
|
+
elsif node and node.single_tag
|
97
|
+
html.push(render_tag(node.single_tag))
|
98
|
+
elsif node and node.html
|
99
|
+
html.push(node.html)
|
100
|
+
end
|
101
|
+
|
102
|
+
html.push(render_closing_tag(node.tag)) if node and node.tag
|
103
|
+
if item['marks']
|
104
|
+
item['marks'].reverse.each do |m|
|
105
|
+
mark = get_matching_mark(m)
|
106
|
+
html.push(render_closing_tag(mark.tag)) if mark
|
107
|
+
end
|
108
|
+
end
|
109
|
+
return html.join("")
|
110
|
+
end
|
111
|
+
|
112
|
+
def render_tag(tags, ending = ' /')
|
113
|
+
return "<#{tags}#{ending}>" if tags.is_a? String
|
114
|
+
all = tags.map do |tag|
|
115
|
+
if tag.is_a? String
|
116
|
+
"<#{tag}#{ending}>"
|
117
|
+
else
|
118
|
+
h = "<#{tag[:tag]}"
|
119
|
+
tag[:attrs].to_h.each_pair { |key, value| h += " #{key}=\"#{CGI.escapeHTML(value)}\"" if !value.nil? } if tag[:attrs]
|
120
|
+
"#{h}#{ending}>"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
return all.join('')
|
124
|
+
end
|
125
|
+
|
126
|
+
def render_opening_tag(tags)
|
127
|
+
render_tag(tags, '')
|
128
|
+
end
|
129
|
+
|
130
|
+
def render_closing_tag(tags)
|
131
|
+
return "</#{tags}>" if tags.is_a? String
|
132
|
+
|
133
|
+
all = tags.reverse.map do |tag|
|
134
|
+
if tag.is_a? String
|
135
|
+
"</#{tag}>"
|
136
|
+
else
|
137
|
+
"</#{tag[:tag]}>"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
return all.join('')
|
141
|
+
end
|
142
|
+
|
143
|
+
def get_matching_node(item)
|
144
|
+
return get_matching_class(item, @nodes)
|
145
|
+
end
|
146
|
+
|
147
|
+
def get_matching_mark(item)
|
148
|
+
return get_matching_class(item, @marks)
|
149
|
+
end
|
150
|
+
|
151
|
+
def get_matching_class(node, classes)
|
152
|
+
found = classes.select do |clazz|
|
153
|
+
instance = clazz.new(node)
|
154
|
+
if (instance.matching())
|
155
|
+
return instance
|
156
|
+
end
|
157
|
+
end
|
158
|
+
found.first
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Storyblok::Richtext
|
2
|
+
module Marks
|
3
|
+
class Mark
|
4
|
+
attr_writer :type
|
5
|
+
|
6
|
+
def type
|
7
|
+
@type || 'mark'
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(data)
|
11
|
+
@node = data
|
12
|
+
end
|
13
|
+
|
14
|
+
def matching
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def tag
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Storyblok::Richtext
|
2
|
+
module Nodes
|
3
|
+
class Blok < Node
|
4
|
+
|
5
|
+
def matching
|
6
|
+
@node['type'] === 'blok'
|
7
|
+
end
|
8
|
+
|
9
|
+
def html
|
10
|
+
body = ''
|
11
|
+
@node['attrs']['body'].each do |blok|
|
12
|
+
body += component_resolver(blok['component'], blok)
|
13
|
+
end
|
14
|
+
body
|
15
|
+
end
|
16
|
+
|
17
|
+
def component_resolver component, data
|
18
|
+
''
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Storyblok::Richtext
|
2
|
+
module Nodes
|
3
|
+
class CodeBlock < Node
|
4
|
+
|
5
|
+
def matching
|
6
|
+
@node['type'] === 'code_block'
|
7
|
+
end
|
8
|
+
|
9
|
+
def tag
|
10
|
+
[
|
11
|
+
'pre',
|
12
|
+
{
|
13
|
+
tag: 'code',
|
14
|
+
attrs: @node['attrs'].slice('class')
|
15
|
+
}
|
16
|
+
]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Storyblok::Richtext
|
2
|
+
module Nodes
|
3
|
+
|
4
|
+
class Node
|
5
|
+
attr_writer :wrapper
|
6
|
+
attr_writer :type
|
7
|
+
|
8
|
+
def type
|
9
|
+
@type || 'node'
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(data)
|
13
|
+
@node = data
|
14
|
+
end
|
15
|
+
|
16
|
+
def matching
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def single_tag
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def tag
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def text
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def html
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/storyblok.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path('../lib/storyblok/richtext/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = 'storyblok-richtext-renderer'
|
5
|
+
gem.version = Storyblok::Richtext::VERSION
|
6
|
+
gem.summary = 'Storyblok richtext renderer'
|
7
|
+
gem.description = 'This is Storyblok\'s rendering service to render html from the data of the richtext field type. The renderer is compatible with Prosemirror\'s json format.'
|
8
|
+
gem.license = 'MIT'
|
9
|
+
gem.authors = ['Storyblok (Alexander Feiglstorfer)']
|
10
|
+
gem.email = 'it@storyblok.com'
|
11
|
+
gem.homepage = 'https://github.com/storyblok/storyblok-ruby-richtext-renderer'
|
12
|
+
|
13
|
+
gem.files = Dir['{**/}{.*,*}'].select { |path| File.file?(path) && !path.start_with?('pkg') && !path.end_with?('.gem') }
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
16
|
+
gem.require_paths = ['lib/storyblok']
|
17
|
+
|
18
|
+
gem.add_development_dependency 'bundler', '~> 1.5'
|
19
|
+
gem.add_development_dependency 'rspec', '~> 3'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: storyblok-richtext-renderer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Storyblok (Alexander Feiglstorfer)
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-09-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3'
|
41
|
+
description: This is Storyblok's rendering service to render html from the data of
|
42
|
+
the richtext field type. The renderer is compatible with Prosemirror's json format.
|
43
|
+
email: it@storyblok.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".DS_Store"
|
49
|
+
- ".editorconfig"
|
50
|
+
- ".gitignore"
|
51
|
+
- ".ruby-version"
|
52
|
+
- Gemfile
|
53
|
+
- README.md
|
54
|
+
- lib/.DS_Store
|
55
|
+
- lib/storyblok/.DS_Store
|
56
|
+
- lib/storyblok/richtext.rb
|
57
|
+
- lib/storyblok/richtext/html_renderer.rb
|
58
|
+
- lib/storyblok/richtext/html_renderer/marks/bold.rb
|
59
|
+
- lib/storyblok/richtext/html_renderer/marks/code.rb
|
60
|
+
- lib/storyblok/richtext/html_renderer/marks/italic.rb
|
61
|
+
- lib/storyblok/richtext/html_renderer/marks/link.rb
|
62
|
+
- lib/storyblok/richtext/html_renderer/marks/mark.rb
|
63
|
+
- lib/storyblok/richtext/html_renderer/marks/strike.rb
|
64
|
+
- lib/storyblok/richtext/html_renderer/marks/strong.rb
|
65
|
+
- lib/storyblok/richtext/html_renderer/marks/underline.rb
|
66
|
+
- lib/storyblok/richtext/html_renderer/nodes/blockquote.rb
|
67
|
+
- lib/storyblok/richtext/html_renderer/nodes/blok.rb
|
68
|
+
- lib/storyblok/richtext/html_renderer/nodes/bullet_list.rb
|
69
|
+
- lib/storyblok/richtext/html_renderer/nodes/code_block.rb
|
70
|
+
- lib/storyblok/richtext/html_renderer/nodes/hard_break.rb
|
71
|
+
- lib/storyblok/richtext/html_renderer/nodes/heading.rb
|
72
|
+
- lib/storyblok/richtext/html_renderer/nodes/horizontal_rule.rb
|
73
|
+
- lib/storyblok/richtext/html_renderer/nodes/image.rb
|
74
|
+
- lib/storyblok/richtext/html_renderer/nodes/list_item.rb
|
75
|
+
- lib/storyblok/richtext/html_renderer/nodes/node.rb
|
76
|
+
- lib/storyblok/richtext/html_renderer/nodes/ordered_list.rb
|
77
|
+
- lib/storyblok/richtext/html_renderer/nodes/paragraph.rb
|
78
|
+
- lib/storyblok/richtext/html_renderer/nodes/text.rb
|
79
|
+
- lib/storyblok/richtext/version.rb
|
80
|
+
- storyblok.gemspec
|
81
|
+
homepage: https://github.com/storyblok/storyblok-ruby-richtext-renderer
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib/storyblok
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.7.6
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: Storyblok richtext renderer
|
105
|
+
test_files: []
|