pure-angular-advanced-searchbox
Version:
Pure angular-based advanced search
2,147 lines (1,170 loc) • 107 kB
JavaScript
'use strict';
angular.module('paasb', [
'paasb.config'
]);
'use strict';
angular.module('paasb.config', [])
.constant('FILTERS', {SELECTORS:[{name:'Contains',key:'contains',selected:true,notAllowed:['restrictedSuggestedValues']},{name:'Does not contain',key:'doesNotContain',notAllowed:['restrictedSuggestedValues']},{name:'Is Equal To',key:'isEqualTo'},{name:'Is Not Equal To',key:'isNotEqualTo'},{name:'Starts with',key:'startsWith'},{name:'Ends with',key:'endsWith'},{name:'Similiarity',key:'similiarity'}],OPERATORS:[{name:'AND',selected:true},{name:'OR'}]})
;
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbAutoSize
* @description
* # Implementation of paasbAutoSize
*/
angular.module('paasb')
.directive('paasbAutoSize', [
'$parse',
'$window',
'$timeout',
'paasbUtils',
function ($parse, $window, $timeout, paasbUtils) {
return {
'restrict': 'A',
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var filter = null,
Filtering = null,
type = $attrs.paasbAutoSizeType;
$attrs.$observe('paasbAutoSize', function () {
filter = $parse($attrs.paasbAutoSize)($scope) || {};
Filtering = filter.$$filtering || {};
angular
.element($element)
.ready(function () {
if(type) {
return Filtering.addAutoSizeElementToFilter(filter, $element, type);
}
});
});
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbDraggable
* @description
* # Implementation of paasbDraggable
*/
angular.module('paasb')
.directive('paasbDraggable', [
'paasbUtils',
function (paasbUtils) {
return {
'restrict': 'A',
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
$element.on('dragstart dragend', function (ev) {
switch(ev.type) {
case 'dragstart':
var elem = angular.element(this),
id = paasbUtils.uuid(),
data = {
'id': id,
'draggable': true,
'trash': true
};
if(!elem.attr('id')) {
elem.attr('id', id);
}
ev.dataTransfer.setData('text', JSON.stringify(data));
break;
case 'dragend':
if($scope.Search && $scope.Search.Filtering) {
var Filtering = $scope.Search.Filtering;
Filtering
.removeClassAllFilters('over-placement-1')
.removeClassAllFilters('over-placement-2')
.removeClassAllFilters('over-placement-3')
.removeClassAllFilters('dragged-item');
}
break;
}
});
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxAddedFilter
* @description
* # Implementation of paasbSearchBoxAddedFilter
*/
angular.module('paasb')
.directive('paasbSearchBoxAddedFilter', [
'$timeout',
'$document',
'paasbUi',
'paasbUtils',
function ($timeout, $document, paasbUi, paasbUtils) {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-added-filter.html',
'require': '^paasbSearchBoxFiltering',
'scope': {
'filter': '=',
'filtering': '=',
'toValue': '=',
'operators': '='
},
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var Filtering = $scope.filtering,
Grouping = Filtering.getGrouping(),
EventHandling = Filtering.getEventHandler(),
filter = $scope.filter,
operators = $scope.operators,
config = null,
input,
dragSourceElem = null,
dragSourceCount = 0;
angular.extend(filter, {
'loading': false,
'$$filtering': Filtering
});
$element.attr('id', paasbUtils.uuid());
if(typeof filter.suggestedValues === 'string') {
config = Filtering.getConfig();
var deepValue = paasbUtils.getDeepValue(config, filter.suggestedValues);
if(deepValue) {
filter.suggestedValues = deepValue;
}
}
if($scope.toValue) {
$scope.value = $scope.toValue;
$scope.dontOpen = true;
}
if(paasbUtils.isURL(filter.suggestedValues) ||
(paasbUtils.isURL(filter.source) && filter.reloadOnCreate)) {
paasbUi.safeApply($scope, function () {
var url = filter.source || filter.suggestedValues;
angular.extend(filter, {
'loading': true,
'suggestedValues': [],
'source': url
});
});
Filtering
.loadSource(filter)
.then(function (data) {
paasbUi.safeApply($scope, function () {
angular.extend(filter, {
'suggestedValues': data,
'loading': false,
'value': ''
});
});
});
} else {
filter.value = '';
}
var scope = Filtering.getFilterScope(filter);
angular.extend(scope, {
enableGrouping: function () {
$document.on('mouseover mouseout', $scope.events.groupingEvents);
},
disableGrouping: function () {
$document.off('mouseover mouseout', $scope.events.groupingEvents);
}
});
paasbUi.extend($scope, {
'inputId': paasbUtils.uuid(),
'Utils': paasbUtils,
getDirection: function (placement) {
var dir = null;
if(typeof placement === 'undefined' || placement === null) {
return dir;
}
if(typeof placement === 'string') {
placement = parseInt(placement);
}
switch(placement) {
case 1:
dir = 'before';
break;
case 3:
dir = 'after';
break;
}
return dir;
},
'events': {
groupingEvents: function (ev) {
var isChild = $element[0].contains(ev.target),
isSelf = $element[0] == ev.target,
isInside = isChild || isSelf;
switch(ev.type) {
case 'mouseover':
if(isInside) {
Grouping.addFake($element);
}
break;
case 'mouseout':
if(!isInside) {
Grouping.removeLastFake();
}
break;
}
},
searchboxClick: function (ev) {
var isChild = $element[0].contains(ev.target),
isSelf = $element[0] == ev.target,
isInside = isChild || isSelf;
if(!isInside) {
$scope.closeFilter();
}
},
inputKeyEvents: function (ev) {
if(ev.keyCode === 13) {
$scope.closeFilter();
}
},
dragEvents: function (ev) {
switch(ev.type) {
case 'dragstart':
dragSourceElem = angular.element(this);
ev.dataTransfer.effectAllowed = 'copyMove';
if(!dragSourceElem.attr('id')) {
dragSourceElem.attr('id', paasbUtils.uuid());
}
ev.dataTransfer.setData('text', dragSourceElem.attr('id'));
dragSourceElem.addClass('dragged-item');
break;
case 'dragenter':
ev.preventDefault();
dragSourceCount ++;
break;
case 'dragleave':
dragSourceCount --;
if(dragSourceCount === 0) {
angular.element(this).removeClass('over');
}
break;
case 'dragover':
var bounding = this.getBoundingClientRect(),
w = (bounding.width / 3);
var placement = Math.abs(Math.ceil((ev.pageX - bounding.left) / w)) || 1;
Filtering
.removeClassAllFilters('over-placement-1')
.removeClassAllFilters('over-placement-2')
.removeClassAllFilters('over-placement-3');
angular
.element(this)
.addClass('over-placement-' + placement)
.attr('data-placement', placement);
if(ev.preventDefault) {
ev.preventDefault();
}
ev.dataTransfer.dropEffect = 'copyMove';
return false;
break;
case 'drop':
if(ev.stopPropagation) {
ev.stopPropagation();
}
var data = ev.dataTransfer.getData('text'),
isJSON = false;
if(paasbUtils.isJson(data)) {
data = JSON.parse(data);
isJSON = true;
}
if(data) {
var id = data;
if(isJSON) {
id = data.id;
}
var elem = document.getElementById(id);
if(isJSON && data.draggable) {
if(data.trash) {
Filtering.removeByElement(this);
}
} else {
if(elem !== this) {
var placement = parseInt(angular
.element(this)
.attr('data-placement') || null),
direction = $scope.getDirection(placement);
Filtering[placement === 2 ? 'swapFilter' : 'moveFilter'](elem, this, direction);
}
}
}
return false;
break;
case 'dragend':
Filtering
.removeClassAllFilters('over-placement-1')
.removeClassAllFilters('over-placement-2')
.removeClassAllFilters('over-placement-3')
.removeClassAllFilters('dragged-item');
break;
}
}
},
takeSuggestion: function (val) {
$scope.value = val;
},
closeFilter: function () {
var self = this;
paasbUi.safeApply($scope, function () {
filter.editing = false;
$scope.$broadcast('filter.isEditing', filter.editing);
$document.unbind('click', self.events.searchboxClick);
if(!filter.value) {
Filtering.remove(filter, true);
} else {
if(filter.suggestedValue) {
console.log(filter.suggestedValue, $scope.value, filter.$$lastValue);
$scope.value = filter.suggestedValue.value;
} else {
if(filter.restrictedSuggestedValues) {
Filtering.remove(filter, true);
}
}
}
EventHandling
.onLeavedEditMode(filter);
});
},
openFilter: function () {
if(!$scope.dontOpen) {
var self = this;
if(!filter.editing) {
filter.editing = true;
$scope.$broadcast('filter.isEditing', filter.editing);
$timeout(function () {
$document.bind('click', self.events.searchboxClick);
}, 25);
$scope.setFocus();
EventHandling
.onEnteredEditMode(filter);
}
}
$scope.dontOpen = false;
},
destroy: function () {
return Filtering.remove($scope.filter, null, false);
},
getElements: function () {
input = $element.find('input');
filter.$$input = input;
return $scope;
},
registerEvents: function (events) {
input.on('keyup', events.inputKeyEvents);
$element.on('dragstart dragenter dragover dragleave drop dragend', events.dragEvents);
return $scope;
},
setFocus: function () {
$timeout(function () {
if(input) {
input[0].focus();
}
}, 50);
return $scope;
},
addWatch: function () {
$scope.$watch('value', function (__new, __old) {
Filtering.autoSizeByFilter(filter);
filter.value = __new || '';
if(filter.value) {
if(__new !== __old) {
if(filter && filter.suggestedValues) {
if(filter.suggestedValue && filter.suggestedValue.value === filter.$$lastValue) {
return;
}
var matchesSuggestedValue = false;
angular.forEach(filter.suggestedValues, function (suggestedValue) {
if(suggestedValue === __new) {
matchesSuggestedValue = true;
}
});
if(matchesSuggestedValue) {
filter.$$lastValue = filter.value;
Filtering.update();
EventHandling
.onFilterChanged(filter);
}
} else {
Filtering.update();
EventHandling
.onFilterChanged(filter);
}
}
}
});
return $scope;
}
});
$scope
.getElements()
.registerEvents($scope.events)
.addWatch()
.openFilter();
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxAutoComplete
* @description
* # Implementation of paasbSearchBoxAutoComplete
*/
angular.module('paasb')
.directive('paasbSearchBoxAutoComplete', [
'$window',
'$document',
'$timeout',
'$interpolate',
'paasbUi',
'paasbUtils',
'paasbAutoComplete',
'paasbMemory',
function ($window, $document, $timeout, $interpolate, paasbUi, paasbUtils, paasbAutoComplete, paasbMemory) {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-auto-complete.html',
'require': '^paasbSearchBox',
'scope': {
'query': '=',
'config': '=',
'input': '='
},
controller: ['$scope', '$element', function ($scope, $element) {
var config = $scope.config,
initialQuery = paasbMemory.getAndSet('query');
$scope.$watch('query', function (__new) {
if($scope.tookSuggestion !== __new) {
$scope.tookSuggestion = null;
if(__new && (initialQuery !== __new)) {
paasbAutoComplete
.load($interpolate(config.autoCompleteUrl)({
'query': __new
}))
.then(function (data) {
paasbUi.extend($scope, {
'autoSuggestions': data,
'showSuggestions': (data && data.length) ? true : false
});
$scope.position();
});
}
}
});
angular.extend($scope, {
'Utils': paasbUtils,
'tookSuggestion': null,
'showSuggestions': false,
autoCompleteClick: function (ev) {
var tgt = ev.target,
elem = $element[0];
if(!elem.contains(tgt)) {
paasbUi.extend($scope, {
'showSuggestions': false
});
}
$document.unbind('click', $scope.autoCompleteClick);
},
position: function () {
$timeout(function () {
var input = $scope.input[0],
inputPadding = paasbUtils.getStyle(input, 'padding-left'),
inputWidth = paasbUtils.getStyle(input, 'width') -
paasbUtils.getStyle(input, 'padding-right') -
inputPadding;
$element
.css('left', inputPadding + 'px')
.css('width', inputWidth + 'px');
});
},
takeAutoComplete: function (suggestion) {
paasbUi.extend($scope, {
'showSuggestions': false,
'tookSuggestion': suggestion
});
$scope.$emit('take.autoSuggestion', suggestion);
$document.unbind('click', $scope.autoCompleteClick);
},
registerEvents: function () {
angular
.element($window)
.on('resize', function () {
$scope.position();
});
$scope.$on('input.focused', function () {
if($scope.autoSuggestions && $scope.autoSuggestions.length) {
paasbUi.extend($scope, {
'showSuggestions': true
});
}
});
$scope.$watch('showSuggestions', function (__new) {
if(__new) {
$document.bind('mousedown', $scope.autoCompleteClick);
}
});
return $scope;
}
});
$scope
.registerEvents();
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxAutoSuggestions
* @description
* # Implementation of paasbSearchBoxAutoSuggestions
*/
angular.module('paasb')
.directive('paasbSearchBoxAutoSuggestions', [
function () {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-auto-suggestions.html',
'require': '^paasbSearchBoxAddedFilter',
'scope': {
'filtering': '=',
'filter': '='
},
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var Filtering = $scope.filtering,
filter = $scope.filter;
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxCacheFilter
* @description
* # Implementation of paasbSearchBoxCacheFilter
*/
angular.module('paasb')
.directive('paasbSearchBoxCacheFilter', [
'paasbMemory',
'paasbUi',
function (paasbMemory, paasbUi) {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-cache-filters.html',
'require': '^paasbSearchBox',
controller: ['$scope', function ($scope) {
paasbUi.extend($scope, {
'cacheActive': paasbMemory.getAndSet('cache') || false,
handleCache: function () {
if(!$scope.paasbSearchBoxCacheFilterPermanent) {
$scope.cacheActive = !$scope.cacheActive;
paasbMemory.getAndSet('cache', $scope.cacheActive);
}
}
});
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxFilterMovedAnimation
* @description
* # Implementation of paasbSearchBoxFilterMovedAnimation
*/
angular.module('paasb')
.directive('paasbSearchBoxFilterMovedAnimation', [
'paasbUtils',
'paasbUi',
function (paasbUtils, paasbUi) {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-filter-moved-animation.html',
'require': '^paasbSearchBoxAddedFilter',
'scope': {
'filter': '='
},
controller: ['$scope', '$element', function ($scope, $element) {
var filter = $scope.filter,
contents = $element.parent(),
elem = null,
boundingBox = null,
height = 0,
width = 0,
radius = 0;
if(filter) {
elem = filter.element;
boundingBox = contents[0].getBoundingClientRect();
radius = paasbUtils.getStyle(contents[0], 'border-radius') || 0;
height = (boundingBox.bottom - boundingBox.top);
width = (boundingBox.width);
var hWidth = (width / 2) + 6;
var hHeight = (height / 2) + 6;
$element
.css('border-left-width', hWidth + 'px')
.css('border-right-width', hWidth + 'px')
.css('border-top-width', hHeight + 'px')
.css('border-bottom-width', hHeight + 'px')
.css('border-radius', radius + 'px');
paasbUi.apply(function () {
$element
.addClass('transition')
.css('border-left-width', '0px')
.css('border-right-width', '0px')
.css('border-top-width', '0px')
.css('border-bottom-width', '0px')
.css('border-radius', radius + 'px')
.css('width', width + 'px')
.css('height', height + 'px');
}, 50);
}
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxFilterMoved
* @description
* # Implementation of paasbSearchBoxFilterMoved
*/
angular.module('paasb')
.directive('paasbSearchBoxFilterMoved', [
'$parse',
'$compile',
function ($parse, $compile) {
return {
'restrict': 'A',
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var filter = null;
$scope.hasRecentlyMoved = function () {
if(filter && filter.recentlyMoved) {
var scope = $scope.$new(true),
compiledTemplate = null;
angular.extend(scope, {
'filter': filter
});
compiledTemplate = $compile('<paasb-search-box-filter-moved-animation filter="filter" />')(scope);
$element.prepend(compiledTemplate);
}
delete filter.recentlyMoved;
};
$attrs.$observe('paasbSearchBoxFilterMoved', function () {
filter = $parse($attrs.paasbSearchBoxFilterMoved)($scope);
angular
.element($element)
.ready(function () {
$scope.hasRecentlyMoved();
});
});
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxFilterOperators
* @description
* # Implementation of paasbSearchBoxFilterOperators
*/
angular.module('paasb')
.directive('paasbSearchBoxFilterOperators', [
'$document',
'paasbUi',
'FILTERS',
function ($document, paasbUi, FILTERS) {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-filter-operators.html',
'require': '^paasbSearchBoxAddedFilter',
'scope': {
'filtering': '=',
'filter': '='
},
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var Filtering = $scope.filtering,
EventHandling = Filtering.getEventHandler(),
operators = angular.copy(FILTERS.OPERATORS),
filter = $scope.filter;
if(Filtering.getFilterCount() > 1) {
$scope.hasOperator = true;
$scope.autoSizeElement = $element;
angular.extend($scope, {
'availableOperators': operators,
'showOperators': false,
'events': {
docClick: function (ev) {
var isChild = $element[0].contains(ev.target);
var isSelf = $element[0] == ev.target;
var isInside = isChild || isSelf;
if(!isInside) {
$document.unbind('click', $scope.events.docClick);
paasbUi.extend($scope, {
'showOperators': false
});
}
}
},
openOperators: function () {
$scope.showOperators = !$scope.showOperators;
$document[$scope.showOperators ? 'bind': 'unbind']('click', $scope.events.docClick);
Filtering.autoSizeByFilter(filter);
},
takeOperator: function (operator) {
angular.forEach(operators, function (availableOperator) {
availableOperator.selected = false;
});
$scope.operator = operator;
Filtering.addOperatorToFilter(operator, filter);
EventHandling
.onOperatorChanged(operator, filter);
operator.selected = true;
},
takeOperatorByName: function (operatorName) {
angular.forEach(operators, function (availableOperator) {
if(availableOperator.name !== operatorName) {
availableOperator.selected = false;
} else {
availableOperator.selected = true;
$scope.operator = availableOperator;
}
});
},
setDefaultOperator: function () {
var operatorByFilter = Filtering.getOperatorByFilterIndex(filter);
if(operatorByFilter === null) {
if(!filter.operator) {
angular.forEach(operators, function (availableOperator) {
if(availableOperator.selected) {
$scope.operator = availableOperator;
}
});
if(!filter.selector && operators &&
operators.length) {
var operator = operators[0];
operator.selected = true;
$scope.operator = operator;
}
} else {
angular.forEach(operators, function (availableOperator) {
availableOperator.selected = (availableOperator.key === filter.selector.key);
});
}
} else {
this.takeOperatorByName(operatorByFilter);
}
return $scope;
},
registerOperator: function () {
Filtering.registerOperator($scope);
return $scope;
},
addOperatorToFilter: function () {
if(!Filtering.hasOperatorAlready(filter)) {
Filtering.addOperatorToFilter($scope.operator, filter, true);
}
return $scope;
}
});
$scope
.setDefaultOperator()
.registerOperator()
.addOperatorToFilter();
}
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxFilterSelectors
* @description
* # Implementation of paasbSearchBoxFilterSelectors
*/
angular.module('paasb')
.directive('paasbSearchBoxFilterSelectors', [
'FILTERS',
function (FILTERS) {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-filter-selectors.html',
'require': '^paasbSearchBoxAddedFilter',
'scope': {
'filtering': '=',
'filter': '='
},
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var Filtering = $scope.filtering,
EventHandling = Filtering.getEventHandler(),
copy = angular.copy(FILTERS.SELECTORS),
filter = $scope.filter;
$scope.autoSizeElement = $element;
angular.extend($scope, {
'availableSelectors': null,
takeSelector: function (selector) {
angular.forEach($scope.availableSelectors,
function (availableSelector) {
availableSelector.selected = false;
});
filter.selector = selector;
selector.selected = true;
if(filter.value) {
Filtering.update();
EventHandling
.onFilterSelectorChanged(selector, filter);
}
Filtering.autoSizeByFilter(filter);
var input = filter.element.find('input')[0];
input.focus();
},
setDefaultSelector: function () {
if(!filter.selector) {
angular.forEach($scope.availableSelectors, function (availableSelector) {
if(availableSelector.selected) {
filter.selector = availableSelector;
}
});
if(!filter.selector && $scope.availableSelectors &&
$scope.availableSelectors.length) {
var selector = $scope.availableSelectors[0];
selector.selected = true;
filter.selector = selector;
}
} else {
angular.forEach($scope.availableSelectors, function (availableSelector) {
availableSelector.selected = (availableSelector.key === filter.selector.key);
});
}
return $scope;
},
setAvailableSelectors: function () {
var availableSelectors = [];
angular.forEach(copy, function (selector) {
var allowed = true;
angular.forEach(selector.notAllowed, function (notAllowed) {
if(filter[notAllowed]) {
allowed = false;
}
});
if(allowed) {
availableSelectors.push(selector);
}
});
$scope.availableSelectors = availableSelectors;
return $scope;
}
});
$scope.$on('filter.isEditing', function (ev, editing) {
if(editing) {
Filtering.autoSizeByFilter(filter);
}
});
$scope
.setAvailableSelectors()
.setDefaultSelector();
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxFiltering
* @description
* # Implementation of paasbSearchBoxFiltering
*/
angular.module('paasb')
.directive('paasbSearchBoxFiltering', [
'$document',
'$timeout',
'$window',
'paasbUtils',
'paasbUi',
function ($document, $timeout, $window, paasbUtils, paasbUi) {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-filtering.html',
'require': '^paasbSearchBox',
'scope': {
'filters': '=',
'search': '='
},
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var Search = null;
$scope.$watch('active', function (__new, __old) {
if(__new && !$scope.windowClickedFn) {
$timeout(function () {
$scope.windowClickedFn = $document.on('click', $scope.windowClicked);
}, 25);
} else {
if($scope.windowClickedFn) {
$document.off('click', $scope.windowClicked);
$scope.windowClickedFn = null;
}
}
});
angular.extend($scope, {
'active': false,
'Utils': paasbUtils,
windowClicked: function (ev) {
var target = ev.target,
elem = $element[0];
if(!elem.contains(target)) {
paasbUi.extend($scope, {
'active': false
});
}
},
position: function () {
if($scope.active) {
$timeout(function () {
var el = $element.parent(),
list = $element.find('ul'),
listBoundingBox = list[0].getBoundingClientRect(),
elBoundingBox = el[0].getBoundingClientRect();
list
.css('top', (elBoundingBox.height - 5) + 'px')
.css('width', (elBoundingBox.width + paasbUtils.getStyle(el[0], 'padding-right') +
paasbUtils.getStyle(el[0], 'padding-left') -
paasbUtils.getScrollbarWidth() / 2) + 'px');
}, 25);
}
},
toggleFilters: function () {
paasbUi.extend($scope, {
'active': !$scope.active
});
this.position();
},
addFilterAndClose: function (filter) {
Search.Filtering.add(filter);
paasbUi.extend($scope, {
'active': !$scope.active
});
},
registerEvents: function () {
angular
.element($window)
.on('resize', function () {
$scope.position();
});
},
addFilter: function (ev) {
var self = this,
target = paasbUtils.getParentByAttribute(ev.target, 'li', 'data-filter-name'),
filterName = target.attr('data-filter-name');
angular.forEach($scope.filters, function (filter) {
if(filter.name === filterName) {
if(filter.restrictedSuggestedValues) {
self.addFilterAndClose(filter);
} else {
if(!filter.multi) {
filter.notFiltered = !filter.notFiltered;
if(!filter.notFiltered) {
self.addFilterAndClose(filter);
}
} else {
self.addFilterAndClose(filter);
}
}
}
});
}
});
$scope.$watch('search', function (__new, __old) {
if((__new !== __old) && angular.isObject(__new)) {
Search = __new;
$scope.filters = angular.copy($scope.filters);
$scope.filters
.slice()
.reverse()
.forEach(function (filter, filterIndex, filterObject) {
filter.notFiltered = true;
if(filter.root) {
filter.filteredFrom = '<i class="fa fa-level-up"></i> (Derived from ' +
'Root <i class="fa fa-angle-double-right"></i> ' + filter.root + ')';
}
if(filter.child) {
filter.filteredFrom = '<i class="fa fa-level-down"></i> (Derived from ' + filter.child + ')';
}
if(filter.dontFilter) {
$scope.filters.splice(filterObject.length - 1 - filterIndex, 1);
}
});
$scope
.registerEvents();
}
});
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBoxGrouping
* @description
* # Implementation of paasbSearchBoxGrouping
*/
angular.module('paasb')
.directive('paasbSearchBoxGrouping', [
function () {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox-grouping.html',
'require': '^paasbSearchBox',
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var Grouper = null;
if($scope.Search && $scope.Search.Grouper) {
Grouper = $scope.Search.Grouper;
angular.extend($scope, {
toggleGrouping: function () {
return Grouper.toggle();
}
});
}
}]
};
}]);
'use strict';
/**
* @ngdoc directive
* @name paasb.directive:paasbSearchBox
* @description
* # Implementation of paasbSearchBox
*/
angular.module('paasb')
.directive('paasbSearchBox', [
'$timeout',
'$window',
'paasbApi',
'paasbUi',
'paasbFiltering',
'paasbGrouping',
'paasbPlaceholders',
'paasbEventHandling',
'paasbMemory',
'paasbUtils',
'FILTERS',
function ($timeout, $window, paasbApi, paasbUi, paasbFiltering, paasbGrouping, paasbPlaceholders, paasbEventHandling, paasbMemory, paasbUtils, FILTERS) {
return {
'restrict': 'E',
'replace': true,
'templateUrl': 'views/directives/searchbox.html',
'scope': {
'searchParams': '=?',
'paasbSearchBoxFiltering': '=?',
'paasbSearchBoxConfig': '=?',
'paasbSearchBoxAutoComplete': '=?',
'paasbSearchBoxCacheFilter': '=?',
'paasbSearchBoxEnableFilteringOperators': '=?',
'paasbSearchBoxFilterSelectors': '=?',
'paasbSearchBoxFilterOperators': '=?',
'paasbSearchBoxEnableGrouping': '=?',
'placeholder': '@'
},
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
var params = null,
config = null,
autoComplete = null,
Filterer = null,
Grouper = null,
Placeholding = null,
API = null,
EventHandling = null,
timer = null,
searchBox = {
'searchInputId': ('searchInput-' + paasbUtils.uuid()),
hasAutoCompleteConfigurations: function () {
return config && config.autoCompleteUrl;
},
make: function (name, extend, method, related) {
var val = $scope[name];
if(angular[method]) {
if(!angular[method](val)) {
if(method === 'isObject') {
$scope[name] = angular.extend({}, extend);
} else {
$scope[name] = extend;
}
} else {
if(extend && _.isEmpty(val)) {
$scope[name] = extend;
$scope[related] = extend[related];
}
}
} else {
if(this[method]) {
val = this[method](val);
}
}
return this;
},
'events': {
handleEraser: function () {
$scope.query = '';
EventHandling
.onEraser();
},
handleSearch: function () {
EventHandling
.onChange(params);
},
handleGarbage: function () {
if((params.query && params.query.length) || $scope.hasFilters) {
Filterer.removeAll(true, true, {
'deleteOperators': true
});
$scope.query = '';
EventHandling
.onGarbage();
}
}
},
shouldStore: function () {
return (paasbMemory.getAndSet('cache') ||
config.store) ? true : false;
},
configure: function () {
var defaultParams = {
'query': '',
'filters': {}
},
configuredParams = {};
if($scope.paasbSearchBoxEnableFilteringOperators) {
angular.extend(defaultParams, {
'operators': []
});
}
if(FILTERS && FILTERS.SELECTORS && $scope.paasbSearchBoxFilterSelectors) {
FILTERS.SELECTORS = $scope.paasbSearchBoxFilterSelectors;
}
if(FILTERS && FILTERS.OPERATORS && $scope.paasbSearchBoxFilterOperators) {
FILTERS.OPERATORS = $scope.paasbSearchBoxFilterOperators;
}
this
.make('paasbSearchBoxFiltering', [], 'isArray')
.make('paasbSearchBoxConfig', {}, 'isObject')
.make('paasbSearchBoxAutoComplete', {}, 'isObject');
config = $scope.paasbSearchBoxConfig;
if(this.shouldStore()) {
configuredParams = paasbMemory.getAll();
if(_.isEmpty(configuredParams)) {
configuredParams = defaultParams;
}
} else {
configuredParams = defaultParams;
}
this
.make('searchParams', configuredParams, 'isObject', 'query');
params = $scope.searchParams;
autoComplete = $scope.paasbSearchBoxAutoComplete;
$scope.autoCompleteEnabled = this.hasAutoCompleteConfigurations();
if($scope.query) {
paasbUi.extend($scope, {