Skip to content

Commit 28710e9

Browse files
committed
Bypass composite decorators in most common br scenario
1 parent 8ae6398 commit 28710e9

File tree

6 files changed

+82
-10
lines changed

6 files changed

+82
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,4 @@ lib64
9393
example.html
9494
.mypy_cache
9595
pip-wheel-metadata
96+
__pycache__

draftjs_exporter/composite_decorators.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
from operator import itemgetter
23
from typing import Any, Dict, Generator, List, Sequence, Tuple
34

@@ -9,6 +10,9 @@
910
Element,
1011
)
1112

13+
br = "\n"
14+
br_strategy = re.compile(r"\n")
15+
1216

1317
def get_decorations(
1418
decorators: CompositeDecorators, text: str
@@ -69,3 +73,20 @@ def render_decorators(
6973
DOM.append_child(decorated_node, decorated_child)
7074

7175
return decorated_node
76+
77+
78+
def should_render_decorators(
79+
decorators: CompositeDecorators, text: str,
80+
) -> bool:
81+
nb_decorators = len(decorators)
82+
83+
if nb_decorators == 0:
84+
return False
85+
86+
is_skippable_br = (
87+
nb_decorators == 1
88+
and decorators[0]["strategy"] == br_strategy
89+
and not (br in text)
90+
)
91+
92+
return not is_skippable_br

draftjs_exporter/dom.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ def use(cls, engine: str) -> None:
3535
cls.dom = import_string(engine)
3636

3737
@classmethod
38-
def create_element(cls, type_: RenderableType = None, props: Optional[Props] = None, *elt_children: Optional[Element]) -> Element:
38+
def create_element(
39+
cls,
40+
type_: RenderableType = None,
41+
props: Optional[Props] = None,
42+
*elt_children: Optional[Element]
43+
) -> Element:
3944
"""
4045
Signature inspired by React.createElement.
4146
createElement(

draftjs_exporter/html.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
from typing import List, Optional, Tuple
44

55
from draftjs_exporter.command import Command
6-
from draftjs_exporter.composite_decorators import render_decorators
6+
from draftjs_exporter.composite_decorators import (
7+
render_decorators,
8+
should_render_decorators,
9+
)
710
from draftjs_exporter.defaults import BLOCK_MAP, STYLE_MAP
811
from draftjs_exporter.dom import DOM
912
from draftjs_exporter.entity_state import EntityState
@@ -27,7 +30,6 @@ class HTML(object):
2730

2831
__slots__ = (
2932
"composite_decorators",
30-
"has_decorators",
3133
"entity_options",
3234
"block_options",
3335
"style_options",
@@ -38,7 +40,6 @@ def __init__(self, config: Optional[Config] = None) -> None:
3840
config = {}
3941

4042
self.composite_decorators = config.get("composite_decorators", [])
41-
self.has_decorators = len(self.composite_decorators) > 0
4243

4344
self.entity_options = Options.map_entities(
4445
config.get("entity_decorators", {})
@@ -86,6 +87,10 @@ def render(self, content_state: Optional[ContentState] = None) -> str:
8687
def render_block(
8788
self, block: Block, entity_map: EntityMap, wrapper_state: WrapperState
8889
) -> Element:
90+
has_decorators = should_render_decorators(
91+
self.composite_decorators, block["text"]
92+
)
93+
8994
if (
9095
"inlineStyleRanges" in block
9196
and block["inlineStyleRanges"]
@@ -102,7 +107,7 @@ def render_block(
102107
style_state.apply(command)
103108

104109
# Decorators are not rendered inside entities.
105-
if entity_state.has_no_entity() and self.has_decorators:
110+
if entity_state.has_no_entity() and has_decorators:
106111
decorated_node = render_decorators(
107112
self.composite_decorators,
108113
text,
@@ -129,7 +134,7 @@ def render_block(
129134
):
130135
DOM.append_child(content, styled_node)
131136
# Fast track for blocks which do not contain styles nor entities, which is very common.
132-
elif self.has_decorators:
137+
elif has_decorators:
133138
content = render_decorators(
134139
self.composite_decorators,
135140
block["text"],

draftjs_exporter/wrapper_state.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,7 @@ def update_stack(self, options: Options, depth: int) -> None:
161161
DOM.append_child(self.stack.head().elt, wrapper_parent)
162162
else:
163163
# Otherwise we can append at the end of the last child.
164-
wrapper_parent = (
165-
self.stack.head().last_child
166-
)
164+
wrapper_parent = self.stack.head().last_child
167165

168166
DOM.append_child(wrapper_parent, new_wrapper.elt)
169167

tests/test_composite_decorators.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import re
22
import unittest
33

4-
from draftjs_exporter.composite_decorators import render_decorators
4+
from draftjs_exporter.composite_decorators import (
5+
render_decorators,
6+
should_render_decorators,
7+
)
58
from draftjs_exporter.constants import BLOCK_TYPES
69
from draftjs_exporter.dom import DOM
710
from example import LINKIFY_RE, br, hashtag, linkify
@@ -87,6 +90,17 @@ def test_render(self):
8790
),
8891
"<br/>",
8992
)
93+
self.assertEqual(
94+
DOM.render(
95+
render_decorators(
96+
[BR_DECORATOR],
97+
"test \n test",
98+
{"type": BLOCK_TYPES.UNSTYLED, "depth": 0},
99+
[],
100+
)
101+
),
102+
"test <br/> test",
103+
)
90104

91105
def test_render_code_block(self):
92106
self.assertEqual(
@@ -169,3 +183,31 @@ def component(props):
169183
blocks[0],
170184
blocks,
171185
)
186+
187+
def test_should_render_decorators_empty(self):
188+
self.assertEqual(
189+
should_render_decorators([], "test"), False,
190+
)
191+
192+
def test_should_render_decorators_more_than_one(self):
193+
self.assertEqual(
194+
should_render_decorators(
195+
[HASHTAG_DECORATOR, LINKIFY_DECORATOR], "test",
196+
),
197+
True,
198+
)
199+
200+
def test_should_render_decorators_single_not_br(self):
201+
self.assertEqual(
202+
should_render_decorators([HASHTAG_DECORATOR], "test"), True,
203+
)
204+
205+
def test_should_render_decorators_single_br_absent(self):
206+
self.assertEqual(
207+
should_render_decorators([BR_DECORATOR], "test"), False,
208+
)
209+
210+
def test_should_render_decorators_single_br_present(self):
211+
self.assertEqual(
212+
should_render_decorators([BR_DECORATOR], "test \n test"), True,
213+
)

0 commit comments

Comments
 (0)