Add image previews in HTML messages
This commit is contained in:
parent
d353e5bf6e
commit
c4f46f42b6
2
TODO.md
2
TODO.md
|
@ -28,3 +28,5 @@
|
||||||
- `<pre>` scrollbar on overflow
|
- `<pre>` scrollbar on overflow
|
||||||
|
|
||||||
- Make links in room subtitle clickable, formatting?
|
- Make links in room subtitle clickable, formatting?
|
||||||
|
|
||||||
|
- Push instead of replacing in stack view
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import html_sanitizer.sanitizer as sanitizer
|
import html_sanitizer.sanitizer as sanitizer
|
||||||
from lxml.html import HtmlElement
|
from lxml.html import HtmlElement, etree
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,8 +39,20 @@ class HtmlFilter(QObject):
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(str, result=str)
|
@pyqtSlot(str, result=str)
|
||||||
def sanitize(self, html: str) -> str:
|
def filter(self, html: str) -> str:
|
||||||
return self._sanitizer.sanitize(html)
|
html = self._sanitizer.sanitize(html)
|
||||||
|
if not html:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
tree = etree.fromstring(html, parser=etree.HTMLParser())
|
||||||
|
|
||||||
|
for el in tree.iter("img"):
|
||||||
|
el = self._wrap_img_in_a(el)
|
||||||
|
|
||||||
|
for el in tree.iter("a"):
|
||||||
|
el = self._append_img_to_a(el)
|
||||||
|
|
||||||
|
return str(etree.tostring(tree[0][0], encoding="utf-8"), "utf-8")
|
||||||
|
|
||||||
|
|
||||||
@pyqtProperty("QVariant")
|
@pyqtProperty("QVariant")
|
||||||
|
@ -73,7 +85,7 @@ class HtmlFilter(QObject):
|
||||||
"link_regexes": self.link_regexes,
|
"link_regexes": self.link_regexes,
|
||||||
"avoid_hosts": [],
|
"avoid_hosts": [],
|
||||||
},
|
},
|
||||||
"sanitize_href": sanitizer.sanitize_href,
|
"sanitize_href": lambda href: href,
|
||||||
"element_preprocessors": [
|
"element_preprocessors": [
|
||||||
sanitizer.bold_span_to_strong,
|
sanitizer.bold_span_to_strong,
|
||||||
sanitizer.italic_span_to_em,
|
sanitizer.italic_span_to_em,
|
||||||
|
@ -101,3 +113,39 @@ class HtmlFilter(QObject):
|
||||||
el.clear()
|
el.clear()
|
||||||
|
|
||||||
return el
|
return el
|
||||||
|
|
||||||
|
|
||||||
|
def _wrap_img_in_a(self, el: HtmlElement) -> HtmlElement:
|
||||||
|
link = el.attrib.get("src", "")
|
||||||
|
width = el.attrib.get("width", "256")
|
||||||
|
height = el.attrib.get("height", "256")
|
||||||
|
|
||||||
|
if el.getparent().tag == "a" or el.tag != "img" or \
|
||||||
|
not self._is_image_path(link):
|
||||||
|
return el
|
||||||
|
|
||||||
|
el.tag = "a"
|
||||||
|
el.attrib.clear()
|
||||||
|
el.attrib["href"] = link
|
||||||
|
el.append(etree.Element("img", src=link, width=width, height=height))
|
||||||
|
return el
|
||||||
|
|
||||||
|
|
||||||
|
def _append_img_to_a(self, el: HtmlElement) -> HtmlElement:
|
||||||
|
link = el.attrib.get("href", "")
|
||||||
|
|
||||||
|
if not (el.tag == "a" and self._is_image_path(link)):
|
||||||
|
return el
|
||||||
|
|
||||||
|
for _ in el.iter("img"): # if the <a> already has an <img> child
|
||||||
|
return el
|
||||||
|
|
||||||
|
el.append(etree.Element("img", src=link, width="256", height="256"))
|
||||||
|
return el
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_image_path(link: str) -> bool:
|
||||||
|
return bool(re.match(
|
||||||
|
r".+\.(jpg|jpeg|png|gif|bmp|webp|tiff|svg)$", link, re.IGNORECASE
|
||||||
|
))
|
||||||
|
|
|
@ -39,7 +39,7 @@ Row {
|
||||||
// (isOwn ? " " + content : "")
|
// (isOwn ? " " + content : "")
|
||||||
|
|
||||||
text: (dict.formatted_body ?
|
text: (dict.formatted_body ?
|
||||||
Backend.htmlFilter.sanitize(dict.formatted_body) :
|
Backend.htmlFilter.filter(dict.formatted_body) :
|
||||||
dict.body) +
|
dict.body) +
|
||||||
" <font size=" + smallSize + "px color=gray>" +
|
" <font size=" + smallSize + "px color=gray>" +
|
||||||
Qt.formatDateTime(date_time, "hh:mm:ss") +
|
Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||||
|
|
|
@ -20,5 +20,9 @@ Rectangle {
|
||||||
clip: true
|
clip: true
|
||||||
topMargin: space
|
topMargin: space
|
||||||
bottomMargin: space
|
bottomMargin: space
|
||||||
|
|
||||||
|
// Keep x scroll pages cached, to limit images having to be
|
||||||
|
// reloaded from network.
|
||||||
|
cacheBuffer: height * 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user