Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit 9d6cb01

Browse files
authored
Merge pull request #288 from coderplanets/editor-table
feat(editor-export): table block
2 parents b2a3b78 + 51e7afc commit 9d6cb01

File tree

11 files changed

+345
-8
lines changed

11 files changed

+345
-8
lines changed

lib/helper/converter/editor_to_html/class.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ defmodule Helper.Converter.EditorToHTML.Class do
4343
"indent_1" => "list-indent-1",
4444
"indent_2" => "list-indent-2",
4545
"indent_3" => "list-indent-3"
46+
},
47+
"table" => %{
48+
"wrapper" => "table-wrapper",
49+
"cell" => "table-cell",
50+
"th_header" => "th_header",
51+
"td_stripe" => "td_stripe",
52+
"align_center" => "align-center",
53+
"align_left" => "align-left",
54+
"align_right" => "align-right"
4655
}
4756
}
4857
end
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
defmodule Helper.Converter.EditorToHTML.Frags.Table do
2+
@moduledoc """
3+
parse editor.js's block fragments, use for test too
4+
5+
see https://editorjs.io/
6+
"""
7+
alias Helper.Converter.EditorToHTML.Class
8+
alias Helper.Types, as: T
9+
10+
@class get_in(Class.article(), ["table"])
11+
12+
@spec get_row([T.editor_table_cell()]) :: T.html()
13+
def get_row(group_items) do
14+
tr_content =
15+
Enum.reduce(group_items, "", fn item, acc ->
16+
cell_type = if Map.has_key?(item, "isHeader"), do: :th, else: :td
17+
acc <> frag(cell_type, item)
18+
end)
19+
20+
~s(<tr>#{tr_content}</tr>)
21+
end
22+
23+
@spec frag(:td, T.editor_table_cell()) :: T.html()
24+
def frag(:td, item) do
25+
%{
26+
"align" => align,
27+
"isStripe" => is_stripe,
28+
"text" => text
29+
} = item
30+
31+
cell_class = @class["cell"]
32+
align_class = get_align_class(align)
33+
scripe_class = if is_stripe, do: @class["td_stripe"], else: ""
34+
35+
case Map.has_key?(item, "width") do
36+
true ->
37+
style = ~s(width: #{Map.get(item, "width")})
38+
39+
~s(<td class="#{scripe_class}" style="#{style}"><div class="#{cell_class} #{align_class}">#{
40+
text
41+
}</div></td>)
42+
43+
false ->
44+
~s(<td class="#{scripe_class}"><div class="#{cell_class} #{align_class}">#{text}</div></td>)
45+
end
46+
end
47+
48+
@spec frag(:th, T.editor_table_cell()) :: T.html()
49+
def frag(:th, item) do
50+
%{"align" => align, "text" => text} = item
51+
52+
cell_class = @class["cell"]
53+
align_class = get_align_class(align)
54+
header_class = @class["th_header"]
55+
56+
~s(<th class="#{header_class}"><div class="#{cell_class} #{align_class}">#{text}</div></th>)
57+
end
58+
59+
defp get_align_class("center"), do: @class["align_center"]
60+
defp get_align_class("right"), do: @class["align_right"]
61+
defp get_align_class(_), do: @class["align_left"]
62+
end

lib/helper/converter/editor_to_html/frontend_test/script.js

Lines changed: 6 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/helper/converter/editor_to_html/frontend_test/styles.css

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,76 @@ body {
204204
}
205205

206206
/* list block end */
207+
208+
/* table block */
209+
.article-viewer-wrapper table {
210+
width: 100%;
211+
border-collapse: collapse;
212+
table-layout: fixed;
213+
border-spacing: 0;
214+
box-sizing: border-box;
215+
216+
display: table;
217+
text-indent: initial;
218+
white-space: normal;
219+
line-height: normal;
220+
font-weight: normal;
221+
font-size: medium;
222+
font-style: normal;
223+
color: -internal-quirk-inherit;
224+
text-align: start;
225+
border-color: grey;
226+
font-variant: normal;
227+
}
228+
229+
.article-viewer-wrapper tbody {
230+
display: table-row-group;
231+
vertical-align: middle;
232+
border-color: inherit;
233+
}
234+
235+
.article-viewer-wrapper tr {
236+
display: table-row;
237+
vertical-align: inherit;
238+
border-color: inherit;
239+
}
240+
241+
.article-viewer-wrapper table tbody tr th,
242+
table td {
243+
position: relative;
244+
border: 1px solid #dbdbe2;
245+
font-size: 15px;
246+
}
247+
248+
td {
249+
display: table-cell;
250+
vertical-align: inherit;
251+
}
252+
253+
.th_header {
254+
padding-top: 18px;
255+
font-weight: bold;
256+
border-bottom: 2px solid #dbdbe2 !important;
257+
display: table-cell;
258+
vertical-align: inherit;
259+
}
260+
.td_stripe {
261+
background: #f7f7f7;
262+
}
263+
264+
.article-viewer-wrapper table .table-cell {
265+
padding: 12px 10px;
266+
vertical-align: top;
267+
}
268+
269+
.article-viewer-wrapper table .align-left {
270+
text-align: left;
271+
}
272+
.article-viewer-wrapper table .align-center {
273+
text-align: center;
274+
}
275+
.article-viewer-wrapper table .align-right {
276+
text-align: right;
277+
}
278+
279+
/* table block end */

lib/helper/converter/editor_to_html/index.ex

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,29 @@ defmodule Helper.Converter.EditorToHTML do
6565
~s(<div class="#{list_wrapper_class}">#{items_content}</div>)
6666
end
6767

68+
defp parse_block(%{"type" => "table", "data" => data}) do
69+
%{"items" => items, "columnCount" => column_count} = data
70+
71+
# IO.inspect(column_count, label: "the fuck column_count")
72+
73+
groupped_items = Enum.chunk_every(items, column_count)
74+
75+
rows_content =
76+
Enum.reduce(groupped_items, "", fn group, acc ->
77+
acc <> Frags.Table.get_row(group)
78+
end)
79+
80+
table_wrapper_class = get_in(@root_class, ["table", "wrapper"])
81+
82+
~s(<div class="#{table_wrapper_class}">
83+
<table>
84+
<tbody>
85+
#{rows_content}
86+
</tbody>
87+
</table>
88+
</div>)
89+
end
90+
6891
# defp parse_block(%{"type" => "image", "data" => data}) do
6992
# url = get_in(data, ["file", "url"])
7093

lib/helper/converter/editor_to_html/validator/editor_schema.ex

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ defmodule Helper.Converter.EditorToHTML.Validator.EditorSchema do
99
@valid_list_label_type ["green", "red", "warn", "default"]
1010
@valid_list_indent [0, 1, 2, 3]
1111

12+
# table
13+
@valid_table_align ["left", "center", "right"]
14+
1215
def get("editor") do
1316
%{
1417
"time" => [:number],
@@ -43,6 +46,19 @@ defmodule Helper.Converter.EditorToHTML.Validator.EditorSchema do
4346
]
4447
end
4548

49+
def get("table") do
50+
[
51+
parent: %{"columnCount" => [:number], "items" => [:list]},
52+
item: %{
53+
"text" => [:string],
54+
"align" => [enum: @valid_table_align],
55+
"isStripe" => [:boolean],
56+
"isHeader" => [:boolean, required: false],
57+
"width" => [:string, required: false]
58+
}
59+
]
60+
end
61+
4662
def get(_) do
4763
%{}
4864
end

lib/helper/converter/editor_to_html/validator/index.ex

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ defmodule Helper.Converter.EditorToHTML.Validator do
88

99
# blocks with no children items
1010
@simple_blocks ["header", "paragraph"]
11-
# blocks with "mode" and "items" fields
12-
@complex_blocks ["list"]
11+
# blocks with "items" fields
12+
@complex_blocks ["list", "table"]
1313

14+
@spec is_valid(map) :: {:error, map} | {:ok, :pass}
1415
def is_valid(data) when is_map(data) do
1516
with {:ok, _} <- validate_editor_fmt(data),
1617
blocks <- Map.get(data, "blocks") do
@@ -82,7 +83,10 @@ defmodule Helper.Converter.EditorToHTML.Validator do
8283

8384
defp validate_with(block, parent_schema, item_schema, data) do
8485
with {:ok, _} <- validate_with(block, parent_schema, data),
85-
%{"mode" => mode, "items" => items} <- data do
86+
%{"items" => items} <- data do
87+
# most block with items will have mode field, if not, just ignore
88+
mode = Map.get(data, "mode", "")
89+
8690
Enum.each(items, fn item ->
8791
validate_with("#{block}(#{mode})", item_schema, item)
8892
end)

lib/helper/converter/html_sanitizer.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ defmodule Helper.Converter.HtmlSanitizer do
3838
Meta.allow_tag_with_these_attributes("ol", ["class"])
3939
Meta.allow_tag_with_these_attributes("li", ["class"])
4040

41+
# table
42+
Meta.allow_tag_with_these_attributes("table", [])
43+
Meta.allow_tag_with_these_attributes("tbody", [])
44+
Meta.allow_tag_with_these_attributes("tr", [])
45+
Meta.allow_tag_with_these_attributes("th", ["class"])
46+
Meta.allow_tag_with_these_attributes("td", ["class", "style"])
47+
4148
Meta.allow_tag_with_these_attributes("svg", [
4249
"t",
4350
"p-id",

lib/helper/types.ex

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,22 @@ defmodule Helper.Types do
5959
required(:text) => String.t(),
6060
prefixIndex: String.t()
6161
}
62+
63+
@typedoc """
64+
editor.js's Table align type
65+
"""
66+
@type editor_table_align :: :center | :left | :right
67+
68+
@typedoc """
69+
editor.js's Table td type
70+
"""
71+
@type editor_table_cell :: %{
72+
required(:text) => String.t(),
73+
required(:align) => editor_table_align,
74+
isStripe: Boolean.t(),
75+
isHeader: Boolean.t()
76+
}
77+
6278
@typedoc """
6379
html fragment
6480
"""

test/helper/converter/editor_to_html_test/header_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ defmodule GroupherServer.Test.Helper.Converter.EditorToHTML.Header do
7171
],
7272
"version" => "2.15.0"
7373
}
74-
@tag :wip2
74+
@tag :wip
7575
test "full header parse should work" do
7676
{:ok, editor_string} = Jason.encode(@editor_json)
7777
{:ok, converted} = Parser.to_html(editor_string)
@@ -88,7 +88,7 @@ defmodule GroupherServer.Test.Helper.Converter.EditorToHTML.Header do
8888
"time" => 1_567_250_876_713,
8989
"version" => "2.15.0"
9090
}
91-
@tag :wip2
91+
@tag :wip
9292
test "optional field should valid properly" do
9393
json =
9494
Map.merge(@editor_json, %{

0 commit comments

Comments
 (0)