Backport panel selection and panel toolbar

Support selection by panel body clicking. Styling changes for highlighted panel.
Self-display multiple item action list. New select all button.
Fix fancybox click area on thumbnail display.
Remove the multi item form processing view.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2019-07-16 01:24:57 -04:00
parent 8c064c953a
commit 49a16acdf5
8 changed files with 194 additions and 146 deletions

View File

@@ -220,6 +220,18 @@ a i {
font-weight: bold;
}
.panel-highlighted {
box-shadow: 0px 0px 3px #18bc9c, 10px 10px 20px #000000;
}
.panel-highlighted:hover {
box-shadow: 0px 0px 3px #18bc9c, 10px 10px 20px #000000, 0px 0px 8px #000000;
}
.panel-item:not(.panel-highlighted):hover {
box-shadow: 0px 0px 8px #000000;
}
/* Content */
@media (min-width:1200px) {
.container-fluid {
@@ -249,14 +261,6 @@ a i {
margin: auto;
}
.thin_border {
border: 1px solid black;
display: block;
margin-left: auto;
margin-right: auto;
}
.thin_border-thumbnail {
display: block;
max-width: 100%;
@@ -266,6 +270,14 @@ a i {
margin: auto;
}
/* Must go after .thin_border-thumbnail */
.thin_border {
border: 1px solid black;
display: inline;
margin-left: 0px;
margin-right: 0px;
}
#ajax-spinner {
position: fixed;
top: 16px;

View File

@@ -6,7 +6,8 @@ var MayanAppClass = MayanApp;
var partialNavigation = new PartialNavigation({
initialURL: initialURL,
disabledAnchorClasses: ['disabled'],
disabledAnchorClasses: [
'btn-multi-item-action', 'disabled', 'pagination-disabled'
],
excludeAnchorClasses: ['fancybox', 'new_window', 'non-ajax'],
formBeforeSerializeCallbacks: [MayanApp.MultiObjectFormProcess],
});

View File

@@ -17,30 +17,36 @@ class MayanApp {
// Class methods and variables
static MultiObjectFormProcess ($form, options) {
/*
* ajaxForm callback to add the external item checkboxes to the
* submitted form
*/
static countChecked() {
var checkCount = $('.check-all-slave:checked').length;
if ($form.hasClass('form-multi-object-action')) {
// Turn form data into an object
var formArray = $form.serializeArray().reduce(function (obj, item) {
obj[item.name] = item.value;
return obj;
}, {});
// Add all checked checkboxes to the form data
$('.form-multi-object-action-checkbox:checked').each(function() {
var $this = $(this);
formArray[$this.attr('name')] = $this.attr('value');
});
// Set the form data as the data to send
options.data = formArray;
if (checkCount) {
$('#multi-item-title').hide();
$('#multi-item-actions').show();
} else {
$('#multi-item-title').show();
$('#multi-item-actions').hide();
}
}
static setupMultiItemActions () {
$('body').on('change', '.check-all-slave', function () {
MayanApp.countChecked();
});
$('body').on('click', '.btn-multi-item-action', function (event) {
var id_list = [];
$('.check-all-slave:checked').each(function (index, value) {
//Split the name (ie:"pk_200") and extract only the ID
id_list.push(value.name.split('_')[1]);
});
event.preventDefault();
partialNavigation.setLocation(
$(this).attr('href') + '?id_list=' + id_list.join(',')
);
});
}
static setupNavBarState () {
$('body').on('click', '.a-main-menu-accordion-link', function (event) {
console.log('ad');
@@ -166,10 +172,10 @@ class MayanApp {
var self = this;
this.setupAJAXSpinner();
this.setupAutoSubmit();
this.setupFormHotkeys();
this.setupFullHeightResizing();
this.setupItemsSelector();
MayanApp.setupMultiItemActions();
this.setupNavbarCollapse();
MayanApp.setupNavBarState();
this.setupNewWindowAnchor();
@@ -177,6 +183,7 @@ class MayanApp {
value.app = self;
app.doRefreshAJAXMenu(value);
});
this.setupPanelSelection();
partialNavigation.initialize();
}
@@ -200,14 +207,6 @@ class MayanApp {
});
}
setupAutoSubmit () {
$('body').on('change', '.select-auto-submit', function () {
if ($(this).val()) {
$(this.form).trigger('submit');
}
});
}
setupFormHotkeys () {
$('body').on('keypress', '.form-hotkey-enter', function (e) {
if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
@@ -238,9 +237,22 @@ class MayanApp {
app.lastChecked = null;
$('body').on('click', '.check-all', function (event) {
var $this = $(this);
var checked = $(event.target).prop('checked');
var $checkBoxes = $('.check-all-slave');
if (checked === undefined) {
checked = $this.data('checked');
checked = !checked;
$this.data('checked', checked);
if (checked) {
$this.find('[data-fa-i2svg]').addClass($this.data('icon-checked')).removeClass($this.data('icon-unchecked'));
} else {
$this.find('[data-fa-i2svg]').addClass($this.data('icon-unchecked')).removeClass($this.data('icon-checked'));
}
}
$checkBoxes.prop('checked', checked);
$checkBoxes.trigger('change');
});
@@ -286,6 +298,58 @@ class MayanApp {
});
}
setupPanelSelection () {
var app = this;
// Setup panel highlighting on check
$('body').on('change', '.check-all-slave', function (event) {
var checked = $(event.target).prop('checked');
if (checked) {
$(this).closest('.panel-item').addClass('panel-highlighted');
} else {
$(this).closest('.panel-item').removeClass('panel-highlighted');
}
});
$('body').on('click', '.panel-item', function (event) {
var $this = $(this);
var targetSrc = $(event.target).prop('src');
var targetHref = $(event.target).prop('href');
var targetIsButton = event.target.tagName === 'BUTTON';
var lastChecked = null;
if ((targetSrc === undefined) && (targetHref === undefined) && (targetIsButton === false)) {
var $checkbox = $this.find('.check-all-slave');
var checked = $checkbox.prop('checked');
if (checked) {
$checkbox.prop('checked', '');
$checkbox.trigger('change');
} else {
$checkbox.prop('checked', 'checked');
$checkbox.trigger('change');
}
if(!app.lastChecked) {
app.lastChecked = $checkbox;
}
if (event.shiftKey) {
var $checkBoxes = $('.check-all-slave');
var start = $checkBoxes.index($checkbox);
var end = $checkBoxes.index(app.lastChecked);
$checkBoxes.slice(
Math.min(start, end), Math.max(start, end) + 1
).prop('checked', app.lastChecked.prop('checked')).trigger('change');
}
app.lastChecked = $checkbox;
window.getSelection().removeAllRanges();
}
});
}
setupScrollView () {
$('.scrollable').scrollview();
}

View File

@@ -23,26 +23,20 @@
{% endif %}
</h4>
<hr>
<div class="well center-block">
<div class="clearfix">
<div class="pull-right">
<form action="{% url 'common:multi_object_action_view' %}" class="form-multi-object-action" method="get">
{% if object_list %}
{% if not hide_multi_item_actions %}
{% get_multi_item_links_form object_list %}
{% endif %}
{% if multi_item_actions %}
<fieldset style="margin-top: -10px;">
<input class="check-all" type="checkbox"/>&nbsp;
{{ multi_item_form }}
</fieldset>
{% endif %}
{% endif %}
</form>
</div>
</div>
{% if object_list %}
{% if not hide_multi_item_actions %}
{% navigation_resolve_menu name='multi item' sort_results=True source=object_list.0 as links_multi_menus_results %}
{% endif %}
{% endif %}
<div class="clearfix">
{% include 'appearance/list_toolbar.html' %}
</div>
{% if links_multi_menus_results %}
<hr style="border-bottom: 1px solid lightgrey;">
{% endif %}
@@ -54,8 +48,8 @@
<div class="form-group">
<div class="checkbox">
<label for="id_indexes_0">
{% if multi_item_actions %}
<input class="form-multi-object-action-checkbox check-all-slave checkbox" type="checkbox" name="pk_{{ object.pk }}" />
{% if links_multi_menus_results %}
<input class="form-multi-object-action-checkbox check-all-slave checkbox" name="pk_{{ object.pk }}" type="checkbox" />
{% endif %}
<span style="color: white; word-break: break-all; overflow-wrap: break-word;">
@@ -82,7 +76,6 @@
</div>
<div class="panel-body">
{% if not hide_columns %}
{% navigation_get_source_columns source=object exclude_identifier=True as source_columns %}
{% for column in source_columns %}

View File

@@ -25,30 +25,27 @@
<hr>
<div class="well center-block">
{% if object_list %}
{% if not hide_multi_item_actions %}
{% navigation_resolve_menu name='multi item' sort_results=True source=object_list.0 as links_multi_menus_results %}
{% endif %}
{% endif %}
<div class="clearfix">
<div class="pull-right">
<form action="{% url 'common:multi_object_action_view' %}" class="form-multi-object-action" method="get">
{% if object_list %}
{% if not hide_multi_item_actions %}
{% get_multi_item_links_form object_list %}
{% endif %}
{% if multi_item_actions %}
<fieldset style="margin-top: -10px; margin-bottom: 10px;">
{{ multi_item_form }}
</fieldset>
{% endif %}
{% endif %}
</form>
</div>
{% include 'appearance/list_toolbar.html' %}
</div>
{% if links_multi_menus_results %}
<hr style="border-bottom: 1px solid lightgrey;">
{% endif %}
<div class="table-responsive">
<table class="table table-condensed table-striped">
<tbody>
{% if not hide_header %}
<tr>
{% if multi_item_actions %}
<th class="first"><input class="checkbox check-all" type="checkbox" /></th>
{% if links_multi_menus_results %}
<th class="first"></th>
{% endif %}
{% if not hide_object %}
@@ -99,9 +96,9 @@
{% for object in object_list %}
<tr>
{% if multi_item_actions %}
{% if links_multi_menus_results %}
<td>
<input type="checkbox" class="form-multi-object-action-checkbox check-all-slave checkbox" name="pk_{{ object.pk }}" value="" />
<input class="form-multi-object-action-checkbox check-all-slave checkbox" name="pk_{{ object.pk }}" type="checkbox" value="" />
</td>
{% endif %}

View File

@@ -0,0 +1,49 @@
{% load i18n %}
{% load common_tags %}
{% load navigation_tags %}
<div class="pull-left">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group">
{% if links_multi_menus_results %}
<a class="btn btn-default btn-sm check-all" data-checked=false data-icon-checked="fa fa-check-square" data-icon-unchecked="far fa-square" title="{% trans 'Select/Deselect all' %}">
<i class="far fa-square"></i>
</a>
{% endif %}
</div>
</div>
</div>
{% if links_multi_menus_results %}
<p class="pull-right" id="multi-item-title" style="margin-top: 4px;">{% trans 'Select items to activate bulk actions. Use Shift + click to select many.' %}</p>
<div class="pull-right btn-group" id="multi-item-actions" style="display: none;">
<button aria-expanded="true" class="btn btn-danger btn-sm dropdown-toggle" data-toggle="dropdown" type="button">
{% trans 'Bulk actions' %}
<span class="caret"></span>
<span class="sr-only">{% trans 'Toggle Dropdown' %}</span>
</button>
<ul class="dropdown-menu" role="menu">
{% for multi_item_menu_results in links_multi_menus_results %}
{% for link_group in multi_item_menu_results.link_groups %}
{% with link_group.links as object_navigation_links %}
{% with 'true' as as_li %}
{% with 'true' as hide_active_anchor %}
{% with 'btn-sm btn-multi-item-action' as link_classes %}
{% include 'navigation/generic_navigation.html' %}
{% endwith %}
{% endwith %}
{% endwith %}
{% endwith %}
{% endfor %}
{% if not forloop.last and link_group %}
<li class="divider"></li>
{% endif %}
{% endfor %}
</ul>
</div>
<div class="clearfix"></div>
{% endif %}

View File

@@ -10,7 +10,7 @@ from .views import (
AboutView, CurrentUserLocaleProfileDetailsView,
CurrentUserLocaleProfileEditView, FaviconRedirectView, HomeView,
LicenseView, ObjectErrorLogEntryListClearView, ObjectErrorLogEntryListView,
RootView, SetupListView, ToolsListView, multi_object_action_view
RootView, SetupListView, ToolsListView
)
urlpatterns = [
@@ -18,10 +18,6 @@ urlpatterns = [
url(regex=r'^home/$', view=HomeView.as_view(), name='home'),
url(regex=r'^about/$', view=AboutView.as_view(), name='about_view'),
url(regex=r'^license/$', view=LicenseView.as_view(), name='license_view'),
url(
regex=r'^object/multiple/action/$', view=multi_object_action_view,
name='multi_object_action_view'
),
url(regex=r'^setup/$', view=SetupListView.as_view(), name='setup_list'),
url(regex=r'^tools/$', view=ToolsListView.as_view(), name='tools_list'),
url(

View File

@@ -220,67 +220,3 @@ class ToolsListView(SimpleView):
'These modules are used to do system maintenance.'
)
}
def multi_object_action_view(request):
"""
Proxy view called first when using a multi object action, which
then redirects to the appropriate specialized view
"""
next = request.POST.get(
'next', request.GET.get(
'next', request.META.get(
'HTTP_REFERER', reverse(setting_home_view.value)
)
)
)
action = request.GET.get('action', None)
id_list = ','.join(
[key[3:] for key in request.GET.keys() if key.startswith('pk_')]
)
items_property_list = [
(key[11:]) for key in request.GET.keys() if key.startswith('properties_')
]
if not action:
messages.error(
message=_('No action selected.'), request=request
)
return HttpResponseRedirect(
redirect_to=request.META.get(
'HTTP_REFERER', reverse(setting_home_view.value)
)
)
if not id_list and not items_property_list:
messages.error(
message=_('Must select at least one item.'),
request=request
)
return HttpResponseRedirect(
redirect_to=request.META.get(
'HTTP_REFERER', reverse(setting_home_view.value)
)
)
# Separate redirects to keep backwards compatibility with older
# functions that don't expect a properties_list parameter
if items_property_list:
return HttpResponseRedirect(
redirect_to='%s?%s' % (
action,
urlencode(
{
'items_property_list': dumps(items_property_list),
'next': next
}
)
)
)
else:
return HttpResponseRedirect(
redirect_to='%s?%s' % (
action, urlencode({'id_list': id_list, 'next': next})
)
)