prosemirror_to_html 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/Gemfile.lock +23 -21
  4. data/lib/prosemirror_to_html/marks/bold.rb +2 -8
  5. data/lib/prosemirror_to_html/marks/code.rb +2 -8
  6. data/lib/prosemirror_to_html/marks/italic.rb +2 -8
  7. data/lib/prosemirror_to_html/marks/link.rb +16 -8
  8. data/lib/prosemirror_to_html/marks/mark.rb +9 -7
  9. data/lib/prosemirror_to_html/marks/strike.rb +8 -0
  10. data/lib/prosemirror_to_html/marks/subscript.rb +8 -0
  11. data/lib/prosemirror_to_html/marks/superscript.rb +8 -0
  12. data/lib/prosemirror_to_html/marks/underline.rb +8 -0
  13. data/lib/prosemirror_to_html/nodes/blockquote.rb +8 -0
  14. data/lib/prosemirror_to_html/nodes/bullet_list.rb +2 -8
  15. data/lib/prosemirror_to_html/nodes/code_block.rb +2 -9
  16. data/lib/prosemirror_to_html/nodes/hard_break.rb +4 -6
  17. data/lib/prosemirror_to_html/nodes/heading.rb +13 -5
  18. data/lib/prosemirror_to_html/nodes/horizontal_rule.rb +12 -0
  19. data/lib/prosemirror_to_html/nodes/image.rb +11 -5
  20. data/lib/prosemirror_to_html/nodes/list_item.rb +2 -12
  21. data/lib/prosemirror_to_html/nodes/node.rb +27 -8
  22. data/lib/prosemirror_to_html/nodes/ordered_list.rb +9 -6
  23. data/lib/prosemirror_to_html/nodes/paragraph.rb +2 -8
  24. data/lib/prosemirror_to_html/nodes/table.rb +8 -0
  25. data/lib/prosemirror_to_html/nodes/table_cell.rb +17 -0
  26. data/lib/prosemirror_to_html/nodes/table_header.rb +17 -0
  27. data/lib/prosemirror_to_html/nodes/table_row.rb +8 -0
  28. data/lib/prosemirror_to_html/version.rb +1 -1
  29. data/lib/prosemirror_to_html.rb +223 -86
  30. data/prosemirror_to_html.gemspec +7 -7
  31. metadata +24 -15
  32. data/lib/prosemirror_to_html/nodes/code_block_wrapper.rb +0 -13
  33. data/lib/prosemirror_to_html/nodes/text.rb +0 -14
  34. data/lib/prosemirror_to_html/nodes/user.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 310a6a3549a6e796525d9623874469d85368541498a971568dba4b037c0c7289
4
- data.tar.gz: 55412b082912e22860b238005c78aee0323d420bce0e8964f9e7d5c227c2cebd
3
+ metadata.gz: f284982bc72b18c9ef678e23833febc9f5326f7c02fa5fcd0f24d2b3b01a068c
4
+ data.tar.gz: 72026340795ebd8a342be9693ebf401f2c37fb75bcdf44c740cec2c351a046e3
5
5
  SHA512:
