edwh-editorjs 2.5.0a4__py3-none-any.whl → 2.6.1__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 CHANGED
@@ -1 +1 @@
1
- __version__ = "2.5.0a4"
1
+ __version__ = "2.6.1"
editorjs/blocks.py CHANGED
@@ -5,15 +5,15 @@ mdast to editorjs
5
5
  import abc
6
6
  import re
7
7
  import typing as t
8
- from html.parser import HTMLParser
9
8
  from urllib.parse import urlparse
10
9
 
10
+ import html2markdown
11
11
  import humanize
12
+ import lxml.html
12
13
  import markdown2
13
14
 
14
15
  from .exceptions import TODO, Unreachable
15
16
  from .types import EditorChildData, MDChildNode
16
- import html2markdown
17
17
 
18
18
 
19
19
  class EditorJSBlock(abc.ABC):
@@ -55,8 +55,6 @@ def process_styled_content(item: MDChildNode, strict: bool = True) -> str:
55
55
  """
56
56
  _type = item.get("type")
57
57
 
58
- print('process_styled_content', _type)
59
-
60
58
  html_wrappers = {
61
59
  "text": "{value}",
62
60
  "html": "{value}",
@@ -110,9 +108,9 @@ class HeadingBlock(EditorJSBlock):
110
108
  raise ValueError("Header level must be between 1 and 6.")
111
109
 
112
110
  if (
113
- tunes.get("alignmentTune")
114
- and (alignment := tunes["alignmentTune"].get("alignment"))
115
- and (alignment != "left")
111
+ tunes.get("alignmentTune")
112
+ and (alignment := tunes["alignmentTune"].get("alignment"))
113
+ and (alignment != "left")
116
114
  ):
117
115
  # can't just return regular HTML because then it will turn into a raw block
118
116
  return AlignmentBlock.to_markdown(
@@ -172,9 +170,9 @@ class ParagraphBlock(EditorJSBlock):
172
170
  tunes = data.get("tunes", {})
173
171
 
174
172
  if (
175
- tunes.get("alignmentTune")
176
- and (alignment := tunes["alignmentTune"].get("alignment"))
177
- and (alignment != "left")
173
+ tunes.get("alignmentTune")
174
+ and (alignment := tunes["alignmentTune"].get("alignment"))
175
+ and (alignment != "left")
178
176
  ):
179
177
  return AlignmentBlock.to_markdown(
180
178
  {
@@ -189,6 +187,18 @@ class ParagraphBlock(EditorJSBlock):
189
187
 
190
188
  return f"{text}\n\n"
191
189
 
190
+ @staticmethod
191
+ def _find_closing_editorjs_tag(nodes: list, start_idx: int) -> int | None:
192
+ """Find index of closing </editorjs> tag."""
193
+ for idx, node in enumerate(nodes[start_idx:], start=start_idx):
194
+ if (
195
+ node.get("type") == "html"
196
+ and node.get("value", "").strip() == "</editorjs>"
197
+ ):
198
+ return idx
199
+
200
+ return None
201
+
192
202
  @classmethod
193
203
  def to_json(cls, node: MDChildNode) -> list[dict]:
194
204
  result = []
@@ -212,14 +222,17 @@ class ParagraphBlock(EditorJSBlock):
212
222
 
213
223
  if child.get("value", "").endswith("/>"):
214
224
  # self-closing
215
- result.append(EditorJSCustom.to_json(node))
225
+ result.append(EditorJSCustom.to_json({"children": [child]}))
216
226
  else:
217
- # <editorjs>something</editorjs> = 3 children
218
- result.extend(
219
- EditorJSCustom.to_json({"children": nodes[idx: idx + 2]})
227
+ # <editorjs>...</editorjs> may include nested HTML; find the closing tag
228
+ end_idx = cls._find_closing_editorjs_tag(nodes, idx + 1)
229
+ children_slice = (
230
+ nodes[idx : idx + 2]
231
+ if end_idx is None
232
+ else nodes[idx : end_idx + 1]
220
233
  )
221
-
222
- skip = 2
234
+ skip = 2 if end_idx is None else end_idx - idx
235
+ result.extend(EditorJSCustom.to_json({"children": children_slice}))
223
236
 
224
237
  continue
225
238
 
@@ -398,7 +411,7 @@ class CodeBlock(EditorJSBlock):
398
411
  @classmethod
399
412
  def to_markdown(cls, data: EditorChildData) -> str:
400
413
  code = data.get("code", "")
401
- return f"```\n" f"{code}" f"\n```\n"
414
+ return f"```\n{code}\n```\n"
402
415
 
403
416
  @classmethod
404
417
  def to_json(cls, node: MDChildNode) -> list[dict]:
@@ -457,9 +470,9 @@ class ImageBlock(EditorJSBlock):
457
470
  border = node.get("border") or ""
458
471
 
459
472
  return f"""
