Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

#28 Refactoring: Modal Component #29

Merged
merged 1 commit into from
Jan 8, 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
112 changes: 99 additions & 13 deletions django_bootstrap_swt/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from abc import ABC
from django.template.loader import render_to_string
from django_bootstrap_swt.enums import ButtonColorEnum, TooltipPlacementEnum, ProgressColorEnum, BadgeColorEnum, \
ButtonSizeEnum, ModalSizeEnum, TextColorEnum, BackgroundColorEnum, BorderColorEnum, DataToggleEnum
ButtonSizeEnum, ModalSizeEnum, TextColorEnum, BackgroundColorEnum, BorderColorEnum, DataToggleEnum, HeadingsEnum

PATH_TO_TEMPLATES = "django_bootstrap_swt/components/"

Expand Down Expand Up @@ -240,7 +240,7 @@ def __init__(self, url: str, content: str, color: TextColorEnum = None, open_in_
super(Link, self).__init__(tag='a', attrs=self.attrs, content=self.content, *args, **kwargs)


class LinkButton(AbstractButton, TooltipSurroundedComponent):
class LinkButton(TooltipSurroundedComponent, AbstractButton):
"""
This class renders the a HTML Link as a Bootstrap Button.
https://getbootstrap.com/docs/4.0/components/buttons/#button-tags
Expand Down Expand Up @@ -268,7 +268,7 @@ def __init__(self, url: str, content: str, color: ButtonColorEnum, size: ButtonS
super(LinkButton, self).__init__(tag='a', attrs=self.attrs, content=self.content, *args, **kwargs)


class Button(AbstractButton, TooltipSurroundedComponent):
class Button(TooltipSurroundedComponent, AbstractButton):
"""
This class renders the Bootstrap Button component.
https://getbootstrap.com/docs/4.0/components/buttons/
Expand Down Expand Up @@ -316,37 +316,123 @@ def __init__(self, content: str, color: ButtonColorEnum = None, size: ButtonSize
super(Button, self).__init__(tag='button', attrs=self.attrs, content=self.content, *args, **kwargs)


class ModalHeader(Tag):
"""
This class renders the Bootstrap ModalHeader component.
https://getbootstrap.com/docs/4.0/components/modal/
"""
def __init__(self, content: str, heading_size: HeadingsEnum = HeadingsEnum.H5, closeable: bool = True, *args,
**kwargs):
"""
:param content: the content of the header
:param heading_size: the size of the content
:param closeable: toggle to show or show not close button on header
"""
self.attrs = {"class": ["modal-header"]}

self.content = Tag(tag=heading_size.value, attrs={"class": ["modal-title"]}, content=content).render()
if closeable:
close_sym = Tag(tag='span', attrs={"aria-hidden": ["true"]}, content="×").render()
self.content += Tag(tag='button',
attrs={"class": ["close"],
"type": ["button"],
"data-dismiss": ["modal"],
"aria-label": ["Close"]},
content=close_sym, )

super(ModalHeader, self).__init__(tag="div", attrs=self.attrs, content=self.content, *args, **kwargs)


class ModalBody(Tag):
"""
This class renders the Bootstrap ModalBody component.
https://getbootstrap.com/docs/4.0/components/modal/
"""
def __init__(self, content: str, *args, **kwargs):
"""
:param content: the content of the header
:param heading_size: the size of the content
:param closeable: toggle to show or show not close button on header
"""
self.attrs = {"class": ["modal-body"]}
self.content = content
super(ModalBody, self).__init__(tag="div", attrs=self.attrs, content=self.content, *args, **kwargs)


class ModalFooter(Tag):
"""
This class renders the Bootstrap ModalBody component.
https://getbootstrap.com/docs/4.0/components/modal/
"""
def __init__(self, content: str, *args, **kwargs):
"""
:param content: the content of the header
:param heading_size: the size of the content
:param closeable: toggle to show or show not close button on header
"""
self.attrs = {"class": ["modal-footer"]}
self.content = content
super(ModalFooter, self).__init__(tag="div", attrs=self.attrs, content=self.content, *args, **kwargs)


class Modal(BootstrapComponent):
"""
This class renders the Bootstrap Modal component.
https://getbootstrap.com/docs/4.0/components/modal/
"""
def __init__(self, title: str, body: str, btn_content: str, btn_attrs: dict = None, footer: str = None,
fade: bool = True, size: ModalSizeEnum = None, fetch_url: str = None, *args, **kwargs):
def __init__(self, btn_content: str, header=None, body=None, btn_attrs: dict = None,
footer=None, fade: bool = True, size: ModalSizeEnum = None, fetch_url: str = None,
btn_tooltip: str = None, backdrop: bool = True, clos_on_esc: bool = True,
*args, **kwargs):
"""
:param title: the title of the modal
:param body: the body content of the modal
:param btn_content: the value of the button which opens the modal
:param btn_color: the color of the button which opens the modal
:param header: Optional: the title of the modal
:param body: Optional: the body content of the modal
:param btn_attrs: Optional: the dict which contains all attributes to update the button attributes
:param btn_size: Optional: the size of the button which opens the modal
:param footer: Optional: the footer content of the modal
:param fade: Optional: toggles the fade flag
:param size: Optional: the size of the modal
:param fetch_url: Optional: the url where the content will be fetched from on modal shown event
:param btn_tooltip: Optional: the tooltip of the modal toggle button
:param args:
:param kwargs:
"""
super(Modal, self).__init__(template_name="modal.html", *args, **kwargs)
self.title = title
self.body = body
self.footer = footer
self.modal_id = 'id_' + str(uuid.uuid4())
if header and isinstance(header, str):
self.header = ModalHeader(content=header)
self.header.update_attribute(attribute="id", values=[f"{self.modal_id}_header"])
elif header and isinstance(header, ModalHeader):
self.header = header
if body and isinstance(body, str):
self.body = ModalBody(content=body)
self.body.update_attribute(attribute="id", values=[f"{self.modal_id}_body"])
elif body and isinstance(body, ModalBody):
self.body = body
if footer and isinstance(footer, str):
self.footer = ModalFooter(content=footer)
self.footer.update_attribute(attribute="id", values=[f"{self.modal_id}_footer"])
elif footer and isinstance(footer, ModalFooter):
self.footer = footer
self.fade = fade
self.size = size
self.modal_id = 'id_' + str(uuid.uuid4())
self.fetch_url = fetch_url
self.backdrop = backdrop
self.clos_on_esc = clos_on_esc
self.button = Button(content=btn_content, data_toggle=DataToggleEnum.MODAL,
data_target=f'{self.modal_id}')
data_target=f'{self.modal_id}', btn_tooltip=btn_tooltip)
self.button.update_attributes(update_attrs=btn_attrs)
self.rendered_button = None

def render(self, safe: bool = False) -> str:
"""Renders a template with self.__dict__ as context

:param safe: switches if the rendered component is returned as SafeString or str
:return: rendered template as string | SafeString
"""
self.rendered_button = self.button.render()
return super().render(safe=safe)


class CardHeader(Tag):
Expand Down
10 changes: 10 additions & 0 deletions django_bootstrap_swt/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class ModalSizeEnum(Enum):
LARGE = "modal-lg"
SMALL = "modal-sm"
EXTRALARGE = "modal-xl"


class ButtonColorEnum(Enum):
Expand Down Expand Up @@ -95,3 +96,12 @@ class DataToggleEnum(Enum):
MODAL = "modal"
DROPDOWN = "dropdown"
TOOLTIP = "tooltip"


class HeadingsEnum(Enum):
H1 = "h1"
H2 = "h2"
H3 = "h3"
H4 = "h4"
H5 = "h5"
H6 = "h6"
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function bootstrapComponentAjaxCall( target, target_body ) {

function modalAjaxInit( parent ) {
$(".modal[data-url]", parent).on('shown.bs.modal', function( event ) {
bootstrapComponentAjaxCall( event.currentTarget, $( '.modal-body', event.currentTarget ) );
bootstrapComponentAjaxCall( event.currentTarget, $( '.modal-content', event.currentTarget ) );
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
<div id="{{modal_id}}" class="modal{% if fade %} fade{% endif %}" tabindex="-1" role="document"{% if fetch_url %} data-url="{{fetch_url}}"{% endif %}>
{{ rendered_button|safe }}
<div id="{{modal_id}}" class="modal{% if fade %} fade{% endif %}" tabindex="-1" role="document"{% if fetch_url %} data-url="{{fetch_url}}"{% endif %}{% if not backdrop %} data-backdrop="static"{% endif %}{% if not clos_on_esc %} data-keyboard="false"{% endif %}>
<div class="modal-dialog{% if size %} {{size.value}}{% endif%}">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{title|safe}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div id="{{modal_id}}_body" class="modal-body">
{% if fetch_url %}
{% if fetch_url %}
{% include 'django_bootstrap_swt/includes/ajax_loading_spinner.html' %}
{% include 'django_bootstrap_swt/includes/ajax_error.html' %}
{% endif %}
{{body|safe}}
</div>
{% if footer %}
<div class="modal-footer">
{{footer}}
</div>
{% else %}
{{ header|safe }}
{{ body|safe }}
{{ footer|safe }}
{% endif %}
</div>
</div>
Expand Down
7 changes: 5 additions & 2 deletions django_bootstrap_swt/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from urllib import parse
from django_bootstrap_swt.components import BootstrapComponent, Tag
from django_bootstrap_swt.components import BootstrapComponent, Tag, Modal


class RenderHelper:
Expand Down Expand Up @@ -52,7 +52,10 @@ def render_item(self, item, safe: bool = False) -> str:
if self.update_url_qs:
self.update_queryparams(item=item)
if self.update_attrs:
item.update_attributes(update_attrs=self.update_attrs)
if isinstance(item, Modal):
item.button.update_attributes(update_attrs=self.update_attrs)
else:
item.update_attributes(update_attrs=self.update_attrs)
rendered_string = item.render(safe=safe)
return rendered_string

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<button id="{{button.button_id}}" type="button" class="btn btn-success" data-toggle="modal" data-target="#{{modal_id}}">nice button</button>
<div id="{{modal_id}}" class="modal fade" tabindex="-1" role="document" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<button id="{{button.button_id}}" type="button" class="btn btn-success" data-toggle="modal" data-target="#{{modal_id}}">nice button</button>
<div id="{{modal_id}}" class="modal fade" tabindex="-1" role="document">
<div class="modal-dialog">
<div class="modal-content">
{% if True %}{% endif %}
{% if True %}{% endif %}
<div class="modal-body">nice body</div>
{% if True %}{% endif %}
{% if True %}{% endif %}
</div>
</div>
</div>
12 changes: 12 additions & 0 deletions tests/app/templates/components/modal/test_modal_body_str.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<button id="{{button.button_id}}" type="button" class="btn btn-success" data-toggle="modal" data-target="#{{modal_id}}">nice button</button>
<div id="{{modal_id}}" class="modal fade" tabindex="-1" role="document">
<div class="modal-dialog">
<div class="modal-content">
{% if True %}{% endif %}
{% if True %}{% endif %}
<div class="modal-body" id="{{modal_id}}_body">nice body</div>
{% if True %}{% endif %}
{% if True %}{% endif %}
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<button id="{{button.button_id}}" type="button" class="btn btn-success" data-toggle="modal" data-target="#{{modal_id}}">nice button</button>
<div id="{{modal_id}}" class="modal fade" tabindex="-1" role="document" data-keyboard="false">
<div class="modal-dialog">
<div class="modal-content">
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
</div>
</div>
</div>
16 changes: 5 additions & 11 deletions tests/app/templates/components/modal/test_modal_fade_false.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
<button id="{{button.button_id}}" type="button" class="btn btn-success" data-toggle="modal" data-target="#{{modal_id}}">nice button</button>
<div id="{{modal_id}}" class="modal" tabindex="-1" role="document">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">nice modal</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div id="{{modal_id}}_body" class="modal-body">
{% if True %}{% endif %}
{% if True %}{% endif %}
something
</div>
{% if False %}
{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
</div>
</div>
</div>
14 changes: 2 additions & 12 deletions tests/app/templates/components/modal/test_modal_fetch_url.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
<button id="{{button.button_id}}" type="button" class="btn btn-success" data-toggle="modal" data-target="#{{modal_id}}">nice button</button>
<div id="{{modal_id}}" class="modal fade" tabindex="-1" role="document" data-url="http://example.com">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">nice modal</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div id="{{modal_id}}_body" class="modal-body">
{% if True %}
{% if True %}
{% include 'django_bootstrap_swt/includes/ajax_loading_spinner.html' %}
{% include 'django_bootstrap_swt/includes/ajax_error.html' %}
{% endif %}
something
</div>
{% if False %}
{% endif %}
</div>
</div>
Expand Down
21 changes: 0 additions & 21 deletions tests/app/templates/components/modal/test_modal_footer.html

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<button id="{{button.button_id}}" type="button" class="btn btn-success" data-toggle="modal" data-target="#{{modal_id}}">nice button</button>
<div id="{{modal_id}}" class="modal fade" tabindex="-1" role="document">
<div class="modal-dialog">
<div class="modal-content">
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
<div class="modal-footer">nice footer</div>
{% if True %}{% endif %}
</div>
</div>
</div>
12 changes: 12 additions & 0 deletions tests/app/templates/components/modal/test_modal_footer_str.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<button id="{{button.button_id}}" type="button" class="btn btn-success" data-toggle="modal" data-target="#{{modal_id}}">nice button</button>
<div id="{{modal_id}}" class="modal fade" tabindex="-1" role="document">
<div class="modal-dialog">
<div class="modal-content">
{% if True %}{% endif %}
{% if True %}{% endif %}
{% if True %}{% endif %}
<div class="modal-footer" id="{{modal_id}}_footer">nice footer</div>
{% if True %}{% endif %}
</div>
</div>
</div>
Loading