6
- metadata.gz: 99009e84b817e6d7a19cc168bdf1a1548ed70ae48b6f67240fbb7fa0ecfef9942b373232fb7d662d9c4df93922aa7864c7166e78b37c5ca26e4464ae9ea48ba5
7
- data.tar.gz: 435eba416a8990cf8c989596e0b5a6b02aeab2fa4e25dfec02472f710b80d2cf4a3937988c0baf29d9d159f795d63e0327722e3c56538a818871120adbdd4c5d
6
+ metadata.gz: 364d04e54e3c17755dca5365798cbb75f72b9b5597d8dda3c513a2a43e9092f90e45764fb06dda0626adc6b78bcc8af8962bf8c54bec74956716e22fff97e35c
7
+ data.tar.gz: 91a7c87d2527b9cf4350722e1f4d454405b7e88b1e8a3ab04524b60d1c76c19d89b527105a7c704c3cfbcdeef938a9a6245a13ffdadc29d098ddba260730b067
data/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ ## [0.2.0] - 2023-07-03
2
+
3
+ Hans Lemuet (@Spone) is the new maintainer. The fork is now hosted at https://github.com/etaminstudio/prosemirror_to_html
4
+
5
+ ### Added
6
+
7
+ - Added support for marks `Strike`, `Subscript`, `Superscript`, `Underline`
8
+ - Added support for nodes `Blockquote`, `HorizontalRule`, `Table`, `TableCell`, `TableHeader`, `TableRow`
9
+ - `Link` mark: added support for conditional `target`, `title`, `rel` attributes
10
+ - `Heading` node: added support for `level` attribute
11
+
12
+ ### Changed
13
+
14
+ - Improve code style (always use snake_case for methods)
15
+ - Refactor `Renderer`
16
+ - Refactor `Node`
17
+ - Refactor specs to have one spec file for each node and mark
18
+ - Update dependencies
19
+
20
+ ### Removed
21
+
22
+ - `CodeBlockWrapper` node removed in favor of `CodeBlock`
23
+ - `Text` node removed
24
+ - `User` node removed
data/Gemfile.lock CHANGED
@@ -1,41 +1,43 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prosemirror_to_html (0.1.0)
4
+ prosemirror_to_html (0.2.0)
5
5
  nokogiri
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- diff-lcs (1.3)
11
- mini_portile2 (2.4.0)
12
- nokogiri (1.10.2)
13
- mini_portile2 (~> 2.4.0)
14
- rake (10.5.0)
15
- rspec (3.8.0)
16
- rspec-core (~> 3.8.0)
17
- rspec-expectations (~> 3.8.0)
18
- rspec-mocks (~> 3.8.0)
19
- rspec-core (3.8.0)
20
- rspec-support (~> 3.8.0)
21
- rspec-expectations (3.8.2)
10
+ diff-lcs (1.5.0)
11
+ mini_portile2 (2.8.2)
12
+ nokogiri (1.15.2)
13
+ mini_portile2 (~> 2.8.2)
14
+ racc (~> 1.4)
15
+ racc (1.7.1)
16
+ rake (13.0.6)
17
+ rspec (3.12.0)
18
+ rspec-core (~> 3.12.0)
19
+ rspec-expectations (~> 3.12.0)
20
+ rspec-mocks (~> 3.12.0)
21
+ rspec-core (3.12.2)
22
+ rspec-support (~> 3.12.0)
23
+ rspec-expectations (3.12.3)
22
24
  diff-lcs (>= 1.2.0, < 2.0)
23
- rspec-support (~> 3.8.0)
24
- rspec-mocks (3.8.0)
25
+ rspec-support (~> 3.12.0)
26
+ rspec-mocks (3.12.5)
25
27
  diff-lcs (>= 1.2.0, < 2.0)
26
- rspec-support (~> 3.8.0)
27
- rspec-support (3.8.0)
28
- yard (0.9.19)
28
+ rspec-support (~> 3.12.0)
29
+ rspec-support (3.12.1)
30
+ yard (0.9.34)
29
31
 
30
32
  PLATFORMS
31
33
  ruby
32
34
 
33
35
  DEPENDENCIES
34
- bundler (~> 2.0.1)
36
+ bundler (~> 2.1.4)
35
37
  prosemirror_to_html!
36
- rake (~> 10.0)
38
+ rake (~> 13.0)
37
39
  rspec (~> 3.0)
38
40
  yard
39
41
 
40
42
  BUNDLED WITH
41
- 2.0.1
43
+ 2.1.4
@@ -1,14 +1,8 @@
1
1
  module ProsemirrorToHtml
2
2
  module Marks
3
3
  class Bold < Mark
4
-
5
- def matching
6
- @node.type === 'bold'
7
- end
8
-
9
- def tag
10
- 'strong'
11
- end
4
+ @mark_type = 'bold'
5
+ @tag_name = 'strong'
12
6
  end
13
7
  end
14
8
  end
@@ -1,14 +1,8 @@
1
1
  module ProsemirrorToHtml
2
2
  module Marks
3
3
  class Code < Mark
4
-
5
- def matching
6
- @node.type === 'code'
7
- end
8
-
9
- def tag
10
- 'code'
11
- end
4
+ @mark_type = 'code'
5
+ @tag_name = 'code'
12
6
  end
13
7
  end
14
8
  end
@@ -1,14 +1,8 @@
1
1
  module ProsemirrorToHtml
2
2
  module Marks
3
3
  class Italic < Mark
4
-
5
- def matching
6
- @node.type === 'italic'
7
- end
8
-
9
- def tag
10
- 'em'
11
- end
4
+ @mark_type = 'italic'
5
+ @tag_name = 'em'
12
6
  end
13
7
  end
14
8
  end
@@ -1,16 +1,24 @@
1
1
  module ProsemirrorToHtml
2
2
  module Marks
3
3
  class Link < Mark
4
-
5
- def matching
6
- @node.type === 'link'
7
- end
4
+ @mark_type = 'link'
5
+ @tag_name = 'a'
8
6
 
9
7
  def tag
10
- [{
11
- tag: "a",
12
- attrs: @node.attrs
13
- }]
8
+ attrs = {}
9
+
10
+ attrs['href'] = @mark.attrs.href
11
+
12
+ attrs['target'] = @mark.attrs.target if @mark.attrs.target
13
+ attrs['title'] = @mark.attrs.title if @mark.attrs.title
14
+ attrs['rel'] = @mark.attrs.rel if @mark.attrs.rel
15
+
16
+ [
17
+ {
18
+ tag: self.class.tag_name,
19
+ attrs: attrs
20
+ }
21
+ ]
14
22
  end
