prosemirror 0.1.0 → 0.3.0
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +69 -46
- data/ROADMAP.md +14 -10
- data/TYPES.md +218 -0
- data/lib/prosemirror/content_match.rb +241 -0
- data/lib/prosemirror/html/builder.rb +154 -0
- data/lib/prosemirror/html/element.rb +84 -0
- data/lib/prosemirror/html/entities.rb +87 -0
- data/lib/prosemirror/html/entities.txt +2231 -0
- data/lib/prosemirror/html/selector.rb +95 -0
- data/lib/prosemirror/html/splitter.rb +68 -0
- data/lib/prosemirror/html/text.rb +23 -0
- data/lib/prosemirror/html_parser.rb +503 -0
- data/lib/prosemirror/json_parser.rb +1 -12
- data/lib/prosemirror/mark_type.rb +11 -0
- data/lib/prosemirror/markdown/builder.rb +200 -0
- data/lib/prosemirror/marks/basic/code.rb +16 -0
- data/lib/prosemirror/marks/basic/em.rb +4 -0
- data/lib/prosemirror/marks/basic/link.rb +1 -0
- data/lib/prosemirror/marks/basic/strong.rb +4 -0
- data/lib/prosemirror/marks/bold.rb +8 -0
- data/lib/prosemirror/marks/code.rb +5 -0
- data/lib/prosemirror/marks/highlight.rb +3 -1
- data/lib/prosemirror/marks/italic.rb +4 -0
- data/lib/prosemirror/marks/link.rb +1 -0
- data/lib/prosemirror/marks/strike.rb +5 -0
- data/lib/prosemirror/marks/subscript.rb +2 -0
- data/lib/prosemirror/marks/superscript.rb +2 -0
- data/lib/prosemirror/marks/underline.rb +3 -0
- data/lib/prosemirror/node.rb +12 -0
- data/lib/prosemirror/node_type.rb +22 -0
- data/lib/prosemirror/nodes/basic/code_block.rb +1 -0
- data/lib/prosemirror/nodes/basic/image.rb +1 -0
- data/lib/prosemirror/nodes/basic/ordered_list.rb +4 -1
- data/lib/prosemirror/nodes/blockquote.rb +1 -0
- data/lib/prosemirror/nodes/bullet_list.rb +1 -0
- data/lib/prosemirror/nodes/code_block.rb +6 -1
- data/lib/prosemirror/nodes/hard_break.rb +2 -0
- data/lib/prosemirror/nodes/heading.rb +1 -0
- data/lib/prosemirror/nodes/horizontal_rule.rb +1 -0
- data/lib/prosemirror/nodes/image.rb +1 -0
- data/lib/prosemirror/nodes/list_item.rb +1 -0
- data/lib/prosemirror/nodes/ordered_list.rb +20 -2
- data/lib/prosemirror/nodes/paragraph.rb +1 -0
- data/lib/prosemirror/nodes/table.rb +1 -0
- data/lib/prosemirror/nodes/table_cell.rb +12 -2
- data/lib/prosemirror/nodes/table_header.rb +2 -0
- data/lib/prosemirror/nodes/table_row.rb +1 -0
- data/lib/prosemirror/parse_rule.rb +50 -0
- data/lib/prosemirror/schema.rb +87 -15
- data/lib/prosemirror/type_definition.rb +34 -4
- data/lib/prosemirror/utf8.rb +16 -0
- data/lib/prosemirror/version.rb +1 -1
- data/lib/prosemirror.rb +22 -1
- metadata +15 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prosemirror
|
|
4
|
+
# How to recognize a node or a mark in HTML, as ProseMirror's ParseRule:
|
|
5
|
+
# https://prosemirror.net/docs/ref/#model.ParseRule
|
|
6
|
+
#
|
|
7
|
+
# - `tag`: a CSS selector the element must match (see HTML::Selector), or
|
|
8
|
+
# - `style`: a CSS property (`"font-style"`), or a property and value (`"font-style=italic"`), for marks;
|
|
9
|
+
# - `attrs`: attributes to give the node or mark;
|
|
10
|
+
# - `get_attrs`: a block called with the element (or the style's value), returning attributes, nil for
|
|
11
|
+
# the defaults, or false when the rule doesn't match;
|
|
12
|
+
# - `priority` (default 50): rules with a higher priority are tried first;
|
|
13
|
+
# - `consuming` (default true): false lets the following rules match the element too;
|
|
14
|
+
# - `context`: the parents the rule needs, as `"list_item/"` or `"blockquote//"`;
|
|
15
|
+
# - `ignore`: skip the element and its content;
|
|
16
|
+
# - `skip`: skip the element, but parse its content;
|
|
17
|
+
# - `close_parent`: close the current node;
|
|
18
|
+
# - `content_element`: a selector for the descendant holding the content;
|
|
19
|
+
# - `get_content`: a block called with the element and the schema, returning the nodes to use as content;
|
|
20
|
+
# - `preserve_whitespace`: true to keep spaces, `:full` to also keep newlines;
|
|
21
|
+
# - `clear_mark`: for style rules, true to remove the type's marks, or a block called with each mark.
|
|
22
|
+
ParseRule = Data.define(
|
|
23
|
+
:type, :tag, :style, :attrs, :get_attrs, :priority, :consuming, :context, :ignore, :skip,
|
|
24
|
+
:close_parent, :content_element, :get_content, :preserve_whitespace, :clear_mark
|
|
25
|
+
) do
|
|
26
|
+
def initialize(type:, tag: nil, style: nil, attrs: nil, get_attrs: nil, priority: 50, consuming: true,
|
|
27
|
+
context: nil, ignore: false, skip: false, close_parent: false, content_element: nil, get_content: nil,
|
|
28
|
+
preserve_whitespace: nil, clear_mark: nil)
|
|
29
|
+
raise ArgumentError, "a parse rule needs a tag or a style" if tag.nil? == style.nil?
|
|
30
|
+
|
|
31
|
+
HTML::Selector.parse(tag) if tag
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def node?
|
|
36
|
+
type < NodeType
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# The style's property, without the value.
|
|
40
|
+
def style_property
|
|
41
|
+
style&.split("=", 2)&.first
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Whether a style rule applies to this property and value.
|
|
45
|
+
def style_matches?(property, value)
|
|
46
|
+
name, expected = style.split("=", 2)
|
|
47
|
+
name == property && (expected.nil? || expected == value)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/prosemirror/schema.rb
CHANGED
|
@@ -32,8 +32,9 @@ module Prosemirror
|
|
|
32
32
|
Nodes::OrderedList, Nodes::ListItem, Nodes::CodeBlock, Nodes::HardBreak, Nodes::HorizontalRule,
|
|
33
33
|
Nodes::Image, Nodes::Table, Nodes::TableRow, Nodes::TableHeader, Nodes::TableCell
|
|
34
34
|
],
|
|
35
|
+
# In Tiptap's order, which sorts and nests marks.
|
|
35
36
|
marks: [
|
|
36
|
-
Marks::Link, Marks::Bold, Marks::
|
|
37
|
+
Marks::Link, Marks::Bold, Marks::Code, Marks::Italic, Marks::Strike, Marks::Underline,
|
|
37
38
|
Marks::Subscript, Marks::Superscript, Marks::Highlight
|
|
38
39
|
],
|
|
39
40
|
**
|
|
@@ -48,7 +49,7 @@ module Prosemirror
|
|
|
48
49
|
Nodes::Basic::CodeBlock, Nodes::Text, Nodes::Basic::Image, Nodes::HardBreak, Nodes::Basic::OrderedList,
|
|
49
50
|
Nodes::BulletList, Nodes::ListItem
|
|
50
51
|
],
|
|
51
|
-
marks: [Marks::Basic::Link, Marks::Basic::Em, Marks::Basic::Strong, Marks::Code],
|
|
52
|
+
marks: [Marks::Basic::Link, Marks::Basic::Em, Marks::Basic::Strong, Marks::Basic::Code],
|
|
52
53
|
**
|
|
53
54
|
)
|
|
54
55
|
end
|
|
@@ -57,9 +58,32 @@ module Prosemirror
|
|
|
57
58
|
@node_lookup = lookup(@nodes)
|
|
58
59
|
@mark_lookup = lookup(@marks)
|
|
59
60
|
@textblocks = @nodes.to_h { |type| [type, textblock_type?(type)] }
|
|
61
|
+
@content_matches = @nodes.to_h { |type| [type, ContentMatch.compile(type.content, self)] }
|
|
60
62
|
raise ArgumentError, "the schema has no #{@top_node} node type" unless node_type(@top_node)
|
|
61
63
|
end
|
|
62
64
|
|
|
65
|
+
# The start state of a node type's content expression.
|
|
66
|
+
def content_match(type)
|
|
67
|
+
@content_matches.fetch(type)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# The node types with this name or in this group, in schema order.
|
|
71
|
+
def node_types_named(name)
|
|
72
|
+
@nodes.select { |type| type.type_name == name || type.group.include?(name) }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# A node of this type, created empty and filled with the content it requires, or nil when its
|
|
76
|
+
# type, or one it requires, has required attributes.
|
|
77
|
+
def create_and_fill(type)
|
|
78
|
+
return nil if type.required_attrs?
|
|
79
|
+
|
|
80
|
+
fill = content_match(type).fill_before([], self, to_end: true)
|
|
81
|
+
content = fill&.map { |child| create_and_fill(child) }
|
|
82
|
+
return nil if content.nil? || content.include?(nil)
|
|
83
|
+
|
|
84
|
+
Node.new(type: type.type_name, attrs: type.default_attrs, content: content)
|
|
85
|
+
end
|
|
86
|
+
|
|
63
87
|
# A copy of the schema with other options.
|
|
64
88
|
def with_options(**)
|
|
65
89
|
self.class.new(**to_h, **)
|
|
@@ -88,11 +112,72 @@ module Prosemirror
|
|
|
88
112
|
Document.new(JSONParser.new(self).parse(json), schema: self)
|
|
89
113
|
end
|
|
90
114
|
|
|
115
|
+
# Build a document from HTML, with the parse rules of the schema's types. Needs the `herb` gem.
|
|
116
|
+
def parse_html(html)
|
|
117
|
+
Document.new(HTMLParser.new(self).parse(html), schema: self)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Build a document from Markdown, with the parse rules of the schema's types. Needs the `commonmarker` gem.
|
|
121
|
+
def parse_markdown(markdown)
|
|
122
|
+
Document.new(HTMLParser.new(self).parse_element(Markdown::Builder.new.call(markdown)), schema: self)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Build a document from plain text: blank lines separate paragraphs, and other line breaks become the
|
|
126
|
+
# schema's line break node, like `hard_break`, or spaces without one. Spaces are kept.
|
|
127
|
+
def parse_text(text)
|
|
128
|
+
paragraph = node_type(:paragraph) || @nodes.find { |type| textblock?(type) }
|
|
129
|
+
linebreak = @nodes.find(&:linebreak_replacement?)
|
|
130
|
+
separator = linebreak ? {"type" => linebreak.type_name.to_s} : {"type" => "text", "text" => " "}
|
|
131
|
+
blocks = UTF8.string(text).gsub(/\r\n?/, "\n").split(/\n[ \t]*\n/).map { |block| block.gsub(/\A\n+|\n+\z/, "") }
|
|
132
|
+
content = blocks.reject { |block| block.strip.empty? }.map do |block|
|
|
133
|
+
inline = block.split("\n").each_with_index.flat_map do |line, index|
|
|
134
|
+
[(separator if index.positive?), ({"type" => "text", "text" => line} unless line.empty?)].compact
|
|
135
|
+
end
|
|
136
|
+
{"type" => paragraph.type_name.to_s, "content" => inline}
|
|
137
|
+
end
|
|
138
|
+
parse({"type" => @top_node.to_s, "content" => content.empty? ? [{"type" => paragraph.type_name.to_s}] : content})
|
|
139
|
+
end
|
|
140
|
+
|
|
91
141
|
# The type name as written in JSON.
|
|
92
142
|
def json_type_name(name)
|
|
93
143
|
(@case == :camel) ? Naming.camel(name) : name.to_s
|
|
94
144
|
end
|
|
95
145
|
|
|
146
|
+
# The set of marks with this mark added, in schema order, as ProseMirror's `Mark#addToSet`: a mark
|
|
147
|
+
# replaces the marks it excludes, and isn't added when a mark of the set excludes it.
|
|
148
|
+
def add_mark(mark, set)
|
|
149
|
+
type = mark_type(mark.type)
|
|
150
|
+
result = []
|
|
151
|
+
placed = false
|
|
152
|
+
set.each do |other|
|
|
153
|
+
return set if other == mark
|
|
154
|
+
|
|
155
|
+
other_type = mark_type(other.type)
|
|
156
|
+
next if type.excludes?(other_type)
|
|
157
|
+
return set if other_type.excludes?(type)
|
|
158
|
+
|
|
159
|
+
if !placed && mark_rank(other.type) > mark_rank(mark.type)
|
|
160
|
+
result << mark
|
|
161
|
+
placed = true
|
|
162
|
+
end
|
|
163
|
+
result << other
|
|
164
|
+
end
|
|
165
|
+
result << mark unless placed
|
|
166
|
+
result
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Whether a URL's scheme is allowed, or the URL is relative. Browsers ignore leading control characters
|
|
170
|
+
# and spaces, and tabs and newlines anywhere in a URL.
|
|
171
|
+
def allowed_url?(url)
|
|
172
|
+
return false unless url.is_a?(String)
|
|
173
|
+
|
|
174
|
+
normalized = url.delete("\t\n\r").sub(/\A[\x00-\x20]+/, "")
|
|
175
|
+
scheme = normalized[%r{\A([^/?#]*):}, 1]
|
|
176
|
+
return true if scheme.nil?
|
|
177
|
+
|
|
178
|
+
scheme.match?(/\A[a-z][a-z\d+.-]*\z/i) && @url_schemes.include?(scheme.downcase)
|
|
179
|
+
end
|
|
180
|
+
|
|
96
181
|
# The order of marks in a node. Marks of unknown types come last.
|
|
97
182
|
def mark_rank(name)
|
|
98
183
|
@marks.index(mark_type(name)) || @marks.size
|
|
@@ -158,19 +243,6 @@ module Prosemirror
|
|
|
158
243
|
end
|
|
159
244
|
end
|
|
160
245
|
|
|
161
|
-
def node_types_named(name)
|
|
162
|
-
@nodes.select { |type| type.type_name == name || type.group.include?(name) }
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# Browsers ignore leading control characters and spaces, and tabs and newlines anywhere in a URL.
|
|
166
|
-
def allowed_url?(url)
|
|
167
|
-
normalized = url.delete("\t\n\r").sub(/\A[\x00-\x20]+/, "")
|
|
168
|
-
scheme = normalized[%r{\A([^/?#]*):}, 1]
|
|
169
|
-
return true if scheme.nil?
|
|
170
|
-
|
|
171
|
-
scheme.match?(/\A[a-z][a-z\d+.-]*\z/i) && @url_schemes.include?(scheme.downcase)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
246
|
# Declared attributes with their JSON names, then the unknown ones, as they were.
|
|
175
247
|
def serialize_node_attrs(node)
|
|
176
248
|
type = node_type(node.type)
|
|
@@ -18,14 +18,34 @@ module Prosemirror
|
|
|
18
18
|
inherited_setting(:@aliases, [])
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
# Declare an attribute. Same as Literal's `prop`, with
|
|
21
|
+
# Declare an attribute. Same as Literal's `prop`, with these options:
|
|
22
22
|
# - `json:` the attribute name in JSON, when it differs from the property name (`"textAlign"`);
|
|
23
|
-
# - `aliases:` other JSON names accepted on input (`["order"]`)
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
# - `aliases:` other JSON names accepted on input (`["order"]`);
|
|
24
|
+
# - `parse_html:` a block reading the attribute from an HTML element, when importing HTML. By default,
|
|
25
|
+
# the HTML attribute with the JSON name is read.
|
|
26
|
+
def prop(name, type, kind = :keyword, json: nil, aliases: [], parse_html: nil, **, &)
|
|
27
|
+
attribute_names[name] = {json: (json || name).to_s, aliases: aliases.map(&:to_s), parse_html:}.freeze
|
|
26
28
|
super(name, type, kind, **, &)
|
|
27
29
|
end
|
|
28
30
|
|
|
31
|
+
# Declare how to recognize this type in HTML. See ParseRule for the options. The block, if given, is the
|
|
32
|
+
# rule's `get_attrs`. A subclass that declares rules replaces the rules of its parent.
|
|
33
|
+
def parse_html(tag: nil, style: nil, **options, &get_attrs)
|
|
34
|
+
(@parse_rules ||= []) << ParseRule.new(type: self, tag:, style:, get_attrs:, **options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def parse_rules
|
|
38
|
+
inherited_setting(:@parse_rules, [])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# The attributes read from an HTML element, by JSON name, without the missing ones.
|
|
42
|
+
def attrs_from_html(element)
|
|
43
|
+
attribute_names.each_value.with_object({}) do |names, attrs|
|
|
44
|
+
value = names[:parse_html] ? names[:parse_html].call(element) : element[names[:json]]
|
|
45
|
+
attrs[names[:json]] = value unless value.nil?
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
29
49
|
def attribute_names
|
|
30
50
|
@attribute_names ||= concrete_superclass ? concrete_superclass.attribute_names.dup : {}
|
|
31
51
|
end
|
|
@@ -54,6 +74,16 @@ module Prosemirror
|
|
|
54
74
|
end
|
|
55
75
|
end
|
|
56
76
|
|
|
77
|
+
# Whether an attribute has no default, so that a node of this type can't be created empty.
|
|
78
|
+
def required_attrs?
|
|
79
|
+
literal_properties.any? { |property| !optional_attribute?(property) }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The attributes of a node of this type created empty: the defaults.
|
|
83
|
+
def default_attrs
|
|
84
|
+
build_attrs({}, report: ->(_) {})
|
|
85
|
+
end
|
|
86
|
+
|
|
57
87
|
# The JSON attributes this type doesn't declare, with String keys, so that `to_h` gives them back.
|
|
58
88
|
def unknown_attrs(given)
|
|
59
89
|
return {} unless given.is_a?(Hash)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prosemirror
|
|
4
|
+
# Imported HTML, Markdown and text, as valid UTF-8.
|
|
5
|
+
module UTF8
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
# The value as a UTF-8 String: nil becomes empty, other encodings are read as UTF-8 (a binary string
|
|
9
|
+
# from a file or an HTTP body), and invalid bytes become U+FFFD, as browsers do.
|
|
10
|
+
def string(value)
|
|
11
|
+
string = value.to_s
|
|
12
|
+
string = string.dup.force_encoding(Encoding::UTF_8) unless string.encoding == Encoding::UTF_8
|
|
13
|
+
string.valid_encoding? ? string : string.scrub
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/prosemirror/version.rb
CHANGED
data/lib/prosemirror.rb
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Phlex 2.4.1 checks attribute values against Date without loading it. Remove once a release includes the fix:
|
|
4
|
+
# https://github.com/yippee-fun/phlex/issues/974
|
|
5
|
+
require "date"
|
|
3
6
|
require "json"
|
|
4
7
|
require "literal"
|
|
5
8
|
require "phlex"
|
|
6
9
|
require "zeitwerk"
|
|
7
10
|
|
|
8
11
|
loader = Zeitwerk::Loader.for_gem
|
|
9
|
-
loader.inflector.inflect(
|
|
12
|
+
loader.inflector.inflect(
|
|
13
|
+
"html" => "HTML", "html_parser" => "HTMLParser", "html_renderer" => "HTMLRenderer", "json_parser" => "JSONParser",
|
|
14
|
+
"utf8" => "UTF8"
|
|
15
|
+
)
|
|
10
16
|
loader.setup
|
|
11
17
|
|
|
12
18
|
# Render ProseMirror and Tiptap documents.
|
|
@@ -35,5 +41,20 @@ module Prosemirror
|
|
|
35
41
|
def parse(json, schema: self.schema)
|
|
36
42
|
schema.parse(json)
|
|
37
43
|
end
|
|
44
|
+
|
|
45
|
+
# Build a document from HTML, with the schema's parse rules. Needs the `herb` gem.
|
|
46
|
+
def from_html(html, schema: self.schema)
|
|
47
|
+
schema.parse_html(html)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Build a document from Markdown, with the schema's parse rules. Needs the `commonmarker` gem.
|
|
51
|
+
def from_markdown(markdown, schema: self.schema)
|
|
52
|
+
schema.parse_markdown(markdown)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Build a document from plain text: blank lines separate paragraphs, other line breaks become hard breaks.
|
|
56
|
+
def from_text(text, schema: self.schema)
|
|
57
|
+
schema.parse_text(text)
|
|
58
|
+
end
|
|
38
59
|
end
|
|
39
60
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: prosemirror
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hans Lemuet
|
|
@@ -64,14 +64,26 @@ files:
|
|
|
64
64
|
- LICENSE.txt
|
|
65
65
|
- README.md
|
|
66
66
|
- ROADMAP.md
|
|
67
|
+
- TYPES.md
|
|
67
68
|
- lib/prosemirror.rb
|
|
68
69
|
- lib/prosemirror/coerce.rb
|
|
69
70
|
- lib/prosemirror/content_expression.rb
|
|
71
|
+
- lib/prosemirror/content_match.rb
|
|
70
72
|
- lib/prosemirror/document.rb
|
|
73
|
+
- lib/prosemirror/html/builder.rb
|
|
74
|
+
- lib/prosemirror/html/element.rb
|
|
75
|
+
- lib/prosemirror/html/entities.rb
|
|
76
|
+
- lib/prosemirror/html/entities.txt
|
|
77
|
+
- lib/prosemirror/html/selector.rb
|
|
78
|
+
- lib/prosemirror/html/splitter.rb
|
|
79
|
+
- lib/prosemirror/html/text.rb
|
|
80
|
+
- lib/prosemirror/html_parser.rb
|
|
71
81
|
- lib/prosemirror/html_renderer.rb
|
|
72
82
|
- lib/prosemirror/json_parser.rb
|
|
73
83
|
- lib/prosemirror/mark.rb
|
|
74
84
|
- lib/prosemirror/mark_type.rb
|
|
85
|
+
- lib/prosemirror/markdown/builder.rb
|
|
86
|
+
- lib/prosemirror/marks/basic/code.rb
|
|
75
87
|
- lib/prosemirror/marks/basic/em.rb
|
|
76
88
|
- lib/prosemirror/marks/basic/link.rb
|
|
77
89
|
- lib/prosemirror/marks/basic/strong.rb
|
|
@@ -106,10 +118,12 @@ files:
|
|
|
106
118
|
- lib/prosemirror/nodes/table_header.rb
|
|
107
119
|
- lib/prosemirror/nodes/table_row.rb
|
|
108
120
|
- lib/prosemirror/nodes/text.rb
|
|
121
|
+
- lib/prosemirror/parse_rule.rb
|
|
109
122
|
- lib/prosemirror/rendering.rb
|
|
110
123
|
- lib/prosemirror/schema.rb
|
|
111
124
|
- lib/prosemirror/text_serializer.rb
|
|
112
125
|
- lib/prosemirror/type_definition.rb
|
|
126
|
+
- lib/prosemirror/utf8.rb
|
|
113
127
|
- lib/prosemirror/version.rb
|
|
114
128
|
- sig/prosemirror.rbs
|
|
115
129
|
homepage: https://github.com/etaminstudio/prosemirror
|