draftail-text-utils 0.1.7__tar.gz → 0.3.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.
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/PKG-INFO +3 -2
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/README.md +1 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/pyproject.toml +2 -2
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/conf.py +20 -1
- draftail_text_utils-0.3.0/src/draftail_text_utils/rich_text/font_size.py +40 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/rich_text/highlight_color.py +37 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/rich_text/text_color.py +37 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/rich_text/text_style.py +294 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/css/color.css +52 -0
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/css/font_family.css → draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/css/common.css +43 -13
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/css/font_family.css +1 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/static/draftail_text_utils/css/font_size.css +0 -51
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/css/highlight_color.css +1 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/css/text_alignment.css +31 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/css/text_color.css +1 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/js/common.js +365 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/static/draftail_text_utils/js/font_family.js +29 -30
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/static/draftail_text_utils/js/font_size.js +35 -142
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/js/highlight_color.js +169 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/js/styled_link_source.js +288 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/static/draftail_text_utils/js/text_alignment.js +8 -10
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/js/text_color.js +161 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/js/text_style_entity.js +145 -0
- draftail_text_utils-0.3.0/src/draftail_text_utils/templates/draftail_text_utils/icons/anchor.svg +1 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templatetags/draftail_text_utils_tags.py +1 -3
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/wagtail_hooks.py +20 -8
- draftail_text_utils-0.1.7/src/draftail_text_utils/rich_text/font_size.py +0 -94
- draftail_text_utils-0.1.7/src/draftail_text_utils/rich_text/highlight_color.py +0 -99
- draftail_text_utils-0.1.7/src/draftail_text_utils/rich_text/text_color.py +0 -95
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/css/highlight_color.css +0 -117
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/css/text_alignment.css +0 -72
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/css/text_color.css +0 -117
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/js/font_size_entity.js +0 -39
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/js/highlight_color.js +0 -350
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/js/highlight_color_entity.js +0 -43
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/js/text_color.js +0 -343
- draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/js/text_color_entity.js +0 -42
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/__init__.py +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/apps.py +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/migrations/__init__.py +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/rich_text/__init__.py +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/rich_text/base.py +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/rich_text/font_family.py +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/rich_text/text_alignment.py +0 -0
- /draftail_text_utils-0.1.7/src/draftail_text_utils/static/draftail_text_utils/css/draftail_text_utils.css → /draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/css/page.css +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templates/draftail_text_utils/icons/align-center.svg +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templates/draftail_text_utils/icons/align-justify.svg +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templates/draftail_text_utils/icons/align-left.svg +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templates/draftail_text_utils/icons/align-right.svg +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templates/draftail_text_utils/icons/font.svg +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templates/draftail_text_utils/icons/highlighter.svg +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templates/draftail_text_utils/icons/palette.svg +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templates/draftail_text_utils/icons/text-height.svg +0 -0
- {draftail_text_utils-0.1.7 → draftail_text_utils-0.3.0}/src/draftail_text_utils/templatetags/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: draftail-text-utils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Extends Draftail's text customization
|
|
5
5
|
Keywords: wagtail,draftail,rich text,text color,highlight,font size,font family,text alignment
|
|
6
6
|
Author: baldwinboy
|
|
@@ -21,7 +21,7 @@ Classifier: Framework :: Wagtail :: 6
|
|
|
21
21
|
Classifier: Framework :: Wagtail :: 7
|
|
22
22
|
Requires-Dist: cssutils>=2.15.0
|
|
23
23
|
Requires-Dist: django>=5.0
|
|
24
|
-
Requires-Dist: wagtail>=
|
|
24
|
+
Requires-Dist: wagtail>=7.3.2
|
|
25
25
|
Requires-Dist: wagtail-traverse>=1.0.1
|
|
26
26
|
Requires-Python: >=3.13
|
|
27
27
|
Project-URL: Homepage, https://github.com/baldwinboy/draftail-text-utils
|
|
@@ -34,6 +34,7 @@ Description-Content-Type: text/markdown
|
|
|
34
34
|
# Draftail Text Utils
|
|
35
35
|
|
|
36
36
|
Extends Draftail's text customization. Includes:
|
|
37
|
+
- Styled Links (preserve colour, highlight, and size in links, with tooltip Edit/Remove)
|
|
37
38
|
- Text Color (with optional palettes)
|
|
38
39
|
- Highlight Color
|
|
39
40
|
- Font Family
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "draftail-text-utils"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Extends Draftail's text customization"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "BSD-3-Clause"
|
|
@@ -28,7 +28,7 @@ classifiers = [
|
|
|
28
28
|
dependencies = [
|
|
29
29
|
"cssutils>=2.15.0",
|
|
30
30
|
"Django>=5.0",
|
|
31
|
-
"Wagtail>=
|
|
31
|
+
"Wagtail>=7.3.2",
|
|
32
32
|
"wagtail-traverse>=1.0.1",
|
|
33
33
|
]
|
|
34
34
|
|
|
@@ -15,8 +15,9 @@ Usage in your Django settings:
|
|
|
15
15
|
# Option A: point to an existing module with a DRAFTAIL_COLORS list
|
|
16
16
|
"COLORS": {
|
|
17
17
|
"MODULE": None, # e.g. "apps.core.models"
|
|
18
|
+
"CALLABLE": None, # e.g. "myapp.utils.get_colors"
|
|
18
19
|
},
|
|
19
|
-
# Option B: provide an explicit palette (ignored if MODULE is set)
|
|
20
|
+
# Option B: provide an explicit palette (ignored if MODULE/CALLABLE is set)
|
|
20
21
|
"COLOR_PALETTE": None, # falls back to built-in defaults
|
|
21
22
|
# ---- Font families ----
|
|
22
23
|
# Option A: point to an existing module with a DRAFTAIL_FONT_FAMILIES list
|
|
@@ -208,6 +209,24 @@ def _normalise_font_urls(font_urls):
|
|
|
208
209
|
|
|
209
210
|
def load_color_palette():
|
|
210
211
|
colors_config = get_setting("COLORS", {})
|
|
212
|
+
|
|
213
|
+
callable_path = colors_config.get("CALLABLE")
|
|
214
|
+
if callable_path:
|
|
215
|
+
try:
|
|
216
|
+
module_path, func_name = callable_path.rsplit(".", 1)
|
|
217
|
+
module = importlib.import_module(module_path)
|
|
218
|
+
func = getattr(module, func_name)
|
|
219
|
+
if callable(func):
|
|
220
|
+
result = func()
|
|
221
|
+
if result is not None:
|
|
222
|
+
return result
|
|
223
|
+
except (ImportError, ValueError, AttributeError) as e:
|
|
224
|
+
logger.warning(
|
|
225
|
+
"Failed to load colours from callable %s: %s",
|
|
226
|
+
callable_path,
|
|
227
|
+
e,
|
|
228
|
+
)
|
|
229
|
+
|
|
211
230
|
module_path = colors_config.get("MODULE")
|
|
212
231
|
|
|
213
232
|
if module_path:
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Draftail rich-text feature: Font size toolbar control.
|
|
3
|
+
|
|
4
|
+
Registers a ``"font-size"`` ControlFeature that applies/removes the
|
|
5
|
+
``size`` property on the unified ``TEXT_STYLE`` entity.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from draftail_text_utils.conf import feature_enabled
|
|
9
|
+
|
|
10
|
+
from .base import (
|
|
11
|
+
control_json_script,
|
|
12
|
+
register_control_feature,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register(features):
|
|
17
|
+
if not feature_enabled("FONT_SIZE"):
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
register_control_feature(
|
|
21
|
+
features,
|
|
22
|
+
feature_name="font-size",
|
|
23
|
+
icon="text-height",
|
|
24
|
+
label="Font Size",
|
|
25
|
+
description="Change font size",
|
|
26
|
+
js=["draftail_text_utils/js/font_size.js"],
|
|
27
|
+
css={"all": ("draftail_text_utils/css/font_size.css",)},
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def control():
|
|
32
|
+
if not feature_enabled("FONT_SIZE"):
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
return control_json_script(
|
|
36
|
+
type_="font-size",
|
|
37
|
+
icon="text-height",
|
|
38
|
+
label="Font Size",
|
|
39
|
+
description="Change font size",
|
|
40
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Draftail rich-text feature: Highlight color toolbar control.
|
|
3
|
+
|
|
4
|
+
Registers a ``"highlight-color"`` ControlFeature that applies/removes the
|
|
5
|
+
``backgroundColor`` property on the unified ``TEXT_STYLE`` entity.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from draftail_text_utils.conf import feature_enabled
|
|
9
|
+
|
|
10
|
+
from .base import (
|
|
11
|
+
control_json_script,
|
|
12
|
+
register_control_feature,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register(features):
|
|
17
|
+
if not feature_enabled("HIGHLIGHT_COLOR"):
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
register_control_feature(
|
|
21
|
+
features,
|
|
22
|
+
feature_name="highlight-color",
|
|
23
|
+
js=["draftail_text_utils/js/highlight_color.js"],
|
|
24
|
+
css={"all": ("draftail_text_utils/css/highlight_color.css",)},
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def control():
|
|
29
|
+
if not feature_enabled("HIGHLIGHT_COLOR"):
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
return control_json_script(
|
|
33
|
+
type_="highlight-color",
|
|
34
|
+
icon="highlighter",
|
|
35
|
+
label="Highlight Color",
|
|
36
|
+
description="Change highlight color",
|
|
37
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Draftail rich-text feature: Text color toolbar control.
|
|
3
|
+
|
|
4
|
+
Registers a ``"text-color"`` ControlFeature that applies/removes the
|
|
5
|
+
``color`` property on the unified ``TEXT_STYLE`` entity.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from draftail_text_utils.conf import feature_enabled
|
|
9
|
+
|
|
10
|
+
from .base import (
|
|
11
|
+
control_json_script,
|
|
12
|
+
register_control_feature,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register(features):
|
|
17
|
+
if not feature_enabled("TEXT_COLOR"):
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
register_control_feature(
|
|
21
|
+
features,
|
|
22
|
+
feature_name="text-color",
|
|
23
|
+
js=["draftail_text_utils/js/text_color.js"],
|
|
24
|
+
css={"all": ("draftail_text_utils/css/text_color.css",)},
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def control():
|
|
29
|
+
if not feature_enabled("TEXT_COLOR"):
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
return control_json_script(
|
|
33
|
+
type_="text-color",
|
|
34
|
+
icon="palette",
|
|
35
|
+
label="Text Color",
|
|
36
|
+
description="Change text color",
|
|
37
|
+
)
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import cssutils
|
|
2
|
+
|
|
3
|
+
from django.urls import reverse_lazy
|
|
4
|
+
from django.utils.html import escape
|
|
5
|
+
from draftjs_exporter.dom import DOM
|
|
6
|
+
from wagtail.admin.rich_text.converters.contentstate_models import (
|
|
7
|
+
Entity,
|
|
8
|
+
EntityRange,
|
|
9
|
+
)
|
|
10
|
+
from wagtail.admin.rich_text.converters.html_to_contentstate import (
|
|
11
|
+
FORCE_WHITESPACE,
|
|
12
|
+
STRIP_WHITESPACE,
|
|
13
|
+
InlineEntityElementHandler,
|
|
14
|
+
)
|
|
15
|
+
from wagtail.admin.rich_text.editors.draftail.features import EntityFeature
|
|
16
|
+
from wagtail.models import Page
|
|
17
|
+
from wagtail.rich_text import LinkHandler
|
|
18
|
+
from wagtail.whitelist import check_url
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
STYLE_KEYS = {"color", "backgroundColor", "size"}
|
|
22
|
+
LINK_KEYS = {"url", "id", "parentId"}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TextStyleEntityHandler(InlineEntityElementHandler):
|
|
26
|
+
"""
|
|
27
|
+
Database HTML to Draft.js ContentState.
|
|
28
|
+
Converts span elements with ``data-entity-type="TEXT_STYLE"``
|
|
29
|
+
and a ``style`` attribute into a single ``TEXT_STYLE`` entity
|
|
30
|
+
with ``color``, ``backgroundColor``, and ``size`` data.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
mutability = "MUTABLE"
|
|
34
|
+
|
|
35
|
+
def get_attribute_data(self, attrs):
|
|
36
|
+
try:
|
|
37
|
+
style = cssutils.parseStyle(attrs["style"])
|
|
38
|
+
data = {"url": ""}
|
|
39
|
+
color = style.getPropertyValue("color")
|
|
40
|
+
if color:
|
|
41
|
+
data["color"] = color
|
|
42
|
+
bg = style.getPropertyValue("background-color")
|
|
43
|
+
if bg:
|
|
44
|
+
data["backgroundColor"] = bg
|
|
45
|
+
size = style.getPropertyValue("font-size")
|
|
46
|
+
if size:
|
|
47
|
+
data["size"] = size
|
|
48
|
+
|
|
49
|
+
return data
|
|
50
|
+
except Exception:
|
|
51
|
+
return {}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class StyledLinkElementHandler(InlineEntityElementHandler):
|
|
55
|
+
"""
|
|
56
|
+
Database HTML to Draft.js ContentState for ``<a>`` tags.
|
|
57
|
+
|
|
58
|
+
Produces a ``LINK`` entity for unstyled links (no
|
|
59
|
+
``data-entity-type="TEXT_STYLE"``), and a ``TEXT_STYLE`` entity
|
|
60
|
+
for styled links (with ``data-entity-type="TEXT_STYLE"``).
|
|
61
|
+
|
|
62
|
+
The entity data carries both link fields (``id``, ``url``,
|
|
63
|
+
``parentId``) and style fields (``color``, ``backgroundColor``,
|
|
64
|
+
``size``) when applicable.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
mutability = "MUTABLE"
|
|
68
|
+
|
|
69
|
+
def handle_starttag(self, name, attrs, state, contentstate):
|
|
70
|
+
if state.current_block is None:
|
|
71
|
+
from wagtail.admin.rich_text.converters.html_to_contentstate import (
|
|
72
|
+
add_paragraph_block,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
add_paragraph_block(state, contentstate)
|
|
76
|
+
|
|
77
|
+
if state.leading_whitespace == FORCE_WHITESPACE:
|
|
78
|
+
state.current_block.text += " "
|
|
79
|
+
state.leading_whitespace = STRIP_WHITESPACE
|
|
80
|
+
|
|
81
|
+
attrs = dict(attrs)
|
|
82
|
+
is_styled = attrs.get("data-entity-type") == "TEXT_STYLE"
|
|
83
|
+
entity_type = "TEXT_STYLE" if is_styled else self.entity_type
|
|
84
|
+
|
|
85
|
+
entity = Entity(
|
|
86
|
+
entity_type,
|
|
87
|
+
self.mutability,
|
|
88
|
+
self.get_attribute_data(attrs),
|
|
89
|
+
)
|
|
90
|
+
key = contentstate.add_entity(entity)
|
|
91
|
+
|
|
92
|
+
entity_range = EntityRange(key)
|
|
93
|
+
entity_range.offset = len(state.current_block.text)
|
|
94
|
+
state.current_block.entity_ranges.append(entity_range)
|
|
95
|
+
state.current_entity_ranges.append(entity_range)
|
|
96
|
+
|
|
97
|
+
def get_attribute_data(self, attrs):
|
|
98
|
+
data = {}
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
style = cssutils.parseStyle(attrs.get("style", ""))
|
|
102
|
+
color = style.getPropertyValue("color")
|
|
103
|
+
if color:
|
|
104
|
+
data["color"] = color
|
|
105
|
+
bg = style.getPropertyValue("background-color")
|
|
106
|
+
if bg:
|
|
107
|
+
data["backgroundColor"] = bg
|
|
108
|
+
size = style.getPropertyValue("font-size")
|
|
109
|
+
if size:
|
|
110
|
+
data["size"] = size
|
|
111
|
+
except Exception: # noqa: S110
|
|
112
|
+
# Style parsing is best-effort; entity data
|
|
113
|
+
# may have just link fields and no style attrs.
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
linktype = attrs.get("linktype")
|
|
117
|
+
href = attrs.get("href")
|
|
118
|
+
|
|
119
|
+
if linktype == "page":
|
|
120
|
+
from wagtail.models import Page
|
|
121
|
+
|
|
122
|
+
page_id = attrs.get("id")
|
|
123
|
+
try:
|
|
124
|
+
page = Page.objects.get(id=page_id).specific
|
|
125
|
+
data["id"] = page.id
|
|
126
|
+
data["url"] = page.url
|
|
127
|
+
parent = page.get_parent()
|
|
128
|
+
data["parentId"] = parent.id if parent else None
|
|
129
|
+
except Page.DoesNotExist:
|
|
130
|
+
data["id"] = int(page_id)
|
|
131
|
+
data["url"] = None
|
|
132
|
+
data["parentId"] = None
|
|
133
|
+
elif href:
|
|
134
|
+
data["url"] = href
|
|
135
|
+
|
|
136
|
+
return data
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _has_styles(props):
|
|
140
|
+
return any(props.get(k) for k in STYLE_KEYS)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def text_style_entity_decorator(props):
|
|
144
|
+
"""
|
|
145
|
+
Draft.js ContentState to database HTML.
|
|
146
|
+
|
|
147
|
+
Converts entities to the corresponding database HTML:
|
|
148
|
+
- ``LINK`` entity without style data → ``<a>`` (plain link, backward
|
|
149
|
+
compatible with Wagtail core format, no ``data-entity-type``).
|
|
150
|
+
- ``TEXT_STYLE`` entity with link data and style data → ``<a>``
|
|
151
|
+
with ``data-entity-type="TEXT_STYLE"`` (styled link).
|
|
152
|
+
- ``TEXT_STYLE`` entity without link data → ``<span>`` with
|
|
153
|
+
``data-entity-type="TEXT_STYLE"`` (plain styled text).
|
|
154
|
+
"""
|
|
155
|
+
color = props.get("color")
|
|
156
|
+
background_color = props.get("backgroundColor")
|
|
157
|
+
size = props.get("size")
|
|
158
|
+
link_id = props.get("id")
|
|
159
|
+
link_url = props.get("url")
|
|
160
|
+
children = props.get("children")
|
|
161
|
+
|
|
162
|
+
styles = []
|
|
163
|
+
if color:
|
|
164
|
+
styles.append(f"color: {color} !important")
|
|
165
|
+
if background_color:
|
|
166
|
+
styles.append(f"background-color: {background_color} !important")
|
|
167
|
+
if size:
|
|
168
|
+
if isinstance(size, (int, float)):
|
|
169
|
+
size = f"{size}px"
|
|
170
|
+
styles.append(f"font-size: {size} !important")
|
|
171
|
+
|
|
172
|
+
has_styles = bool(styles)
|
|
173
|
+
|
|
174
|
+
attrs = {}
|
|
175
|
+
if has_styles:
|
|
176
|
+
attrs["style"] = "; ".join(styles) + ";"
|
|
177
|
+
|
|
178
|
+
if link_id is not None:
|
|
179
|
+
attrs["linktype"] = "page"
|
|
180
|
+
attrs["id"] = link_id
|
|
181
|
+
if has_styles:
|
|
182
|
+
attrs["data-entity-type"] = "TEXT_STYLE"
|
|
183
|
+
return DOM.create_element("a", attrs, children)
|
|
184
|
+
|
|
185
|
+
if link_url:
|
|
186
|
+
attrs["href"] = check_url(link_url)
|
|
187
|
+
if has_styles:
|
|
188
|
+
attrs["data-entity-type"] = "TEXT_STYLE"
|
|
189
|
+
return DOM.create_element("a", attrs, children)
|
|
190
|
+
|
|
191
|
+
# span (no link) — always add data-entity-type for backward compatibility
|
|
192
|
+
attrs["data-entity-type"] = "TEXT_STYLE"
|
|
193
|
+
return DOM.create_element("span", attrs, children)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class StyledPageLinkHandler(LinkHandler):
|
|
197
|
+
identifier = "page"
|
|
198
|
+
|
|
199
|
+
@classmethod
|
|
200
|
+
def get_model(cls):
|
|
201
|
+
return Page
|
|
202
|
+
|
|
203
|
+
@classmethod
|
|
204
|
+
def expand_db_attributes(cls, attrs):
|
|
205
|
+
style = attrs.get("style", "")
|
|
206
|
+
try:
|
|
207
|
+
page = cls.get_instance(attrs)
|
|
208
|
+
href = page.url
|
|
209
|
+
tag = f'<a href="{href}"'
|
|
210
|
+
except Page.DoesNotExist:
|
|
211
|
+
tag = "<a"
|
|
212
|
+
if style:
|
|
213
|
+
tag += f' style="{escape(style)}"'
|
|
214
|
+
return tag + ">"
|
|
215
|
+
|
|
216
|
+
@classmethod
|
|
217
|
+
def expand_db_attributes_many(cls, attrs_list):
|
|
218
|
+
instances = cls.get_many(attrs_list)
|
|
219
|
+
results = []
|
|
220
|
+
for attrs, page in zip(attrs_list, instances, strict=True):
|
|
221
|
+
style = attrs.get("style", "")
|
|
222
|
+
if page:
|
|
223
|
+
href = page.url
|
|
224
|
+
tag = f'<a href="{href}"'
|
|
225
|
+
else:
|
|
226
|
+
tag = "<a"
|
|
227
|
+
if style:
|
|
228
|
+
tag += f' style="{escape(style)}"'
|
|
229
|
+
tag += ">"
|
|
230
|
+
results.append(tag)
|
|
231
|
+
return results
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def register(features):
|
|
235
|
+
features.register_editor_plugin(
|
|
236
|
+
"draftail",
|
|
237
|
+
"text-style-entity",
|
|
238
|
+
EntityFeature(
|
|
239
|
+
{
|
|
240
|
+
"type": "TEXT_STYLE",
|
|
241
|
+
"attributes": [
|
|
242
|
+
"color",
|
|
243
|
+
"backgroundColor",
|
|
244
|
+
"size",
|
|
245
|
+
"url",
|
|
246
|
+
"id",
|
|
247
|
+
"parentId",
|
|
248
|
+
],
|
|
249
|
+
"chooserUrls": {
|
|
250
|
+
"pageChooser": reverse_lazy("wagtailadmin_choose_page"),
|
|
251
|
+
"externalLinkChooser": reverse_lazy(
|
|
252
|
+
"wagtailadmin_choose_page_external_link"
|
|
253
|
+
),
|
|
254
|
+
"emailLinkChooser": reverse_lazy(
|
|
255
|
+
"wagtailadmin_choose_page_email_link"
|
|
256
|
+
),
|
|
257
|
+
"phoneLinkChooser": reverse_lazy(
|
|
258
|
+
"wagtailadmin_choose_page_phone_link"
|
|
259
|
+
),
|
|
260
|
+
"anchorLinkChooser": reverse_lazy(
|
|
261
|
+
"wagtailadmin_choose_page_anchor_link"
|
|
262
|
+
),
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
js=[
|
|
266
|
+
"wagtailadmin/js/page-chooser-modal.js",
|
|
267
|
+
"draftail_text_utils/js/styled_link_source.js",
|
|
268
|
+
"draftail_text_utils/js/text_style_entity.js",
|
|
269
|
+
],
|
|
270
|
+
),
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
features.register_converter_rule(
|
|
274
|
+
"contentstate",
|
|
275
|
+
"text-style-entity",
|
|
276
|
+
{
|
|
277
|
+
"from_database_format": {
|
|
278
|
+
'span[data-entity-type="TEXT_STYLE"]': TextStyleEntityHandler(
|
|
279
|
+
"TEXT_STYLE"
|
|
280
|
+
),
|
|
281
|
+
'a[data-entity-type="TEXT_STYLE"]': StyledLinkElementHandler(
|
|
282
|
+
"TEXT_STYLE"
|
|
283
|
+
),
|
|
284
|
+
},
|
|
285
|
+
"to_database_format": {
|
|
286
|
+
"entity_decorators": {
|
|
287
|
+
"TEXT_STYLE": text_style_entity_decorator,
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
features.register_link_type(StyledPageLinkHandler)
|
|
294
|
+
features.default_features.append("text-style-entity")
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* stylelint-disable selector-class-pattern */
|
|
2
|
+
/* stylelint-disable declaration-property-value-allowed-list */
|
|
3
|
+
/* stylelint-disable declaration-no-important */
|
|
4
|
+
/* stylelint-disable scale-unlimited/declaration-strict-value */
|
|
5
|
+
/* stylelint-disable property-disallowed-list */
|
|
6
|
+
/* stylelint-disable color-named */
|
|
7
|
+
.Draftail--dtu-color-input-wrapper {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.Draftail--dtu-color-input-wrapper input[type='color'] {
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
border: 0;
|
|
16
|
+
padding: 0;
|
|
17
|
+
inline-size: 2rem;
|
|
18
|
+
block-size: 1.5rem;
|
|
19
|
+
background: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.Draftail--dtu-color-option-wrapper {
|
|
23
|
+
flex: 0 0 calc(25% - 12px);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.Draftail--dtu-color-option {
|
|
27
|
+
position: relative;
|
|
28
|
+
background: attr(name type(<color>), black) !important;
|
|
29
|
+
border: 0.3125rem solid var(--w-color-surface-menu-hover, #e8e8e8);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.Draftail--dtu-color-option:hover,
|
|
33
|
+
.Draftail--dtu-color-option.Draftail-ToolbarButton--active {
|
|
34
|
+
border: 0.3125rem solid var(--w-color-text-button-outline-default, #007d7e) !important;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.Draftail--dtu-color-hr {
|
|
38
|
+
width: 100%;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.Draftail--dtu-color-option > .Draftail-ToolbarButton__label {
|
|
42
|
+
display: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.Draftail--dtu-color-option.Draftail-ToolbarButton--active
|
|
46
|
+
> .Draftail-ToolbarButton__label {
|
|
47
|
+
display: inline-block;
|
|
48
|
+
position: relative;
|
|
49
|
+
text-align: center;
|
|
50
|
+
top: -2px;
|
|
51
|
+
color: var(--w-color-text-button-outline-default, #007d7e);
|
|
52
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/* stylelint-disable declaration-no-important */
|
|
4
4
|
/* stylelint-disable scale-unlimited/declaration-strict-value */
|
|
5
5
|
/* stylelint-disable property-disallowed-list */
|
|
6
|
-
.Draftail--
|
|
6
|
+
.Draftail--dtu-control {
|
|
7
7
|
cursor: default !important;
|
|
8
8
|
position: relative;
|
|
9
9
|
display: inline-block;
|
|
@@ -13,44 +13,74 @@
|
|
|
13
13
|
outline-width: 0 !important;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
.Draftail--
|
|
17
|
-
display: none;
|
|
16
|
+
.Draftail--dtu-dropdown {
|
|
18
17
|
position: absolute;
|
|
19
18
|
top: 100%;
|
|
20
19
|
left: 0;
|
|
21
|
-
|
|
22
|
-
min-width: 180px;
|
|
20
|
+
display: none;
|
|
23
21
|
max-height: 260px;
|
|
24
|
-
overflow-y: auto;
|
|
25
22
|
margin: 0;
|
|
26
|
-
|
|
27
|
-
list-style: none;
|
|
23
|
+
z-index: 100;
|
|
28
24
|
background: var(--w-color-surface-page, #fff);
|
|
29
25
|
border: 1px solid var(--w-color-border-furniture, #ddd);
|
|
30
26
|
border-radius: 4px;
|
|
31
27
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
28
|
+
list-style: none;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
|
-
.Draftail--
|
|
31
|
+
.Draftail--dtu-dropdown[aria-expanded='false'] {
|
|
32
|
+
border: 0;
|
|
33
|
+
clip: rect(0 0 0 0);
|
|
34
|
+
clip-path: inset(50%);
|
|
35
|
+
height: 1px;
|
|
36
|
+
margin: -1px;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
padding: 0;
|
|
39
|
+
white-space: nowrap;
|
|
40
|
+
width: 1px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.Draftail--dtu-dropdown[aria-expanded='true'] {
|
|
35
44
|
display: block;
|
|
45
|
+
min-width: 180px;
|
|
46
|
+
overflow-y: auto;
|
|
47
|
+
padding: 4px 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.Draftail--dtu-dropdown-row[aria-expanded='true'] {
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
justify-content: space-evenly;
|
|
54
|
+
overflow: inherit;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.Draftail--dtu-dropdown-palette[aria-expanded='true'] {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-flow: row wrap;
|
|
60
|
+
justify-content: center;
|
|
61
|
+
align-items: center;
|
|
62
|
+
gap: 4px;
|
|
63
|
+
min-width: calc((1.875rem * 4) + 24px);
|
|
64
|
+
overflow: inherit;
|
|
65
|
+
padding: 0.5rem 4px;
|
|
36
66
|
}
|
|
37
67
|
|
|
38
|
-
.Draftail--
|
|
68
|
+
.Draftail--dtu-option {
|
|
39
69
|
padding: 6px 12px;
|
|
40
70
|
cursor: pointer;
|
|
41
71
|
font-size: 13px;
|
|
42
72
|
}
|
|
43
73
|
|
|
44
|
-
.Draftail--
|
|
74
|
+
.Draftail--dtu-option:hover {
|
|
45
75
|
background: var(--w-color-surface-menu-hover, #f0f0f0);
|
|
46
76
|
}
|
|
47
77
|
|
|
48
|
-
.Draftail--
|
|
78
|
+
.Draftail--dtu-option[aria-selected='true'] {
|
|
49
79
|
background: var(--w-color-surface-menu-hover, #e8e8e8);
|
|
50
80
|
font-weight: 600;
|
|
51
81
|
}
|
|
52
82
|
|
|
53
|
-
.Draftail--
|
|
83
|
+
.Draftail--dtu-icon {
|
|
54
84
|
font-family: serif;
|
|
55
85
|
font-size: 14px;
|
|
56
86
|
font-weight: 700;
|
draftail_text_utils-0.3.0/src/draftail_text_utils/static/draftail_text_utils/css/font_family.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* stylelint-disable no-empty-source */
|