15
23
  end
16
24
  end
@@ -1,24 +1,26 @@
1
1
  module ProsemirrorToHtml
2
2
  module Marks
3
3
  class Mark
4
- attr_writer :type
4
+ @mark_type = nil
5
+ @tag_name = nil
5
6
 
6
- def type
7
- @type || 'mark'
7
+ class << self
8
+ attr_reader :mark_type, :tag_name
8
9
  end
9
10
 
10
- def initialize(data)
11
- @node = data
11
+ def initialize(mark)
12
+ @mark = mark
12
13
  end
13
14
 
14
15
  def matching
16
+ return @mark.type == self.class.mark_type if @mark.type
17
+
15
18
  false
16
19
  end
17
20
 
18
21
  def tag
19
- nil
22
+ self.class.tag_name
20
23
  end
21
-
22
24
  end
23
25
  end
24
26
  end
@@ -0,0 +1,8 @@
1
+ module ProsemirrorToHtml
2
+ module Marks
3
+ class Strike < Mark
4
+ @mark_type = 'strike'
5
+ @tag_name = 'strike'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module ProsemirrorToHtml
2
+ module Marks
3
+ class Subscript < Mark
4
+ @mark_type = 'subscript'
5
+ @tag_name = 'sub'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module ProsemirrorToHtml
2
+ module Marks
3
+ class Superscript < Mark
4
+ @mark_type = 'superscript'
5
+ @tag_name = 'sup'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module ProsemirrorToHtml
2
+ module Marks
3
+ class Underline < Mark
4
+ @mark_type = 'underline'
5
+ @tag_name = 'u'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module ProsemirrorToHtml
2
+ module Nodes
3
+ class Blockquote < Node
4
+ @node_type = 'blockquote'
5
+ @tag_name = 'blockquote'
6
+ end
7
+ end
8
+ end
@@ -1,14 +1,8 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
3
  class BulletList < Node
4
-
5
- def matching
6
- @node.type === 'bullet_list'
7
- end
8
-
9
- def data
10
- 'ul'
11
- end
4
+ @node_type = 'bullet_list'
5
+ @tag_name = 'ul'
12
6
  end
13
7
  end
14
8
  end
@@ -1,15 +1,8 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
3
  class CodeBlock < Node
4
-
5
- def matching
6
- @node.type === 'code_block'
7
- end
8
-
9
- def tag
10
- ['pre', 'tag']
11
- end
12
-
4
+ @node_type = 'code_block'
5
+ @tag_name = ['pre', 'code']
13
6
  end
14
7
  end
15
8
  end
@@ -1,13 +1,11 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
3
  class HardBreak < Node
4
+ @node_type = 'hard_break'
5
+ @tag_name = 'br'
4
6
 
5
- def matching
6
- @node.type === 'hard_break'
7
- end
8
-
9
- def data
10
- 'br'
7
+ def self_closing
8
+ true
11
9
  end
12
10
  end
13
11
  end
@@ -1,15 +1,23 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
3
  class Heading < Node
4
+ @node_type = 'heading'
4
5
 
5
- def matching
6
- @node.type === 'heading'
6
+ def tag
7
+ [
8
+ {
9
+ tag: "h#{@node.attrs.level}",
10
+ attrs: tag_attrs
11
+ }
12
+ ]
7
13
  end
8
14
 
9
- def tag
10
- "h#{@node.attrs.level}"
15
+ private
16
+
17
+ def tag_attrs
18
+ attrs_hash = @node.attrs.to_h
19
+ attrs_hash.slice(*attrs_hash.keys - %i[level])
11
20
  end
12
-
13
21
  end
14
22
  end
15
23
  end
@@ -0,0 +1,12 @@
1
+ module ProsemirrorToHtml
2
+ module Nodes
3
+ class HorizontalRule < Node
4
+ @node_type = 'horizontal_rule'
5
+ @tag_name = 'hr'
6
+
7
+ def self_closing
8
+ true
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,14 +1,20 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
3
  class Image < Node
4
+ @node_type = 'image'
5
+ @tag_name = 'img'
4
6
 
5
- def matching
6
- @node.type === 'img'
7
+ def tag
8
+ [
9
+ {
10
+ tag: self.class.tag_name,
11
+ attrs: @node.attrs
12
+ }
13
+ ]
7
14
  end
8
15
 
9
- def tag
10
- # doc.img(:src => @node.attrs.src)
11
- 'img'
16
+ def self_closing
17
+ true
12
18
  end
13
19
  end
14
20
  end
@@ -1,18 +1,8 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
3
  class ListItem < Node
