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

Css: Delete confirmation with css-only modal #2946

Merged
6 commits merged into from
Feb 2, 2018
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
10 changes: 10 additions & 0 deletions securedrop/journalist_templates/_confirmation_modal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div id="{{ modal_data.modal_id }}" class="modal-dialog">
<a href="#close" class="external"></a>
<div>
<a href="#close" title="{{ gettext('Close') }}" class="close">X</a>
<h2>{{ modal_data.modal_header }}</h2>
<p>{{ modal_data.modal_body }}</p>
<a href="#close" id="{{ modal_data.cancel_id }}" title="{{ gettext('Cancel') }}" class="btn sd-button">{{ gettext('Cancel') }}</a>
<button type="submit" id="{{ modal_data.submit_id }}" name="action" value="delete" class="sd-button {{ modal_data.submit_btn_type }}">{{ modal_data.submit_btn_text }}</button>
</div>
</div>
38 changes: 36 additions & 2 deletions securedrop/journalist_templates/col.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
<p>
<div id="select-container"></div>
<button type="submit" name="action" value="download" class="small"><i class="fa fa-download"></i> {{ gettext('Download Selected') }}</button>
<button type="submit" name="action" value="confirm_delete" id="delete-selected" class="small danger"><i class="fa fa-trash-o"></i> {{ gettext('Delete Selected') }}</button>
<a href="#delete-selected-confirmation-modal" id="delete-selected-link" class="btn small danger">
<i class="fa fa-trash-o"></i> {{ gettext('Delete Selected') }}
</a>
</p>

<ul id="submissions" class="plain submissions">
Expand Down Expand Up @@ -62,6 +64,21 @@
{% endfor %}
</ul>

<!-- Confirmation modal for selected documents -->
{% with %}
{% set modal_data = {
"modal_id": "delete-selected-confirmation-modal",
"modal_header": gettext('Delete Confirmation'),
"modal_body": gettext('Are you sure you want to delete the selected documents?'),
"cancel_id": "cancel-selected-deletions",
"submit_id": "delete-selected",
"submit_btn_type": "danger",
"submit_btn_text": gettext('Delete')
}
%}
{% include '_confirmation_modal.html' %}
{% endwith %}

<input name="csrf_token" type="hidden" value="{{ csrf_token() }}">
<input type="hidden" name="filesystem_id" value="{{ filesystem_id }}">

Expand Down Expand Up @@ -101,7 +118,24 @@ <h3><i class="fa fa-reply"></i> {{ gettext('Reply') }}</h3>
<input name="csrf_token" type="hidden" value="{{ csrf_token() }}">
<input type="hidden" name="filesystem_id" value="{{ filesystem_id }}">
<input type="hidden" name="col_name" value="{{ source.journalist_designation }}">
<button id="delete-collection-button" type="submit" class="sd-button danger"><i class="fa fa-trash-o"></i> {{ gettext('DELETE COLLECTION') }}</button>
<a href="#delete-collection-confirmation-modal" id="delete-collection-link" class="btn sd-button danger">
<i class="fa fa-trash-o"></i> {{ gettext('DELETE COLLECTION') }}
</a>

<!-- Confirmation modal for entire collection deletion -->
{% with %}
{% set modal_data = {
"modal_id": "delete-collection-confirmation-modal",
"modal_header": gettext('Delete Confirmation'),
"modal_body": gettext('Are you sure you want to delete this collection?'),
"cancel_id": "cancel-collection-deletions",
"submit_id": "delete-collection-button",
"submit_btn_type": "danger",
"submit_btn_text": gettext('Delete')
}
%}
{% include '_confirmation_modal.html' %}
{% endwith %}
</form>

</div>
Expand Down
19 changes: 18 additions & 1 deletion securedrop/journalist_templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ <h1><span class="headline">{{ gettext('Sources') }}</span></h1>
<button type="submit" name="action" value="download-all" class="small"><i class="fa fa-download"></i> {{ gettext('Download') }}</button>
<button type="submit" name="action" value="star" class="small"><i class="fa fa-star"></i> {{ gettext('Star') }}</button>
<button type="submit" name="action" value="un-star" class="small"><i class="fa fa-star-half-full"></i> {{ gettext('Un-star') }}</button>
<button type="submit" id="delete-collections" name="action" value="delete" class="small-danger"><i class="fa fa-trash-o"></i> {{ gettext('Delete') }}</button>
<a href="#delete-confirmation-modal" id="delete-collections-link" class="btn small danger">
<i class="fa fa-trash-o"></i> {{ gettext('Delete') }}
</a>
</p>

{% if starred %}
Expand All @@ -37,6 +39,21 @@ <h1><span class="headline">{{ gettext('Sources') }}</span></h1>
</ul>
{% endif %}

<!-- Delete confirmation modal -->
{% with %}
{% set modal_data = {
"modal_id": "delete-confirmation-modal",
"modal_header": gettext('Delete Confirmation'),
"modal_body": gettext('Are you sure you want to delete the selected collections?'),
"cancel_id": "cancel-collections-deletions",
"submit_id": "delete-collections",
"submit_btn_type": "danger",
"submit_btn_text": gettext('Delete')
}
%}
{% include '_confirmation_modal.html' %}
{% endwith %}

