Skip to content

Commit

Permalink
Fixed the confirmation dialog for action links
Browse files Browse the repository at this point in the history
Added support for variables in the dialog box
Added default redirection to DeleteViews
  • Loading branch information
mmarcos committed Feb 28, 2018
1 parent 63865f9 commit e60f9c4
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 67 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Always reference the ticket number at the end of the issue description.

- Search form JS submitting selector - [#248][248]
- Float Label styling for a number of HTML5 inputs - [#247][247]
- confirm_links feature in ListViews now works properly - [#54][54].

## Changed

Expand All @@ -26,6 +27,7 @@ Always reference the ticket number at the end of the issue description.

[248]: //github.com/sanoma/django-arctic/issues/248
[247]: //github.com/sanoma/django-arctic/issues/247
[54]: //github.com/sanoma/django-arctic/issues/54
[257]: //github.com/sanoma/django-arctic/issues/257
[265]: //github.com/sanoma/django-arctic/issues/265
[259]: //github.com/sanoma/django-arctic/issues/259
Expand Down
5 changes: 5 additions & 0 deletions arctic/generics.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ def get_context_data(self, **kwargs):

class DeleteView(SuccessMessageMixin, View, base.DeleteView):
template_name = 'arctic/base_confirm_delete.html'
redirect = True

def get(self, request, *args, **kwargs):
"""
Expand All @@ -765,6 +766,10 @@ def get(self, request, *args, **kwargs):
protected_objects = e.protected_objects
can_delete = False

if can_delete and self.redirect:
self.delete(request, *args, **kwargs)
return redirect(self.success_url)

context = self.get_context_data(object=self.object,
can_delete=can_delete,
collector_message=collector_message,
Expand Down
35 changes: 29 additions & 6 deletions arctic/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import (ImproperlyConfigured, PermissionDenied)
from django.template import (Template, Context)
from django.urls import reverse
from django.utils import six

Expand Down Expand Up @@ -488,9 +489,32 @@ def get_field_classes(self, obj):
field_classes[field_name] = get_field_name_classes(obj)
return field_classes

def get_confirm_link(self, url, obj):
"""
Returns the metadata for a link that needs to be confirmed, if it
exists, it also parses the message and title of the url to include
row field data if needed.
"""
try:
if type(obj) != dict:
obj = vars(obj)
link = {key: value.replace('"', '"') for (key, value) in
self.confirm_links[url].items()}
link['message'] = Template(link['message']).render(Context(obj))
link['title'] = Template(link['title']).render(Context(obj))
link['ok'] # this triggers a KeyError exception if not existent
link['cancel']
return link
except KeyError as e:
raise ImproperlyConfigured(
'confirm_links requires a dictionary with \'message\', '
'\'title\', \'ok\' and \'cancel\' strings, the named url \'' +
url + '\' misses ' + str(e))
except AttributeError:
return None

def _get_field_actions(self, obj):
all_actions = self.get_action_links()
has_confirm_links = hasattr(self, 'confirm_links')
get_field_actions = getattr(self, 'get_field_actions', None)
if get_field_actions:
field_actions = get_field_actions(obj)
Expand All @@ -506,11 +530,10 @@ def _get_field_actions(self, obj):
actions.append({'label': field_action['label'],
'icon': field_action['icon'],
'url': self._reverse_field_link(
field_action['url'], obj)})
field_url_name = field_action['url']
if has_confirm_links and field_url_name in self.confirm_links:
actions[0].update({'confirm':
self.confirm_links[field_url_name]})
field_action['url'], obj),
'confirm': self.get_confirm_link(
field_action['url'], obj),
})
return {'type': 'actions', 'actions': actions}

def _get_allowed_field_actions(self, field_actions, all_actions):
Expand Down
1 change: 1 addition & 0 deletions arctic/static/arctic/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ PATHS:
- "src/assets/js/components/widgets.js"
- "src/assets/js/components/sortable.js"
- "src/assets/js/components/float_label.js"
- "src/assets/js/components/confirm_dialog.js"
- "src/assets/js/!(app).js"
- "src/assets/js/app.js"
15 changes: 14 additions & 1 deletion arctic/static/arctic/dist/assets/js/app.js

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions arctic/static/arctic/src/assets/js/components/confirm_dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
$(document).ready(function() {
$('#confirm-dialog').on('show.bs.modal', function (event) {
var modal = $(this)
var button = $(event.relatedTarget) // Button that triggered the modal
modal.find('.modal-title').text(button.data('confirm-title'));
modal.find('.modal-body').text(button.data('confirm-message'));
modal.find('.modal-footer .confirm-cancel').text(button.data('confirm-cancel'))
modal.find('.modal-footer .confirm-ok').text(button.data('confirm-ok'))
modal.find('.modal-footer .confirm-ok').prop('href', button.prop('href'));
});
});
91 changes: 38 additions & 53 deletions arctic/templates/arctic/partials/base_data_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,32 +128,9 @@ <h4 class="arctic-card__title">
{% for row in list_items %}
<tr>
{% for column in row %}
{% if column.confirm %}
<div class="modal fade" id="modal{{ column.value }}" tabindex="-1" role="dialog" aria-labelledby="modal{{ column.value }}Label" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalLabel">Confirm your action</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{{ column.confirm|lookup:'message' }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ column.confirm|lookup:'cancel' }}</button>
<a class="btn btn-primary" href="{{ column.url }}" onclick="$('#modal{{ column.value }}').modal('hide')">{{ column.confirm|lookup:'yes' }}</a>
</div>
</div>
</div>
</div>
{% endif %}
{% if column.type == 'field' %}
<td {% if column.class %}class="{{ column.class }}"{%endif%}>
{% if column.confirm %}
<a data-toggle="modal" data-target="#modal{{ column.value }}">
{% elif column.url %}
{% if column.url %}
<a href="{{ column.url }}"{% if list_items.0.0.type == 'sorting' %}style="display:block;"{% endif %}>
{% endif %}
{% if column.value|typename != 'list' %}
Expand All @@ -172,35 +149,21 @@ <h5 class="modal-title" id="modalLabel">Confirm your action</h5>
{% block list_actions %}
<div class="list-actions">
{% for link in column.actions %}
{% if link.confirm %}
<div class="modal fade" id="modal{{ link.label }}" tabindex="-1" role="dialog" aria-labelledby="modal{{ link.label }}Label" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Confirm your action</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{{ link.confirm|lookup:'message' }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ link.confirm|lookup:'cancel' }}</button>
<a class="btn btn-primary" href="{{ link.url }}" onclick="$('#modal{{ link.value }}').modal('hide')">{{ link.confirm|lookup:'yes' }}</a>
</div>
</div>
</div>
</div>
<a data-toggle="modal" class="action-{{ link.label }} btn btn-secondary btn-sm show-on-hover" data-target="#modal{{ link.label }}" title=" 2{{ link.label|capfirst }}">
{% elif not link.confirm %}
<a href="{{ link.url }}" class="action-{{ link.label }} btn btn-secondary btn-sm show-on-hover" title="{{ link.label|capfirst }}">
{% endif %}
{% if link.icon %}
<i class="fa {{ link.icon }} fa-lg"></i>
{% else %}
{{ link.label|capfirst }}
{% endif %}
<a href="{{ link.url }}" class="action-{{ link.label }} btn btn-secondary btn-sm show-on-hover" title="{{ link.label|capfirst }}"
{% if link.confirm %}
data-toggle="modal"
data-target="#confirm-dialog"
data-confirm-title="{{ link.confirm.title }}"
data-confirm-message="{{ link.confirm.message }}"
data-confirm-ok="{{ link.confirm.ok }}"
data-confirm-cancel="{{ link.confirm.cancel }}"
{% endif %}
>
{% if link.icon %}
<i class="fa {{ link.icon }} fa-lg"></i>
{% else %}
{{ link.label|capfirst }}
{% endif %}
</a>
{% endfor %}
<div class="list-actions-placeholder"></div>
Expand Down Expand Up @@ -231,4 +194,26 @@ <h3 class="col text-center">{% trans 'No result...' %}</h3>
</div>
{% endblock %}

{% block confirm_dialog %}
<div class="modal fade" id="confirm-dialog" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary confirm-cancel" data-dismiss="modal">Cancel</button>
<a href="#" role="button" class="btn btn-primary confirm-ok">OK</a>
</div>
</div>
</div>
</div>
{% endblock %}

{% block extra_data %}{% endblock %}
14 changes: 13 additions & 1 deletion docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,19 @@ links or, if only one tool link set, it would be use as default icon.

### `confirm_links`

dictionary as `{'url_field': {'message': 'Would you like to continue?', 'yes': 'Yes', 'cancel': 'No'}}'` which wraps every `url_field` displayed on a `ListView` with a confirmation dialog.
Dictionary of named urls that will display a confirmation dialog. The format is:

{'named_url': {
'title': 'Delete "{{ field_name }}"',
'message': 'Would you like to delete this?',
'ok': 'Delete',
'cancel': 'Cancel'},
...
}

Both `title` and `message` can contain field names wrapped as django template
variables, which will be parsed into the field value for the row instance.
Currently `confirm_links` work only on the `action_links` area.

### `advanced_search_form_class`

Expand Down
9 changes: 3 additions & 6 deletions example/articles/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,10 @@ class CategoryListView(ListView):
]
confirm_links = {
'articles:category-delete': {
'title': _('Delete "{{ name }}"'),
'message': _('Are you sure you want to delete this?'),
'yes': _('Yes'),
'cancel': _('No')},
'articles:category-detail': {
'message': _('Are you sure you want to proceed'),
'yes': _('Yes'),
'cancel': _('No')}}
'ok': _('Delete'),
'cancel': _('Cancel')}}


class CategoryArticlesListView(ArticleListView):
Expand Down

0 comments on commit e60f9c4

Please sign in to comment.