draftjs_exporter 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f8d59bea7ea1b40766a3e78d33535290d288026b
4
- data.tar.gz: 96f8e16bfede94708c613c5205fc6450d22f428e
3
+ metadata.gz: 09a55e5243dc77a0e6b9711abced8fd26cab0776
4
+ data.tar.gz: d0f789f42a140cfcc4bd92bd8f1aa653bd2e033a
5
5
  SHA512:
6
- metadata.gz: 0133625911008a1a5f663dc5356dd47c54c9fc3abd097ab6f6f52f770a89fd89c4f329827d24e416c83988f29acbd9abafc471fac1e08717c23e5f6eeeed43e4
7
- data.tar.gz: 4b6ca1fed16749d841f3ad4b58af395bb927a12ad5cf88b869a26901635a93c70f6042358b841c322f0311430d69c152a40685c55548dd891ef6c83c4bf9275b
6
+ metadata.gz: 5bf865cb2d2a3a1305e13698800d028c38695a694212cdd5534eb1bdeef4a40c04dadbaa5f1bfbc913f022cb64555a9ef864aa26e06a346b78afcb7be275061a
7
+ data.tar.gz: 565b824cbd6355dd65bef816aa553dca4ca9562b9981557594145bb8f797fb31b67221b97d0eefeeeb12370f322ece790e4538374d707af852a0ac8913b0f754
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
  require 'draftjs_exporter/entities/null'
3
+ require 'draftjs_exporter/error'
3
4
 
4
5
  module DraftjsExporter
6
+ class InvalidEntity < DraftjsExporter::Error; end
7
+
5
8
  class EntityState
6
9
  attr_reader :entity_decorators, :entity_map, :entity_stack, :root_element
7
10
 
@@ -40,7 +43,7 @@ module DraftjsExporter
40
43
  _element, expected_entity_details = entity_stack.last
41
44
 
42
45
  if expected_entity_details != entity_details
43
- raise "Invalid entity. Expected #{expected_entity_details.inspect} got #{entity_details.inspect}"
46
+ raise InvalidEntity, "Expected #{expected_entity_details.inspect} got #{entity_details.inspect}"
44
47
  end
45
48
 
46
49
  entity_stack.pop
@@ -0,0 +1,3 @@
1
+ module DraftjsExporter
2
+ class Error < StandardError; end
3
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'nokogiri'
3
+ require 'draftjs_exporter/wrapper_state'
3
4
  require 'draftjs_exporter/entity_state'
4
5
  require 'draftjs_exporter/style_state'
5
6
  require 'draftjs_exporter/command'
@@ -15,23 +16,17 @@ module DraftjsExporter
15
16
  end
16
17
 
17
18
  def call(content_state)
18
- content_state.fetch(:blocks, []).map { |block|
19
- content_state_block(block, content_state.fetch(:entityMap, {}))
20
- }.inject(:+)
19
+ wrapper_state = WrapperState.new(block_map)
20
+ content_state.fetch(:blocks, []).each do |block|
21
+ element = wrapper_state.element_for(block)
22
+ entity_map = content_state.fetch(:entityMap, {})
23
+ block_contents(element, block, entity_map)
24
+ end
25
+ wrapper_state.to_s
21
26
  end
22
27
 
23
28
  private
24
29
 
25
- def content_state_block(block, entity_map)
26
- document = Nokogiri::HTML::Document.new
27
- fragment = Nokogiri::HTML::DocumentFragment.new(document)
28
- type = block.fetch(:type, 'unstyled')
29
- element = document.create_element(*block_options(type)) { |e|
30
- block_contents(e, block, entity_map)
31
- }
32
- fragment.add_child(element).to_s
33
- end
34
-
35
30
  def block_contents(element, block, entity_map)
36
31
  style_state = StyleState.new(style_map)
37
32
  entity_state = EntityState.new(element, entity_decorators, entity_map)
@@ -45,18 +40,6 @@ module DraftjsExporter
45
40
  end
46
41
  end
47
42
 
48
- def block_options(type)
49
- options = block_map.fetch(type)
50
- return [options.fetch(:element)] unless options.key?(:wrapper)
51
-
52
- wrapper = options.fetch(:wrapper)
53
- name = wrapper[0]
54
- config = wrapper[1] || {}
55
- options = {}
56
- options[:class] = config.fetch(:className) if config.key?(:className)
57
- [name, options]
58
- end
59
-
60
43
  def add_node(element, text, state)
61
44
  document = element.document
62
45
  node = if state.text?
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module DraftjsExporter
3
- VERSION = '0.0.2'.freeze
3
+ VERSION = '0.0.3'.freeze
4
4
  end
