core (XMLUI): new XHTMLBox widget:

XHTMLBox is a textbox specialised in XHTML, i.e. it renders the XHTML when in read_only, and it allows to edit it.
The XHTML is cleaned by default, the cleaning is done by Text Syntaxes plugin (actually there is a cleaning method which can be set by any plugin, but Text Syntaxes is the one which does it).
This commit is contained in:
Goffi 2019-01-19 11:39:02 +01:00
commit 87871fabca
2 changed files with 52 additions and 2 deletions

View file

@ -26,6 +26,7 @@ log = getLogger(__name__)
from twisted.internet import defer
from twisted.internet.threads import deferToThread
from sat.core import exceptions
from sat.tools import xml_tools
try:
from lxml import html
@ -205,6 +206,9 @@ class TextSyntaxes(object):
host.bridge.addMethod(
"syntaxGet", ".plugin", in_sign="s", out_sign="s", method=self.getSyntax
)
if xml_tools.cleanXHTML is None:
log.debug(u"Installing cleaning method")
xml_tools.cleanXHTML = self.cleanXHTML
def _updateParamOptions(self):
data_synt = TextSyntaxes.syntaxes

View file

@ -41,6 +41,10 @@ SAT_PARAM_SEPARATOR = "_XMLUI_PARAM_" # used to have unique elements names
html_entity_re = re.compile(r"&([a-zA-Z]+?);")
XML_ENTITIES = ("quot", "amp", "apos", "lt", "gt")
# method to clean XHTML, receive raw unsecure XML or HTML, must return cleaned raw XHTML
# this method must be set during runtime
cleanXHTML = None
# TODO: move XMLUI stuff in a separate module
# TODO: rewrite this with lxml or ElementTree or domish.Element: it's complicated and difficult to maintain with current minidom implementation
@ -58,11 +62,28 @@ def _dataFormField2XMLUIData(field, read_only=False):
"""
widget_args = [field.value]
widget_kwargs = {}
if field.fieldType == "fixed" or field.fieldType is None:
if field.fieldType is None and field.ext_type is not None:
# we have an extended field
if field.ext_type == u"xml":
element = field.value
if element.uri == C.NS_XHTML:
widget_type = "xhtmlbox"
widget_args[0] = element.toXml()
widget_kwargs["read_only"] = read_only
else:
log.warning(u"unknown XML element, falling back to textbox")
widget_type = "textbox"
widget_args[0] = element.toXml()
widget_kwargs["read_only"] = read_only
else:
raise exceptions.DataError(u"unknown extended type {ext_type}".format(
ext_type = field.ext_type))
elif field.fieldType == "fixed" or field.fieldType is None:
widget_type = "text"
if field.value is None:
if field.label is None:
log.warning(_("Fixed field has neither value nor label, ignoring it"))
log.warning(_(u"Fixed field has neither value nor label, ignoring it"))
field.value = ""
else:
field.value = field.label
@ -1011,6 +1032,26 @@ class TextBoxWidget(StringWidget):
type = "textbox"
class XHTMLBoxWidget(StringWidget):
"""Specialized textbox to manipulate XHTML"""
type = "xhtmlbox"
def __init__(self, xmlui, value, name=None, parent=None, read_only=False, clean=True):
"""
@param clean(bool): if True, the XHTML is considered insecure and will be cleaned
Only set to False if you are absolutely sure that the XHTML is safe (in other
word, set to False only if you made the XHTML yourself)
"""
if clean:
if cleanXHTML is None:
raise exceptions.NotFound(
u"No cleaning method set, can't clean the XHTML")
value = cleanXHTML(value)
super(XHTMLBoxWidget, self).__init__(
xmlui, value=value, name=name, parent=parent, read_only=read_only)
class JidInputWidget(StringWidget):
type = "jid_input"
@ -1623,6 +1664,11 @@ def deferConfirm(*args, **kwargs):
# Misc other funtions
def isXHTMLField(field):
"""Check if a data_form.Field is an XHTML one"""
return (field.fieldType is None and field.ext_type == u"xml" and
field.value.uri == C.NS_XHTML)
class ElementParser(object):
"""callable class to parse XML string into Element"""