-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b56a331
commit 89ba323
Showing
18 changed files
with
868 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from django.apps import AppConfig | ||
from django.utils.translation import gettext_lazy as _ | ||
|
||
|
||
class FormIODisplayApp(AppConfig): | ||
name = "openforms.formio.display" | ||
label = "formio_display" | ||
verbose_name = _("FormIO display") | ||
|
||
def ready(self): | ||
# register the plugin | ||
from . import default # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from enum import Enum, auto | ||
|
||
|
||
# TODO convert to django-choices | ||
class OutputMode(Enum): | ||
summary = auto() | ||
pdf = auto() | ||
email_confirmation = auto() | ||
email_registration = auto() | ||
|
||
@classmethod | ||
def all(cls): | ||
return list(cls) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
from typing import TYPE_CHECKING, Iterable | ||
|
||
from openforms.formio.display.constants import OutputMode | ||
from openforms.formio.display.elements import Element, Header, HTMLElement, LabelValue | ||
from openforms.formio.display.registry import register | ||
from openforms.formio.display.render import RenderContext | ||
from openforms.formio.display.wrap import Node | ||
from openforms.plugins.plugin import AbstractBasePlugin | ||
|
||
|
||
class RenderBasePlugin(AbstractBasePlugin): | ||
def create_elements(self, node: Node, context: RenderContext) -> Iterable[Element]: | ||
# as base no output | ||
return [] | ||
|
||
def is_visible(self, node: Node, context: RenderContext): | ||
if not self.is_self_visible(node, context): | ||
return False | ||
|
||
if self.has_visible_children(node, context): | ||
# as base show when children are visible | ||
return True | ||
elif self.has_children(node, context): | ||
# as base hide container with all hidden children | ||
return False | ||
else: | ||
# as base show non-containers | ||
return True | ||
|
||
def is_self_visible(self, node: Node, context: RenderContext): | ||
return True | ||
|
||
def has_children(self, node: Node, context: RenderContext): | ||
return bool(node.children) | ||
|
||
def has_visible_children(self, node: Node, context: RenderContext): | ||
# verbose for override consistency | ||
return self.has_children(node, context) and any( | ||
n.plugin.is_visible(n, context) for n in node.children | ||
) | ||
|
||
def check_config(self): | ||
pass | ||
|
||
|
||
class FormioBasePlugin(RenderBasePlugin): | ||
def is_self_visible(self, node: Node, context: RenderContext): | ||
return not node.component.get("hidden", False) | ||
|
||
|
||
class ValueBasePlugin(FormioBasePlugin): | ||
def is_self_visible(self, node: Node, context: RenderContext): | ||
# TODO is this the best place? | ||
if not context.allows_value_key(node.key): | ||
return False | ||
return super().is_self_visible(node, context) | ||
|
||
|
||
@register("default") | ||
class LabelValuePlugin(ValueBasePlugin): | ||
def create_elements(self, node: Node, context: RenderContext): | ||
if not self.is_visible(node, context): | ||
return | ||
yield LabelValue(node) | ||
|
||
|
||
@register("fieldset") | ||
class FieldsetPlugin(FormioBasePlugin): | ||
def is_visible(self, node: Node, context: RenderContext): | ||
if not self.is_self_visible(node, context): | ||
return False | ||
if self.has_visible_children(node, context): | ||
return True | ||
else: | ||
return False | ||
|
||
def create_elements(self, node: Node, context: RenderContext): | ||
if not self.is_visible(node, context): | ||
return | ||
# is it hideLabel ? | ||
if not node.component.get("hideLabel", False): | ||
yield Header(node.get_default_label()) | ||
|
||
for n in node.children: | ||
yield from n.plugin.create_elements(n, context) | ||
|
||
|
||
@register("columns") | ||
class ColumsPlugin(FormioBasePlugin): | ||
def is_visible(self, node: Node, context: RenderContext): | ||
if not self.is_self_visible(node, context): | ||
return False | ||
if self.has_visible_children(node, context): | ||
return True | ||
else: | ||
return False | ||
|
||
def create_elements(self, node: Node, context: RenderContext): | ||
if not self.is_visible(node, context): | ||
return | ||
for n in node.children: | ||
yield from n.plugin.create_elements(n, context) | ||
|
||
|
||
@register("content") | ||
class ContentPlugin(ValueBasePlugin): | ||
def is_visible(self, node: Node, context: RenderContext): | ||
# only in PDF | ||
return context.mode == OutputMode.pdf and super().is_visible(node, context) | ||
|
||
def create_elements(self, node: Node, context: RenderContext): | ||
if not self.is_visible(node, context): | ||
return | ||
# no label | ||
# danger zone.. | ||
html = node.component["html"] | ||
yield HTMLElement(html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import html | ||
from dataclasses import dataclass | ||
from typing import TYPE_CHECKING, Iterable | ||
|
||
from django.utils.html import conditional_escape, escape, format_html | ||
from django.utils.safestring import mark_safe | ||
|
||
from openforms.formio.formatters.service import format_value | ||
|
||
if TYPE_CHECKING: | ||
from openforms.formio.display.render import RenderContext | ||
from openforms.formio.display.wrap import Node | ||
|
||
|
||
def create_elements( | ||
nodes: Iterable["Node"], context: "RenderContext" | ||
) -> Iterable["Element"]: | ||
for node in nodes: | ||
yield from node.plugin.create_elements(node, context) | ||
|
||
|
||
class Element: | ||
def render(self, context: "RenderContext") -> Iterable[str]: | ||
return [] | ||
|
||
|
||
@dataclass | ||
class NodeElement(Element): | ||
node: "Node" | ||
|
||
def format_value(self, context: "RenderContext") -> str: | ||
value = format_value(self.node.component, self.node.value, context.as_html) | ||
if context.as_html: | ||
value = conditional_escape(value) | ||
return value | ||
|
||
|
||
@dataclass | ||
class LabelValue(NodeElement): | ||
def render(self, context): | ||
label = self.node.get_default_label() | ||
if context.as_html: | ||
yield format_html( | ||
"<td>{}</td><td>{}</td>", label, self.format_value(context) | ||
) | ||
else: | ||
yield f"{label}: {self.format_value(context)}" | ||
|
||
|
||
@dataclass | ||
class ValueElement(NodeElement): | ||
def render(self, context): | ||
text = self.format_value(context) | ||
if context.as_html: | ||
yield format_html('<td colspan="2">{}<td>', text) | ||
else: | ||
yield text | ||
|
||
|
||
@dataclass | ||
class Header(Element): | ||
text: str | ||
# TODO .wrap should be something like .level:int and do something for text | ||
wrap: str = "h1" | ||
|
||
def render(self, context): | ||
if context.as_html: | ||
if self.wrap: | ||
text = format_html( | ||
"<{tag}>{text}</{tag}>", tag=self.wrap, text=self.text | ||
) | ||
else: | ||
text = self.text | ||
yield format_html('<td colspan="2">{}<td>', text) | ||
else: | ||
yield self.text | ||
|
||
|
||
@dataclass | ||
class TextElement(Element): | ||
text: str | ||
|
||
def render(self, context): | ||
if context.as_html: | ||
yield format_html('<td colspan="2">{}<td>', self.text) | ||
else: | ||
yield self.text | ||
|
||
|
||
@dataclass | ||
class HTMLElement(Element): | ||
# danger | ||
html: str | ||
|
||
def render(self, context): | ||
if context.as_html: | ||
yield format_html('<td colspan="2">{}<td>', mark_safe(self.html)) | ||
else: | ||
# TODO add whitespace cleanup from elsewhere | ||
yield html.unescape(self.html) | ||
|
||
|
||
@dataclass | ||
class GroupBreakElement(Element): | ||
def render(self, context): | ||
if context.as_html: | ||
yield escape('<td colspan="2"> <td>') | ||
else: | ||
yield "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from openforms.plugins.registry import BaseRegistry | ||
|
||
|
||
class Registry(BaseRegistry): | ||
""" | ||
A registry for the FormIO submission rendering component plugins. | ||
""" | ||
|
||
pass | ||
|
||
|
||
# Sentinel to provide the default registry. You an easily instantiate another | ||
# :class:`Registry` object to use as dependency injection in tests. | ||
register = Registry() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
from dataclasses import dataclass, field | ||
from typing import TYPE_CHECKING, Iterable, Set | ||
|
||
from django.utils.html import conditional_escape | ||
from django.utils.safestring import mark_safe | ||
|
||
if TYPE_CHECKING: | ||
from openforms.formio.display.constants import OutputMode | ||
from openforms.formio.display.elements import Element | ||
|
||
|
||
@dataclass | ||
class RenderContext: | ||
mode: "OutputMode" | ||
as_html: bool | ||
|
||
limit_value_keys: Set[str] = field(default_factory=set) | ||
|
||
def allows_value_key(self, key: str): | ||
return bool(not self.limit_value_keys or key in self.limit_value_keys) | ||
|
||
|
||
def render_elements(elements: Iterable["Element"], context: RenderContext) -> str: | ||
res = "\n".join(_render_elements(elements, context)) | ||
if context.as_html: | ||
# booya | ||
res = mark_safe(res) | ||
return res | ||
|
||
|
||
def _render_elements( | ||
elements: Iterable["Element"], context: RenderContext | ||
) -> Iterable[str]: | ||
if context.as_html: | ||
# TODO support more then simple table | ||
for elem in elements: | ||
# TODO make full generator until join | ||
output = list(elem.render(context)) | ||
if output: | ||
yield "<tr>" | ||
yield from map(conditional_escape, output) | ||
yield "</tr>" | ||
else: | ||
for elem in elements: | ||
yield from elem.render(context) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from openforms.submissions.models import Submission | ||
|
||
from .constants import OutputMode | ||
from .elements import create_elements | ||
from .registry import register | ||
from .render import RenderContext, render_elements | ||
from .wrap import get_submission_tree | ||
|
||
__all__ = ["render", "OutputMode"] | ||
|
||
|
||
def render(submission: Submission, *, mode: OutputMode, as_html: bool) -> str: | ||
context = RenderContext(mode=mode, as_html=as_html) | ||
root = get_submission_tree(submission, register) | ||
|
||
elements = create_elements(root.children, context) | ||
return render_elements(elements, context) |
Empty file.
Oops, something went wrong.