@@ -0,0 +1,70 @@
1
+ module DraftjsExporter
2
+ class WrapperState
3
+ def initialize(block_map)
4
+ @block_map = block_map
5
+ @document = Nokogiri::HTML::Document.new
6
+ @fragment = Nokogiri::HTML::DocumentFragment.new(document)
7
+ reset_wrapper
8
+ end
9
+
10
+ def element_for(block)
11
+ type = block.fetch(:type, 'unstyled')
12
+ document.create_element(block_options(type)).tap do |e|
13
+ parent_for(type).add_child(e)
14
+ end
15
+ end
16
+
17
+ def to_s
18
+ fragment.to_s
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :fragment, :document, :block_map, :wrapper
24
+
25
+ def set_wrapper(element, options = {})
26
+ @wrapper = [element, options]
27
+ end
28
+
29
+ def wrapper_element
30
+ @wrapper[0] || fragment
31
+ end
32
+
33
+ def wrapper_options
34
+ @wrapper[1]
35
+ end
36
+
37
+ def parent_for(type)
38
+ options = block_map.fetch(type)
39
+ return reset_wrapper unless options.key?(:wrapper)
40
+
41
+ new_options = nokogiri_options(*options.fetch(:wrapper))
42
+ return wrapper_element if new_options == wrapper_options
43
+
44
+ create_wrapper(new_options)
45
+ end
46
+
47
+ def reset_wrapper
48
+ set_wrapper(fragment)
49
+ wrapper_element
50
+ end
51
+
52
+ def nokogiri_options(element_name, element_attributes)
53
+ config = element_attributes || {}
54
+ options = {}
55
+ options[:class] = config.fetch(:className) if config.key?(:className)
56
+ [element_name, options]
57
+ end
58
+
59
+ def block_options(type)
60
+ block_map.fetch(type).fetch(:element)
61
+ end
62
+
63
+ def create_wrapper(options)
64
+ document.create_element(*options).tap do |new_element|
65
+ reset_wrapper.add_child(new_element)
66
+ set_wrapper(new_element, options)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -24,55 +24,181 @@ RSpec.describe DraftjsExporter::HTML do
24
24
  end
25
25
 
26
26
  describe '#call' do