4
- # def initialize(dom_node)
5
- # super(dom_node)
6
- # @wrapper = { type: 'paragraph' }
7
- # end
8
-
9
- def matching
10
- @node.type === 'list_item'
11
- end
12
-
13
- def tag
14
- 'li'
15
- end
4
+ @node_type = 'list_item'
5
+ @tag_name = 'li'
16
6
  end
17
7
  end
18
8
  end
@@ -1,29 +1,48 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
-
4
3
  class Node
5
- attr_writer :wrapper
6
- attr_writer :type
4
+ @node_type = nil
5
+ @tag_name = nil
7
6
 
8
- def type
9
- @type || 'node'
7
+ class << self
8
+ attr_reader :node_type, :tag_name
10
9
  end
11
10
 
12
- def initialize(data)
13
- @node = data
11
+ def initialize(node)
12
+ @node = node
14
13
  end
15
14
 
16
15
  def matching
16
+ return underscore(@node.type) == self.class.node_type if @node.type
17
+
18
+ false
19
+ end
20
+
21
+ def self_closing
17
22
  false
18
23
  end
19
24
 
20
25
  def tag
21
- nil
26
+ self.class.tag_name
22
27
  end
23
28
 
24
29
  def text
25
30
  nil
26
31
  end
32
+
33
+ private
34
+
35
+ # from https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/activesupport/lib/active_support/inflector/methods.rb#L92
36
+ def underscore(camel_cased_word)
37
+ return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
38
+
39
+ word = camel_cased_word.to_s.gsub("::", "/")
40
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
41
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
42
+ word.tr!("-", "_")
43
+ word.downcase!
44
+ word
45
+ end
27
46
  end
28
47
  end
29
48
  end
@@ -1,13 +1,16 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
3
  class OrderedList < Node
4
+ @node_type = 'ordered_list'
5
+ @tag_name = 'ol'
4
6
 
5
- def matching
6
- @node.type === 'ordered_list'
7
- end
8
-
9
- def data
10
- 'ol'
7
+ def tag
8
+ [
9
+ {
10
+ tag: self.class.tag_name,
11
+ attrs: @node.attrs
12
+ }
13
+ ]
11
14
  end
12
15
  end
13
16
  end
@@ -1,14 +1,8 @@
1
1
  module ProsemirrorToHtml
2
2
  module Nodes
3
3
  class Paragraph < Node
4
-
5
- def matching
6
- @node.type === 'paragraph'
7
- end
8
-
9
- def tag
10
- 'p'
11
- end
4
+ @node_type = 'paragraph'
5
+ @tag_name = 'p'
12
6
  end
13
7
  end
14
8
  end
@@ -0,0 +1,8 @@
1
+ module ProsemirrorToHtml
2
+ module Nodes
3
+ class Table < Node
4
+ @node_type = 'table'
5
+ @tag_name = ['table', 'tbody']
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ module ProsemirrorToHtml
2
+ module Nodes
3
+ class TableCell < Node
4
+ @node_type = 'table_cell'
5
+ @tag_name = 'td'
6
+
7
+ def tag
8
+ [
9
+ {
10
+ tag: self.class.tag_name,
11
+ attrs: @node.attrs
12
+ }
13
+ ]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module ProsemirrorToHtml
2
+ module Nodes
3
+ class TableHeader < TableCell
4
+ @node_type = 'table_header'
5
+ @tag_name = 'th'
6
+
7
+ def tag
8
+ [
9
+ {
10
+ tag: self.class.tag_name,
11
+ attrs: @node.attrs
12
+ }
13
+ ]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ module ProsemirrorToHtml
2
+ module Nodes
3
+ class TableRow < Node
4
+ @node_type = 'table_row'
5
+ @tag_name = 'tr'
6
+ end
7
+ end
8
+ end
@@ -1,3 +1,3 @@
1
1
  module ProsemirrorToHtml
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -4,145 +4,282 @@ require "prosemirror_to_html/marks/bold"
4
4
  require "prosemirror_to_html/marks/code"
5
5
  require "prosemirror_to_html/marks/italic"
6
6
  require "prosemirror_to_html/marks/link"
7
+ require "prosemirror_to_html/marks/strike"
8
+ require "prosemirror_to_html/marks/subscript"
9
+ require "prosemirror_to_html/marks/superscript"
10
+ require "prosemirror_to_html/marks/underline"
7
11
  require "prosemirror_to_html/nodes/node"
12
+ require "prosemirror_to_html/nodes/blockquote"
8
13
  require "prosemirror_to_html/nodes/bullet_list"
9
- require "prosemirror_to_html/nodes/code_block_wrapper"
10
14
  require "prosemirror_to_html/nodes/code_block"
11
15
  require "prosemirror_to_html/nodes/hard_break"
16
+ require "prosemirror_to_html/nodes/horizontal_rule"
12
17
  require "prosemirror_to_html/nodes/heading"
