djpress-tiptap 0.2.0__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.
- djpress_tiptap-0.2.0/PKG-INFO +40 -0
- djpress_tiptap-0.2.0/README.md +28 -0
- djpress_tiptap-0.2.0/pyproject.toml +49 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/__init__.py +1 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/apps.py +10 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/conf.py +121 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/static/dj_tiptap/content.bundle.js +5 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/static/dj_tiptap/content.css +2 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/static/dj_tiptap/djtiptap.bundle.js +736 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/static/dj_tiptap/djtiptap.css +2 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/static/djpress_tiptap/content.bundle.js +5 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/static/djpress_tiptap/content.css +2 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/static/djpress_tiptap/djtiptap.bundle.js +736 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/static/djpress_tiptap/djtiptap.css +2 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/templates/djpress_tiptap/attachment_browse.html +29 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/templates/djpress_tiptap/widgets/djpress_tiptap_editor.html +63 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/urls.py +11 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/views.py +184 -0
- djpress_tiptap-0.2.0/src/djpress_tiptap/widgets.py +49 -0
- djpress_tiptap-0.2.0/tests/__init__.py +1 -0
- djpress_tiptap-0.2.0/tests/conftest.py +7 -0
- djpress_tiptap-0.2.0/tests/fixtures/clip.mp4 +0 -0
- djpress_tiptap-0.2.0/tests/fixtures/photo.png +0 -0
- djpress_tiptap-0.2.0/tests/fixtures/pixel.png +0 -0
- djpress_tiptap-0.2.0/tests/test_conf.py +106 -0
- djpress_tiptap-0.2.0/tests/test_editor_e2e.py +615 -0
- djpress_tiptap-0.2.0/tests/test_views.py +199 -0
- djpress_tiptap-0.2.0/tests/test_widgets.py +75 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: djpress-tiptap
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Rich text editor for DJ Press based on Tiptap.
|
|
5
|
+
Author-Email: Stuart Maxwell <stuart@amanzi.nz>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.14
|
|
8
|
+
Requires-Dist: djpress>=0.30.0
|
|
9
|
+
Requires-Dist: pillow~=12.3
|
|
10
|
+
Requires-Dist: puremagic~=2.2
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# DJ Tiptap
|
|
14
|
+
|
|
15
|
+
Opinionated TipTap editor implementation for Django sites.
|
|
16
|
+
|
|
17
|
+
Docs are still a work in progress.
|
|
18
|
+
See the example app for usage.
|
|
19
|
+
|
|
20
|
+
## Settings
|
|
21
|
+
|
|
22
|
+
All settings are optional; the package works with sensible defaults. Upload
|
|
23
|
+
and browse buttons only appear in the toolbar when the corresponding URL is
|
|
24
|
+
configured.
|
|
25
|
+
|
|
26
|
+
| Setting | Default | Purpose |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `DJPRESS_TIPTAP_UPLOAD_URL` | unset (uploads disabled) | URL name or path of the attachment upload endpoint |
|
|
29
|
+
| `DJPRESS_TIPTAP_BROWSE_URL` | unset (library disabled) | URL name or path of the media-library browse endpoint |
|
|
30
|
+
| `DJPRESS_TIPTAP_MAX_UPLOAD_SIZE_MB` | `10` | Maximum image upload size |
|
|
31
|
+
| `DJPRESS_TIPTAP_MAX_VIDEO_UPLOAD_SIZE_MB` | `100` | Maximum video upload size |
|
|
32
|
+
| `DJPRESS_TIPTAP_ALLOWED_IMAGE_TYPES` | JPEG/PNG/GIF/WebP | Dict of Pillow format → mime type accepted by the upload view |
|
|
33
|
+
| `DJPRESS_TIPTAP_ALLOWED_VIDEO_TYPES` | `{"video/mp4", "video/webm"}` | Set of video mime types accepted by the upload view; set to `set()` to disable video uploads |
|
|
34
|
+
|
|
35
|
+
Images are inserted as `<img>` and validated with Pillow; videos are inserted
|
|
36
|
+
as HTML5 `<video controls>` elements and validated by magic bytes with
|
|
37
|
+
[puremagic](https://github.com/cdgriffith/puremagic). The upload endpoint
|
|
38
|
+
lives in the host project (see `example/website/views.py` for the reference
|
|
39
|
+
implementation) — its JSON response's `content_type` field tells the editor
|
|
40
|
+
which element to insert.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# DJ Tiptap
|
|
2
|
+
|
|
3
|
+
Opinionated TipTap editor implementation for Django sites.
|
|
4
|
+
|
|
5
|
+
Docs are still a work in progress.
|
|
6
|
+
See the example app for usage.
|
|
7
|
+
|
|
8
|
+
## Settings
|
|
9
|
+
|
|
10
|
+
All settings are optional; the package works with sensible defaults. Upload
|
|
11
|
+
and browse buttons only appear in the toolbar when the corresponding URL is
|
|
12
|
+
configured.
|
|
13
|
+
|
|
14
|
+
| Setting | Default | Purpose |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `DJPRESS_TIPTAP_UPLOAD_URL` | unset (uploads disabled) | URL name or path of the attachment upload endpoint |
|
|
17
|
+
| `DJPRESS_TIPTAP_BROWSE_URL` | unset (library disabled) | URL name or path of the media-library browse endpoint |
|
|
18
|
+
| `DJPRESS_TIPTAP_MAX_UPLOAD_SIZE_MB` | `10` | Maximum image upload size |
|
|
19
|
+
| `DJPRESS_TIPTAP_MAX_VIDEO_UPLOAD_SIZE_MB` | `100` | Maximum video upload size |
|
|
20
|
+
| `DJPRESS_TIPTAP_ALLOWED_IMAGE_TYPES` | JPEG/PNG/GIF/WebP | Dict of Pillow format → mime type accepted by the upload view |
|
|
21
|
+
| `DJPRESS_TIPTAP_ALLOWED_VIDEO_TYPES` | `{"video/mp4", "video/webm"}` | Set of video mime types accepted by the upload view; set to `set()` to disable video uploads |
|
|
22
|
+
|
|
23
|
+
Images are inserted as `<img>` and validated with Pillow; videos are inserted
|
|
24
|
+
as HTML5 `<video controls>` elements and validated by magic bytes with
|
|
25
|
+
[puremagic](https://github.com/cdgriffith/puremagic). The upload endpoint
|
|
26
|
+
lives in the host project (see `example/website/views.py` for the reference
|
|
27
|
+
implementation) — its JSON response's `content_type` field tells the editor
|
|
28
|
+
which element to insert.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "djpress-tiptap"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Rich text editor for DJ Press based on Tiptap."
|
|
5
|
+
authors = [
|
|
6
|
+
{ name = "Stuart Maxwell", email = "stuart@amanzi.nz" },
|
|
7
|
+
]
|
|
8
|
+
requires-python = ">=3.14"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"djpress>=0.30.0",
|
|
12
|
+
"pillow~=12.3",
|
|
13
|
+
"puremagic~=2.2",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.license]
|
|
17
|
+
text = "MIT"
|
|
18
|
+
|
|
19
|
+
[dependency-groups]
|
|
20
|
+
dev = [
|
|
21
|
+
"pytest~=9.1",
|
|
22
|
+
"playwright~=1.61",
|
|
23
|
+
"pytest-django~=4.12",
|
|
24
|
+
"pytest-playwright>=0.8.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[build-system]
|
|
28
|
+
requires = [
|
|
29
|
+
"pdm-backend",
|
|
30
|
+
]
|
|
31
|
+
build-backend = "pdm.backend"
|
|
32
|
+
|
|
33
|
+
[tool.pdm]
|
|
34
|
+
distribution = true
|
|
35
|
+
|
|
36
|
+
[tool.pytest.ini_options]
|
|
37
|
+
pythonpath = ". example"
|
|
38
|
+
DJANGO_SETTINGS_MODULE = "config.settings_testing"
|
|
39
|
+
python_files = "tests.py test_*.py *_tests.py"
|
|
40
|
+
markers = [
|
|
41
|
+
"e2e: browser tests driving the live server (deselect with -m 'not e2e')",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.djangofmt]
|
|
45
|
+
line-length = 240
|
|
46
|
+
indent-width = 2
|
|
47
|
+
profile = "django"
|
|
48
|
+
html-void-self-closing = "never"
|
|
49
|
+
preserve-unquoted-attrs = false
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""DJ Press Tiptap."""
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""djpress-tiptap configuration.
|
|
2
|
+
|
|
3
|
+
Every setting is optional in the host project: these functions return the
|
|
4
|
+
project's DJPRESS_TIPTAP_* value when set, or the package default otherwise.
|
|
5
|
+
|
|
6
|
+
Functions rather than module-level constants so the settings are read lazily
|
|
7
|
+
(at request/render time): override_settings keeps working in tests, and the
|
|
8
|
+
module can be imported during app loading before settings are configured.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from django.conf import settings
|
|
12
|
+
from django.shortcuts import resolve_url
|
|
13
|
+
|
|
14
|
+
# Pillow format name -> mime type. Keys validate what Pillow detected in the
|
|
15
|
+
# upload view; values are stored as Attachment.content_type and forwarded to
|
|
16
|
+
# the editor JS (file picker + drag-drop filter) via the widget's data-accept
|
|
17
|
+
# attribute. No SVG: it can carry scripts, making it an XSS vector.
|
|
18
|
+
DEFAULT_ALLOWED_IMAGE_TYPES = {
|
|
19
|
+
"JPEG": "image/jpeg",
|
|
20
|
+
"PNG": "image/png",
|
|
21
|
+
"GIF": "image/gif",
|
|
22
|
+
"WEBP": "image/webp",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# Mime types accepted by the video upload path, as detected by puremagic in
|
|
26
|
+
# the upload view, stored as Attachment.content_type, and forwarded to the
|
|
27
|
+
# editor JS via the widget's data-accept-video attribute. A set of mime types
|
|
28
|
+
# (not a format->mime dict like images) because puremagic reports mime types
|
|
29
|
+
# directly. Only web-playable formats: video/quicktime et al. would upload
|
|
30
|
+
# fine but not play in most browsers' <video> element. Set to an empty set to
|
|
31
|
+
# disable video uploads entirely.
|
|
32
|
+
DEFAULT_ALLOWED_VIDEO_TYPES = {
|
|
33
|
+
"video/mp4",
|
|
34
|
+
"video/webm",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
DEFAULT_MAX_UPLOAD_SIZE_MB = 10
|
|
38
|
+
|
|
39
|
+
# Videos get their own, larger cap: even a short clip dwarfs any photo.
|
|
40
|
+
DEFAULT_MAX_VIDEO_UPLOAD_SIZE_MB = 100
|
|
41
|
+
|
|
42
|
+
# DJ Press Tiptap views to upload media
|
|
43
|
+
DJPRESS_TIPTAP_UPLOAD_URL = "djpress_tiptap:media_upload"
|
|
44
|
+
DJPRESS_TIPTAP_BROWSE_URL = "djpress_tiptap:media_browse"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def max_upload_size_mb() -> int:
|
|
48
|
+
"""Maximum attachment upload size in megabytes.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
The maximum upload size in megabytes, as configured via DJPRESS_TIPTAP_MAX_UPLOAD_SIZE_MB.
|
|
52
|
+
"""
|
|
53
|
+
return getattr(settings, "DJPRESS_TIPTAP_MAX_UPLOAD_SIZE_MB", DEFAULT_MAX_UPLOAD_SIZE_MB)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def max_video_upload_size_mb() -> int:
|
|
57
|
+
"""Maximum video upload size in megabytes.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
The maximum video upload size in megabytes, as configured via
|
|
61
|
+
DJPRESS_TIPTAP_MAX_VIDEO_UPLOAD_SIZE_MB.
|
|
62
|
+
"""
|
|
63
|
+
return getattr(settings, "DJPRESS_TIPTAP_MAX_VIDEO_UPLOAD_SIZE_MB", DEFAULT_MAX_VIDEO_UPLOAD_SIZE_MB)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def allowed_image_types() -> dict[str, str]:
|
|
67
|
+
"""Mapping of accepted Pillow image formats to their mime types.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
The allowed image types, as configured via DJPRESS_TIPTAP_ALLOWED_IMAGE_TYPES.
|
|
71
|
+
"""
|
|
72
|
+
return getattr(settings, "DJPRESS_TIPTAP_ALLOWED_IMAGE_TYPES", DEFAULT_ALLOWED_IMAGE_TYPES)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def allowed_video_types() -> set[str]:
|
|
76
|
+
"""Set of accepted video mime types.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
The allowed video mime types, as configured via DJPRESS_TIPTAP_ALLOWED_VIDEO_TYPES.
|
|
80
|
+
"""
|
|
81
|
+
return getattr(settings, "DJPRESS_TIPTAP_ALLOWED_VIDEO_TYPES", DEFAULT_ALLOWED_VIDEO_TYPES)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def upload_url(override: str | None = None) -> str:
|
|
85
|
+
"""URL of the attachment upload endpoint.
|
|
86
|
+
|
|
87
|
+
Priority: explicit widget argument, then DJPRESS_TIPTAP_UPLOAD_URL setting.
|
|
88
|
+
Values may be a URL name or a path (LOGIN_URL semantics); the view just
|
|
89
|
+
has to keep the JSON contract:
|
|
90
|
+
POST multipart {file} -> 201 {url, alt?, ...} or 4xx {error}.
|
|
91
|
+
|
|
92
|
+
When neither is set (or set to None/empty), returns "" and the widget
|
|
93
|
+
disables uploads.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
override: Optional URL override for the upload endpoint.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
The upload URL, as configured via DJPRESS_TIPTAP_UPLOAD_URL, or "" if unset.
|
|
100
|
+
"""
|
|
101
|
+
url = override or getattr(settings, "DJPRESS_TIPTAP_UPLOAD_URL", DJPRESS_TIPTAP_UPLOAD_URL)
|
|
102
|
+
return resolve_url(url) if url else ""
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def browse_url(override: str | None = None) -> str:
|
|
106
|
+
"""URL of the media-library browse endpoint.
|
|
107
|
+
|
|
108
|
+
Same priority and name-or-path semantics as upload_url, and likewise
|
|
109
|
+
returns "" (feature disabled) when unset. The view returns an HTML
|
|
110
|
+
fragment honouring the picker's data attributes: data-image-url /
|
|
111
|
+
data-image-alt (insert), data-fetch (load another page), data-close
|
|
112
|
+
(dismiss).
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
override: Optional URL override for the browse endpoint.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
The browse URL, as configured via DJPRESS_TIPTAP_BROWSE_URL, or "" if unset.
|
|
119
|
+
"""
|
|
120
|
+
url = override or getattr(settings, "DJPRESS_TIPTAP_BROWSE_URL", DJPRESS_TIPTAP_BROWSE_URL)
|
|
121
|
+
return resolve_url(url) if url else ""
|