draftjs_html 0.24.0 → 0.26.0

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
  SHA256:
3
- metadata.gz: 7c2703fb050f796abd4f8af851d16b654a2ab84f03e5f8865c92b373b2acfefa
4
- data.tar.gz: eced6f85cfefd34f4c50c7fc383526675f26dd7c212a4f7de145721d254b1a28
3
+ metadata.gz: 9fe4601ed10ebae8924fe906ffad4cd56bebf7867ec80182876ad0a1b5a3b739
4
+ data.tar.gz: 5d14c45c7192c936fbbe524a72c4886acddaf20f1f2dff5ccf9c1ce3d8de8a5f
5
5
  SHA512:
6
- metadata.gz: 432d7b8900153f89f8ba506ded86208fe71a4b6b832911693059e0f57cb31b93412ef8fa5a40a8f7d857b370b65e8a523f29d0029dfa2ee8f917ebae2235827e
7
- data.tar.gz: 69878d4330ef0d4947f1d95ed165720c0a59b8c0d54793d2e28aad8f5fea40754f95afacc1fc1a29c5b5b9f03e02399d9502924c7c580e7bc953b674f6292644
6
+ metadata.gz: 38f78c86afbac0244a8eb967be90c6b647001e6a3bbbe3a6648190a45ac9cbecc2359c45f1fee5f995ed9584d037b2c337b8e267dece3c38e15a16a4dde8b775
7
+ data.tar.gz: 249423024673740842728d7b5cb8ca4ef1aa9bec1ee521be4402e21d5d89afa7f36563232de9c6af62831ae9cac3768c654537d75a8dbb44e25735f4d2dc0ac1
@@ -0,0 +1,36 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_dispatch:
7
+ # schedule:
8
+ # - cron: '42 5 * * *'
9
+
10
+ jobs:
11
+ test:
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ ruby: [ '3.0' ]
16
+
17
+ runs-on: ubuntu-latest
18
+ name: Ruby ${{matrix.ruby}}
19
+ container: ruby:${{matrix.ruby}}
20
+
21
+ steps:
22
+ - uses: actions/checkout@v3
23
+
24
+ - name: Show ruby Version
25
+ run: |
26
+ ruby -v
27
+
28
+ - name: Install Modules
29
+ run: |
30
+ ./bin/setup
31
+
32
+ - name: Run tests
33
+ run: |
34
+ rake spec
35
+
36
+
data/README.md CHANGED
@@ -229,14 +229,43 @@ The callable should return a Hash with symbol keys. The supported values are:
229
229
  - `data` (optional, default `{}`)
230
230
  - an arbitrary data-bag (Hash) of entity data
231
231
 
232
- #### `:is_semantic_markup:`
232
+ ### Spec support
233
233
 
234
- Defaults to `true`.
234
+ To make it easier to test our own code, we've developed a few RSpec matchers that
235
+ make normalization and comparison of raw DraftJS use the RawBuilder DSL. To take
236
+ advantage of this, you can (for RSpec only, currently) include the following in
237
+ your `spec_helper`, or equivalent.
235
238
 