13
18
  require "prosemirror_to_html/nodes/image"
14
19
  require "prosemirror_to_html/nodes/list_item"
15
20
  require "prosemirror_to_html/nodes/ordered_list"
16
21
  require "prosemirror_to_html/nodes/paragraph"
17
- require "prosemirror_to_html/nodes/text"
18
- require "prosemirror_to_html/nodes/user"
22
+ require "prosemirror_to_html/nodes/table"
23
+ require "prosemirror_to_html/nodes/table_cell"
24
+ require "prosemirror_to_html/nodes/table_header"
25
+ require "prosemirror_to_html/nodes/table_row"
19
26
  require 'nokogiri'
20
27
  require 'json'
21
28
  require "ostruct"
22
29
 
23
30
  module ProsemirrorToHtml
24
31
  class Error < StandardError; end
25
- # Your code goes here...
32
+
26
33
  class Renderer
27
- def initialize()
28
- @storedMarks = []
29
- @marks = [
30
- ProsemirrorToHtml::Marks::Bold,
31
- ProsemirrorToHtml::Marks::Code,
32
- ProsemirrorToHtml::Marks::Italic,
33
- ProsemirrorToHtml::Marks::Link
34
- ]
34
+ def initialize
35
+ @document = nil
36
+
35
37
  @nodes = [
38
+ ProsemirrorToHtml::Nodes::Blockquote,
36
39
  ProsemirrorToHtml::Nodes::BulletList,
37
- ProsemirrorToHtml::Nodes::CodeBlockWrapper,
38
40
  ProsemirrorToHtml::Nodes::CodeBlock,
39
41
  ProsemirrorToHtml::Nodes::HardBreak,
40
42
  ProsemirrorToHtml::Nodes::Heading,
43
+ ProsemirrorToHtml::Nodes::HorizontalRule,
41
44
  ProsemirrorToHtml::Nodes::Image,
42
45
  ProsemirrorToHtml::Nodes::ListItem,
43
46
  ProsemirrorToHtml::Nodes::OrderedList,
44
47
  ProsemirrorToHtml::Nodes::Paragraph,
45
- # ProsemirrorToHtml::Nodes::Text,
46
- ProsemirrorToHtml::Nodes::User
48
+ ProsemirrorToHtml::Nodes::Table,
49
+ ProsemirrorToHtml::Nodes::TableCell,
50
+ ProsemirrorToHtml::Nodes::TableHeader,
51
+ ProsemirrorToHtml::Nodes::TableRow,
47
52
  ]
53
+
54
+ @marks = [
55
+ ProsemirrorToHtml::Marks::Bold,
56
+ ProsemirrorToHtml::Marks::Code,
57
+ ProsemirrorToHtml::Marks::Italic,
58
+ ProsemirrorToHtml::Marks::Link,
59
+ ProsemirrorToHtml::Marks::Strike,
60
+ ProsemirrorToHtml::Marks::Subscript,
61
+ ProsemirrorToHtml::Marks::Superscript,
62
+ ProsemirrorToHtml::Marks::Underline,
63
+ ]
64
+ end
65
+
66
+ def with_marks(marks = nil)
67
+ @marks = marks if marks.is_a? Array
68
+
69
+ self
48
70
  end
49
71
 
50
- def addNode(node)
51
- @nodes.push(node)
72
+ def with_nodes(nodes = nil)
73
+ @nodes = nodes if nodes.is_a? Array
74
+
75
+ self
52
76
  end
53
- def addNodes(nodes)
54
- nodes.each do |node|
55
- addNode(node);
77
+
78
+ def render(value)
79
+ json = case value
80
+ when Hash then value.to_json
81
+ when String then value
82
+ else raise Error
83
+ end
84
+
85
+ @document = JSON.parse(json, object_class: OpenStruct)
86
+
87
+ html = ''
88
+
89
+ content = @document.content.is_a?(Array) ? @document.content : []
90
+
91
+ content.each_with_index do |node, index|
92
+ prev_node = content[index - 1]
93
+ next_node = content[index + 1]
94
+
95
+ html << render_node(node, prev_node, next_node)
56
96
  end
97
+
98
+ html
57
99
  end
58
- def addMark(mark)
59
- @marks.push(mark)
100
+
101
+ def add_node(node)
102
+ @nodes << node
103
+
104
+ self
60
105
  end
61
- def addMarks(marks)
62
- marks.each do |mark|
63
- addMark(mark);
106
+
107
+ def add_nodes(nodes)
108
+ @nodes.push nodes
109
+
110
+ self
111
+ end
112
+
113
+ def add_mark(mark)
114
+ @marks << mark
115
+
116
+ self
117
+ end
118
+
119
+ def add_marks(marks)
120
+ @marks.push marks
121
+
122
+ self
123
+ end
124
+
125
+ def replace_node(search_node, replace_node)
126
+ @nodes.each do |key, node_klass|
127
+ if node_klass == search_node
128
+ @nodes[key] = replace_node
129
+ end
64
130
  end
