Mercurial > libervia-desktop-kivy
annotate libervia/desktop_kivy/core/simple_xhtml.py @ 508:d87b9a6b0b69
doc (calls): updated documentation to describe the new UI features:
fix 425
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 25 Oct 2023 15:29:33 +0200 |
parents | b3cedbee561d |
children |
rev | line source |
---|---|
379 | 1 #!/usr/bin/env python3 |
2 | |
22 | 3 |
493
b3cedbee561d
refactoring: rename `cagou` to `libervia.desktop_kivy` + update imports and names following backend changes
Goffi <goffi@goffi.org>
parents:
491
diff
changeset
|
4 #Libervia Desktop-Kivy |
461 | 5 # Copyright (C) 2016-2021 Jérôme Poisson (goffi@goffi.org) |
22 | 6 |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 | |
325 | 21 from xml.etree import ElementTree as ET |
57 | 22 from kivy.uix.stacklayout import StackLayout |
23 from kivy.uix.label import Label | |
24 from kivy.utils import escape_markup | |
422
efee0e0afb78
core (common): moved simple_xhtml's image code to a generic "SizedImage" widget
Goffi <goffi@goffi.org>
parents:
379
diff
changeset
|
25 from kivy.metrics import sp |
22 | 26 from kivy import properties |
493
b3cedbee561d
refactoring: rename `cagou` to `libervia.desktop_kivy` + update imports and names following backend changes
Goffi <goffi@goffi.org>
parents:
491
diff
changeset
|
27 from libervia.backend.core import log as logging |
b3cedbee561d
refactoring: rename `cagou` to `libervia.desktop_kivy` + update imports and names following backend changes
Goffi <goffi@goffi.org>
parents:
491
diff
changeset
|
28 from libervia.frontends.tools import css_color, strings as sat_strings |
b3cedbee561d
refactoring: rename `cagou` to `libervia.desktop_kivy` + update imports and names following backend changes
Goffi <goffi@goffi.org>
parents:
491
diff
changeset
|
29 from libervia.desktop_kivy import G |
b3cedbee561d
refactoring: rename `cagou` to `libervia.desktop_kivy` + update imports and names following backend changes
Goffi <goffi@goffi.org>
parents:
491
diff
changeset
|
30 from libervia.desktop_kivy.core.common import SizedImage |
325 | 31 |
32 | |
33 log = logging.getLogger(__name__) | |
22 | 34 |
35 | |
312 | 36 class Escape(str): |
57 | 37 """Class used to mark that a message need to be escaped""" |
38 | |
39 | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
40 class SimpleXHTMLWidgetEscapedText(Label): |
100
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
41 |
185
ab3f5173ef5c
chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
42 def on_parent(self, instance, parent): |
288
44752e8031f8
simple XHTML: fixed crash when parent is set to None + fixed bold restoration when escaped message is modified
Goffi <goffi@goffi.org>
parents:
284
diff
changeset
|
43 if parent is not None: |
44752e8031f8
simple XHTML: fixed crash when parent is set to None + fixed bold restoration when escaped message is modified
Goffi <goffi@goffi.org>
parents:
284
diff
changeset
|
44 self.font_size = parent.font_size |
185
ab3f5173ef5c
chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
45 |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
46 def _add_url_markup(self, text): |
100
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
47 text_elts = [] |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
48 idx = 0 |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
49 links = 0 |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
50 while True: |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
51 m = sat_strings.RE_URL.search(text[idx:]) |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
52 if m is not None: |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
53 text_elts.append(escape_markup(m.string[0:m.start()])) |
312 | 54 link_key = 'link_' + str(links) |
100
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
55 url = m.group() |
325 | 56 escaped_url = escape_markup(url) |
57 text_elts.append( | |
58 f'[color=5500ff][ref={link_key}]{escaped_url}[/ref][/color]') | |
100
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
59 if not links: |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
60 self.ref_urls = {link_key: url} |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
61 else: |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
62 self.ref_urls[link_key] = url |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
63 links += 1 |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
64 idx += m.end() |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
65 else: |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
66 if links: |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
67 text_elts.append(escape_markup(text[idx:])) |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
68 self.markup = True |
312 | 69 self.text = ''.join(text_elts) |
100
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
70 break |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
71 |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
72 def on_text(self, instance, text): |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
73 # do NOT call the method if self.markup is set |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
74 # this would result in infinite loop (because self.text |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
75 # is changed if an URL is found, and in this case markup too) |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
76 if text and not self.markup: |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
77 self._add_url_markup(text) |
100
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
78 |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
79 def on_ref_press(self, ref): |
d7447c585603
chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents:
98
diff
changeset
|
80 url = self.ref_urls[ref] |
344
83697218b9b2
core: handle URLs opening in a per-platform way:
Goffi <goffi@goffi.org>
parents:
335
diff
changeset
|
81 G.local_platform.open_url(url, self) |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
82 |
59 | 83 |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
84 class SimpleXHTMLWidgetText(Label): |
185
ab3f5173ef5c
chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
85 |
ab3f5173ef5c
chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
86 def on_parent(self, instance, parent): |
325 | 87 if parent is not None: |
88 self.font_size = parent.font_size | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
89 |
59 | 90 |
57 | 91 class SimpleXHTMLWidget(StackLayout): |
92 """widget handling simple XHTML parsing""" | |
93 xhtml = properties.StringProperty() | |
94 color = properties.ListProperty([1, 1, 1, 1]) | |
95 # XXX: bold is only used for escaped text | |
96 bold = properties.BooleanProperty(False) | |
185
ab3f5173ef5c
chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
97 font_size = properties.NumericProperty(sp(14)) |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
98 |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
99 # text/XHTML input |
57 | 100 |
101 def on_xhtml(self, instance, xhtml): | |
102 """parse xhtml and set content accordingly | |
103 | |
288
44752e8031f8
simple XHTML: fixed crash when parent is set to None + fixed bold restoration when escaped message is modified
Goffi <goffi@goffi.org>
parents:
284
diff
changeset
|
104 if xhtml is an instance of Escape, a Label with no markup will be used |
57 | 105 """ |
106 self.clear_widgets() | |
107 if isinstance(xhtml, Escape): | |
288
44752e8031f8
simple XHTML: fixed crash when parent is set to None + fixed bold restoration when escaped message is modified
Goffi <goffi@goffi.org>
parents:
284
diff
changeset
|
108 label = SimpleXHTMLWidgetEscapedText( |
44752e8031f8
simple XHTML: fixed crash when parent is set to None + fixed bold restoration when escaped message is modified
Goffi <goffi@goffi.org>
parents:
284
diff
changeset
|
109 text=xhtml, color=self.color, bold=self.bold) |
325 | 110 self.bind(font_size=label.setter('font_size')) |
57 | 111 self.bind(color=label.setter('color')) |
112 self.bind(bold=label.setter('bold')) | |
113 self.add_widget(label) | |
114 else: | |
325 | 115 xhtml = ET.fromstring(xhtml.encode()) |
57 | 116 self.current_wid = None |
117 self.styles = [] | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
118 self._call_parse_method(xhtml) |
325 | 119 if len(self.children) > 1: |
120 self._do_split_labels() | |
57 | 121 |
122 def escape(self, text): | |
123 """mark that a text need to be escaped (i.e. no markup)""" | |
124 return Escape(text) | |
125 | |
325 | 126 def _do_split_labels(self): |
127 """Split labels so their content can flow with images""" | |
128 # XXX: to make things easier, we split labels in words | |
129 log.debug("labels splitting start") | |
130 children = self.children[::-1] | |
131 self.clear_widgets() | |
132 for child in children: | |
133 if isinstance(child, Label): | |
134 log.debug("label before split: {}".format(child.text)) | |
135 styles = [] | |
136 tag = False | |
137 new_text = [] | |
138 current_tag = [] | |
139 current_value = [] | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
140 current_wid = self._create_text() |
325 | 141 value = False |
142 close = False | |
143 # we will parse the text and create a new widget | |
144 # on each new word (actually each space) | |
145 # FIXME: handle '\n' and other white chars | |
146 for c in child.text: | |
147 if tag: | |
148 # we are parsing a markup tag | |
149 if c == ']': | |
150 current_tag_s = ''.join(current_tag) | |
151 current_style = (current_tag_s, ''.join(current_value)) | |
152 if close: | |
153 for idx, s in enumerate(reversed(styles)): | |
154 if s[0] == current_tag_s: | |
155 del styles[len(styles) - idx - 1] | |
156 break | |
157 else: | |
158 styles.append(current_style) | |
159 current_tag = [] | |
160 current_value = [] | |
161 tag = False | |
162 value = False | |
163 close = False | |
164 elif c == '/': | |
165 close = True | |
166 elif c == '=': | |
167 value = True | |
168 elif value: | |
169 current_value.append(c) | |
170 else: | |
171 current_tag.append(c) | |
172 new_text.append(c) | |
173 else: | |
174 # we are parsing regular text | |
175 if c == '[': | |
176 new_text.append(c) | |
177 tag = True | |
178 elif c == ' ': | |
179 # new word, we do a new widget | |
180 new_text.append(' ') | |
181 for t, v in reversed(styles): | |
182 new_text.append('[/{}]'.format(t)) | |
183 current_wid.text = ''.join(new_text) | |
184 new_text = [] | |
185 self.add_widget(current_wid) | |
186 log.debug("new widget: {}".format(current_wid.text)) | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
187 current_wid = self._create_text() |
325 | 188 for t, v in styles: |
189 new_text.append('[{tag}{value}]'.format( | |
190 tag = t, | |
191 value = '={}'.format(v) if v else '')) | |
192 else: | |
193 new_text.append(c) | |
194 if current_wid.text: | |
195 # we may have a remaining widget after the parsing | |
196 close_styles = [] | |
197 for t, v in reversed(styles): | |
198 close_styles.append('[/{}]'.format(t)) | |
199 current_wid.text = ''.join(close_styles) | |
200 self.add_widget(current_wid) | |
201 log.debug("new widget: {}".format(current_wid.text)) | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
202 else: |
325 | 203 # non Label widgets, we just add them |
204 self.add_widget(child) | |
205 self.splitted = True | |
206 log.debug("split OK") | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
207 |
57 | 208 # XHTML parsing methods |
209 | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
210 def _call_parse_method(self, e): |
325 | 211 """Call the suitable method to parse the element |
57 | 212 |
213 self.xhtml_[tag] will be called if it exists, else | |
214 self.xhtml_generic will be used | |
215 @param e(ET.Element): element to parse | |
216 """ | |
217 try: | |
325 | 218 method = getattr(self, f"xhtml_{e.tag}") |
57 | 219 except AttributeError: |
325 | 220 log.warning(f"Unhandled XHTML tag: {e.tag}") |
57 | 221 method = self.xhtml_generic |
222 method(e) | |
223 | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
224 def _add_style(self, tag, value=None, append_to_list=True): |
57 | 225 """add a markup style to label |
226 | |
227 @param tag(unicode): markup tag | |
228 @param value(unicode): markup value if suitable | |
229 @param append_to_list(bool): if True style we be added to self.styles | |
230 self.styles is needed to keep track of styles to remove | |
231 should most probably be set to True | |
232 """ | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
233 label = self._get_label() |
312 | 234 label.text += '[{tag}{value}]'.format( |
57 | 235 tag = tag, |
312 | 236 value = '={}'.format(value) if value else '' |
57 | 237 ) |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
238 if append_to_list: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
239 self.styles.append((tag, value)) |
57 | 240 |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
241 def _remove_style(self, tag, remove_from_list=True): |
57 | 242 """remove a markup style from the label |
243 | |
244 @param tag(unicode): markup tag to remove | |
245 @param remove_from_list(bool): if True, remove from self.styles too | |
246 should most probably be set to True | |
247 """ | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
248 label = self._get_label() |
312 | 249 label.text += '[/{tag}]'.format( |
57 | 250 tag = tag |
251 ) | |
252 if remove_from_list: | |
253 for rev_idx, style in enumerate(reversed(self.styles)): | |
254 if style[0] == tag: | |
255 tag_idx = len(self.styles) - 1 - rev_idx | |
256 del self.styles[tag_idx] | |
257 break | |
258 | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
259 def _get_label(self): |
57 | 260 """get current Label if it exists, or create a new one""" |
261 if not isinstance(self.current_wid, Label): | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
262 self._add_label() |
57 | 263 return self.current_wid |
264 | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
265 def _add_label(self): |
57 | 266 """add a new Label |
267 | |
268 current styles will be closed and reopened if needed | |
269 """ | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
270 self._close_label() |
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
271 self.current_wid = self._create_text() |
57 | 272 for tag, value in self.styles: |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
273 self._add_style(tag, value, append_to_list=False) |
57 | 274 self.add_widget(self.current_wid) |
275 | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
276 def _create_text(self): |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
277 label = SimpleXHTMLWidgetText(color=self.color, markup=True) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
278 self.bind(color=label.setter('color')) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
279 label.bind(texture_size=label.setter('size')) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
280 return label |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
281 |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
282 def _close_label(self): |
57 | 283 """close current style tags in current label |
284 | |
285 needed when you change label to keep style between | |
286 different widgets | |
287 """ | |
288 if isinstance(self.current_wid, Label): | |
289 for tag, value in reversed(self.styles): | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
290 self._remove_style(tag, remove_from_list=False) |
57 | 291 |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
292 def _parse_css(self, e): |
57 | 293 """parse CSS found in "style" attribute of element |
294 | |
295 self._css_styles will be created and contained markup styles added by this method | |
296 @param e(ET.Element): element which may have a "style" attribute | |
297 """ | |
298 styles_limit = len(self.styles) | |
312 | 299 styles = e.attrib['style'].split(';') |
57 | 300 for style in styles: |
301 try: | |
312 | 302 prop, value = style.split(':') |
57 | 303 except ValueError: |
325 | 304 log.warning(f"can't parse style: {style}") |
57 | 305 continue |
312 | 306 prop = prop.strip().replace('-', '_') |
57 | 307 value = value.strip() |
308 try: | |
325 | 309 method = getattr(self, f"css_{prop}") |
57 | 310 except AttributeError: |
325 | 311 log.warning(f"Unhandled CSS: {prop}") |
57 | 312 else: |
313 method(e, value) | |
314 self._css_styles = self.styles[styles_limit:] | |
315 | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
316 def _close_css(self): |
57 | 317 """removed CSS styles |
318 | |
319 styles in self._css_styles will be removed | |
320 and the attribute will be deleted | |
321 """ | |
284 | 322 for tag, __ in reversed(self._css_styles): |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
323 self._remove_style(tag) |
57 | 324 del self._css_styles |
325 | |
326 def xhtml_generic(self, elem, style=True, markup=None): | |
325 | 327 """Generic method for adding HTML elements |
57 | 328 |
329 this method handle content, style and children parsing | |
330 @param elem(ET.Element): element to add | |
331 @param style(bool): if True handle style attribute (CSS) | |
332 @param markup(tuple[unicode, (unicode, None)], None): kivy markup to use | |
333 """ | |
334 # we first add markup and CSS style | |
335 if markup is not None: | |
312 | 336 if isinstance(markup, str): |
57 | 337 tag, value = markup, None |
338 else: | |
339 tag, value = markup | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
340 self._add_style(tag, value) |
57 | 341 style_ = 'style' in elem.attrib and style |
342 if style_: | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
343 self._parse_css(elem) |
57 | 344 |
345 # then content | |
346 if elem.text: | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
347 self._get_label().text += escape_markup(elem.text) |
57 | 348 |
349 # we parse the children | |
350 for child in elem: | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
351 self._call_parse_method(child) |
57 | 352 |
353 # closing CSS style and markup | |
354 if style_: | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
355 self._close_css() |
57 | 356 if markup is not None: |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
357 self._remove_style(tag) |
57 | 358 |
359 # and the tail, which is regular text | |
360 if elem.tail: | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
361 self._get_label().text += escape_markup(elem.tail) |
57 | 362 |
363 # method handling XHTML elements | |
364 | |
365 def xhtml_br(self, elem): | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
366 label = self._get_label() |
57 | 367 label.text+='\n' |
453
2d277a3d9cec
core (simple_xhtml): fixed xhtml_generic call in xhtml_br
Goffi <goffi@goffi.org>
parents:
422
diff
changeset
|
368 self.xhtml_generic(elem, style=False) |
57 | 369 |
370 def xhtml_em(self, elem): | |
371 self.xhtml_generic(elem, markup='i') | |
372 | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
373 def xhtml_img(self, elem): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
374 try: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
375 src = elem.attrib['src'] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
376 except KeyError: |
312 | 377 log.warning("<img> element without src: {}".format(ET.tostring(elem))) |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
378 return |
59 | 379 try: |
312 | 380 target_height = int(elem.get('height', 0)) |
59 | 381 except ValueError: |
325 | 382 log.warning(f"Can't parse image height: {elem.get('height')}") |
383 target_height = None | |
59 | 384 try: |
312 | 385 target_width = int(elem.get('width', 0)) |
59 | 386 except ValueError: |
325 | 387 log.warning(f"Can't parse image width: {elem.get('width')}") |
388 target_width = None | |
59 | 389 |
422
efee0e0afb78
core (common): moved simple_xhtml's image code to a generic "SizedImage" widget
Goffi <goffi@goffi.org>
parents:
379
diff
changeset
|
390 img = SizedImage( |
efee0e0afb78
core (common): moved simple_xhtml's image code to a generic "SizedImage" widget
Goffi <goffi@goffi.org>
parents:
379
diff
changeset
|
391 source=src, target_height=target_height, target_width=target_width) |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
392 self.current_wid = img |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
393 self.add_widget(img) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
394 |
57 | 395 def xhtml_p(self, elem): |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
396 if isinstance(self.current_wid, Label): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
397 self.current_wid.text+="\n\n" |
57 | 398 self.xhtml_generic(elem) |
399 | |
400 def xhtml_span(self, elem): | |
401 self.xhtml_generic(elem) | |
402 | |
403 def xhtml_strong(self, elem): | |
404 self.xhtml_generic(elem, markup='b') | |
405 | |
406 # methods handling CSS properties | |
407 | |
408 def css_color(self, elem, value): | |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
409 self._add_style("color", css_color.parse(value)) |
57 | 410 |
411 def css_text_decoration(self, elem, value): | |
312 | 412 if value == 'underline': |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
413 self._add_style('u') |
312 | 414 elif value == 'line-through': |
491
203755bbe0fe
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
461
diff
changeset
|
415 self._add_style('s') |
57 | 416 else: |
312 | 417 log.warning("unhandled text decoration: {}".format(value)) |