236
- By setting to `false`, the user is stating they want to treat `div` tags as semantic,
237
- block-level tags. In some markup (emails, for example), there are no semantic tags
238
- (read, no `p` tags), so the only indications of whitespace and structure come from
239
- `div` tags. This flag will flush content wrapped in a `div` as a DraftJS block.
239
+ ```ruby
240
+ require 'draftjs_html/spec_support/rspec'
241
+
242
+ RSpec.configure do |config|
243
+ config.include DraftjsHtml::SpecSupport::RSpecMatchers
244
+ end
245
+ ```
246
+
247
+ Then, later in your tests, you can assert on raw DraftJS "json" like this:
248
+
249
+ ```ruby
250
+ my_raw_draftjs_hash = { blocks: [{ key: 'a-random-uuid', text: 'Hi!' }], entityMap: {} }
251
+
252
+ expect(my_raw_draftjs_hash).to eq_raw_draftjs {
253
+ text_block 'Hi!'
254
+ }
255
+ ```
256
+
257
+ This will normalize the `key` values and other IDs to make _actual_ differences
258
+ easier to spot.
259
+
260
+ There's also a matcher called `eq_raw_draftjs_ignoring_keys` that takes an explicit
261
+ raw DraftJS hash on both sides.
262
+
263
+ ```ruby
264
+ my_raw_draftjs_hash = { blocks: [{ key: 'a-random-uuid', text: 'Hi!' }], entityMap: {} }
265
+ my_other_draftjs_hash = { blocks: [{ key: 'a-different-random-uuid', text: 'Hi!' }], entityMap: {} }
266
+
267
+ expect(my_raw_draftjs_hash).to eq_raw_draftjs_ignoring_keys my_other_draftjs_hash
268
+ ```
240
269
 
241
270
  ## Development
242
271
 
@@ -60,6 +60,10 @@ module DraftjsHtml
60
60
  size > 0
61
61
  end
62
62
 
63
+ def more_than_whitespace?
64
+ !text.match?(/^[[:space:]]*$/)
65
+ end
66
+
63
67
  def atomic?
64
68
  @chars.any? && @chars.all?(&:atomic?)
65
69
  end
@@ -1,16 +1,16 @@
1
1
  module DraftjsHtml
2
2
  class FromHtml < Nokogiri::XML::SAX::Document
3
3
  class DepthStack
4
- def initialize(is_semantic_markup: true)
4
+ def initialize(options)
5
5
  @stack = []
6
6
  @nodes = []
7
7
  @list_depth = -1
8
8
  @active_styles = []
9
- @is_semantic_markup = is_semantic_markup
9
+ @options = options
10
10
  end
11
11
 
12
12
  def push(tagname, attrs)
13
- @stack << PendingBlock.from_tag(tagname, attrs, @nodes.dup, @list_depth, is_semantic_markup: @is_semantic_markup)
13
+ @stack << PendingBlock.from_tag(tagname, attrs, @nodes.dup, @list_depth, options: @options)
14
14
  track_block_node(tagname)
15
15
  end
16
16
 
@@ -1,8 +1,9 @@
1
1
  module DraftjsHtml
2
2
  class FromHtml < Nokogiri::XML::SAX::Document
3
3
  INLINE_STYLE_ELEMENTS = HtmlDefaults::HTML_STYLE_TAGS_TO_STYLE.keys.freeze
4
- LIST_PARENT_ELEMENTS = %w[ol ul table].freeze
5
- INLINE_NON_STYLE_ELEMENTS = %w[a abbr cite font img output q samp span thead tbody td time var].freeze
4
+ LIST_PARENT_ELEMENTS = %w[ol ul].freeze
5
+ INLINE_NON_STYLE_ELEMENTS = %w[a abbr cite font img output q samp span table thead tbody td time var].freeze
6
6
  BLOCK_CONTENT_ELEMENTS = %w[p dl h1 h2 h3 h4 h5 h6].freeze
7
+ FLUSH_BOUNDARIES = %w[OPENING div ol ul li tr].freeze
7
8
  end
8
9
  end
@@ -1,7 +1,7 @@
1
1
  module DraftjsHtml
2
2
  class FromHtml < Nokogiri::XML::SAX::Document
3
- PendingBlock = Struct.new(:tagname, :attrs, :chars, :entities, :pending_entities, :parent_tagnames, :depth, :is_semantic_markup, keyword_init: true) do
4
- def self.from_tag(name, attrs, parent_tagnames, depth, is_semantic_markup: true)
3
+ PendingBlock = Struct.new(:tagname, :attrs, :chars, :entities, :pending_entities, :parent_tagnames, :depth, :options, keyword_init: true) do
4
+ def self.from_tag(name, attrs, parent_tagnames, depth, options: {})
5
5
  self.new(
6
6
  tagname: name,
7
7
  attrs: attrs,
@@ -10,7 +10,7 @@ module DraftjsHtml
10
10
  pending_entities: [],
11
11
  depth: depth,
12
12
  parent_tagnames: parent_tagnames,
13
- is_semantic_markup: is_semantic_markup,
13
+ options: options
14
14
  )