131
+
132
+ self
65
133
  end
66
134
 
67
- def render(hash)
68
- html = ""
69
- json = hash.to_json
70
- object = JSON.parse(json, object_class: OpenStruct)
71
- object.content.each do |node|
72
- html += renderNode(node)
135
+ def replace_mark(search_mark, replace_mark)
136
+ @marks.each do |key, mark_klass|
137
+ if mark_klass == search_mark
138
+ @marks[key] = replace_mark
139
+ end
73
140
  end
74
-
75
- html
141
+
142
+ self
76
143
  end
77
- private
78
- def renderNode(item)
79
- html = []
80
- if item.marks
81
- item.marks.each do |m|
82
- mark = get_matching_mark(m)
83
- html.push(renderOpeningTag(mark.tag)) if mark
144
+
145
+ private
146
+
147
+ def render_node(node, prev_node, next_node)
148
+ html = ''
149
+ render_klass = nil
150
+
151
+ if node&.marks
152
+ node.marks.each do |mark|
153
+ @marks.each do |klass|
154
+ render_klass = klass.new(mark)
155
+
156
+ if render_klass.matching && mark_should_open(mark, prev_node)
157
+ html << render_opening_tag(render_klass.tag)
158
+ end
84
159
  end
85
160
  end
86
-
87
- node = get_matching_node(item)
88
- html.push(renderOpeningTag(node.tag)) if node
161
+ end
89
162
 
90
- if item.content
91
- item.content.each do |content|
92
- html.push(renderNode(content))
93
- end
94
- elsif item.text
95
- html.push(item.text)
163
+ @nodes.each do |klass|
164
+ render_klass = klass.new(node)
165
+
166
+ if render_klass.matching
167
+ html << render_opening_tag(render_klass.tag)
168
+ break
96
169
  end
97
-
98
- html.push(renderClosingTag(node.tag)) if node
99
- if item.marks
100
- item.marks.reverse.each do |m|
101
- mark = get_matching_mark(m)
102
- html.push(renderClosingTag(mark.tag)) if mark
103
- end
170
+ end
171
+
172
+ if node&.content
173
+ node.content.each_with_index do |nested_node, index|
174
+ prev_nested_node = node.content[index - 1]
175
+ next_nested_node = node.content[index + 1]
176
+
177
+ html << render_node(nested_node, prev_nested_node, next_nested_node)
178
+ prev_node = nested_node
104
179
  end
105
- return html.join("");
180
+ elsif node&.text
181
+ html << CGI.escapeHTML(node.text)
182
+ elsif text = render_klass.text
183
+ html << text
106
184
  end
107
185
 
108
- def renderOpeningTag(tags)
109
- return "<#{tags}>" if tags.is_a? String
110
- all = tags.map do |tag|
111
- return "<#{tags}>" if tag.is_a? String
112
- h = "<#{tag[:tag]}"
113
- tag[:attrs].to_h.each_pair { |key, value| h += " #{key}=\"#{value}\"" } if tag[:attrs]
114
- "#{h}>"
186
+ @nodes.each do |klass|
187
+ render_klass = klass.new(node)
188
+
189
+ if render_klass.self_closing
190
+ next
191
+ end
192
+
193
+ if render_klass.matching
194
+ html << render_closing_tag(render_klass.tag)
195
+ end
115
196
  end
116
- return all.join('')
117
- end
118
197
 
119
- def renderClosingTag(tags)
120
- return "</#{tags}>" if tags.is_a? String
121
- all = tags.reverse.map do |tag|
122
- return "</#{tag}>" if tag.is_a? String
123
- "</#{tag[:tag]}>"
198
+ if node&.marks
199
+ node.marks.reverse.each do |mark|
200
+ @marks.each do |klass|
201
+ render_klass = klass.new(mark)
202
+
203
+ if render_klass.matching && mark_should_close(mark, next_node)
204
+ html << render_closing_tag(render_klass.tag)
205
+ end
206
+ end
207
+ end
124
208
  end
125
- return all.join('')
209
+
210
+ html
126
211
  end
127
212
 
128
- # Find which Node matches the Html Node
129
- def get_matching_node(item)
130
- return get_matching_class(item, @nodes)
213
+ def mark_should_open(mark, prev_node)
214
+ node_has_mark(prev_node, mark)
131
215
  end
132
- # Find which Mark matches the HtmlElement
133
- def get_matching_mark(item)
134
- return get_matching_class(item, @marks)
216
+
217
+ def mark_should_close(mark, next_node)
218
+ node_has_mark(next_node, mark)
135
219
  end
