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 4 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
32 changes: 30 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,18 @@
{% endfor %}
</ul>

<!-- Confirmation modal for selected documents -->
<div id="delete-selected-confirmation-modal" class="modal-dialog">
<a href="#close" class="external"></a>
<div>
<a href="#close" title="{{ gettext('Close') }}" class="close">X</a>
<h2>{{ gettext('Delete Confirmation') }}</h2>
<p>{{ gettext('Are you sure you want to delete the selected documents?') }}</p>
<a href="#close" id="cancel-selected-deletions" title="{{ gettext('Cancel') }}" class="btn sd-button">{{ gettext('Cancel') }}</a>
<button type="submit" name="action" value="confirm_delete" id="delete-selected" class="sd-button danger">{{ gettext('Delete') }}</button>
</div>
</div>

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

Expand Down Expand Up @@ -101,7 +115,21 @@ <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 -->
<div id="delete-collection-confirmation-modal" class="modal-dialog">
<a href="#close" class="external"></a>
<div>
<a href="#close" title="{{ gettext('Close') }}" class="close">X</a>
<h2>{{ gettext('Delete Confirmation') }}</h2>
<p>{{ gettext('Are you sure you want to delete this collection?') }}</p>
<a href="#close" id="cancel-collection-deletions" title="{{ gettext('Cancel') }}" class="btn sd-button">{{ gettext('Cancel') }}</a>
<button type="submit" id="delete-collection-button" name="action" value="delete" class="sd-button danger">{{ gettext('Delete') }}</button>
</div>
</div>
</form>

</div>
Expand Down
16 changes: 15 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,18 @@ <h1><span class="headline">{{ gettext('Sources') }}</span></h1>
</ul>
{% endif %}

<!-- Delete confirmation modal -->
<div id="delete-confirmation-modal" class="modal-dialog">
<a href="#close" class="external"></a>
<div>
<a href="#close" title="{{ gettext('Close') }}" class="close">X</a>
<h2>{{ gettext('Delete Confirmation') }}</h2>
<p>{{ gettext('Are you sure you want to delete the selected collections?') }}</p>
<a href="#close" id="cancel-collections-deletions" title="{{ gettext('Cancel') }}" class="btn sd-button">{{ gettext('Cancel') }}</a>
<button type="submit" id="delete-collections" name="action" value="delete" class="sd-button danger">{{ gettext('Delete') }}</button>
</div>
</div>

</form>
{% else %}
<p>{{ gettext('No documents have been submitted!') }}</p>
Expand Down
52 changes: 52 additions & 0 deletions securedrop/sass/journalist.sass
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,58 @@ p.breadcrumbs
&:dir(rtl)
text-align: right

.modal-dialog
Copy link

Choose a reason for hiding this comment

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

What about moving this to modules/_modal.sass or a similar name which would then be included in _base.sass ? Do you envision problems if doing that ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will check on this.

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


#regenerate-code .confirm-prompt
font-size: 14px
font-style: italic
Expand Down
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
89 changes: 59 additions & 30 deletions securedrop/tests/functional/journalist_navigation_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,60 +75,90 @@ 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_collections_javascript(self):
def _journalist_clicks_delete_collection_cancel_on_modal(self):
self.driver.find_element_by_id('cancel-collection-deletions').click()

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):
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):
self._journalist_selects_first_doc()
self._journalist_clicks_delete_selected_javascript()
self._alert_dismiss()
self._journalist_clicks_delete_selected_link()
self._journalist_clicks_delete_selected_cancel_on_modal()
Copy link

Choose a reason for hiding this comment

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

These should be after assert select_count > 0 because this assert verifies there are selected docs to work with. And after self._journalist_clicks_delete_selected_cancel_on_modal() there should be an assert like

assert selected_count == len(self.driver.find_elements_by_name('doc_names_selected'))

to verify no deletion took place.


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_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):
def _journalist_uses_delete_collections_button_confirmation(self):
self.driver.find_element_by_id('select_all').click()

self._journalist_clicks_delete_collections_javascript()
self._alert_dismiss()
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 +694,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 +712,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
16 changes: 8 additions & 8 deletions securedrop/tests/functional/test_journalist.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class TestJournalist(
source_navigation_steps.SourceNavigationStepsMixin,
journalist_navigation_steps.JournalistNavigationStepsMixin):

def test_journalist_verifies_deletion_of_one_submission_javascript(self):
def test_journalist_verifies_deletion_of_one_submission_modal(self):
# This deletion button is displayed on the individual source page
self._source_visits_source_homepage()
self._source_chooses_to_submit_documents()
Expand All @@ -34,9 +34,9 @@ def test_journalist_verifies_deletion_of_one_submission_javascript(self):
self._source_logs_out()
self._journalist_logs_in()
self._journalist_visits_col()
self._journalist_uses_delete_selected_button_javascript()
self._journalist_uses_delete_selected_button_confirmation()

def test_journalist_uses_col_delete_collection_button_javascript(self):
def test_journalist_uses_col_delete_collection_button_modal(self):
# This delete button is displayed on the individual source page
self._source_visits_source_homepage()
self._source_chooses_to_submit_documents()
Expand All @@ -45,19 +45,19 @@ def test_journalist_uses_col_delete_collection_button_javascript(self):
self._source_logs_out()
self._journalist_logs_in()
self._journalist_visits_col()
self._journalist_uses_delete_collection_button_javascript()
self._journalist_uses_delete_collection_button_confirmation()

def test_journalist_uses_index_delete_collections_button_javascript(self):
def test_journalist_uses_index_delete_collections_button_modal(self):
# This deletion button is displayed on the index page
self._source_visits_source_homepage()
self._source_chooses_to_submit_documents()
self._source_continues_to_submit_page()
self._source_submits_a_file()
self._source_logs_out()
self._journalist_logs_in()
self._journalist_uses_delete_collections_button_javascript()
self._journalist_uses_delete_collections_button_confirmation()

def test_journalist_interface_ui_with_javascript(self):
def test_journalist_interface_ui_with_modal(self):
self._source_visits_source_homepage()
self._source_chooses_to_submit_documents()
self._source_continues_to_submit_page()
Expand All @@ -68,4 +68,4 @@ def test_journalist_interface_ui_with_javascript(self):
self._journalist_selects_all_sources_then_selects_none()
self._journalist_selects_the_first_source()
self._journalist_uses_js_buttons_to_download_unread()
self._journalist_delete_all_javascript()
self._journalist_delete_all_confirmation()
Loading