460
- <div class="ce-block {stretched and 'ce-block--stretched'}">
473
+ <div class="ce-block {stretched and "ce-block--stretched"}">
461
474
  <div class="ce-block__content">
462
- <div class="cdx-block image-tool image-tool--filled {background and 'image-tool--withBackground'} {stretched and 'image-tool--stretched'} {border and 'image-tool--withBorder'}">
475
+ <div class="cdx-block image-tool image-tool--filled {background and "image-tool--withBackground"} {stretched and "image-tool--stretched"} {border and "image-tool--withBorder"}">
463
476
  <div class="image-tool__image">
464
477
  <figure>
465
478
  <img class="image-tool__image-picture" src="{url}" title="{caption}" alt="{caption}">
@@ -514,7 +527,6 @@ class QuoteBlock(EditorJSBlock):
514
527
 
515
528
  @block("raw", "html")
516
529
  class RawBlock(EditorJSBlock):
517
-
518
530
  @classmethod
519
531
  def to_markdown(cls, data: EditorChildData) -> str:
520
532
  text = data.get("html", "")
@@ -537,7 +549,6 @@ class RawBlock(EditorJSBlock):
537
549
 
538
550
  @block("table")
539
551
  class TableBlock(EditorJSBlock):
540
-
541
552
  @classmethod
542
553
  def to_markdown(cls, data: EditorChildData) -> str:
543
554
  """
@@ -656,7 +667,6 @@ class LinkBlock(EditorJSBlock):
656
667
 
657
668
  @block("attaches")
658
669
  class AttachmentBlock(EditorJSBlock):
659
-
660
670
  @classmethod
661
671
  def to_markdown(cls, data: EditorChildData) -> str:
662
672
  title = data.get("title", "")
@@ -721,7 +731,7 @@ class AttachmentBlock(EditorJSBlock):
721
731
  </div>
722
732
  {file_size}
723
733
  </div>
724
- <a class="cdx-attaches__download-button" href="{node.get('file', '')}" target="_blank" rel="nofollow noindex noreferrer" title="{node.get('name', '')}">
734
+ <a class="cdx-attaches__download-button" href="{node.get("file", "")}" target="_blank" rel="nofollow noindex noreferrer" title="{node.get("name", "")}">
725
735
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M7 10L11.8586 14.8586C11.9367 14.9367 12.0633 14.9367 12.1414 14.8586L17 10"></path></svg>
726
736
  </a>
727
737
  </div>
@@ -773,7 +783,6 @@ class AlignmentBlock(EditorJSBlock):
773
783
 
774
784
  @block("embed")
775
785
  class EmbedBlock(EditorJSBlock):
776
-
777
786
  @classmethod
778
787
  def to_markdown(cls, data: EditorChildData) -> str:
779
788
  service = data.get("service", "")
@@ -802,20 +811,6 @@ class EmbedBlock(EditorJSBlock):
802
811
  ### end blocks
803
812
 
804
813
 
805
- class AttributeParser(HTMLParser):
806
- def __init__(self):
807
- super().__init__()
808
- self.attributes = {}
809
- self.data = None
810
-
811
- def handle_starttag(self, tag, attrs):
812
- # Collect attributes when the tag is encountered
813
- self.attributes = dict(attrs)
814
-
815
- def handle_data(self, data):
816
- self.data = data
817
-
818
-
819
814
  class EditorJSCustom(EditorJSBlock, markdown2.Extra):
820
815
  """
821
816
  Special type of block to deal with custom attributes.
@@ -828,10 +823,29 @@ class EditorJSCustom(EditorJSBlock, markdown2.Extra):
828
823
 
829
824
  @classmethod
830
825
  def parse_html(cls, html: str):