15
15
  end
16
16
 
@@ -23,9 +23,7 @@ module DraftjsHtml
23
23
  end
24
24
 
25
25
  def flushable?
26
- %w[OPENING ol ul li table].include?(parent_tagnames.last) ||
27
- (parent_tagnames.last == 'div' && tagname != 'div') ||
28
- (!is_semantic_markup && tagname == 'div')
26
+ FLUSH_BOUNDARIES.include?(parent_tagnames.last)
29
27
  end
30
28
 
31
29
  def consume(other_pending_block)
@@ -35,21 +33,23 @@ module DraftjsHtml
35
33
  end
36
34
 
37
35
  def flush_to(draftjs)
38
- if text_buffer.any?
39
- text_buffer.each_line do |line|
40
- block_type = line.atomic? ? 'atomic' : block_name
41
- draftjs.typed_block(block_type, line.text, depth: [depth, 0].max)
36
+ text_buffer.each_line do |line|
37
+ block_type = line.atomic? ? 'atomic' : block_name
38
+ next unless should_flush_line?(line)
42
39
 
43
- line.entity_ranges.each do |entity_range|
44
- entity = entity_range.entity
45
- draftjs.apply_entity entity[:type], entity_range.range, data: entity[:data], mutability: entity.fetch(:mutability, 'IMMUTABLE')
46
- end
40
+ draftjs.typed_block(block_type, line.text, depth: [depth, 0].max)
47
41
 
48
- line.style_ranges.each do |style_range|
49
- draftjs.inline_style(style_range.style, style_range.range)
50
- end
42
+ line.entity_ranges.each do |entity_range|
43
+ entity = entity_range.entity
44
+ draftjs.apply_entity entity[:type], entity_range.range, data: entity[:data], mutability: entity.fetch(:mutability, 'IMMUTABLE')
45
+ end
46
+
47
+ line.style_ranges.each do |style_range|
48
+ draftjs.inline_style(style_range.style, style_range.range)
51
49
  end
52
50
  end
51
+
52
+ self.text_buffer = CharList.new
53
53
  end
54
54
 
55
55
  def block_name
@@ -65,6 +65,13 @@ module DraftjsHtml
65
65
  def text_buffer=(other)
66
66
  self[:chars] = other
67
67
  end
68
+
69
+ def should_flush_line?(chars)
70
+ return true if chars.atomic?
71
+ return true unless options[:squeeze_whitespace_blocks]
72
+
73
+ options[:squeeze_whitespace_blocks] && chars.more_than_whitespace?
74
+ end
68
75
  end
69
76
  end
70
77
  end
@@ -11,8 +11,8 @@ module DraftjsHtml
11
11
  def initialize(options = {})
12
12
  @draftjs = Draftjs::RawBuilder.new
13
13
  @parser = Nokogiri::HTML4::SAX::Parser.new(self)
14
- @depth_stack = DepthStack.new(is_semantic_markup: options.fetch(:is_semantic_markup, true))
15
14
  @options = ensure_options!(options.dup)
15
+ @depth_stack = DepthStack.new(@options)
16
16
  end
17
17
 
18
18
  def convert(raw_html)
@@ -56,6 +56,7 @@ module DraftjsHtml
56
56
  when *FromHtml::LIST_PARENT_ELEMENTS
57
57
  @depth_stack.push_parent(name, attrs)
58
58
  else
59
+ @depth_stack.flush_to(@draftjs) if FromHtml::FLUSH_BOUNDARIES.include?(name)
59
60
  @depth_stack.push(name, attributes)
60
61
  end