</form>
{% else %}
<p>{{ gettext('No documents have been submitted!') }}</p>
Expand Down
3 changes: 0 additions & 3 deletions securedrop/journalist_templates/js-strings.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
<div id="select-all-string" hidden>{{ gettext('Select All') }}</div>
<div id="select-unread-string" hidden>{{ gettext('Select Unread') }}</div>
<div id="select-none-string" hidden>{{ gettext('Select None') }}</div>
<div id="collection-delete-confirm-string" hidden>{{ gettext('Are you sure you want to delete this collection?') }}</div>
<div id="collection-multi-delete-confirm-string" hidden>{{ gettext('Are you sure you want to delete the {size} selected collections?') }}</div>
<div id="submission-multi-delete-confirm-string" hidden>{{ gettext('Are you sure you want to delete the {size} selected submissions?') }}</div>
<div id="delete-user-confirm-string" hidden>{{ gettext('Are you sure you want to delete the user {username}?') }}</div>
<div id="reset-user-mfa-confirm-string" hidden>{{ gettext('Are you sure you want to reset two-factor authentication for {username}?') }}</div>
</div>
1 change: 1 addition & 0 deletions securedrop/sass/journalist.sass
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import base
@import modules/visually-hidden
@import modules/menu
@import modules/confirm-modal

+base_rules

Expand Down
50 changes: 50 additions & 0 deletions securedrop/sass/modules/_confirm-modal.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.modal-dialog
position: fixed
top: 0
right: 0
bottom: 0
left: 0
background: rgba(0, 0, 0, 0.8)
z-index: 99999
opacity: 0
-moz-transition: opacity 100ms ease-in
transition: opacity 100ms ease-in
pointer-events: none

&:target
opacity: 1
pointer-events: auto

.external
position: fixed
top: 0
left: 0
width: 100%
height: 100%

div
width: 400px
position: relative
margin: 10% auto
padding: 5px 20px 13px 20px
border-radius: 10px
background: white

.close
background: $color_grey_medium
color: white
line-height: 25px
position: absolute
right: -12px
text-align: center
top: -10px
width: 24px
text-decoration: none
font-weight: bold
-moz-border-radius: 12px
border-radius: 12px
-moz-box-shadow: 1px 1px 3px #000
box-shadow: 1px 1px 3px #000

&:hover
background: $color_purple_medium
26 changes: 0 additions & 26 deletions securedrop/static/js/journalist.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,32 +61,6 @@ $(function () {
}
});

$("#delete-collection").submit(function () {
return confirm(get_string("collection-delete-confirm-string"));
});

$("#delete-collections").click(function () {
var checked = $(".panel ul#cols li :checkbox").filter(":visible").filter(function(index) {
return $(this).prop('checked');
});
if (checked.length > 0) {
return confirm(get_string("collection-multi-delete-confirm-string").supplant({ size: checked.length }));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All get_string must also be revomved from the securedrop/journalist_templates/js-strings.html file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved this.

}
// Don't submit the form if no collections are selected
return false;
});

$("#delete-selected").click(function () {
var checked = $(".panel ul#submissions li :checkbox").filter(function() {
return $(this).prop('checked')
});
if (checked.length > 0) {
return confirm(get_string('submission-multi-delete-confirm-string').supplant({ size: checked.length }));
}
// Don't submit the form if no submissions are selected
return false;
});

$("#unread a").click(function(){
$("#unread").html("unread: 0");
});
Expand Down
97 changes: 65 additions & 32 deletions securedrop/tests/functional/journalist_navigation_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,60 +75,94 @@ def _journalist_visits_col(self):
def _journalist_selects_first_doc(self):
self.driver.find_elements_by_name('doc_names_selected')[0].click()

def _journalist_clicks_delete_selected_javascript(self):
self.driver.find_element_by_id('delete-selected').click()
self._alert_wait()
def _journalist_clicks_delete_collections_cancel_on_modal(self):
self.driver.find_element_by_id('cancel-collections-deletions').click()

def _journalist_clicks_delete_selected_cancel_on_modal(self):
self.driver.find_element_by_id('cancel-selected-deletions').click()

def _journalist_clicks_delete_collection_cancel_on_modal(self):
self.driver.find_element_by_id('cancel-collection-deletions').click()

def _journalist_clicks_delete_collections_javascript(self):
def _journalist_clicks_delete_collections_on_modal(self):
self.driver.find_element_by_id('delete-collections').click()
self._alert_wait()

def _journalist_clicks_delete_collection_javascript(self):
def _journalist_clicks_delete_selected_on_modal(self):
self.driver.find_element_by_id('delete-selected').click()

def _journalist_clicks_delete_collection_on_modal(self):
self.driver.find_element_by_id('delete-collection-button').click()
self._alert_wait()

