From e8f4931d29f59f65af93ec2f1a6a293d57b738fd Mon Sep 17 00:00:00 2001 From: Amritanshu Date: Wed, 28 May 2014 16:43:52 +0530 Subject: [PATCH] Fix/Feature: Tokenizer improved to support flags and files missed in last commit updated. --- brewman/static/scripts/account.js | 45 +++++++++++++- brewman/static/scripts/angular_service.js | 74 ++++++++++++++++++++++- brewman/static/scripts/product.js | 43 +++++++------ 3 files changed, 139 insertions(+), 23 deletions(-) diff --git a/brewman/static/scripts/account.js b/brewman/static/scripts/account.js index 65f8f98b..88f498bb 100644 --- a/brewman/static/scripts/account.js +++ b/brewman/static/scripts/account.js @@ -1,8 +1,47 @@ 'use strict'; -var AccountListCtrl = ['$scope', 'accounts', function ($scope, accounts) { - $scope.info = accounts; -}]; +var AccountListCtrl = ['$scope', '$location', '$routeParams', 'Tokenizer', 'accounts', function ($scope, $location, $routeParams, Tokenizer, accounts) { + $scope.search = $routeParams.q || ''; + $scope.info = accounts; + + $scope.$watch('search', function (value) { + $scope.filterAccounts(value); + }, true); + + $scope.searchInfo = { + comparator: { + 'def': 'n', + 'n': {'Col': 'Name', 'Comparator': 'text'}, + 't': {'Col': 'Type', 'Comparator': 'text'}, + 'a': {'Col': 'IsActive', 'Comparator': 'boolean'}, + 'r': {'Col': 'IsReconcilable', 'Comparator': 'boolean'}, + 'c': {'Col': 'CostCenter', 'Comparator': 'text'} + }, + sorter: { + 'n': 'Name', + 't': 'Type', + 'a': 'IsActive', + 'r': 'IsReconcilable', + 'c': 'CostCenter' + } + }; + $scope.filterAccounts = _.debounce(function (q) { + if (q !== $scope._search) { + $scope._search = q; + if (angular.isUndefined(q) || q === '') { + $location.path('/Accounts').search('q', null).replace(); + } else { + $location.path('/Accounts').search({'q': q}).replace(); + } + $scope.$apply(function () { + var matches = Tokenizer.parseFilterString(q, $scope.searchInfo); + $scope.accounts = Tokenizer.doFilter('/Accounts ' + q, $scope.info, matches); + + }); + } + }, 350); + }] + ; AccountListCtrl.resolve = { accounts: ['Account', function (Account) { return Account.query({}).$promise; diff --git a/brewman/static/scripts/angular_service.js b/brewman/static/scripts/angular_service.js index 6041f02a..0c615214 100644 --- a/brewman/static/scripts/angular_service.js +++ b/brewman/static/scripts/angular_service.js @@ -233,4 +233,76 @@ overlord_service.service('EventSource', function () { this.status = 'Closed' } } -}); \ No newline at end of file +}); + +overlord_service.factory('Tokenizer', ['$filter', function ($filter) { + var parseFilterString = function (q, searchInfo) { + var re = /((([^ ]+):\s*('[^':]+'|"[^":]+"|[^ ]+))|[^ ]+[^: '"]*)/g, + comparator = searchInfo.comparator, + sorter = searchInfo.sorter, + defaultKey = comparator[comparator.def], + matches = [], + sorting = [], + flags = {}; + + + function isTrue(value) { + return !_.any(['f', 'fa', 'fal', 'fals', 'false', 'n', 'no', '0'], function (item) { + return item === value; + }); + } + + function pushObject(comparator, value) { + return {'Col': comparator.Col, 'Comparator': comparators[comparator.Comparator], 'Value': value}; + } + + var comparators = { + 'text': function (obj, text) { + return obj.toLowerCase().indexOf(text) > -1; + }, + 'boolean': function (obj, text) { + return obj === isTrue(text); + }, + 'true': function (obj, text) { + return true; + } + }; + var m = q.match(re); + _.forEach(m, function (item) { + item = item.trim(); + if (item.indexOf(':') === -1) { + if ((item.length > 1) && (item.charAt(0) === '+' || item.charAt(0) === '-') && (item.substr(1) in sorter)) { + sorting.push(item.charAt(0) + sorter[item.substr(1).toLowerCase()]); + } else if (item.length >= 1 && item.charAt(0) !== '+' && item.charAt(0) !== '-') { + matches.push(pushObject(defaultKey, item)); + } + } else { + var key = item.substr(0, item.indexOf(':')).toLowerCase(); + var value = item.substr(item.indexOf(':') + 1, item.length).trim().toLowerCase(); + if (value.indexOf("'") !== -1 || value.indexOf('"') !== -1) { + value = value.substring(1, value.length - 1).trim(); + } + if (key !== '' && value !== '' && key in comparator) { + matches.push(pushObject(comparator[key], value)); + } else if (key !== '' && key in searchInfo.flags) { + flags[key] = value; + } + } + }); + return {'q': matches, 'o': sorting, 'f': flags}; + }; + var doFilter = _.memoize(function (q, array, matches) { + var filterExpressions = matches.q, + sortPredicates = matches.o, + filterCount = filterExpressions.length; + var arrayCopy = filterCount === 0 ? array : _.filter(array, function (item) { + return _.every(filterExpressions, function (expression) { + return expression.Comparator(item[expression.Col], expression.Value); + }); + }); + arrayCopy = sortPredicates.length === 0 ? arrayCopy : $filter('orderBy')(arrayCopy, sortPredicates); + return arrayCopy; + }); + + return {'parseFilterString': parseFilterString, 'doFilter': doFilter }; +}]); \ No newline at end of file diff --git a/brewman/static/scripts/product.js b/brewman/static/scripts/product.js index baf0ff97..a508c4e3 100644 --- a/brewman/static/scripts/product.js +++ b/brewman/static/scripts/product.js @@ -9,20 +9,28 @@ var ProductListCtrl = ['$scope', '$location', '$routeParams', 'Tokenizer', 'prod $scope.filterProducts(newValue); }, true); - $scope.comparator = { - 'def': 'n', - 'n': {'Col': 'Name', 'Comparator': 'text'}, - 'a': {'Col': 'IsActive', 'Comparator': 'boolean'}, - 'u': {'Col': 'Units', 'Comparator': 'text'}, - 't': {'Col': 'ProductGroup', 'Comparator': 'text'} - }; - $scope.sorter = { - 'c': 'Code', - 'n': 'Name', - 'u': 'Units', - 'p': 'Price', - 't': 'ProductGroup', - 'a': 'IsActive' + $scope.searchInfo = { + comparator: { + 'def': 'n', + 'n': {'Col': 'Name', 'Comparator': 'text'}, + 'a': {'Col': 'IsActive', 'Comparator': 'boolean'}, + 'u': {'Col': 'Units', 'Comparator': 'text'}, + 't': {'Col': 'ProductGroup', 'Comparator': 'text'} + }, + sorter: { + 'c': 'Code', + 'n': 'Name', + 'u': 'Units', + 'p': 'Price', + 't': 'ProductGroup', + 'a': 'IsActive', + 'y': 'ProductYield', + 'f':'Fraction', + 'fu': 'FractionUnits' + }, + flags: { + 'e': 'boolean' + } }; $scope.filterProducts = _.debounce(function (q) { @@ -34,11 +42,8 @@ var ProductListCtrl = ['$scope', '$location', '$routeParams', 'Tokenizer', 'prod $location.path('/Products').search({'q': q}).replace(); } $scope.$apply(function () { - var matches = Tokenizer.parseFilterString(q, $scope.comparator, $scope.sorter); - $scope.show_extended = _.any(matches.q, function (item) { - return ((item.key === 'e' || item.key === 'ext') && $scope.isTrue(item.value)); - }); - + var matches = Tokenizer.parseFilterString(q, $scope.searchInfo); + $scope.show_extended = 'e' in matches.f; $scope.products = Tokenizer.doFilter('/Products ' + q, $scope.info, matches); });