edwh-editorjs 2.6.0__tar.gz → 2.6.1__tar.gz
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.
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/CHANGELOG.md +6 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/PKG-INFO +1 -1
- edwh_editorjs-2.6.1/blocks-diff.txt +42 -0
- edwh_editorjs-2.6.1/debug.py +22 -0
- edwh_editorjs-2.6.1/editorjs/__about__.py +1 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/editorjs/blocks.py +21 -6
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/tests/test_core.py +45 -0
- edwh_editorjs-2.6.0/debug.py +0 -18
- edwh_editorjs-2.6.0/editorjs/__about__.py +0 -1
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/.gitignore +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/README.md +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/blog.md +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/editorjs/__init__.py +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/editorjs/core.py +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/editorjs/exceptions.py +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/editorjs/helpers.py +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/editorjs/types.py +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/pyproject.toml +0 -0
- {edwh_editorjs-2.6.0 → edwh_editorjs-2.6.1}/tests/__init__.py +0 -0
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
<!--next-version-placeholder-->
|
|
4
4
|
|
|
5
|
+
## v2.6.1 (2026-02-05)
|
|
6
|
+
|
|
7
|
+
### Fix
|
|
8
|
+
|
|
9
|
+
* **paragraph:** Handle nested HTML in alignment tag closing detection ([`7f910e1`](https://github.com/educationwarehouse/edwh-editorjs/commit/7f910e15103fe25ae0e4d1158deecc15d267d926))
|
|
10
|
+
|
|
5
11
|
## v2.6.0 (2026-02-05)
|
|
6
12
|
|
|
7
13
|
### Fix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: edwh-editorjs
|
|
3
|
-
Version: 2.6.
|
|
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>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
diff --git a/editorjs/blocks.py b/editorjs/blocks.py
|
|
2
|
+
index 9627a82..bc93cee 100644
|
|
3
|
+
--- a/editorjs/blocks.py
|
|
4
|
+
+++ b/editorjs/blocks.py
|
|
5
|
+
@@ -210,14 +210,30 @@ class ParagraphBlock(EditorJSBlock):
|
|
6
|
+
|
|
7
|
+
if child.get("value", "").endswith("/>"):
|
|
8
|
+
# self-closing
|
|
9
|
+
- result.append(EditorJSCustom.to_json(node))
|
|
10
|
+
+ result.append(EditorJSCustom.to_json({"children": [child]}))
|
|
11
|
+
else:
|
|
12
|
+
- # <editorjs>something</editorjs> = 3 children
|
|
13
|
+
- result.extend(
|
|
14
|
+
- EditorJSCustom.to_json({"children": nodes[idx : idx + 2]})
|
|
15
|
+
- )
|
|
16
|
+
-
|
|
17
|
+
- skip = 2
|
|
18
|
+
+ # <editorjs>...</editorjs> may include nested HTML; find the closing tag
|
|
19
|
+
+ end_idx = None
|
|
20
|
+
+ for j, next_child in enumerate(nodes[idx + 1 :], start=idx + 1):
|
|
21
|
+
+ if next_child.get("type") == "html" and next_child.get(
|
|
22
|
+
+ "value", ""
|
|
23
|
+
+ ).strip() == "</editorjs>":
|
|
24
|
+
+ end_idx = j
|
|
25
|
+
+ break
|
|
26
|
+
+
|
|
27
|
+
+ if end_idx is None:
|
|
28
|
+
+ # fallback to previous behavior if tag is malformed
|
|
29
|
+
+ result.extend(
|
|
30
|
+
+ EditorJSCustom.to_json({"children": nodes[idx : idx + 2]})
|
|
31
|
+
+ )
|
|
32
|
+
+ skip = 2
|
|
33
|
+
+ else:
|
|
34
|
+
+ result.extend(
|
|
35
|
+
+ EditorJSCustom.to_json(
|
|
36
|
+
+ {"children": nodes[idx : end_idx + 1]}
|
|
37
|
+
+ )
|
|
38
|
+
+ )
|
|
39
|
+
+ skip = end_idx - idx
|
|
40
|
+
|
|
41
|
+
continue
|
|
42
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from editorjs import EditorJS
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
# blog = Path("blog.md").read_text()
|
|
8
|
+
|
|
9
|
+
ejs = EditorJS.from_json(
|
|
10
|
+
'{"time":1770292823347,"blocks":[{"id":"QKelxSHz2Y","type":"paragraph","data":{"text":"rechts basis"},"tunes":{"alignmentTune":{"alignment":"right"}}},{"id":"IUX70yigzz","type":"paragraph","data":{"text":"links"},"tunes":{"alignmentTune":{"alignment":"left"}}},{"id":"SaWthD_Vlr","type":"paragraph","data":{"text":"<b>rechts duur</b>"},"tunes":{"alignmentTune":{"alignment":"right"}}}],"version":"2.30.7"}'
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# if html = <editorjs type='alignment' tag='p' alignment='center'> <b>Werk dat ertoe doet </b> </editorjs>
|
|
14
|
+
# assert parse_html(html).type == 'alignment'
|
|
15
|
+
|
|
16
|
+
print(ejs.to_html()) # good
|
|
17
|
+
print(ejs.to_json()) # bad, fixme
|
|
18
|
+
# {"time": 1770292880600, "blocks": [{"type": "paragraph", "data": {"text": ""}, "tunes": {"alignmentTune": {"alignment": "right"}}}, {"type": "paragraph", "data": {"text": "links"}}, {"type": "paragraph", "data": {"text": "<b></b>"}, "tunes": {"alignmentTune": {"alignment": "right"}}}, {"type": "raw", "data": {"html": "</b></editorjs>"}}], "version": "2.30.6"}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.6.1"
|
|
@@ -187,6 +187,18 @@ class ParagraphBlock(EditorJSBlock):
|
|
|
187
187
|
|
|
188
188
|
return f"{text}\n\n"
|
|
189
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
|
+
|
|
190
202
|
@classmethod
|
|
191
203
|
def to_json(cls, node: MDChildNode) -> list[dict]:
|
|
192
204
|
result = []
|
|
@@ -210,14 +222,17 @@ class ParagraphBlock(EditorJSBlock):
|
|
|
210
222
|
|
|
211
223
|
if child.get("value", "").endswith("/>"):
|
|
212
224
|
# self-closing
|
|
213
|
-
result.append(EditorJSCustom.to_json(
|
|
225
|
+
result.append(EditorJSCustom.to_json({"children": [child]}))
|
|
214
226
|
else:
|
|
215
|
-
# <editorjs
|
|
216
|
-
|
|
217
|
-
|
|
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]
|
|
218
233
|
)
|
|
219
|
-
|
|
220
|
-
|
|
234
|
+
skip = 2 if end_idx is None else end_idx - idx
|
|
235
|
+
result.extend(EditorJSCustom.to_json({"children": children_slice}))
|
|
221
236
|
|
|
222
237
|
continue
|
|
223
238
|
|
|
@@ -328,3 +328,48 @@ def test_editorjs_alignment_tag():
|
|
|
328
328
|
|
|
329
329
|
assert "<b>Werk dat ertoe doet" in html
|
|
330
330
|
assert "<editorjs" not in html
|
|
331
|
+
assert "<code" not in html
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def test_alignment_with_nested_bold_roundtrip():
|
|
335
|
+
"""
|
|
336
|
+
Test that alignment tags preserve nested bold HTML through JSON roundtrip.
|
|
337
|
+
|
|
338
|
+
Regression test for issue where nested HTML in alignment tags causes:
|
|
339
|
+
- Text content to disappear
|
|
340
|
+
- Malformed closing tags to appear as separate raw blocks
|
|
341
|
+
"""
|
|
342
|
+
# Input: three paragraphs with different alignments, one with nested bold
|
|
343
|
+
input_json = r"""{"time":1770292823347,"blocks":[{"id":"QKelxSHz2Y","type":"paragraph","data":{"text":"rechts basis"},"tunes":{"alignmentTune":{"alignment":"right"}}},{"id":"IUX70yigzz","type":"paragraph","data":{"text":"links"},"tunes":{"alignmentTune":{"alignment":"left"}}},{"id":"SaWthD_Vlr","type":"paragraph","data":{"text":"<b>rechts duur</b>"},"tunes":{"alignmentTune":{"alignment":"right"}}}],"version":"2.30.7"}"""
|
|
344
|
+
# faulty output: {"time": 1770292880600, "blocks": [{"type": "paragraph", "data": {"text": ""}, "tunes": {"alignmentTune": {"alignment": "right"}}}, {"type": "paragraph", "data": {"text": "links"}}, {"type": "paragraph", "data": {"text": "<b></b>"}, "tunes": {"alignmentTune": {"alignment": "right"}}}, {"type": "raw", "data": {"html": "</b></editorjs>"}}], "version": "2.30.6"}
|
|
345
|
+
|
|
346
|
+
e = EditorJS.from_json(input_json)
|
|
347
|
+
|
|
348
|
+
# Convert through markdown and back to JSON
|
|
349
|
+
md = e.to_markdown()
|
|
350
|
+
print("Markdown output:", md)
|
|
351
|
+
|
|
352
|
+
e2 = EditorJS.from_markdown(md)
|
|
353
|
+
output_json = json.loads(e2.to_json())
|
|
354
|
+
|
|
355
|
+
output_str = json.dumps(output_json, indent=2)
|
|
356
|
+
print("Output JSON:", output_str)
|
|
357
|
+
|
|
358
|
+
# Should have exactly 3 blocks (not 4 with a malformed raw block)
|
|
359
|
+
assert len(output_json["blocks"]) == 3
|
|
360
|
+
|
|
361
|
+
# All should be paragraphs (not raw blocks)
|
|
362
|
+
for block in output_json["blocks"]:
|
|
363
|
+
assert block["type"] == "paragraph"
|
|
364
|
+
|
|
365
|
+
# Third block should preserve the bold content
|
|
366
|
+
assert (
|
|
367
|
+
"<b>rechts duur</b>" in output_json["blocks"][2]["data"]["text"]
|
|
368
|
+
or "<b>rechts duur </b>" in output_json["blocks"][2]["data"]["text"]
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
# Third block should preserve alignment
|
|
372
|
+
assert output_json["blocks"][2]["tunes"]["alignmentTune"]["alignment"] == "right"
|
|
373
|
+
|
|
374
|
+
assert "raw" not in output_str
|
|
375
|
+
assert "html" not in output_str
|
edwh_editorjs-2.6.0/debug.py
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
|
-
from editorjs import EditorJS
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def main():
|
|
7
|
-
blog = Path("blog.md").read_text()
|
|
8
|
-
|
|
9
|
-
ejs = EditorJS.from_markdown(blog)
|
|
10
|
-
|
|
11
|
-
# if html = <editorjs type='alignment' tag='p' alignment='center'> <b>Werk dat ertoe doet </b> </editorjs>
|
|
12
|
-
# assert parse_html(html).type == 'alignment'
|
|
13
|
-
|
|
14
|
-
print(ejs.to_html())
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if __name__ == "__main__":
|
|
18
|
-
main()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.6.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|