annotate cagou/core/simple_xhtml.py @ 354:aa860c10acfc

chat: new chat selector: Using the new ScreenManager feature, a widget to select a chat to display is shown when a user opens the chat (except if an entity jid is specified, in which case it opens directly the Chat widget), or when user presses ESC. When on ChatSelector, pressing ESC brings to the root widget (i.e. default widget). The ChatSelect is a first draft, it is planned to show opened chats, rooms, and a way to create new chats.
author Goffi <goffi@goffi.org>
date Fri, 17 Jan 2020 18:44:35 +0100
parents 83697218b9b2
children 4d660b252487
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
22
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/python
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # Cagou: desktop/mobile frontend for Salut à Toi XMPP client
282
1b835bcfa663 date update
Goffi <goffi@goffi.org>
parents: 185
diff changeset
5 # Copyright (C) 2016-2019 Jérôme Poisson (goffi@goffi.org)
22
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
21 from xml.etree import ElementTree as ET
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
22 from kivy.uix.stacklayout import StackLayout
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
23 from kivy.uix.label import Label
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
24 from kivy.utils import escape_markup
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
25 from kivy.metrics import sp, dp
22
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from kivy import properties
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
27 from sat.core import log as logging
106
9909ed7a7a20 moved SimpleXHTMLWidget to a dedicated module
Goffi <goffi@goffi.org>
parents: 105
diff changeset
28 from sat_frontends.tools import css_color, strings as sat_strings
335
597cc207c8e7 core (simple_xhtml): handle `aesgcm` schemes:
Goffi <goffi@goffi.org>
parents: 325
diff changeset
29 from cagou import G
106
9909ed7a7a20 moved SimpleXHTMLWidget to a dedicated module
Goffi <goffi@goffi.org>
parents: 105
diff changeset
30 from cagou.core.image import AsyncImage
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
31 from cagou.core.constants import Const as C
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
32
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
33
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
34 log = logging.getLogger(__name__)
22
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
35
74117b733bac plugin chat: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
36
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
37 class Escape(str):
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
38 """Class used to mark that a message need to be escaped"""
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
39
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
40
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
41 class SimpleXHTMLWidgetEscapedText(Label):
100
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
42
185
ab3f5173ef5c chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents: 126
diff changeset
43 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
44 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
45 self.font_size = parent.font_size
185
ab3f5173ef5c chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents: 126
diff changeset
46
100
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
47 def _addUrlMarkup(self, text):
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
48 text_elts = []
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
49 idx = 0
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
50 links = 0
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
51 while True:
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
52 m = sat_strings.RE_URL.search(text[idx:])
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
53 if m is not None:
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
54 text_elts.append(escape_markup(m.string[0:m.start()]))
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
55 link_key = 'link_' + str(links)
100
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
56 url = m.group()
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
57 escaped_url = escape_markup(url)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
58 text_elts.append(
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
59 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
60 if not links:
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
61 self.ref_urls = {link_key: url}
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
62 else:
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
63 self.ref_urls[link_key] = url
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
64 links += 1
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
65 idx += m.end()
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
66 else:
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
67 if links:
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
68 text_elts.append(escape_markup(text[idx:]))
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
69 self.markup = True
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
70 self.text = ''.join(text_elts)
100
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
71 break
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
72
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
73 def on_text(self, instance, text):
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
74 # 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
75 # 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
76 # 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
77 if text and not self.markup:
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
78 self._addUrlMarkup(text)
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
79
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
80 def on_ref_press(self, ref):
d7447c585603 chat: added url detection on text messages
Goffi <goffi@goffi.org>
parents: 98
diff changeset
81 url = self.ref_urls[ref]
344
83697218b9b2 core: handle URLs opening in a per-platform way:
Goffi <goffi@goffi.org>
parents: 335
diff changeset
82 G.local_platform.open_url(url, self)
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
83
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
84
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
85 class SimpleXHTMLWidgetText(Label):
185
ab3f5173ef5c chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents: 126
diff changeset
86
ab3f5173ef5c chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents: 126
diff changeset
87 def on_parent(self, instance, parent):
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
88 if parent is not None:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
89 self.font_size = parent.font_size
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
90
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
91
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
92 class SimpleXHTMLWidgetImage(AsyncImage):
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
93 # following properties are desired height/width
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
94 # i.e. the ones specified in height/width attributes of <img>
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
95 # (or wanted for whatever reason)
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
96 # set to None to ignore them
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
97 target_height = properties.NumericProperty(allownone=True)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
98 target_width = properties.NumericProperty(allownone=True)
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
99
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
100 def __init__(self, **kwargs):
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
101 # best calculated size
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
102 self._best_width = self._best_height = 100
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
103 super().__init__(**kwargs)
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
104
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
105 def on_texture(self, instance, texture):
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
106 """Adapt the size according to max size and target_*"""
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
107 if texture is None:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
108 return
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
109 max_width, max_height = dp(C.IMG_MAX_WIDTH), dp(C.IMG_MAX_HEIGHT)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
110 width, height = texture.size
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
111 if self.target_width:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
112 width = min(width, self.target_width)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
113 if width > max_width:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
114 width = C.IMG_MAX_WIDTH
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
115
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
116 height = width / self.image_ratio
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
117
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
118 if self.target_height:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
119 height = min(height, self.target_height)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
120
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
121 if height > max_height:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
122 height = max_height
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
123 width = height * self.image_ratio
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
124
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
125 self.width, self.height = self._best_width, self._best_height = width, height
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
126
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
127 def on_parent(self, instance, parent):
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
128 if parent is not None:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
129 parent.bind(width=self.on_parent_width)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
130
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
131 def on_parent_width(self, instance, width):
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
132 if self._best_width > width:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
133 self.width = width
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
134 self.height = width / self.image_ratio
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
135 else:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
136 self.width, self.height = self._best_width, self._best_height
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
137
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
138
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
139 class SimpleXHTMLWidget(StackLayout):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
140 """widget handling simple XHTML parsing"""
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
141 xhtml = properties.StringProperty()
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
142 color = properties.ListProperty([1, 1, 1, 1])
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
143 # XXX: bold is only used for escaped text
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
144 bold = properties.BooleanProperty(False)
185
ab3f5173ef5c chat, simple XHTML: font size adjustement
Goffi <goffi@goffi.org>
parents: 126
diff changeset
145 font_size = properties.NumericProperty(sp(14))
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
146
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
147 # text/XHTML input
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
148
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
149 def on_xhtml(self, instance, xhtml):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
150 """parse xhtml and set content accordingly
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
151
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
152 if xhtml is an instance of Escape, a Label with no markup will be used
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
153 """
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
154 self.clear_widgets()
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
155 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
156 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
157 text=xhtml, color=self.color, bold=self.bold)
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
158 self.bind(font_size=label.setter('font_size'))
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
159 self.bind(color=label.setter('color'))
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
160 self.bind(bold=label.setter('bold'))
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
161 self.add_widget(label)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
162 else:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
163 xhtml = ET.fromstring(xhtml.encode())
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
164 self.current_wid = None
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
165 self.styles = []
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
166 self._callParseMethod(xhtml)
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
167 if len(self.children) > 1:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
168 self._do_split_labels()
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
169
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
170 def escape(self, text):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
171 """mark that a text need to be escaped (i.e. no markup)"""
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
172 return Escape(text)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
173
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
174 def _do_split_labels(self):
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
175 """Split labels so their content can flow with images"""
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
176 # XXX: to make things easier, we split labels in words
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
177 log.debug("labels splitting start")
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
178 children = self.children[::-1]
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
179 self.clear_widgets()
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
180 for child in children:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
181 if isinstance(child, Label):
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
182 log.debug("label before split: {}".format(child.text))
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
183 styles = []
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
184 tag = False
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
185 new_text = []
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
186 current_tag = []
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
187 current_value = []
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
188 current_wid = self._createText()
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
189 value = False
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
190 close = False
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
191 # we will parse the text and create a new widget
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
192 # on each new word (actually each space)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
193 # FIXME: handle '\n' and other white chars
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
194 for c in child.text:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
195 if tag:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
196 # we are parsing a markup tag
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
197 if c == ']':
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
198 current_tag_s = ''.join(current_tag)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
199 current_style = (current_tag_s, ''.join(current_value))
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
200 if close:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
201 for idx, s in enumerate(reversed(styles)):
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
202 if s[0] == current_tag_s:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
203 del styles[len(styles) - idx - 1]
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
204 break
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
205 else:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
206 styles.append(current_style)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
207 current_tag = []
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
208 current_value = []
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
209 tag = False
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
210 value = False
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
211 close = False
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
212 elif c == '/':
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
213 close = True
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
214 elif c == '=':
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
215 value = True
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
216 elif value:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
217 current_value.append(c)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
218 else:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
219 current_tag.append(c)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
220 new_text.append(c)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
221 else:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
222 # we are parsing regular text
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
223 if c == '[':
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
224 new_text.append(c)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
225 tag = True
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
226 elif c == ' ':
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
227 # new word, we do a new widget
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
228 new_text.append(' ')
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
229 for t, v in reversed(styles):
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
230 new_text.append('[/{}]'.format(t))
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
231 current_wid.text = ''.join(new_text)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
232 new_text = []
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
233 self.add_widget(current_wid)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
234 log.debug("new widget: {}".format(current_wid.text))
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
235 current_wid = self._createText()
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
236 for t, v in styles:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
237 new_text.append('[{tag}{value}]'.format(
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
238 tag = t,
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
239 value = '={}'.format(v) if v else ''))
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
240 else:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
241 new_text.append(c)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
242 if current_wid.text:
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
243 # we may have a remaining widget after the parsing
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
244 close_styles = []
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
245 for t, v in reversed(styles):
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
246 close_styles.append('[/{}]'.format(t))
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
247 current_wid.text = ''.join(close_styles)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
248 self.add_widget(current_wid)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
249 log.debug("new widget: {}".format(current_wid.text))
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
250 else:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
251 # non Label widgets, we just add them
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
252 self.add_widget(child)
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
253 self.splitted = True
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
254 log.debug("split OK")
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
255
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
256 # XHTML parsing methods
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
257
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
258 def _callParseMethod(self, e):
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
259 """Call the suitable method to parse the element
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
260
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
261 self.xhtml_[tag] will be called if it exists, else
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
262 self.xhtml_generic will be used
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
263 @param e(ET.Element): element to parse
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
264 """
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
265 try:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
266 method = getattr(self, f"xhtml_{e.tag}")
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
267 except AttributeError:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
268 log.warning(f"Unhandled XHTML tag: {e.tag}")
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
269 method = self.xhtml_generic
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
270 method(e)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
271
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
272 def _addStyle(self, tag, value=None, append_to_list=True):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
273 """add a markup style to label
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
274
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
275 @param tag(unicode): markup tag
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
276 @param value(unicode): markup value if suitable
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
277 @param append_to_list(bool): if True style we be added to self.styles
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
278 self.styles is needed to keep track of styles to remove
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
279 should most probably be set to True
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
280 """
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
281 label = self._getLabel()
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
282 label.text += '[{tag}{value}]'.format(
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
283 tag = tag,
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
284 value = '={}'.format(value) if value else ''
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
285 )
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
286 if append_to_list:
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
287 self.styles.append((tag, value))
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
288
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
289 def _removeStyle(self, tag, remove_from_list=True):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
290 """remove a markup style from the label
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
291
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
292 @param tag(unicode): markup tag to remove
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
293 @param remove_from_list(bool): if True, remove from self.styles too
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
294 should most probably be set to True
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
295 """
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
296 label = self._getLabel()
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
297 label.text += '[/{tag}]'.format(
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
298 tag = tag
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
299 )
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
300 if remove_from_list:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
301 for rev_idx, style in enumerate(reversed(self.styles)):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
302 if style[0] == tag:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
303 tag_idx = len(self.styles) - 1 - rev_idx
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
304 del self.styles[tag_idx]
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
305 break
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
306
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
307 def _getLabel(self):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
308 """get current Label if it exists, or create a new one"""
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
309 if not isinstance(self.current_wid, Label):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
310 self._addLabel()
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
311 return self.current_wid
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
312
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
313 def _addLabel(self):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
314 """add a new Label
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
315
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
316 current styles will be closed and reopened if needed
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
317 """
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
318 self._closeLabel()
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
319 self.current_wid = self._createText()
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
320 for tag, value in self.styles:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
321 self._addStyle(tag, value, append_to_list=False)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
322 self.add_widget(self.current_wid)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
323
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
324 def _createText(self):
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
325 label = SimpleXHTMLWidgetText(color=self.color, markup=True)
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
326 self.bind(color=label.setter('color'))
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
327 label.bind(texture_size=label.setter('size'))
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
328 return label
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
329
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
330 def _closeLabel(self):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
331 """close current style tags in current label
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
332
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
333 needed when you change label to keep style between
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
334 different widgets
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
335 """
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
336 if isinstance(self.current_wid, Label):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
337 for tag, value in reversed(self.styles):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
338 self._removeStyle(tag, remove_from_list=False)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
339
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
340 def _parseCSS(self, e):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
341 """parse CSS found in "style" attribute of element
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
342
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
343 self._css_styles will be created and contained markup styles added by this method
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
344 @param e(ET.Element): element which may have a "style" attribute
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
345 """
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
346 styles_limit = len(self.styles)
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
347 styles = e.attrib['style'].split(';')
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
348 for style in styles:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
349 try:
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
350 prop, value = style.split(':')
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
351 except ValueError:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
352 log.warning(f"can't parse style: {style}")
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
353 continue
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
354 prop = prop.strip().replace('-', '_')
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
355 value = value.strip()
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
356 try:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
357 method = getattr(self, f"css_{prop}")
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
358 except AttributeError:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
359 log.warning(f"Unhandled CSS: {prop}")
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
360 else:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
361 method(e, value)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
362 self._css_styles = self.styles[styles_limit:]
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
363
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
364 def _closeCSS(self):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
365 """removed CSS styles
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
366
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
367 styles in self._css_styles will be removed
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
368 and the attribute will be deleted
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
369 """
284
ca4daced4638 misc: replaced "dummy" by "__"
Goffi <goffi@goffi.org>
parents: 282
diff changeset
370 for tag, __ in reversed(self._css_styles):
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
371 self._removeStyle(tag)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
372 del self._css_styles
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
373
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
374 def xhtml_generic(self, elem, style=True, markup=None):
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
375 """Generic method for adding HTML elements
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
376
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
377 this method handle content, style and children parsing
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
378 @param elem(ET.Element): element to add
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
379 @param style(bool): if True handle style attribute (CSS)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
380 @param markup(tuple[unicode, (unicode, None)], None): kivy markup to use
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
381 """
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
382 # we first add markup and CSS style
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
383 if markup is not None:
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
384 if isinstance(markup, str):
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
385 tag, value = markup, None
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
386 else:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
387 tag, value = markup
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
388 self._addStyle(tag, value)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
389 style_ = 'style' in elem.attrib and style
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
390 if style_:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
391 self._parseCSS(elem)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
392
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
393 # then content
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
394 if elem.text:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
395 self._getLabel().text += escape_markup(elem.text)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
396
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
397 # we parse the children
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
398 for child in elem:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
399 self._callParseMethod(child)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
400
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
401 # closing CSS style and markup
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
402 if style_:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
403 self._closeCSS()
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
404 if markup is not None:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
405 self._removeStyle(tag)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
406
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
407 # and the tail, which is regular text
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
408 if elem.tail:
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
409 self._getLabel().text += escape_markup(elem.tail)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
410
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
411 # method handling XHTML elements
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
412
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
413 def xhtml_br(self, elem):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
414 label = self._getLabel()
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
415 label.text+='\n'
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
416 self.xhtml_generic(style=False)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
417
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
418 def xhtml_em(self, elem):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
419 self.xhtml_generic(elem, markup='i')
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
420
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
421 def xhtml_img(self, elem):
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
422 try:
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
423 src = elem.attrib['src']
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
424 except KeyError:
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
425 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
426 return
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
427 try:
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
428 target_height = int(elem.get('height', 0))
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
429 except ValueError:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
430 log.warning(f"Can't parse image height: {elem.get('height')}")
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
431 target_height = None
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
432 try:
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
433 target_width = int(elem.get('width', 0))
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
434 except ValueError:
325
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
435 log.warning(f"Can't parse image width: {elem.get('width')}")
5868a5575e01 chat: cleaning + some improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
436 target_width = None
59
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
437
2aa44a82d0e7 chat: XHTML image size handling:
Goffi <goffi@goffi.org>
parents: 58
diff changeset
438 img = SimpleXHTMLWidgetImage(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
439 self.current_wid = img
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
440 self.add_widget(img)
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
441
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
442 def xhtml_p(self, elem):
58
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
443 if isinstance(self.current_wid, Label):
7aa2ffff9067 chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents: 57
diff changeset
444 self.current_wid.text+="\n\n"
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
445 self.xhtml_generic(elem)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
446
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
447 def xhtml_span(self, elem):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
448 self.xhtml_generic(elem)
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
449
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
450 def xhtml_strong(self, elem):
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
451 self.xhtml_generic(elem, markup='b')
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
452
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
453 # methods handling CSS properties
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
454
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
455 def css_color(self, elem, value):
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
456 self._addStyle("color", css_color.parse(value))
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
457
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
458 def css_text_decoration(self, elem, value):
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
459 if value == 'underline':
299
86b1cd8121dd core (simple_xhtml): activated underline and line-through which are now available
Goffi <goffi@goffi.org>
parents: 288
diff changeset
460 self._addStyle('u')
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
461 elif value == 'line-through':
299
86b1cd8121dd core (simple_xhtml): activated underline and line-through which are now available
Goffi <goffi@goffi.org>
parents: 288
diff changeset
462 self._addStyle('s')
57
a51ea7874e43 chat: XHTML parsing first draft:
Goffi <goffi@goffi.org>
parents: 54
diff changeset
463 else:
312
772c170b47a9 Python3 port:
Goffi <goffi@goffi.org>
parents: 299
diff changeset
464 log.warning("unhandled text decoration: {}".format(value))