def _journalist_uses_delete_selected_button_javascript(self):
self._journalist_selects_first_doc()
self._journalist_clicks_delete_selected_javascript()
self._alert_dismiss()
def _journalist_sees_delete_collections_confirmation(self):
assert self.driver.find_element_by_id(
'delete-confirmation-modal').is_displayed()

def _journalist_sees_delete_selected_confirmation(self):
assert self.driver.find_element_by_id(
'delete-selected-confirmation-modal').is_displayed()

def _journalist_sees_delete_collection_confirmation(self):
assert self.driver.find_element_by_id(
'delete-collection-confirmation-modal').is_displayed()

def _journalist_clicks_delete_selected_link(self):
self.driver.find_element_by_id('delete-selected-link').click()
self._journalist_sees_delete_selected_confirmation()

def _journalist_clicks_delete_collections_link(self):
self.driver.find_element_by_id('delete-collections-link').click()
self._journalist_sees_delete_collections_confirmation()

def _journalist_clicks_delete_collection_link(self):
self.driver.find_element_by_id('delete-collection-link').click()
self._journalist_sees_delete_collection_confirmation()

def _journalist_uses_delete_selected_button_confirmation(self):
selected_count = len(self.driver.find_elements_by_name(
'doc_names_selected'))
assert selected_count > 0

self._journalist_clicks_delete_selected_javascript()
self._alert_accept()
self._journalist_selects_first_doc()
self._journalist_clicks_delete_selected_link()
self._journalist_clicks_delete_selected_cancel_on_modal()
assert selected_count == len(self.driver.find_elements_by_name(
'doc_names_selected'))

self._journalist_clicks_delete_selected_link()
self._journalist_clicks_delete_selected_on_modal()
assert selected_count > len(self.driver.find_elements_by_name(
'doc_names_selected'))

def _journalist_uses_delete_collection_button_javascript(self):
self._journalist_clicks_delete_collection_javascript()
self._alert_dismiss()
def _journalist_uses_delete_collection_button_confirmation(self):
self._journalist_clicks_delete_collection_link()
self._journalist_clicks_delete_collection_cancel_on_modal()

# After deletion the button will redirect us. Let's ensure we still
# see the delete collection button.
assert self.driver.find_element_by_id(
'delete-collection-button').is_displayed()
'delete-collection-link').is_displayed()

self._journalist_clicks_delete_collection_javascript()
self._alert_accept()
self._journalist_clicks_delete_collection_link()
self._journalist_clicks_delete_collection_on_modal()

# Now we should be redirected to the index.
if not hasattr(self, 'accept-languages'):
assert "Sources" in self.driver.find_element_by_tag_name('h1').text

def _journalist_uses_delete_collections_button_javascript(self):
self.driver.find_element_by_id('select_all').click()
def _journalist_uses_delete_collections_button_confirmation(self):
sources = self.driver.find_elements_by_class_name("code-name")
assert len(sources) > 0

self._journalist_clicks_delete_collections_javascript()
self._alert_dismiss()
self.driver.find_element_by_id('select_all').click()
self._journalist_clicks_delete_collections_link()
self._journalist_clicks_delete_collections_cancel_on_modal()

self.driver.find_element_by_id('select_all').click()
sources = self.driver.find_elements_by_class_name("code-name")
assert len(sources) > 0

self._journalist_clicks_delete_collections_javascript()
self._alert_accept()
self._journalist_clicks_delete_collections_link()
self._journalist_clicks_delete_collections_on_modal()

# We should be redirected to the index without those boxes selected.
sources = self.driver.find_elements_by_class_name("code-name")
Expand Down Expand Up @@ -664,12 +698,12 @@ def _journalist_delete_all(self):
for checkbox in self.driver.find_elements_by_name(
'doc_names_selected'):
checkbox.click()
self.driver.find_element_by_id('delete-selected').click()
self.driver.find_element_by_id('delete-selected-link').click()

def _journalist_confirm_delete_all(self):
self.wait_for(
lambda: self.driver.find_element_by_id('confirm-delete'))
confirm_btn = self.driver.find_element_by_id('confirm-delete')
lambda: self.driver.find_element_by_id('delete-selected'))
confirm_btn = self.driver.find_element_by_id('delete-selected')
confirm_btn.click()

def _source_delete_key(self):
Expand All @@ -682,14 +716,13 @@ def _journalist_continues_after_flagging(self):
def _journalist_delete_none(self):
self.driver.find_element_by_id('delete-selected').click()

def _journalist_delete_all_javascript(self):
def _journalist_delete_all_confirmation(self):
self.driver.find_element_by_id('select_all').click()
self.driver.find_element_by_id('delete-selected').click()
self._alert_wait()
self.driver.find_element_by_id('delete-selected-link').click()

def _journalist_delete_one(self):
self.driver.find_elements_by_name('doc_names_selected')[0].click()
self.driver.find_element_by_id('delete-selected').click()
self.driver.find_element_by_id('delete-selected-link').click()

def _journalist_flags_source(self):
self.driver.find_element_by_id('flag-button').click()
Expand Down
Loading