Add action buttons to filter popups (#3882)

Adds action buttons ("Apply" & "Clear") to filter popups for UX improvement (past experience was click out of the popup to apply the selected filters and manually remove all applied filters). Credit to @Teranode. Fixes #3304.
This commit is contained in:
Teranode 2018-10-30 20:18:42 -04:00 committed by Luke Towers
parent 5e877ea2ba
commit 8383f555ed
3 changed files with 139 additions and 84 deletions

View File

@ -84,14 +84,14 @@
$scope.addClass('filter-scope-open')
})
$(document).on('click', '#controlFilterPopover [data-trigger="filter"]', function (e) {
$(document).on('click', '#controlFilterPopoverDate [data-trigger="filter"]', function (e) {
e.preventDefault()
e.stopPropagation()
self.filterByDate()
})
$(document).on('click', '#controlFilterPopover [data-trigger="clear"]', function (e) {
$(document).on('click', '#controlFilterPopoverDate [data-trigger="clear"]', function (e) {
e.preventDefault()
e.stopPropagation()
@ -106,7 +106,7 @@
return ' \
<form> \
<input type="hidden" name="scopeName" value="{{ scopeName }}" /> \
<div id="controlFilterPopover" class="control-filter-popover control-filter-box-popover"> \
<div id="controlFilterPopoverDate" class="control-filter-popover control-filter-box-popover"> \
<div class="filter-search loading-indicator-container size-input-text"> \
<div class="field-datepicker"> \
<div class="input-with-icon right-align"> \
@ -135,46 +135,46 @@
* Get popover range template
*/
FilterWidget.prototype.getPopoverRangeTemplate = function () {
return ' \
<form> \
<input type="hidden" name="scopeName" value="{{ scopeName }}" /> \
<div id="controlFilterPopover" class="control-filter-popover control-filter-box-popover --range"> \
<div class="filter-search loading-indicator-container size-input-text"> \
<div class="field-datepicker"> \
<div class="input-with-icon right-align"> \
<i class="icon icon-calendar-o"></i> \
<input \
type="text" \
name="date" \
value="{{ date }}" \
class="form-control align-right popup-allow-focus" \
autocomplete="off" \
placeholder="{{ after_placeholder }}" /> \
</div> \
</div> \
<div class="field-datepicker"> \
<div class="input-with-icon right-align"> \
<i class="icon icon-calendar-o"></i> \
<input \
type="text" \
name="date" \
value="{{ date }}" \
class="form-control align-right" \
autocomplete="off" \
placeholder="{{ before_placeholder }}" /> \
</div> \
</div> \
<div class="filter-buttons"> \
<button class="btn btn-block btn-primary" data-trigger="filter"> \
{{ filter_button_text }} \
</button> \
<button class="btn btn-block btn-secondary" data-trigger="clear"> \
{{ reset_button_text }} \
</button> \
</div> \
</div> \
</div> \
</form> \
return ' \
<form> \
<input type="hidden" name="scopeName" value="{{ scopeName }}" /> \
<div id="controlFilterPopoverDate" class="control-filter-popover control-filter-box-popover --range"> \
<div class="filter-search loading-indicator-container size-input-text"> \
<div class="field-datepicker"> \
<div class="input-with-icon right-align"> \
<i class="icon icon-calendar-o"></i> \
<input \
type="text" \
name="date" \
value="{{ date }}" \
class="form-control align-right popup-allow-focus" \
autocomplete="off" \
placeholder="{{ after_placeholder }}" /> \
</div> \
</div> \
<div class="field-datepicker"> \
<div class="input-with-icon right-align"> \
<i class="icon icon-calendar-o"></i> \
<input \
type="text" \
name="date" \
value="{{ date }}" \
class="form-control align-right" \
autocomplete="off" \
placeholder="{{ before_placeholder }}" /> \
</div> \
</div> \
<div class="filter-buttons"> \
<button class="btn btn-block btn-primary" data-trigger="filter"> \
{{ filter_button_text }} \
</button> \
<button class="btn btn-block btn-secondary" data-trigger="clear"> \
{{ reset_button_text }} \
</button> \
</div> \
</div> \
</div> \
</form> \
'
}
@ -238,7 +238,7 @@
FilterWidget.prototype.initDatePickers = function (isRange) {
var self = this,
scopeData = this.$activeScope.data('scope-data'),
$inputs = $('.field-datepicker input', '#controlFilterPopover'),
$inputs = $('.field-datepicker input', '#controlFilterPopoverDate'),
data = this.scopeValues[this.activeScopeName]
if (!data) {
@ -277,7 +277,7 @@
}
FilterWidget.prototype.clearDatePickers = function () {
var $inputs = $('.field-datepicker input', '#controlFilterPopover')
var $inputs = $('.field-datepicker input', '#controlFilterPopoverDate')
$inputs.each(function (index, datepicker) {
var $datepicker = $(datepicker)
@ -330,7 +330,7 @@
dates = []
if (!isReset) {
var datepickers = $('.field-datepicker input', '#controlFilterPopover')
var datepickers = $('.field-datepicker input', '#controlFilterPopoverDate')
datepickers.each(function (index, datepicker) {
var date = $(datepicker).data('pikaday').toString('YYYY-MM-DD')

View File

@ -40,41 +40,49 @@
* Get popover template
*/
FilterWidget.prototype.getPopoverTemplate = function() {
return ' \
<form> \
<input type="hidden" name="scopeName" value="{{ scopeName }}" /> \
<div id="controlFilterPopover" class="control-filter-popover"> \
<div class="filter-search loading-indicator-container size-input-text"> \
<button class="close" data-dismiss="popover" type="button">&times;</button> \
<input \
type="text" \
name="search" \
autocomplete="off" \
class="filter-search-input form-control icon search popup-allow-focus" \
data-request="{{ optionsHandler }}" \
data-load-indicator-opaque \
data-load-indicator \
data-track-input /> \
</div> \
<div class="filter-items"> \
<ul> \
{{#available}} \
<li data-item-id="{{id}}"><a href="javascript:;">{{name}}</a></li> \
{{/available}} \
{{#loading}} \
<li class="loading"><span></span></li> \
{{/loading}} \
</ul> \
</div> \
<div class="filter-active-items"> \
<ul> \
{{#active}} \
<li data-item-id="{{id}}"><a href="javascript:;">{{name}}</a></li> \
{{/active}} \
</ul> \
</div> \
</div> \
</form> \
return ' \
<form> \
<input type="hidden" name="scopeName" value="{{ scopeName }}" /> \
<div id="controlFilterPopover" class="control-filter-popover control-filter-box-popover --range"> \
<div class="filter-search loading-indicator-container size-input-text"> \
<button class="close" data-dismiss="popover" type="button">&times;</button> \
<input \
type="text" \
name="search" \
autocomplete="off" \
class="filter-search-input form-control icon search popup-allow-focus" \
data-request="{{ optionsHandler }}" \
data-load-indicator-opaque \
data-load-indicator \
data-track-input /> \
<div class="filter-items"> \
<ul> \
{{#available}} \
<li data-item-id="{{id}}"><a href="javascript:;">{{name}}</a></li> \
{{/available}} \
{{#loading}} \
<li class="loading"><span></span></li> \
{{/loading}} \
</ul> \
</div> \
<div class="filter-active-items"> \
<ul> \
{{#active}} \
<li data-item-id="{{id}}"><a href="javascript:;">{{name}}</a></li> \
{{/active}} \
</ul> \
</div> \
<div class="filter-buttons"> \
<button class="btn btn-block btn-primary oc-icon-filter" data-trigger="apply"> \
{{ apply_button_text }} \
</button> \
<button class="btn btn-block btn-secondary oc-icon-eraser" data-trigger="clear"> \
{{ clear_button_text }} \
</button> \
</div> \
</div> \
</div> \
</form> \
'
}
@ -137,6 +145,16 @@
$(document).on('ajaxDone', '#controlFilterPopover input.filter-search-input', function(event, context, data){
self.filterAvailable(data.scopeName, data.options.available)
})
$(document).on('click', '#controlFilterPopover [data-trigger="apply"]', function (e) {
e.preventDefault()
self.filterScope()
})
$(document).on('click', '#controlFilterPopover [data-trigger="clear"]', function (e) {
e.preventDefault()
self.filterScope(true)
})
}
FilterWidget.prototype.focusSearch = function() {
@ -195,6 +213,7 @@
if (item)
toItems.push(item)
this.toggleFilterButtons(items)
this.updateScopeSetting(this.$activeScope, items.active.length)
this.isActiveScopeDirty = true
this.focusSearch()
@ -210,7 +229,12 @@
data = { loading: true }
isLoaded = false
}
data = $.extend({}, data, {
apply_button_text: this.getLang('filter.scopes.apply_button_text', 'Apply'),
clear_button_text: this.getLang('filter.scopes.clear_button_text', 'Clear')
})
data.scopeName = scopeName
data.optionsHandler = self.options.optionsHandler
@ -224,7 +248,9 @@
closeOnPageClick: true,
placement: 'bottom'
})
this.toggleFilterButtons()
// Load options for the first time
if (!isLoaded) {
self.loadOptions(scopeName)
@ -256,6 +282,7 @@
data: data,
success: function(data) {
self.fillOptions(scopeName, data.options)
self.toggleFilterButtons()
}
})
}
@ -328,6 +355,18 @@
})
}
FilterWidget.prototype.toggleFilterButtons = function(data)
{
var items = $('#controlFilterPopover .filter-active-items > ul'),
buttonContainer = $('#controlFilterPopover .filter-buttons')
if(data) {
data.active.length > 0 ? buttonContainer.show() : buttonContainer.hide()
} else {
items.children().length > 0 ? buttonContainer.show() : buttonContainer.hide()
}
}
/*
* Saves the options to the update handler
*/
@ -399,6 +438,19 @@
$scope.toggleClass('active', !!switchValue)
}
FilterWidget.prototype.filterScope = function (isReset) {
var scopeName = this.$activeScope.data('scope-name')
if (isReset) {
this.scopeValues[scopeName] = null
this.updateScopeSetting(this.$activeScope, 0)
}
this.pushOptions(scopeName);
this.isActiveScopeDirty = true;
this.$activeScope.data('oc.popover').hide()
}
FilterWidget.prototype.getLang = function(name, defaultValue) {
if ($.oc === undefined || $.oc.lang === undefined) {
return defaultValue
@ -407,7 +459,6 @@
return $.oc.lang.get(name, defaultValue)
}
// FILTER WIDGET PLUGIN DEFINITION
// ============================

View File

@ -63,6 +63,10 @@ return [
'group' => [
'all' => 'all'
],
'scopes' => [
'apply_button_text' => 'Apply',
'clear_button_text' => 'Clear'
],
'dates' => [
'all' => 'all',
'filter_button_text' => 'Filter',