831
- parser = AttributeParser()
832
- parser.feed(html)
826
+ """
827
+ Extract attributes from the outermost HTML element and return its inner HTML.
828
+
829
+ This function parses the provided markup, identifies the root element,
830
+ returns its attributes as a dictionary, and serializes all direct child
831
+ nodes back into an HTML string.
832
+
833
+ Args:
834
+ html: A string containing a single root HTML element.
835
+
836
+ Returns:
837
+ A tuple of:
838
+ - dict[str, str]: Attributes of the root element
839
+ - str: Inner HTML of the root element
840
+ """
841
+ root = lxml.html.fromstring(html)
842
+
843
+ attributes = dict(root.attrib)
844
+ inner_html = "".join(
845
+ lxml.html.tostring(child, encoding="unicode") for child in root
846
+ )
833
847
 
834
- return parser.attributes, parser.data
848
+ return attributes, inner_html
835
849
 
836
850
  @classmethod
837
851
  def to_markdown(cls, data: EditorChildData) -> str:
@@ -846,6 +860,7 @@ class EditorJSCustom(EditorJSBlock, markdown2.Extra):
846
860
  handler = BLOCKS.get(_type)
847
861
 
848
862
  if not handler:
863
+ raise ValueError(f"debug: {attrs = } {body = }") # fixme
849
864
  raise ValueError(f"Unknown custom type {_type}")
850
865
 
851
866
  return handler, attrs
editorjs/core.py CHANGED
@@ -100,13 +100,11 @@ class EditorJS:
100
100
  try:
101
101
  blocks.extend(block.to_json(child))
102
102
  except Exception as e:
103
-
104
103
  warnings.warn(
105
104
  "to_json: Oh oh, unexpected block failure!",
106
105
  category=RuntimeWarning,
107
106
  source=e,
108
107
  )
109
- raise e
110
108
  # if isinstance(e, TODO):
111
109
  # raise e
112
110
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: edwh-editorjs
3
- Version: 2.5.0a4
3
+ Version: 2.6.1
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>
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.13
15
15
  Requires-Python: >=3.10
16
16
  Requires-Dist: html2markdown
17
17
  Requires-Dist: humanize
18
+ Requires-Dist: lxml
18
19
  Requires-Dist: markdown2
19
20
  Requires-Dist: mdast
20
21
  Provides-Extra: dev
@@ -0,0 +1,10 @@
1
+ editorjs/__about__.py,sha256=yv0wJuq7dd_PlBhLN8iuPUYVsoACKuk2R3Gg5WU-tHk,22
2
+ editorjs/__init__.py,sha256=-OHUf7ZXfkbdFB1r85eIjpHRfql-GCNUCKuBEdEt2Rc,58
3
+ editorjs/blocks.py,sha256=5FJwfky4QEiNPJxQ61O1D0nQ8eEVWu3a1Qhi79JJKco,30176
4
+ editorjs/core.py,sha256=4igv2l8Rm1S92kxKrIXGIUlNHh6pnjq8F28XQr91I9o,4510
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.6.1.dist-info/METADATA,sha256=pUeVwld9qEefDaWs0azSpu8mz-2FSq6HlrkZpvWqT-I,1045
9
+ edwh_editorjs-2.6.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
10
+ edwh_editorjs-2.6.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,10 +0,0 @@
1
- editorjs/__about__.py,sha256=NsEXgGmZNz_m0FN93bP4ym1D0nmcEnCsVmXyWVDMaGI,24
2
- editorjs/__init__.py,sha256=-OHUf7ZXfkbdFB1r85eIjpHRfql-GCNUCKuBEdEt2Rc,58
3
- editorjs/blocks.py,sha256=Iq6JzxoD5a00ud3KsaUFacBD-zDf9wu1FL5ipxJI_h8,29140
4
- editorjs/core.py,sha256=9qYmKHr-Wp8TqmMQNfmk0ZCgeARPo0QRS1IV_sLPRag,4535
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.5.0a4.dist-info/METADATA,sha256=iIPI5nHDiIjmqlXj3yhPe3AiEpIzGoIgxCGFr8oc3nk,1027
9
- edwh_editorjs-2.5.0a4.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
10
- edwh_editorjs-2.5.0a4.dist-info/RECORD,,