Introduce scope "switch" type, allow options to be passed

This commit is contained in:
Samuel Georges 2016-04-27 19:09:19 +10:00
parent 28a8f84692
commit 0d8a30730e
12 changed files with 325 additions and 60 deletions

View File

@ -343,7 +343,8 @@ return [
'email' => 'Email'
],
'filter' => [
'all' => 'all'
'all' => 'all',
'options_method_not_exists' => "The model class :model must define a method :method() returning options for the ':filter' filter."
],
'import_export' => [
'upload_csv_file' => '1. Upload a CSV file',

View File

@ -1,6 +1,8 @@
<?php namespace Backend\Widgets;
use Db;
use Str;
use Lang;
use Event;
use DbDongle;
use Backend\Classes\WidgetBase;
@ -126,6 +128,11 @@ class Filter extends WidgetBase
$checked = post('value') == 'true' ? true : false;
$this->setScopeValue($scope, $checked);
break;
case 'switch':
$value = post('value');
$this->setScopeValue($scope, $value);
break;
}
/*
@ -179,12 +186,12 @@ class Filter extends WidgetBase
*/
protected function getAvailableOptions($scope, $searchQuery = null)
{
if (count($scope->options)) {
return $scope->options;
if ($scope->options) {
return $this->getOptionsFromArray($scope, $searchQuery);
}
$available = [];
$nameColumn = $this->getScopeNameColumn($scope);
$nameColumn = $this->getScopeNameFrom($scope);
$options = $this->getOptionsFromModel($scope, $searchQuery);
foreach ($options as $option) {
$available[$option->getKey()] = $option->{$nameColumn};
@ -216,6 +223,7 @@ class Filter extends WidgetBase
/**
* Looks at the model for defined scope items.
* @return Collection
*/
protected function getOptionsFromModel($scope, $searchQuery = null)
{
@ -232,10 +240,97 @@ class Filter extends WidgetBase
return $query->get();
}
$searchFields = [$model->getKeyName(), $this->getScopeNameColumn($scope)];
$searchFields = [$model->getKeyName(), $this->getScopeNameFrom($scope)];
return $query->searchWhere($searchQuery, $searchFields)->get();
}
/**
* Look at the defined set of options for scope items, or the model method.
* @return array
*/
protected function getOptionsFromArray($scope, $searchQuery = null)
{
/*
* Load the data
*/
$options = $scope->options;
if (is_scalar($options)) {
$model = $this->scopeModels[$scope->scopeName];
$methodName = $options;
if (!$model->methodExists($methodName)) {
throw new ApplicationException(Lang::get(
'backend::lang.filter.options_method_not_exists',
['model'=>get_class($model), 'method'=>$methodName, 'filter'=>$scope->scopeName]
));
}
$options = $model->$methodName();
}
elseif (!is_array($options)) {
$options = [];
}
/*
* Apply the search
*/
$searchQuery = Str::lower($searchQuery);
if (strlen($searchQuery)) {
$options = $this->filterOptionsBySearch($options, $searchQuery);
}
return $options;
}
/**
* Filters an array of options by a search term.
* @param array $options
* @param string $query
* @return array
*/
protected function filterOptionsBySearch($options, $query)
{
$filteredOptions = [];
$optionMatchesSearch = function($words, $option) {
foreach ($words as $word) {
$word = trim($word);
if (!strlen($word)) {
continue;
}
if (!Str::contains(Str::lower($option), $word)) {
return false;
}
}
return true;
};
/*
* Exact
*/
foreach ($options as $index => $option) {
if (Str::is(Str::lower($option), $query)) {
$filteredOptions[$index] = $option;
unset($options[$index]);
}
}
/*
* Fuzzy
*/
$words = explode(' ', $query);
foreach ($options as $index => $option) {
if ($optionMatchesSearch($words, $option)) {
$filteredOptions[$index] = $option;
}
}
return $filteredOptions;
}
/**
* Creates a flat array of filter scopes from the configuration.
*/
@ -362,6 +457,15 @@ class Filter extends WidgetBase
* Condition
*/
if ($scopeConditions = $scope->conditions) {
/*
* Switch scope: multiple conditions, value either 1 or 2
*/
if (is_array($scopeConditions)) {
$conditionNum = is_array($value) ? 0 : $value - 1;
list($scopeConditions) = array_slice($scopeConditions, $conditionNum);
}
if (is_array($value)) {
$filtered = implode(',', array_build($value, function ($key, $_value) {
return [$key, Db::getPdo()->quote($_value)];
@ -444,7 +548,7 @@ class Filter extends WidgetBase
* @param string $scope
* @return string
*/
public function getScopeNameColumn($scope)
public function getScopeNameFrom($scope)
{
if (is_string($scope)) {
$scope = $this->getScope($scope);

View File

@ -0,0 +1,7 @@
<!-- Switch scope -->
<div
class="filter-scope checkbox custom-checkbox is-indeterminate"
data-scope-name="<?= $scope->scopeName ?>">
<input type="checkbox" id="<?= $scope->getId() ?>" data-checked="<?= $scope->value ?: '0' ?>" />
<label for="<?= $scope->getId() ?>"><?= e(trans($scope->label)) ?></label>
</div>

View File

@ -1,6 +1,7 @@
<?php
$fieldOptions = $field->options();
$checkedValues = (array) $field->value;
$isScrollable = count($fieldOptions) > 10;
?>
<!-- Checkbox List -->
<?php if ($this->previewMode && $field->value): ?>
@ -34,8 +35,8 @@
<?php elseif (!$this->previewMode && count($fieldOptions)): ?>
<div class="field-checkboxlist">
<?php if (count($fieldOptions) > 10): ?>
<div class="field-checkboxlist <?= $isScrollable ? 'is-scrollable' : '' ?>">
<?php if ($isScrollable): ?>
<!-- Quick selection -->
<small>
<?= e(trans('backend::lang.form.select')) ?>:
@ -76,7 +77,7 @@
</div>
<?php endforeach ?>
<?php if (count($fieldOptions) > 10): ?>
<?php if ($isScrollable): ?>
</div>
</div>
<?php endif ?>

View File

@ -322,7 +322,7 @@ class TemplateList extends WidgetBase
return true;
}
protected function itemContainsWord($word, $item , $exact = false)
protected function itemContainsWord($word, $item, $exact = false)
{
$operator = $exact ? 'is' : 'contains';

View File

@ -24,4 +24,68 @@
}
})
//
// Intermediate checkboxes
//
$(document).render(function() {
$('div.custom-checkbox.is-indeterminate > input').each(function() {
var $el = $(this),
checked = $el.data('checked')
switch (checked) {
// Unchecked
case 1:
$el.prop('indeterminate', true)
break
// Checked
case 2:
$el.prop('indeterminate', false)
$el.prop('checked', true)
break
// Unchecked
default:
$el.prop('indeterminate', false)
$el.prop('checked', false)
}
})
})
$(document).on('click', 'div.custom-checkbox.is-indeterminate > label', function() {
var $el = $(this).parent().find('input:first'),
checked = $el.data('checked')
if (checked === undefined) {
checked = $el.is(':checked') ? 1 : 0
}
switch (checked) {
// Unchecked, going indeterminate
case 0:
$el.data('checked', 1)
$el.prop('indeterminate', true)
break
// Indeterminate, going checked
case 1:
$el.data('checked', 2)
$el.prop('indeterminate', false)
$el.prop('checked', true)
break
// Checked, going unchecked
default:
$el.data('checked', 0)
$el.prop('indeterminate', false)
$el.prop('checked', false)
}
$el.trigger('change')
return false
})
})(jQuery);

View File

@ -82,14 +82,14 @@
var self = this
this.$el.on('change', '.filter-scope input[type="checkbox"]', function(){
var isChecked = $(this).is(':checked'),
$scope = $(this).closest('.filter-scope'),
scopeName = $scope.data('scope-name')
var $scope = $(this).closest('.filter-scope')
self.scopeValues[scopeName] = isChecked
self.checkboxToggle(scopeName, isChecked)
$scope.toggleClass('active', isChecked)
if ($scope.hasClass('is-indeterminate')) {
self.switchToggle($(this))
}
else {
self.checkboxToggle($(this))
}
})
$('.filter-scope input[type="checkbox"]', this.$el).each(function() {
@ -351,10 +351,14 @@
})
}
FilterWidget.prototype.checkboxToggle = function(scopeName, isChecked) {
if (!this.options.updateHandler)
return
FilterWidget.prototype.checkboxToggle = function($el) {
var isChecked = $el.is(':checked'),
$scope = $el.closest('.filter-scope'),
scopeName = $scope.data('scope-name')
this.scopeValues[scopeName] = isChecked
if (this.options.updateHandler) {
var $form = this.$el.closest('form'),
data = {
scopeName: scopeName,
@ -369,6 +373,34 @@
})
}
$scope.toggleClass('active', isChecked)
}
FilterWidget.prototype.switchToggle = function($el) {
var switchValue = $el.data('checked'),
$scope = $el.closest('.filter-scope'),
scopeName = $scope.data('scope-name')
this.scopeValues[scopeName] = switchValue
if (this.options.updateHandler) {
var $form = this.$el.closest('form'),
data = {
scopeName: scopeName,
value: switchValue
}
$.oc.stripeLoadIndicator.show()
$form.request(this.options.updateHandler, {
data: data
}).always(function(){
$.oc.stripeLoadIndicator.hide()
})
}
$scope.toggleClass('active', !!switchValue)
}
// FILTER WIDGET PLUGIN DEFINITION
// ============================

View File

@ -71,7 +71,7 @@
top: 0;
background-color: #FFFFFF;
border: 1px solid @color-checkbox-border;
.box-shadow(~"inset 0 1px 0 @{input-border}, 0 1px 0 #fff");
.box-shadow(~"inset 0 1px 0 @{input-border}, 0 1px 0 rgba(255,255,255,.5)");
}
&:hover:before {
border-color: darken(@color-checkbox-border, 10%);
@ -123,8 +123,8 @@
}
}
input[type=checkbox]:indeterminate + label:before,
input[type=checkbox]:checked + label:before {
.icon(@check);
border-color: @color-checkbox-checked;
background-color: @color-checkbox-checked;
font-size: 12px;
@ -133,6 +133,22 @@
.box-shadow(none);
}
input[type=checkbox]:checked + label:before {
.icon(@check);
}
input[type=checkbox]:indeterminate + label:before {
.icon(@minus);
}
input:disabled + label:before {
border: 1px solid @color-checkbox-border !important;
}
input:disabled:checked + label:before {
background-color: #999;
}
&:focus {
outline: none;
label:before {

View File

@ -79,10 +79,6 @@
label {
padding-left: 25px;
&:before {
top: -1px;
}
}
&:after {
@ -116,6 +112,7 @@
border: none;
border-bottom: 1px solid @color-filter-border;
.border-bottom-radius(0);
.box-shadow(none);
background-color: transparent;
}
@ -159,7 +156,7 @@
}
.filter-items {
height: 100px;
max-height: 135px;
overflow: auto;
background-color: @color-filter-items-bg;
@ -191,7 +188,7 @@
@media (max-width: @screen-xs) {
.control-filter-popover {
.filter-items {
height: 200px;
max-height: 200px;
}
.filter-search {
input {

View File

@ -153,6 +153,10 @@
margin-top: -5px;
}
&.field-align-above {
margin-top: -5px;
}
&.field-slim {
&.span-left, &.span-right {
width: 50%;
@ -287,18 +291,25 @@
&.size-giant { min-height: @size-giant; }
}
.field-checkboxlist {
.field-checkboxlist:not(.is-scrollable) {
padding: 20px 20px 2px 20px;
.border-radius(@border-radius-base);
background: @color-form-checkboxlist-background;
border: 1px solid @color-form-checkboxlist-border;
.checkbox:last-of-type {
margin-bottom: 0;
//.checkbox:last-of-type {
// margin-bottom: 0;
//}
}
.field-checkboxlist.is-scrollable {
small {
color: @text-muted;
}
}
.field-checkboxlist-scrollable {
background: white;
background: @color-form-checkboxlist-background;
border: 1px solid @color-form-checkboxlist-border;
padding-left: 15px;
height: @size-large + 100;

View File

@ -1925,7 +1925,29 @@ return
$cb.get(0).checked=!$cb.get(0).checked
$cb.data('oc-space-timestamp',e.timeStamp)
$cb.trigger('change')
return false}})})(jQuery);+function($){"use strict";var BalloonSelector=function(element,options){this.$el=$(element)
return false}})
$(document).render(function(){$('div.custom-checkbox.is-indeterminate > input').each(function(){var $el=$(this),checked=$el.data('checked')
switch(checked){case 1:$el.prop('indeterminate',true)
break
case 2:$el.prop('indeterminate',false)
$el.prop('checked',true)
break
default:$el.prop('indeterminate',false)
$el.prop('checked',false)}})})
$(document).on('click','div.custom-checkbox.is-indeterminate > label',function(){var $el=$(this).parent().find('input:first'),checked=$el.data('checked')
if(checked===undefined){checked=$el.is(':checked')?1:0}
switch(checked){case 0:$el.data('checked',1)
$el.prop('indeterminate',true)
break
case 1:$el.data('checked',2)
$el.prop('indeterminate',false)
$el.prop('checked',true)
break
default:$el.data('checked',0)
$el.prop('indeterminate',false)
$el.prop('checked',false)}
$el.trigger('change')
return false})})(jQuery);+function($){"use strict";var BalloonSelector=function(element,options){this.$el=$(element)
this.$field=$('input',this.$el)
this.options=options||{};var self=this;$('li',this.$el).click(function(){if(self.$el.hasClass('control-disabled'))
return
@ -2076,10 +2098,9 @@ FilterWidget.prototype.getPopoverTemplate=function(){return'
</form> \
'}
FilterWidget.prototype.init=function(){var self=this
this.$el.on('change','.filter-scope input[type="checkbox"]',function(){var isChecked=$(this).is(':checked'),$scope=$(this).closest('.filter-scope'),scopeName=$scope.data('scope-name')
self.scopeValues[scopeName]=isChecked
self.checkboxToggle(scopeName,isChecked)
$scope.toggleClass('active',isChecked)})
this.$el.on('change','.filter-scope input[type="checkbox"]',function(){var $scope=$(this).closest('.filter-scope')
if($scope.hasClass('is-indeterminate')){self.switchToggle($(this))}
else{self.checkboxToggle($(this))}})
$('.filter-scope input[type="checkbox"]',this.$el).each(function(){$(this).closest('.filter-scope').toggleClass('active',$(this).is(':checked'))})
this.$el.on('click','a.filter-scope',function(){var $scope=$(this),scopeName=$scope.data('scope-name')
if($scope.hasClass('filter-scope-open'))return
@ -2166,11 +2187,18 @@ return
var $form=this.$el.closest('form'),data={scopeName:scopeName,options:this.scopeValues[scopeName]}
$.oc.stripeLoadIndicator.show()
$form.request(this.options.updateHandler,{data:data}).always(function(){$.oc.stripeLoadIndicator.hide()})}
FilterWidget.prototype.checkboxToggle=function(scopeName,isChecked){if(!this.options.updateHandler)
return
var $form=this.$el.closest('form'),data={scopeName:scopeName,value:isChecked}
FilterWidget.prototype.checkboxToggle=function($el){var isChecked=$el.is(':checked'),$scope=$el.closest('.filter-scope'),scopeName=$scope.data('scope-name')
this.scopeValues[scopeName]=isChecked
if(this.options.updateHandler){var $form=this.$el.closest('form'),data={scopeName:scopeName,value:isChecked}
$.oc.stripeLoadIndicator.show()
$form.request(this.options.updateHandler,{data:data}).always(function(){$.oc.stripeLoadIndicator.hide()})}
$scope.toggleClass('active',isChecked)}
FilterWidget.prototype.switchToggle=function($el){var switchValue=$el.data('checked'),$scope=$el.closest('.filter-scope'),scopeName=$scope.data('scope-name')
this.scopeValues[scopeName]=switchValue
if(this.options.updateHandler){var $form=this.$el.closest('form'),data={scopeName:scopeName,value:switchValue}
$.oc.stripeLoadIndicator.show()
$form.request(this.options.updateHandler,{data:data}).always(function(){$.oc.stripeLoadIndicator.hide()})}
$scope.toggleClass('active',!!switchValue)}
var old=$.fn.filterWidget
$.fn.filterWidget=function(option){var args=arguments,result
this.each(function(){var $this=$(this)

View File

@ -2348,7 +2348,7 @@ html.cssanimations .cursor-loading-indicator.hide{display:none}
.custom-checkbox,.custom-radio{padding-left:23px;margin-top:0}
.custom-checkbox input[type=radio],.custom-radio input[type=radio],.custom-checkbox input[type=checkbox],.custom-radio input[type=checkbox]{display:none}
.custom-checkbox label,.custom-radio label{display:inline-block;cursor:pointer;position:relative;padding-left:25px;margin-right:15px;margin-left:-20px;font-size:13px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
.custom-checkbox label:before,.custom-radio label:before{content:"";display:inline-block;text-align:center;color:#ffffff;width:18px;height:18px;margin-right:15px;position:absolute;left:-3px;top:0;background-color:#FFFFFF;border:1px solid #bdc3c7;-webkit-box-shadow:inset 0 1px 0 #bdc3c7,0 1px 0 #fff;box-shadow:inset 0 1px 0 #bdc3c7,0 1px 0 #fff}
.custom-checkbox label:before,.custom-radio label:before{content:"";display:inline-block;text-align:center;color:#ffffff;width:18px;height:18px;margin-right:15px;position:absolute;left:-3px;top:0;background-color:#FFFFFF;border:1px solid #bdc3c7;-webkit-box-shadow:inset 0 1px 0 #bdc3c7,0 1px 0 rgba(255,255,255,.5);box-shadow:inset 0 1px 0 #bdc3c7,0 1px 0 rgba(255,255,255,.5)}
.custom-checkbox label:hover:before,.custom-radio label:hover:before{border-color:#a1aab0}
.custom-checkbox label:active:before,.custom-radio label:active:before{border-color:#869198;border-width:2px}
.custom-checkbox input[type=radio]:checked + label:before,.custom-radio input[type=radio]:checked + label:before{border-color:#1f99dc;line-height:17px;border-width:2px}
@ -2357,7 +2357,11 @@ html.cssanimations .cursor-loading-indicator.hide{display:none}
.custom-checkbox input[type=radio][data-radio-color=green]:checked + label:after,.custom-radio input[type=radio][data-radio-color=green]:checked + label:after{background-color:#76a544}
.custom-checkbox input[type=radio][data-radio-color=red]:checked + label:before,.custom-radio input[type=radio][data-radio-color=red]:checked + label:before{border-color:#bb2424}
.custom-checkbox input[type=radio][data-radio-color=red]:checked + label:after,.custom-radio input[type=radio][data-radio-color=red]:checked + label:after{background-color:#bb2424}
.custom-checkbox input[type=checkbox]:checked + label:before,.custom-radio input[type=checkbox]:checked + label:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f00c";border-color:#1f99dc;background-color:#1f99dc;font-size:12px;line-height:17px;border-width:2px;-webkit-box-shadow:none;box-shadow:none}
.custom-checkbox input[type=checkbox]:indeterminate + label:before,.custom-radio input[type=checkbox]:indeterminate + label:before,.custom-checkbox input[type=checkbox]:checked + label:before,.custom-radio input[type=checkbox]:checked + label:before{border-color:#1f99dc;background-color:#1f99dc;font-size:12px;line-height:17px;border-width:2px;-webkit-box-shadow:none;box-shadow:none}
.custom-checkbox input[type=checkbox]:checked + label:before,.custom-radio input[type=checkbox]:checked + label:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f00c"}
.custom-checkbox input[type=checkbox]:indeterminate + label:before,.custom-radio input[type=checkbox]:indeterminate + label:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f068"}
.custom-checkbox input:disabled + label:before,.custom-radio input:disabled + label:before{border:1px solid #bdc3c7 !important}
.custom-checkbox input:disabled:checked + label:before,.custom-radio input:disabled:checked + label:before{background-color:#999}
.custom-checkbox:focus,.custom-radio:focus{outline:none}
.custom-checkbox:focus label:before,.custom-radio:focus label:before{border-color:#3498db}
.custom-checkbox p.help-block,.custom-radio p.help-block{padding-left:6px;margin-bottom:17px}
@ -2409,6 +2413,7 @@ html.cssanimations .cursor-loading-indicator.hide{display:none}
.form-group.checkbox-field{padding-bottom:5px}
.form-group.number-field > .form-control{text-align:right}
.form-group.checkbox-align{padding-left:28px;margin-top:-5px}
.form-group.field-align-above{margin-top:-5px}
.form-group.field-slim.span-left,.form-group.field-slim.span-right{width:50%}
.form-group.field-indent{padding-left:23px}
.form-group.input-sidebar-control{padding-right:35px}
@ -2438,9 +2443,9 @@ html.cssanimations .cursor-loading-indicator.hide{display:none}
.field-textarea.size-large{min-height:200px}
.field-textarea.size-huge{min-height:250px}
.field-textarea.size-giant{min-height:350px}
.field-checkboxlist{padding:20px 20px 2px 20px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background:#ffffff}
.field-checkboxlist .checkbox:last-of-type{margin-bottom:0}
.field-checkboxlist-scrollable{background:white;border:1px solid #e2e2e2;padding-left:15px;height:300px}
.field-checkboxlist:not(.is-scrollable){padding:20px 20px 2px 20px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background:#ffffff;border:1px solid #e2e2e2}
.field-checkboxlist.is-scrollable small{color:#999999}
.field-checkboxlist-scrollable{background:#ffffff;border:1px solid #e2e2e2;padding-left:15px;height:300px}
.field-checkboxlist-scrollable .checkbox{margin-top:15px;margin-bottom:5px}
.field-checkboxlist-scrollable .checkbox ~ .checkbox{margin-top:0}
.field-recordfinder{background-color:#ffffff;border:1px solid #bdc3c7;overflow:hidden;position:relative;-webkit-box-shadow:inset 0 1px 0 #bdc3c7,0 1px 0 #fff;box-shadow:inset 0 1px 0 #bdc3c7,0 1px 0 #fff;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
@ -2753,14 +2758,13 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a{padding:5px 12px;white
.control-filter > .filter-scope.checkbox{padding-left:35px}
.control-filter > .filter-scope.checkbox,.control-filter > .filter-scope.checkbox label{margin-bottom:0}
.control-filter > .filter-scope.checkbox label{padding-left:25px}
.control-filter > .filter-scope.checkbox label:before{top:-1px}
.control-filter > .filter-scope.checkbox:after{content:''}
.control-filter > .filter-scope:hover,.control-filter > .filter-scope.active,.control-filter > .filter-scope:hover.custom-checkbox label,.control-filter > .filter-scope.active.custom-checkbox label{color:#000000}
.control-filter > .filter-scope:hover .filter-label,.control-filter > .filter-scope.active .filter-label{color:#000000}
.control-filter > .filter-scope:hover.active .filter-setting,.control-filter > .filter-scope.active.active .filter-setting{background-color:#5f9a4c}
.control-filter-popover{min-width:275px}
.control-filter-popover .filter-search{min-height:36px}
.control-filter-popover .filter-search input{min-height:36px;border:none;border-bottom:1px solid #d7dbdd;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:transparent}
.control-filter-popover .filter-search input{min-height:36px;border:none;border-bottom:1px solid #d7dbdd;border-bottom-right-radius:0;border-bottom-left-radius:0;-webkit-box-shadow:none;box-shadow:none;background-color:transparent}
.control-filter-popover .filter-search .form-control.icon.search{background-position:right -81px}
.control-filter-popover .filter-search .close{display:none}
.control-filter-popover .filter-items,.control-filter-popover .filter-active-items{color:rgba(0,0,0,0.6);font-size:13px}
@ -2769,14 +2773,14 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a{padding:5px 12px;white
.control-filter-popover .filter-items a,.control-filter-popover .filter-active-items a{text-decoration:none;color:rgba(0,0,0,0.6);display:block;padding:7px 15px}
.control-filter-popover .filter-items a:before,.control-filter-popover .filter-active-items a:before{margin-right:8px;display:inline-block;vertical-align:baseline}
.control-filter-popover .filter-items a:hover,.control-filter-popover .filter-active-items a:hover{background-color:#4da7e8;color:#FFFFFF}
.control-filter-popover .filter-items{height:100px;overflow:auto;background-color:#fafafa;border-bottom:1px solid #d7dbdd}
.control-filter-popover .filter-items{max-height:135px;overflow:auto;background-color:#fafafa;border-bottom:1px solid #d7dbdd}
.control-filter-popover .filter-items a:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f067"}
.control-filter-popover .filter-items li.loading{padding:7px}
.control-filter-popover .filter-items li.loading > span{display:block;height:20px;width:20px;background-image:url('images/loader-transparent.svg');background-size:20px 20px;background-position:50% 50%;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}
.control-filter-popover .filter-items li.animate-enter{-webkit-animation:fadeInUp 0.5s;animation:fadeInUp 0.5s}
.control-filter-popover .filter-active-items a:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f00d"}
.control-filter-popover .filter-active-items li.animate-enter{-webkit-animation:fadeInDown 0.5s;animation:fadeInDown 0.5s}
@media (max-width:480px){.control-filter-popover .filter-items{height:200px}
@media (max-width:480px){.control-filter-popover .filter-items{max-height:200px}
.control-filter-popover .filter-search input{padding-left:36px;padding-right:36px}
.control-filter-popover .filter-search .form-control.icon.search{background-position:0 -81px}
.control-filter-popover .filter-search .close{width:30px;display:block;position:absolute;top:5px;right:5px;font-size:28px;z-index:2}