61
62
 
@@ -101,6 +102,7 @@ module DraftjsHtml
101
102
  when 'img' then { type: 'IMAGE', mutability: 'IMMUTABLE', atomic: true, data: attrs }
102
103
  end
103
104
  }
105
+ opts[:squeeze_whitespace_blocks] ||= false
104
106
  opts
105
107
  end
106
108
  end
@@ -1,6 +1,7 @@
1
1
  module DraftjsHtml
2
2
  module HtmlDefaults
3
3
  BLOCK_TYPE_TO_HTML = {
4
+ 'article' => 'p',
4
5
  'paragraph' => 'p',
5
6
  'unstyled' => 'p',
6
7
  'header-one' => 'h1',
@@ -0,0 +1,42 @@
1
+ require 'rspec/expectations'
2
+ require 'draftjs_html/spec_support'
3
+
4
+ module DraftjsHtml
5
+ module SpecSupport
6
+ module RSpecMatchers
7
+ extend RSpec::Matchers::DSL
8
+
9
+ matcher :eq_raw_draftjs do |expected|
10
+ include DraftjsHtml::SpecSupport::KeyNormalization
11
+ match do |actual|
12
+ @raw_draftjs = normalize_keys(DraftjsHtml::Draftjs::RawBuilder.build(&block_arg))
13
+ @actual = normalize_keys(actual)
14
+
15
+ values_match?(@raw_draftjs, @actual)
16
+ end
17
+
18
+ diffable
19
+
20
+ def expected
21
+ @raw_draftjs
22
+ end
23
+ end
24
+
25
+ matcher :eq_raw_draftjs_ignoring_keys do |expected|
26
+ include DraftjsHtml::SpecSupport::KeyNormalization
27
+ match do |actual|
28
+ @raw_draftjs = normalize_keys(expected)
29
+ @actual = normalize_keys(actual)
30
+
31
+ values_match?(@raw_draftjs, @actual)
32
+ end
33
+
34
+ diffable
35
+
36
+ def expected
37
+ @raw_draftjs
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DraftjsHtml
4
+ module SpecSupport
5
+ module KeyNormalization
6
+ def normalize_keys(raw_draftjs)
7
+ draftjs = DraftjsHtml::Draftjs::Content.parse(raw_draftjs)
8
+ draftjs.blocks.each.with_index do |block, i|
9
+ block.key = "block-key-#{i}"
10
+ end
11
+
12
+ draftjs.entity_map.keys.each.with_index do |entity_key, i|
13
+ new_key = "entity-key-#{i}"
14
+ draftjs.entity_map[new_key] = draftjs.entity_map.delete(entity_key)
15
+ matching_entity_ranges = draftjs.blocks.flat_map { |block| block.raw_entity_ranges.select { |entity_range| entity_range['key'] == entity_key } }
16
+ matching_entity_ranges.each { |range| range['key'] = new_key }
17
+ end
18
+
19
+ DraftjsHtml::Draftjs::ToRaw.new.convert(draftjs)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DraftjsHtml
4
- VERSION = "0.24.0"
4
+ VERSION = "0.26.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: draftjs_html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - TJ Taylor
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-19 00:00:00.000000000 Z
11
+ date: 2023-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -45,6 +45,7 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
+ - ".github/workflows/ci.yml"
48
49
  - ".gitignore"
49
50
  - ".rspec"
50
51
  - ".travis.yml"
@@ -76,6 +77,8 @@ files:
76
77
  - lib/draftjs_html/html_depth.rb
77
78
  - lib/draftjs_html/node.rb
78
79
  - lib/draftjs_html/overrideable_map.rb
80
+ - lib/draftjs_html/spec_support.rb
81
+ - lib/draftjs_html/spec_support/rspec.rb
79
82
  - lib/draftjs_html/to_html.rb
80
83
  - lib/draftjs_html/version.rb
81
84
  homepage: https://github.com/dugancathal/draftjs_html