136
- # Find which class matches the HtmlElement
137
- def get_matching_class(node, classes)
138
- found = classes.select do |clazz|
139
- instance = clazz.new(node)
140
- if (instance.matching())
141
- return instance
220
+
221
+ def node_has_mark(node, mark)
222
+ return true unless node
223
+ return true if node.respond_to?(:marks)
224
+
225
+ # Other node has same mark
226
+ node.marks&.each do |other_mark|
227
+ if mark == other_mark
228
+ return false
142
229
  end
143
230
  end
144
- found.first
231
+
232
+ true
233
+ end
234
+
235
+ def render_opening_tag(tags)
236
+ tags = array_wrap(tags)
237
+
238
+ return nil if tags.empty?
239
+
240
+ tags.map do |tag|
241
+ if tag.is_a? String
242
+ "<#{tag}>"
243
+ else
244
+ tag = OpenStruct.new(tag) unless tag.is_a?(OpenStruct)
245
+
246
+ attrs = ''
247
+ if tag&.attrs
248
+ tag.attrs.each_pair do |attr, value|
249
+ attrs << " #{attr}=\"#{value}\""
250
+ end
251
+ end
252
+
253
+ "<#{tag.tag}#{attrs}>"
254
+ end
255
+ end.join
256
+ end
257
+
258
+ def render_closing_tag(tags)
259
+ tags = array_wrap(tags).reverse
260
+
261
+ return nil if tags.empty?
262
+
263
+ tags.map do |tag|
264
+ if tag.is_a? String
265
+ "</#{tag}>"
266
+ else
267
+ tag = OpenStruct.new(tag) unless tag.is_a?(OpenStruct)
268
+
269
+ "</#{tag.tag}>"
270
+ end
271
+ end.join
272
+ end
273
+
274
+ # From https://github.com/rails/rails/blob/5f3ff60084ab5d5921ca3499814e4697f8350ee7/activesupport/lib/active_support/core_ext/array/wrap.rb
275
+ def array_wrap(object)
276
+ if object.nil?
277
+ []
278
+ elsif object.respond_to?(:to_ary)
279
+ object.to_ary || [object]
280
+ else
281
+ [object]
282
+ end
145
283
  end
146
-
147
284
  end
148
285
  end
@@ -6,15 +6,15 @@ require "prosemirror_to_html/version"
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "prosemirror_to_html"
8
8
  spec.version = ProsemirrorToHtml::VERSION
9
- spec.authors = ["Brian Kimball"]
10
- spec.email = ["bvkimball@gmail.com"]
11
-
9
+ spec.authors = ["Hans Lemuet", "Brian Kimball"]
10
+ spec.email = ["hans@etamin.studio", "bvkimball@gmail.com"]
11
+
12
12
  spec.summary = %q{Takes ProseMirror compatible JSON and outputs HTML.}
13
13
  spec.description = %q{Takes ProseMirror compatible JSON and outputs HTML.}
14
- spec.homepage = "https://github.com/inputhq/prosemirror_to_html"
14
+ spec.homepage = "https://github.com/etaminstudio/prosemirror_to_html"
15
15
  spec.license = "MIT"
16
16
 
17
-
17
+
18
18
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
19
  # to allow pushing to a single host or delete this section to allow pushing to any host.
20
20
  # if spec.respond_to?(:metadata)
@@ -37,8 +37,8 @@ Gem::Specification.new do |spec|
37
37
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
38
38
  spec.require_paths = ["lib"]
39
39
 
40
- spec.add_development_dependency "bundler", "~> 2.0.1"
41
- spec.add_development_dependency "rake", "~> 10.0"
40
+ spec.add_development_dependency "bundler", "~> 2.1.4"
41
+ spec.add_development_dependency "rake", "~> 13.0"
42
42
  spec.add_development_dependency "rspec", "~> 3.0"
43
43
  spec.add_development_dependency "yard"
44
44
  spec.add_dependency "nokogiri"
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prosemirror_to_html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
+ - Hans Lemuet
7
8
  - Brian Kimball
8
- autorequire:
9
+ autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2019-04-20 00:00:00.000000000 Z
12
+ date: 2023-07-03 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
@@ -16,28 +17,28 @@ dependencies:
16
17
  requirements:
17
18
  - - "~>"
18
19
  - !ruby/object:Gem::Version
19
- version: 2.0.1
20
+ version: 2.1.4
20
21
  type: :development
21
22
  prerelease: false
22
23
  version_requirements: !ruby/object:Gem::Requirement
23
24
  requirements:
24
25
  - - "~>"
25
26
  - !ruby/object:Gem::Version
26
- version: 2.0.1
27
+ version: 2.1.4
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: rake
29
30
  requirement: !ruby/object:Gem::Requirement
30
31
  requirements:
31
32
  - - "~>"
