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

Commit 5f839e7

Browse files
committed
feat(editor-export): add quote block parse && test
1 parent 31a6911 commit 5f839e7

File tree

11 files changed

+316
-4
lines changed

11 files changed

+316
-4
lines changed

lib/helper/converter/editor_to_html/class.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ defmodule Helper.Converter.EditorToHTML.Class do
2222
"eyebrow_title" => "eyebrow-title",
2323
"footer_title" => "footer-title"
2424
},
25+
# quote block
26+
"quote" => %{
27+
"short_wrapper" => "quote-short",
28+
"long_wrapper" => "quote-long",
29+
"text" => "quote__text",
30+
"caption" => "quote-caption",
31+
"caption_line" => "quote-caption__line",
32+
"caption_text" => "quote-caption__text"
33+
},
2534
# list
2635
"list" => %{
2736
"wrapper" => "list-wrapper",
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
defmodule Helper.Converter.EditorToHTML.Frags.Quote do
2+
@moduledoc """
3+
parse editor.js's block fragments, use for test too
4+
5+
see https://editorjs.io/
6+
"""
7+
import Helper.Validator.Guards, only: [g_none_empty_str: 1]
8+
9+
alias Helper.Types, as: T
10+
alias Helper.Converter.EditorToHTML.Class
11+
12+
@class get_in(Class.article(), ["quote"])
13+
14+
@spec get(T.editor_quote()) :: T.html()
15+
def get(%{"mode" => "short", "text" => text}) do
16+
wrapper_class = @class["short_wrapper"]
17+
text_class = @class["text"]
18+
19+
~s(<blockquote class="#{wrapper_class}">
20+
<div class="#{text_class}">#{text}</div>
21+
</blockquote>)
22+
end
23+
24+
def get(%{"mode" => "long", "text" => text, "caption" => caption})
25+
when g_none_empty_str(caption) do
26+
wrapper_class = @class["long_wrapper"]
27+
text_class = @class["text"]
28+
29+
caption = frag(:caption, caption)
30+
31+
~s(<blockquote class="#{wrapper_class}">
32+
<div class="#{text_class}">#{text}</div>
33+
#{caption}
34+
</blockquote>)
35+
end
36+
37+
def get(%{"mode" => "long", "text" => text}) do
38+
wrapper_class = @class["long_wrapper"]
39+
text_class = @class["text"]
40+
41+
~s(<blockquote class="#{wrapper_class}">
42+
<div class="#{text_class}">#{text}</div>
43+
</blockquote>)
44+
end
45+
46+
def frag(:caption, caption) do
47+
caption_class = @class["caption"]
48+
caption_line_class = @class["caption_line"]
49+
caption_text_class = @class["caption_text"]
50+
51+
~s(<div class="#{caption_class}">
52+
<div class="#{caption_line_class}"/>
53+
<div class="#{caption_text_class}">#{caption}</div>
54+
</div>)
55+
end
56+
end

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

Lines changed: 5 additions & 2 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: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,3 +277,92 @@ td {
277277
}
278278

279279
/* table block end */
280+
281+
/* quote block */
282+
283+
.article-viewer-wrapper .quote-short {
284+
margin-left: 15px;
285+
min-height: 0;
286+
border: none;
287+
border-radius: 0;
288+
border-left: 4px solid;
289+
border-left-color: #388ae5;
290+
color: grey;
291+
box-shadow: none;
292+
}
293+
294+
.article-viewer-wrapper .quote__text {
295+
line-height: 1.8em;
296+
min-height: 30px;
297+
border: none;
298+
border-radius: 0;
299+
color: grey;
300+
box-shadow: none;
301+
padding: 10px 12px;
302+
outline: none;
303+
width: 100%;
304+
box-sizing: border-box;
305+
}
306+
307+
.article-viewer-wrapper .quote-long {
308+
position: relative;
309+
border: 2px solid;
310+
border-left: 1px solid;
311+
border-right: 1px solid;
312+
border-bottom: 1px solid;
313+
border-color: lightgrey;
314+
margin: 15px;
315+
margin-left: 22px;
316+
margin-right: 42px;
317+
min-height: 140px;
318+
padding: 6px 30px;
319+
padding-bottom: 60px;
320+
border-top-right-radius: 12px;
321+
border-bottom-left-radius: 12px;
322+
}
323+
324+
.article-viewer-wrapper .quote-long::before {
325+
position: absolute;
326+
content: "\201C";
327+
font-size: 50px;
328+
color: #e8e7e7;
329+
left: -16px;
330+
top: 9px;
331+
height: 35px;
332+
background: white;
333+
}
334+
335+
.article-viewer-wrapper .quote-long::after {
336+
position: absolute;
337+
content: "\201D";
338+
font-size: 42px;
339+
color: #e8e7e7;
340+
right: -13px;
341+
bottom: 9px;
342+
height: 28px;
343+
background: white;
344+
}
345+
346+
.article-viewer-wrapper .quote-caption {
347+
position: absolute;
348+
bottom: 10px;
349+
right: 42px;
350+
display: flex;
351+
align-items: center;
352+
}
353+
354+
.article-viewer-wrapper .quote-caption__line {
355+
width: 30px;
356+
height: 1px;
357+
margin-right: 10px;
358+
background: #bbb;
359+
}
360+
361+
.article-viewer-wrapper .quote-caption__text {
362+
cursor: text;
363+
outline: none;
364+
color: grey;
365+
font-size: 14px;
366+
}
367+
368+
/* quote block end */

lib/helper/converter/editor_to_html/index.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ defmodule Helper.Converter.EditorToHTML do
4545

4646
defp parse_block(%{"type" => "header", "data" => data}), do: Frags.Header.get(data)
4747

48+
defp parse_block(%{"type" => "quote", "data" => data}), do: Frags.Quote.get(data)
49+
4850
defp parse_block(%{"type" => "list", "data" => data}) do
4951
%{"items" => items, "mode" => mode} = data
5052

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ defmodule Helper.Converter.EditorToHTML.Validator.EditorSchema do
44
# header
55
@valid_header_level [1, 2, 3]
66

7+
# quote
8+
@valid_quote_mode ["short", "long"]
9+
710
# list
811
@valid_list_mode ["checklist", "order_list", "unorder_list"]
912
@valid_list_label_type ["green", "red", "warn", "default"]
@@ -12,6 +15,7 @@ defmodule Helper.Converter.EditorToHTML.Validator.EditorSchema do
1215
# table
1316
@valid_table_align ["left", "center", "right"]
1417

18+
@spec get(String.t()) :: map
1519
def get("editor") do
1620
%{
1721
"time" => [:number],
@@ -31,6 +35,15 @@ defmodule Helper.Converter.EditorToHTML.Validator.EditorSchema do
3135

3236
def get("paragraph"), do: %{"text" => [:string]}
3337

38+
def get("quote") do
39+
%{
40+
"text" => [:string],
41+
"mode" => [enum: @valid_quote_mode],
42+
"caption" => [:string, required: false]
43+
}
44+
end
45+
46+
@spec get(String.t()) :: [parent: map, item: map]
3447
def get("list") do
3548
[
3649
parent: %{"mode" => [enum: @valid_list_mode], "items" => [:list]},

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ defmodule Helper.Converter.EditorToHTML.Validator do
77
alias Converter.EditorToHTML.Validator.EditorSchema
88

99
# blocks with no children items
10-
@simple_blocks ["header", "paragraph"]
10+
@normal_blocks ["header", "paragraph", "quote"]
1111
# blocks with "items" fields
1212
@complex_blocks ["list", "table"]
1313

@@ -54,7 +54,7 @@ defmodule Helper.Converter.EditorToHTML.Validator do
5454
end
5555

5656
# validate block which have no nested items
57-
defp validate_block(%{"type" => type, "data" => data}) when type in @simple_blocks do
57+
defp validate_block(%{"type" => type, "data" => data}) when type in @normal_blocks do
5858
validate_with(type, EditorSchema.get(type), data)
5959
end
6060

lib/helper/converter/html_sanitizer.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ defmodule Helper.Converter.HtmlSanitizer do
4545
Meta.allow_tag_with_these_attributes("th", ["class"])
4646
Meta.allow_tag_with_these_attributes("td", ["class", "style"])
4747

48+
# blockquote
49+
Meta.allow_tag_with_these_attributes("blockquote", ["class"])
50+
4851
Meta.allow_tag_with_these_attributes("svg", [
4952
"t",
5053
"p-id",

lib/helper/types.ex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ defmodule Helper.Types do
3838
footerTitle: String.t()
3939
}
4040

41+
@type editor_quote_mode :: :short | :long
42+
@typedoc """
43+
editor.js's quote tool data format
44+
"""
45+
@type editor_quote :: %{
46+
required(:text) => String.t(),
47+
required(:mode) => editor_quote_mode,
48+
caption: String.t(),
49+
}
50+
4151
@typedoc """
4252
valid editor.js's list item indent
4353
"""

lib/helper/validator/guards.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ defmodule Helper.Validator.Guards do
44
"""
55
defguard g_pos_int(value) when is_integer(value) and value >= 0
66
defguard g_not_nil(value) when not is_nil(value)
7+
8+
defguard g_none_empty_str(value) when is_binary(value) and byte_size(value) > 0
79
end

0 commit comments

Comments
 (0)