markbridge 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 356955e6ba849a6acb08902465ed0d45c710020183d75eca66d3904b93995f3c
|
|
4
|
+
data.tar.gz: 4c1bf20ea2c024478cdfa6bbea5ceade531de96085a2cc911499a0c8d31d78ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0fbb3282126a07f194e4c833bc2694b91a64b877144e6ea0317ff2f62785a28dd144a969cc5d4a3fc1eda3306fa1416496cc478b6fe51ffe4862dba9f468a288
|
|
7
|
+
data.tar.gz: 0624ec779e99b904de91eb2d519b65ee7c123d2b8e8d51c659b4ce5005afc521bd2290e07517a7f9aaf5ea9e19998354b31e7a6818e27fe55dceb02da22cad41
|
|
@@ -32,8 +32,13 @@ module Markbridge
|
|
|
32
32
|
def register(tag_names, handler)
|
|
33
33
|
element_class = handler.element_class
|
|
34
34
|
Array(tag_names).each { |tag_name| @handlers[tag_name.to_s.downcase] = handler }
|
|
35
|
-
|
|
35
|
+
# The conditional write goes first. Both writes are independent and
|
|
36
|
+
# keyed by element_class, so the order makes no difference to a
|
|
37
|
+
# successful register. On a frozen registry it decides which
|
|
38
|
+
# collection raises, and only a write that can be skipped lets a
|
|
39
|
+
# spec reach the one behind it.
|
|
36
40
|
@auto_closeable_elements << element_class if handler.auto_closeable?
|
|
41
|
+
@element_handlers[element_class] = handler
|
|
37
42
|
self
|
|
38
43
|
end
|
|
39
44
|
|
|
@@ -70,9 +70,21 @@ module Markbridge
|
|
|
70
70
|
# a <pre> keep their semantics.
|
|
71
71
|
@preserve_depth = initial_preserve_depth(doc)
|
|
72
72
|
|
|
73
|
+
# Whitespace collapsing follows the browser rule (CSS Text
|
|
74
|
+
# §4.1.1): a collapsible space is dropped at the start of a
|
|
75
|
+
# line, at the end of a line, and right after another
|
|
76
|
+
# collapsible space — wherever the inline boundaries fall, so
|
|
77
|
+
# `<b>a </b> b` keeps one space and `<p><b>x </b></p>` none.
|
|
78
|
+
# A line starts at the parse root and on every block-level tag
|
|
79
|
+
# boundary. @space_tail is the element whose last child is a
|
|
80
|
+
# collapsible Text ending in a space (the candidate for the
|
|
81
|
+
# end-of-line trim), or nil.
|
|
82
|
+
@line_start = true
|
|
83
|
+
@space_tail = nil
|
|
84
|
+
|
|
73
85
|
# Process all nodes
|
|
74
86
|
children.each { |node| process_node(node, document) }
|
|
75
|
-
|
|
87
|
+
end_line
|
|
76
88
|
|
|
77
89
|
document
|
|
78
90
|
end
|
|
@@ -117,17 +129,27 @@ module Markbridge
|
|
|
117
129
|
|
|
118
130
|
if @preserve_depth.positive?
|
|
119
131
|
parent << AST::Text.new(text)
|
|
132
|
+
# Preserved whitespace is content: it neither starts a line
|
|
133
|
+
# nor collapses against a space that follows it.
|
|
134
|
+
@line_start = false
|
|
135
|
+
@space_tail = nil
|
|
120
136
|
return
|
|
121
137
|
end
|
|
122
138
|
|
|
123
|
-
text =
|
|
124
|
-
|
|
125
|
-
# matching the browser rule that whitespace at the beginning of a
|
|
126
|
-
# block (or before any inline content) is collapsed away.
|
|
127
|
-
text = text.lstrip if parent.children.empty?
|
|
139
|
+
text = collapse_whitespace(text)
|
|
140
|
+
text = text.lstrip if @line_start || @space_tail
|
|
128
141
|
return if text.empty?
|
|
129
142
|
|
|
130
143
|
parent << AST::Text.new(text)
|
|
144
|
+
@line_start = false
|
|
145
|
+
@space_tail = (parent if text.end_with?(" "))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Collapse runs of whitespace to a single space.
|
|
149
|
+
# @param text [String]
|
|
150
|
+
# @return [String]
|
|
151
|
+
def collapse_whitespace(text)
|
|
152
|
+
text.match?(COLLAPSIBLE_WHITESPACE) ? text.gsub(WHITESPACE_RUN, " ") : text
|
|
131
153
|
end
|
|
132
154
|
|
|
133
155
|
# Process an element node
|
|
@@ -137,19 +159,21 @@ module Markbridge
|
|
|
137
159
|
tag_name = node.name
|
|
138
160
|
return if IGNORED_TAGS.include?(tag_name)
|
|
139
161
|
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
|
|
162
|
+
# A block-level tag ends the line before it and the line inside
|
|
163
|
+
# it, matching browser behavior where whitespace collapses
|
|
164
|
+
# against the block boundary. Applies whether or not a handler
|
|
165
|
+
# is registered, so unknown tags like <div> or <section> still
|
|
166
|
+
# end lines.
|
|
167
|
+
block = @handlers.block_level_tags.include?(tag_name)
|
|
168
|
+
end_line if block
|
|
146
169
|
|
|
147
170
|
preserving = @handlers.whitespace_preserving_tags.include?(tag_name)
|
|
148
171
|
@preserve_depth += 1 if preserving
|
|
149
172
|
|
|
150
|
-
dispatch_element(node, tag_name, parent
|
|
173
|
+
dispatch_element(node, tag_name, parent)
|
|
151
174
|
|
|
152
175
|
@preserve_depth -= 1 if preserving
|
|
176
|
+
end_line if block
|
|
153
177
|
end
|
|
154
178
|
|
|
155
179
|
# Dispatch an element to its handler (or the unknown-tag path) and
|
|
@@ -157,18 +181,22 @@ module Markbridge
|
|
|
157
181
|
# @param node [Nokogiri::XML::Element]
|
|
158
182
|
# @param tag_name [String]
|
|
159
183
|
# @param parent [AST::Element]
|
|
160
|
-
|
|
161
|
-
def dispatch_element(node, tag_name, parent, preserving)
|
|
184
|
+
def dispatch_element(node, tag_name, parent)
|
|
162
185
|
handler = @handlers[tag_name]
|
|
163
186
|
return handle_unknown_tag(node, parent) unless handler
|
|
164
187
|
|
|
165
188
|
# Handler returns element if children should be processed, nil otherwise
|
|
189
|
+
size = parent.children.size
|
|
166
190
|
ast_element = handler.process(element: node, parent:)
|
|
167
191
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
192
|
+
if ast_element
|
|
193
|
+
process_children(node, ast_element)
|
|
194
|
+
elsif parent.children.size > size
|
|
195
|
+
# The handler appended a leaf (image, line break, ...), which
|
|
196
|
+
# is content on the current line like a word.
|
|
197
|
+
@line_start = false
|
|
198
|
+
@space_tail = nil
|
|
199
|
+
end
|
|
172
200
|
end
|
|
173
201
|
|
|
174
202
|
# Handle unknown tag by tracking it and ignoring the wrapper
|
|
@@ -180,6 +208,16 @@ module Markbridge
|
|
|
180
208
|
process_children(node, parent)
|
|
181
209
|
end
|
|
182
210
|
|
|
211
|
+
# End the current line: the collapsible space that closed it goes,
|
|
212
|
+
# and the next collapsible space starts a line. @space_tail is
|
|
213
|
+
# not cleared here: the trim is idempotent, so a stale tail is
|
|
214
|
+
# harmless until the next text or leaf on the new line resets it,
|
|
215
|
+
# and @line_start already covers the lstrip.
|
|
216
|
+
def end_line
|
|
217
|
+
trim_trailing_whitespace(@space_tail) if @space_tail
|
|
218
|
+
@line_start = true
|
|
219
|
+
end
|
|
220
|
+
|
|
183
221
|
# Number of whitespace-preserving elements enclosing the parse
|
|
184
222
|
# root, the root itself included. Computed once per parse; from
|
|
185
223
|
# there the counter is maintained during descent. Documents and
|
|
@@ -28,18 +28,25 @@ module Markbridge
|
|
|
28
28
|
|
|
29
29
|
if interface.html_mode?
|
|
30
30
|
%(<a href="#{HtmlEscaper.escape(href)}">#{text}</a>)
|
|
31
|
-
elsif element.bare? || text
|
|
31
|
+
elsif element.bare? || blank?(text)
|
|
32
32
|
# Url#bare? judges the AST (so label escaping can't confuse
|
|
33
33
|
# it); the rendered-text check additionally catches labels
|
|
34
|
-
# that render to nothing (e.g. an empty formatting child)
|
|
34
|
+
# that render to nothing (e.g. an empty formatting child)
|
|
35
|
+
# or to whitespace only, which wrap_inline would leave
|
|
36
|
+
# unlinked.
|
|
35
37
|
href
|
|
36
38
|
else
|
|
37
|
-
"[
|
|
39
|
+
interface.wrap_inline(text, "[", "](#{markdown_destination(href)})")
|
|
38
40
|
end
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
private
|
|
42
44
|
|
|
45
|
+
# Unicode-aware, matching the guard in RenderingInterface#wrap_inline.
|
|
46
|
+
def blank?(text)
|
|
47
|
+
!text.match?(/[^[:space:]]/)
|
|
48
|
+
end
|
|
49
|
+
|
|
43
50
|
# CommonMark link destinations cannot contain whitespace unless
|
|
44
51
|
# wrapped in <> — relevant for relative targets like MediaWiki
|
|
45
52
|
# page names ("Main Page").
|
data/lib/markbridge/version.rb
CHANGED