27
- it 'decodes the content_state to html' do
28
- input = {
29
- entityMap: {
30
- '0' => {
31
- type: 'LINK',
32
- mutability: 'MUTABLE',
33
- data: {
34
- url: 'http://example.com'
27
+ context 'with different blocks' do
28
+ it 'decodes the content_state to html' do
29
+ input = {
30
+ entityMap: {},
31
+ blocks: [
32
+ {
33
+ key: '5s7g9',
34
+ text: 'Header',
35
+ type: 'header-one',
36
+ depth: 0,
37
+ inlineStyleRanges: [],
38
+ entityRanges: []
39
+ },
40
+ {
41
+ key: 'dem5p',
42
+ text: 'some paragraph text',
43
+ type: 'unstyled',
44
+ depth: 0,
45
+ inlineStyleRanges: [],
46
+ entityRanges: []
47
+ }
48
+ ]
49
+ }
50
+
51
+ expected_output = <<-OUTPUT.strip
52
+ <h1>Header</h1><div>some paragraph text</div>
53
+ OUTPUT
54
+
55
+ expect(mapper.call(input)).to eq(expected_output)
56
+ end
57
+ end
58
+
59
+ context 'with inline styles' do
60
+ it 'decodes the content_state to html' do
61
+ input = {
62
+ entityMap: {},
63
+ blocks: [
64
+ {
65
+ key: 'dem5p',
66
+ text: 'some paragraph text',
67
+ type: 'unstyled',
68
+ depth: 0,
69
+ inlineStyleRanges: [
70
+ {
71
+ offset: 0,
72
+ length: 4,
73
+ style: 'ITALIC'
74
+ }
75
+ ],
76
+ entityRanges: []
77
+ }
78
+ ]
79
+ }
80
+
81
+ expected_output = <<-OUTPUT.strip
82
+ <div>
83
+ <span style="fontStyle: italic;">some</span> paragraph text</div>
84
+ OUTPUT
85
+
86
+ expect(mapper.call(input)).to eq(expected_output)
87
+ end
88
+ end
89
+
90
+ context 'with entities' do
91
+ it 'decodes the content_state to html' do
92
+ input = {
93
+ entityMap: {
94
+ '0' => {
95
+ type: 'LINK',
96
+ mutability: 'MUTABLE',
97
+ data: {
98
+ url: 'http://example.com'
99
+ }
35
100
  }
36
- }
37
- },
38
- blocks: [
39
- {
40
- key: '5s7g9',
41
- text: 'Header',
42
- type: 'header-one',
43
- depth: 0,
44
- inlineStyleRanges: [],
45
- entityRanges: []
46
101
  },
47
- {
48
- key: 'dem5p',
49
- text: 'some paragraph text',
50
- type: 'unstyled',
51
- depth: 0,
52
- inlineStyleRanges: [
53
- {
54
- offset: 0,
55
- length: 4,
56
- style: 'ITALIC'
102
+ blocks: [
103
+ {
104
+ key: 'dem5p',
105
+ text: 'some paragraph text',
106
+ type: 'unstyled',
107
+ depth: 0,
108
+ inlineStyleRanges: [],
109
+ entityRanges: [
110
+ {
111
+ offset: 5,
112
+ length: 9,
113
+ key: 0
114
+ }
115
+ ]
116
+ }
117
+ ]
118
+ }
119
+
120
+ expected_output = <<-OUTPUT.strip
121
+ <div>some <a href="http://example.com">paragraph</a> text</div>
122
+ OUTPUT
123
+
124
+ expect(mapper.call(input)).to eq(expected_output)
125
+ end
126
+
127
+ it 'throws an error if entities cross over' do
128
+ input = {
129
+ entityMap: {
130
+ '0' => {
131
+ type: 'LINK',
132
+ mutability: 'MUTABLE',
133
+ data: {
134
+ url: 'http://foo.example.com'
57
135
  }
58
- ],
59
- entityRanges: [
60
- {
61
- offset: 5,
62
- length: 9,
63
- key: 0
136
+ },
137
+ '1' => {
138
+ type: 'LINK',
139
+ mutability: 'MUTABLE',
140
+ data: {
141
+ url: 'http://bar.example.com'
64
142
  }
65
- ]
66
- }
67
- ]
68
- }
143
+ }
144
+ },
145
+ blocks: [
146
+ {
147
+ key: 'dem5p',
148
+ text: 'some paragraph text',
149
+ type: 'unstyled',
150
+ depth: 0,
151
+ inlineStyleRanges: [],
152
+ entityRanges: [
153
+ {
154
+ offset: 5,
155
+ length: 9,
156
+ key: 0
157
+ },
158
+ {
159
+ offset: 2,
160
+ length: 9,
161
+ key: 1
162
+ }
163
+ ]
164
+ }
165
+ ]
166
+ }
167
+
168
+ expect { mapper.call(input) }.to raise_error(DraftjsExporter::InvalidEntity)
169
+ end
170
+ end
171
+
172
+ context 'with wrapped blocks' do
173
+ it 'decodes the content_state to html' do
174
+ input = {
175
+ entityMap: {},
176
+ blocks: [
177
+ {
178
+ key: 'dem5p',
179
+ text: 'item1',
180
+ type: 'unordered-list-item',
181
+ depth: 0,
182
+ inlineStyleRanges: [],
183
+ entityRanges: []
184
+ },
185
+ {
186
+ key: 'dem5p',
187
+ text: 'item2',
188
+ type: 'unordered-list-item',
189
+ depth: 0,
190
+ inlineStyleRanges: [],
191
+ entityRanges: []
192
+ }
193
+ ]
194
+ }
69
195
 
70
- expected_output = <<-OUTPUT.strip
71
- <h1>Header</h1><div>
72
- <span style="fontStyle: italic;">some</span> <a href="http://example.com">paragraph</a> text</div>
73
- OUTPUT
196
+ expected_output = <<-EOS.strip
197
+ <ul class="public-DraftStyleDefault-ul">\n<li>item1</li>\n<li>item2</li>\n</ul>
198
+ EOS
74
199
 
75
- expect(mapper.call(input)).to eq(expected_output)
200
+ expect(mapper.call(input)).to eq(expected_output)
201
+ end
76
202
  end
77
203
  end
78
204
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: draftjs_exporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Theo Cushion
@@ -126,9 +126,11 @@ files:
126
126
  - lib/draftjs_exporter/entities/link.rb
127
127
  - lib/draftjs_exporter/entities/null.rb
128
128
  - lib/draftjs_exporter/entity_state.rb
129
+ - lib/draftjs_exporter/error.rb
129
130
  - lib/draftjs_exporter/html.rb
130
131
  - lib/draftjs_exporter/style_state.rb
131
132
  - lib/draftjs_exporter/version.rb
133
+ - lib/draftjs_exporter/wrapper_state.rb
132
134
  - spec/integrations/html_spec.rb
133
135
  - spec/integrations/requires_spec.rb
134
136
  - spec/spec_helper.rb
@@ -152,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
154
  version: '0'
153
155
  requirements: []
154
156
  rubyforge_project:
155
- rubygems_version: 2.5.1
157
+ rubygems_version: 2.2.5
156
158
  signing_key:
157
159
  specification_version: 4
158
160
  summary: Export Draft.js content state into HTML