32
33
  - !ruby/object:Gem::Version
33
- version: '10.0'
34
+ version: '13.0'
34
35
  type: :development
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
38
39
  - - "~>"
39
40
  - !ruby/object:Gem::Version
40
- version: '10.0'
41
+ version: '13.0'
41
42
  - !ruby/object:Gem::Dependency
42
43
  name: rspec
43
44
  requirement: !ruby/object:Gem::Requirement
@@ -82,6 +83,7 @@ dependencies:
82
83
  version: '0'
83
84
  description: Takes ProseMirror compatible JSON and outputs HTML.
84
85
  email:
86
+ - hans@etamin.studio
85
87
  - bvkimball@gmail.com
86
88
  executables: []
87
89
  extensions: []
@@ -91,6 +93,7 @@ files:
91
93
  - ".gitignore"
92
94
  - ".rspec"
93
95
  - ".travis.yml"
96
+ - CHANGELOG.md
94
97
  - CODE_OF_CONDUCT.md
95
98
  - Gemfile
96
99
  - Gemfile.lock
@@ -105,27 +108,34 @@ files:
105
108
  - lib/prosemirror_to_html/marks/italic.rb
106
109
  - lib/prosemirror_to_html/marks/link.rb
107
110
  - lib/prosemirror_to_html/marks/mark.rb
111
+ - lib/prosemirror_to_html/marks/strike.rb
112
+ - lib/prosemirror_to_html/marks/subscript.rb
113
+ - lib/prosemirror_to_html/marks/superscript.rb
114
+ - lib/prosemirror_to_html/marks/underline.rb
115
+ - lib/prosemirror_to_html/nodes/blockquote.rb
108
116
  - lib/prosemirror_to_html/nodes/bullet_list.rb
109
117
  - lib/prosemirror_to_html/nodes/code_block.rb
110
- - lib/prosemirror_to_html/nodes/code_block_wrapper.rb
111
118
  - lib/prosemirror_to_html/nodes/hard_break.rb
112
119
  - lib/prosemirror_to_html/nodes/heading.rb
120
+ - lib/prosemirror_to_html/nodes/horizontal_rule.rb
113
121
  - lib/prosemirror_to_html/nodes/image.rb
114
122
  - lib/prosemirror_to_html/nodes/list_item.rb
115
123
  - lib/prosemirror_to_html/nodes/node.rb
116
124
  - lib/prosemirror_to_html/nodes/ordered_list.rb
117
125
  - lib/prosemirror_to_html/nodes/paragraph.rb
118
- - lib/prosemirror_to_html/nodes/text.rb
119
- - lib/prosemirror_to_html/nodes/user.rb
126
+ - lib/prosemirror_to_html/nodes/table.rb
127
+ - lib/prosemirror_to_html/nodes/table_cell.rb
128
+ - lib/prosemirror_to_html/nodes/table_header.rb
129
+ - lib/prosemirror_to_html/nodes/table_row.rb
120
130
  - lib/prosemirror_to_html/version.rb
121
131
  - prosemirror_to_html.gemspec
122
132
  - scripts/package
123
133
  - scripts/release
124
- homepage: https://github.com/inputhq/prosemirror_to_html
134
+ homepage: https://github.com/etaminstudio/prosemirror_to_html
125
135
  licenses:
126
136
  - MIT
127
137
  metadata: {}
128
- post_install_message:
138
+ post_install_message:
129
139
  rdoc_options: []
130
140
  require_paths:
131
141
  - lib
@@ -140,9 +150,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
150
  - !ruby/object:Gem::Version
141
151
  version: '0'
142
152
  requirements: []
143
- rubyforge_project:
144
- rubygems_version: 2.7.6
145
- signing_key:
153
+ rubygems_version: 3.3.26
154
+ signing_key:
146
155
  specification_version: 4
147
156
  summary: Takes ProseMirror compatible JSON and outputs HTML.
148
157
  test_files: []
@@ -1,13 +0,0 @@
1
- module ProsemirrorToHtml
2
- module Nodes
3
- class CodeBlockWrapper < Node
4
- def matching
5
- @node.name === 'pre'
6
- end
7
-
8
- def data
9
- nil
10
- end
11
- end
12
- end
13
- end
@@ -1,14 +0,0 @@
1
- module ProsemirrorToHtml
2
- module Nodes
3
- class Text < Node
4
-
5
- def matching
6
- @node.type === 'text'
7
- end
8
-
9
- def tag
10
- @node.text
11
- end
12
- end
13
- end
14
- end
@@ -1,14 +0,0 @@
1
- module ProsemirrorToHtml
2
- module Nodes
3
- class User < Node
4
-
5
- def matching
6
- @node.natypeme === 'user'
7
- end
8
-
9
- def tag
10
- nil
11
- end
12
- end
13
- end
14
- end