Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Quill - small tweaks to implementation #80

Merged
merged 2 commits into from
Jun 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Unreleased

## Changes
* Quill editor supports a toolbar and theme set at runtime.
https://github.com/anvilistas/anvil-extras/pull/80
# v1.4 07-June-2021

## New Features
Expand Down
99 changes: 73 additions & 26 deletions client_code/Quill/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,76 @@
}


def _quill_init_prop(propname):
def getter(self):
return self._props[propname]

def setter(self, val):
self._props[propname] = val
self._init_quill()

return property(getter, setter)


class Quill(QuillTemplate):
_quill = None # otherwise we get a recursion error from __getattr__

def __init__(self, **properties):
# Set Form properties and Data Bindings.
dom_node = self._dom_node = _get_dom_node(self)
self._rt = None
## remove html that was used for the designer - prevents script tags loading
while dom_node.firstElementChild:
dom_node.removeChild(dom_node.firstElementChild)
self._dom_node = _get_dom_node(self)
self._spacer = _Spacer()
self._el = _get_dom_node(self._spacer)
self.add_component(self._spacer)
self._quill = None
self._rt = None
self._min_height = None

def click_guard(e):
q = self._quill
if not q.hasFocus():
q.focus()
q.setSelection(len(q.getText()))

self._el.addEventListener("click", click_guard)

properties = _defaults | properties
self._props = props = _defaults | properties
props_to_init = {
key: props[key]
for key in (
"height",
"content",
"auto_expand",
"spacing_above",
"spacing_below",
)
}
init_if_false = {
key: props[key] for key in ("enabled", "visible") if not props[key]
}
self._init_quill()
self.init_components(**props_to_init, **init_if_false)

@staticmethod
def _clear_elements(el):
while el.firstElementChild:
el.removeChild(el.firstElementChild)

def _init_quill(self):
html = self.get_html()

self._spacer.remove_from_parent()
self._clear_elements(self._dom_node)
self._clear_elements(self._el)
self.add_component(self._spacer)

# these properties have to be set for initialization and cannot be changed
# If they are changed at runtime we need to create a new quill object
q = self._quill = _Quill(
self._el,
{
"modules": {"toolbar": properties["toolbar"]},
"theme": properties["theme"],
"placeholder": properties["placeholder"],
"readOnly": properties["readonly"],
"modules": {"toolbar": self._props["toolbar"]},
"theme": self._props["theme"],
"placeholder": self._props["placeholder"],
"readOnly": self._props["readonly"],
"bounds": self._dom_node,
},
)
Expand All @@ -82,14 +128,8 @@ def __init__(self, **properties):
),
)

def click_guard(e):
if not q.hasFocus():
q.focus()
q.setSelection(len(q.getText()))

self._el.addEventListener("click", click_guard)
# Any code you write here will run when the form opens.
self.init_components(**properties)
if html:
self.set_html(html)

def __getattr__(self, name):
init, *rest = name.split("_")
Expand All @@ -99,12 +139,12 @@ def __getattr__(self, name):
#### Properties ####
@property
def enabled(self):
return self._enabled
return self._props["enabled"]

@enabled.setter
def enabled(self, value):
self._quill.enable(bool(value))
self._enabled = value
self._props["enabled"] = value

@property
def content(self):
Expand All @@ -120,19 +160,20 @@ def content(self, value):

@property
def auto_expand(self):
return self._auto_expand
return self._props["auto_expand"]

@auto_expand.setter
def auto_expand(self, value):
self._auto_expand = value
self._props["auto_expand"] = value
self._spacer.height = "auto" if value else self._min_height

@property
def height(self):
return self._min_height
return self._props["height"]

@height.setter
def height(self, value):
self._props["height"] = value
if isinstance(value, (int, float)) or value.isdigit():
value = f"{value}px"
self._el.style.minHeight = value
Expand All @@ -142,6 +183,12 @@ def height(self, value):
spacing_below = _spacing_property("below")
visible = _HtmlPanel.visible

#### QUILL INIT PROPS ####
toolbar = _quill_init_prop("toolbar")
readonly = _quill_init_prop("readonly")
theme = _quill_init_prop("theme")
placeholder = _quill_init_prop("placeholder")

#### ANVIL METHODS ####
def get_markdown(self):
"""Not yet implemented"""
Expand All @@ -153,12 +200,12 @@ def get_html(self):
"""convert the contents of the quill object to html which can be used
as the content to a RichText editor in 'restricted_html' format
Can also be used as a classmethod by calling it with a simple object Quill.to_html(content)"""
return self._quill.root.innerHTML
return self._quill and self._quill.root.innerHTML

def set_html(self, html):
"""set the content to html. This method sanitizes the html
in the same way the RichText compeonent does"""
self._rt = self._rt or _RT(visible=False, format="restricted_html")
self._rt.content = html
html = _get_dom_node(self._rt).innerHTML
self._quill.clipboard.dangerouslyPasteHTML(html)
self._quill.root.innerHTML = html
7 changes: 3 additions & 4 deletions docs/guides/components/quill.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Properties

:readonly: Boolean

Check the Quill docs. This property cannot be updated after the Quill editor has been instantiated.
Check the Quill docs.

:spacing_above: String

Expand All @@ -45,12 +45,11 @@ Properties

:theme: String

Quill supports ``"snow"`` or ``"bubble"`` theme. (Cannot be updated after instantiation).
Quill supports ``"snow"`` or ``"bubble"`` theme.

:toolbar: Boolean or Object

Check the Quill docs. This property cannot be updated after the Quill editor has been instantiated.
If you want to use an Object you should construct the Quill instance in code.
Check the Quill docs. If you want to use an Object you can set this at runtime. See quill docs for examples.

:visible: Boolean

Expand Down