edwh-editorjs 2.3.1__py3-none-any.whl → 2.4.0__py3-none-any.whl
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.
- editorjs/__about__.py +1 -1
- editorjs/blocks.py +57 -28
- editorjs/core.py +38 -10
- editorjs/exceptions.py +5 -0
- {edwh_editorjs-2.3.1.dist-info → edwh_editorjs-2.4.0.dist-info}/METADATA +1 -1
- edwh_editorjs-2.4.0.dist-info/RECORD +10 -0
- edwh_editorjs-2.3.1.dist-info/RECORD +0 -10
- {edwh_editorjs-2.3.1.dist-info → edwh_editorjs-2.4.0.dist-info}/WHEEL +0 -0
editorjs/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.
|
|
1
|
+
__version__ = "2.4.0"
|
editorjs/blocks.py
CHANGED
|
@@ -4,7 +4,6 @@ mdast to editorjs
|
|
|
4
4
|
|
|
5
5
|
import abc
|
|
6
6
|
import re
|
|
7
|
-
import traceback
|
|
8
7
|
import typing as t
|
|
9
8
|
from html.parser import HTMLParser
|
|
10
9
|
from urllib.parse import urlparse
|
|
@@ -12,7 +11,7 @@ from urllib.parse import urlparse
|
|
|
12
11
|
import humanize
|
|
13
12
|
import markdown2
|
|
14
13
|
|
|
15
|
-
from .exceptions import TODO
|
|
14
|
+
from .exceptions import TODO, Unreachable
|
|
16
15
|
from .types import EditorChildData, MDChildNode
|
|
17
16
|
|
|
18
17
|
|
|
@@ -62,7 +61,6 @@ def process_styled_content(item: MDChildNode, strict: bool = True) -> str:
|
|
|
62
61
|
"strongEmphasis": "<b><i>{value}</i></b>",
|
|
63
62
|
"link": '<a href="{url}">{value}</a>',
|
|
64
63
|
"inlineCode": '<code class="inline-code">{value}</code>',
|
|
65
|
-
# todo: <mark>, linktool
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
if _type in BLOCKS:
|
|
@@ -314,12 +312,6 @@ class ListBlock(EditorJSBlock):
|
|
|
314
312
|
}
|
|
315
313
|
)
|
|
316
314
|
|
|
317
|
-
# todo: detect 'checklist':
|
|
318
|
-
"""
|
|
319
|
-
type: checklist
|
|
320
|
-
data: {items: [{text: "a", checked: false}, {text: "b", checked: false}, {text: "c", checked: true},…]}
|
|
321
|
-
"""
|
|
322
|
-
|
|
323
315
|
if could_be_checklist:
|
|
324
316
|
return [
|
|
325
317
|
{
|
|
@@ -414,7 +406,20 @@ class ImageBlock(EditorJSBlock):
|
|
|
414
406
|
def to_markdown(cls, data: EditorChildData) -> str:
|
|
415
407
|
url = data.get("url", "") or data.get("file", {}).get("url", "")
|
|
416
408
|
caption = data.get("caption", "")
|
|
417
|
-
|
|
409
|
+
|
|
410
|
+
with_border = "1" if data.get("withBorder") else ""
|
|
411
|
+
with_background = "1" if data.get("withBackground") else ""
|
|
412
|
+
stretched = "1" if data.get("stretched") else ""
|
|
413
|
+
|
|
414
|
+
if any((with_border, with_background, stretched)):
|
|
415
|
+
# custom type to support custom options:
|
|
416
|
+
return f"""<editorjs type="image" caption="{caption}" border="{with_border}" background="{with_background}" stretched="{stretched}" url="{url}" />\n\n"""
|
|
417
|
+
else:
|
|
418
|
+
return f"""\n\n"""
|
|
419
|
+
|
|
420
|
+
@classmethod
|
|
421
|
+
def _caption(cls, node: MDChildNode):
|
|
422
|
+
return node.get("alt") or node.get("caption") or ""
|
|
418
423
|
|
|
419
424
|
@classmethod
|
|
420
425
|
def to_json(cls, node: MDChildNode) -> list[dict]:
|
|
@@ -422,15 +427,34 @@ class ImageBlock(EditorJSBlock):
|
|
|
422
427
|
{
|
|
423
428
|
"type": "image",
|
|
424
429
|
"data": {
|
|
425
|
-
"caption": cls.to_text(node),
|
|
426
430
|
"file": {"url": node.get("url")},
|
|
431
|
+
"caption": cls._caption(node),
|
|
432
|
+
"withBorder": bool(node.get("border", False)),
|
|
433
|
+
"stretched": bool(node.get("stretched", False)),
|
|
434
|
+
"withBackground": bool(node.get("background", False)),
|
|
427
435
|
},
|
|
428
436
|
}
|
|
429
437
|
]
|
|
430
438
|
|
|
431
439
|
@classmethod
|
|
432
440
|
def to_text(cls, node: MDChildNode) -> str:
|
|
433
|
-
|
|
441
|
+
caption = cls._caption(node)
|
|
442
|
+
url = node.get("url")
|
|
443
|
+
|
|
444
|
+
background = node.get("background") or ""
|
|
445
|
+
stretched = node.get("stretched") or ""
|
|
446
|
+
border = node.get("border") or ""
|
|
447
|
+
|
|
448
|
+
return f"""
|
|
449
|
+
<div class="ce-block {stretched and 'ce-block--stretched'}">
|
|
450
|
+
<div class="ce-block__content">
|
|
451
|
+
<div class="cdx-block image-tool image-tool--filled {background and 'image-tool--withBackground'} {stretched and 'image-tool--stretched'} {border and 'image-tool--withBorder'}">
|
|
452
|
+
<div class="image-tool__image">
|
|
453
|
+
<img class="image-tool__image-picture" src="{url}" title="{caption}" alt="{caption}">
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
</div>
|
|
457
|
+
"""
|
|
434
458
|
|
|
435
459
|
|
|
436
460
|
@block("blockquote", "quote")
|
|
@@ -482,10 +506,10 @@ class RawBlock(EditorJSBlock):
|
|
|
482
506
|
|
|
483
507
|
@classmethod
|
|
484
508
|
def to_json(cls, node: MDChildNode) -> list[dict]:
|
|
485
|
-
# todo: apply same logic as paragraph block to find <editorjs/> items!!!
|
|
486
509
|
raw = cls.to_text(node)
|
|
487
510
|
|
|
488
511
|
if raw.startswith("<editorjs"):
|
|
512
|
+
# not a raw block but (probably) a self-closing editorjs block
|
|
489
513
|
return EditorJSCustom.to_json({"children": [node]})
|
|
490
514
|
else:
|
|
491
515
|
return [raw_block(raw)]
|
|
@@ -559,7 +583,8 @@ class TableBlock(EditorJSBlock):
|
|
|
559
583
|
|
|
560
584
|
@classmethod
|
|
561
585
|
def to_text(cls, node: MDChildNode) -> str:
|
|
562
|
-
|
|
586
|
+
# I think this might be triggered if there is a table (deeply) within a paragraph block?
|
|
587
|
+
raise TODO(["TableBlock.to_text", node])
|
|
563
588
|
|
|
564
589
|
|
|
565
590
|
@block("linkTool")
|
|
@@ -712,7 +737,7 @@ class AlignmentBlock(EditorJSBlock):
|
|
|
712
737
|
data["level"] = int(tag.removeprefix("h"))
|
|
713
738
|
else:
|
|
714
739
|
# doesn't support alignment
|
|
715
|
-
raise
|
|
740
|
+
raise NotImplementedError(f"Unsupported tag for alignment: {tag}")
|
|
716
741
|
|
|
717
742
|
return [
|
|
718
743
|
{
|
|
@@ -777,7 +802,9 @@ class AttributeParser(HTMLParser):
|
|
|
777
802
|
|
|
778
803
|
class EditorJSCustom(EditorJSBlock, markdown2.Extra):
|
|
779
804
|
"""
|
|
780
|
-
Special type of block to deal with custom attributes
|
|
805
|
+
Special type of block to deal with custom attributes.
|
|
806
|
+
|
|
807
|
+
This is both a special editorjs block as well as a markdown2 plugin!
|
|
781
808
|
"""
|
|
782
809
|
|
|
783
810
|
name = "editorjs"
|
|
@@ -792,23 +819,31 @@ class EditorJSCustom(EditorJSBlock, markdown2.Extra):
|
|
|
792
819
|
|
|
793
820
|
@classmethod
|
|
794
821
|
def to_markdown(cls, data: EditorChildData) -> str:
|
|
795
|
-
raise
|
|
822
|
+
raise Unreachable("Custom Blocks have their own to_markdown logic.")
|
|
796
823
|
|
|
797
824
|
@classmethod
|
|
798
|
-
def
|
|
799
|
-
html = "".join(_["value"] for _ in node.get("children", []))
|
|
825
|
+
def _find_right_block(cls, html: str) -> tuple[EditorJSBlock, dict]:
|
|
800
826
|
attrs, body = cls.parse_html(html)
|
|
801
827
|
_type = attrs.get("type", "")
|
|
802
828
|
attrs.setdefault("body", body) # only if there is no such attribute yet
|
|
803
829
|
|
|
804
|
-
|
|
830
|
+
handler = BLOCKS.get(_type)
|
|
831
|
+
|
|
832
|
+
if not handler:
|
|
805
833
|
raise ValueError(f"Unknown custom type {_type}")
|
|
806
834
|
|
|
835
|
+
return handler, attrs
|
|
836
|
+
|
|
837
|
+
@classmethod
|
|
838
|
+
def to_json(cls, node: MDChildNode) -> list[dict]:
|
|
839
|
+
html = "".join(_["value"] for _ in node.get("children", []))
|
|
840
|
+
handler, attrs = cls._find_right_block(html)
|
|
807
841
|
return handler.to_json(attrs)
|
|
808
842
|
|
|
809
843
|
@classmethod
|
|
810
844
|
def to_text(cls, node: MDChildNode) -> str:
|
|
811
|
-
|
|
845
|
+
handler, attrs = cls._find_right_block(node.get("value", ""))
|
|
846
|
+
return handler.to_text(attrs)
|
|
812
847
|
|
|
813
848
|
# markdown2:
|
|
814
849
|
re_short = re.compile(r"<editorjs.*?/>")
|
|
@@ -816,13 +851,7 @@ class EditorJSCustom(EditorJSBlock, markdown2.Extra):
|
|
|
816
851
|
|
|
817
852
|
def run(self, text: str) -> str:
|
|
818
853
|
def replace_html(match):
|
|
819
|
-
|
|
820
|
-
_type = attrs.get("type", "")
|
|
821
|
-
attrs.setdefault("body", body) # only if there is no such attribute yet
|
|
822
|
-
|
|
823
|
-
if not (handler := BLOCKS.get(_type)):
|
|
824
|
-
raise ValueError(f"Unknown custom type {_type}")
|
|
825
|
-
|
|
854
|
+
handler, attrs = self._find_right_block(match.group())
|
|
826
855
|
return handler.to_text(attrs)
|
|
827
856
|
|
|
828
857
|
# Substitute using the replacement functions
|
editorjs/core.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import typing as t
|
|
3
|
+
import warnings
|
|
3
4
|
|
|
4
5
|
import markdown2
|
|
5
6
|
import mdast
|
|
6
7
|
from typing_extensions import Self
|
|
7
8
|
|
|
8
9
|
from .blocks import BLOCKS
|
|
10
|
+
from .exceptions import TODO
|
|
9
11
|
from .helpers import unix_timestamp
|
|
10
12
|
from .types import MDRootNode
|
|
11
13
|
|
|
@@ -41,13 +43,26 @@ class EditorJS:
|
|
|
41
43
|
for child in blocks:
|
|
42
44
|
_type = child["type"]
|
|
43
45
|
if not (block := BLOCKS.get(_type)):
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
warnings.warn(
|
|
47
|
+
f"from_json: Unsupported block type `{_type}`",
|
|
48
|
+
category=RuntimeWarning,
|
|
49
|
+
)
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
data = child.get("data", {})
|
|
54
|
+
# forward any 'tunes' via data:
|
|
55
|
+
data["tunes"] = data.get("tunes") or child.get("tunes") or {}
|
|
56
|
+
|
|
57
|
+
markdown_items.append(block.to_markdown(data))
|
|
58
|
+
except Exception as e:
|
|
59
|
+
warnings.warn(
|
|
60
|
+
"from_json: Oh oh, unexpected block failure!",
|
|
61
|
+
category=RuntimeWarning,
|
|
62
|
+
source=e,
|
|
63
|
+
)
|
|
64
|
+
# if isinstance(e, TODO):
|
|
65
|
+
# raise e
|
|
51
66
|
|
|
52
67
|
markdown = "".join(markdown_items)
|
|
53
68
|
return cls.from_markdown(markdown)
|
|
@@ -76,9 +91,22 @@ class EditorJS:
|
|
|
76
91
|
for child in self._mdast["children"]:
|
|
77
92
|
_type = child["type"]
|
|
78
93
|
if not (block := BLOCKS.get(_type)):
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
warnings.warn(
|
|
95
|
+
f"to_json: Unsupported block type `{_type}`",
|
|
96
|
+
category=RuntimeWarning,
|
|
97
|
+
)
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
blocks.extend(block.to_json(child))
|
|
102
|
+
except Exception as e:
|
|
103
|
+
warnings.warn(
|
|
104
|
+
"to_json: Oh oh, unexpected block failure!",
|
|
105
|
+
category=RuntimeWarning,
|
|
106
|
+
source=e,
|
|
107
|
+
)
|
|
108
|
+
# if isinstance(e, TODO):
|
|
109
|
+
# raise e
|
|
82
110
|
|
|
83
111
|
data = {"time": unix_timestamp(), "blocks": blocks, "version": EDITORJS_VERSION}
|
|
84
112
|
|
editorjs/exceptions.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: edwh-editorjs
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: EditorJS.py
|
|
5
5
|
Project-URL: Homepage, https://github.com/educationwarehouse/edwh-EditorJS
|
|
6
6
|
Author-email: SKevo <skevo.cw@gmail.com>, Robin van der Noord <robin.vdn@educationwarehouse.nl>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
editorjs/__about__.py,sha256=yLaFvd-K80rs_ClRVYULStijkok4RfYSaanIt_E-aKM,22
|
|
2
|
+
editorjs/__init__.py,sha256=-OHUf7ZXfkbdFB1r85eIjpHRfql-GCNUCKuBEdEt2Rc,58
|
|
3
|
+
editorjs/blocks.py,sha256=QDUJ55UmDDZxZOxkigGHZ-JC7CP_sDH94Y_z-PRVXf8,28648
|
|
4
|
+
editorjs/core.py,sha256=ra1LADSPiZpbzeAZaVzsJ8aGc3m3xYUO4bpyQLPV3h0,4576
|
|
5
|
+
editorjs/exceptions.py,sha256=oKuWqi4CSnFGZfVZWtTZ2XZeHXm5xF-nAtX_1YLm6sI,230
|
|
6
|
+
editorjs/helpers.py,sha256=q861o5liNibMTp-Ozay17taF7CTNsRe901lYhhxdwHg,73
|
|
7
|
+
editorjs/types.py,sha256=W7IZWMWgzJaQulybIt0Gx5N63rVj4mEy73VJWo4VAQA,1029
|
|
8
|
+
edwh_editorjs-2.4.0.dist-info/METADATA,sha256=Jwtr4YkhOPCssoqI4pLpvl7kpvHMFgpU74tHPQyG7Gc,996
|
|
9
|
+
edwh_editorjs-2.4.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
10
|
+
edwh_editorjs-2.4.0.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
editorjs/__about__.py,sha256=neZxeMmEfjhVZM6xetRikrBdHWt5T5ehL72ZYdPtJ-E,22
|
|
2
|
-
editorjs/__init__.py,sha256=-OHUf7ZXfkbdFB1r85eIjpHRfql-GCNUCKuBEdEt2Rc,58
|
|
3
|
-
editorjs/blocks.py,sha256=iJI6-UzMHjaYbFKzON_6DRe05OdXMu-gQkRQfsgN_P4,27073
|
|
4
|
-
editorjs/core.py,sha256=WSBmAIKwSqHIP_NFmUVUJiyHPgq7D8902Jm9HRf1nSk,3669
|
|
5
|
-
editorjs/exceptions.py,sha256=TyfHvk2Z5RbKxTDK7lrjgwAgVgInXIuDW63eO5jzVFw,106
|
|
6
|
-
editorjs/helpers.py,sha256=q861o5liNibMTp-Ozay17taF7CTNsRe901lYhhxdwHg,73
|
|
7
|
-
editorjs/types.py,sha256=W7IZWMWgzJaQulybIt0Gx5N63rVj4mEy73VJWo4VAQA,1029
|
|
8
|
-
edwh_editorjs-2.3.1.dist-info/METADATA,sha256=cwC8hA7CozYCK2z9H-ZH_t8ozqWpnACbGhcqs3ig_qI,996
|
|
9
|
-
edwh_editorjs-2.3.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
10
|
-
edwh_editorjs-2.3.1.dist-info/RECORD,,
|
|
File without changes
|