From 3df2146ba28ab5f096c64c42247db3ea85141fa5 Mon Sep 17 00:00:00 2001 From: tanshu Date: Wed, 16 Mar 2016 14:41:58 +0530 Subject: [PATCH] Fix: Date filtering works properly in Tokenizer (requires moment.js) Feature: Selecting Start/Finish Date in Recipe list updates the search string. --- brewman/static/partial/product-list.html | 8 +-- brewman/static/partial/recipe-detail.html | 6 +- brewman/static/partial/recipe-list.html | 79 +++++++++++++---------- brewman/static/scripts/angular_service.js | 30 ++------- brewman/static/scripts/overlord.js | 2 +- brewman/static/scripts/recipe.js | 78 +++++++++++++++++++++- 6 files changed, 134 insertions(+), 69 deletions(-) diff --git a/brewman/static/partial/product-list.html b/brewman/static/partial/product-list.html index c358d22c..95bd941b 100644 --- a/brewman/static/partial/product-list.html +++ b/brewman/static/partial/product-list.html @@ -1,10 +1,10 @@

Products

-
- - + + - + Add diff --git a/brewman/static/partial/recipe-detail.html b/brewman/static/partial/recipe-detail.html index 5e63ca14..5dba6a63 100644 --- a/brewman/static/partial/recipe-detail.html +++ b/brewman/static/partial/recipe-detail.html @@ -1,7 +1,7 @@

Recipe Detail

-
+
-
+
-
+
-

Recipes -
-
- -
-
- Add -
-
-

- - - - - - - - - - - - - - - - - - - - - -
NameValid FromValid ToCost PriceSale PriceCosting
{{items.Name}}{{item.ValidFrom}}{{item.ValidTo}}{{item.CostPrice | currency}}{{item.SalePrice | currency}}{{item.Costing | percent}}
- \ No newline at end of file +

Recipes

+
+ + + + + Add + +
+
+
+ + +
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + +
NameValid FromValid ToCost PriceSale PriceCosting
{{items.Name}}{{item.ValidFrom}}{{item.ValidTo}}{{item.CostPrice | currency}}{{item.SalePrice | currency}}{{item.Costing | percent}}
diff --git a/brewman/static/scripts/angular_service.js b/brewman/static/scripts/angular_service.js index f93ae009..c7a3ecf3 100644 --- a/brewman/static/scripts/angular_service.js +++ b/brewman/static/scripts/angular_service.js @@ -270,33 +270,17 @@ overlordService.factory('Tokenizer', ['$filter', function ($filter) { } }, 'date': function (obj, text) { - var reGoodDate = /^((0?[1-9]|[12][0-9]|3[01])[- /.](0?[1-9]|1[012]|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[- /.](19|20)?[0-9]{2})*$/i, - asDateObject = function (input) { - if (angular.isDate(input)) { - return input; - } - - }, - op = opLength(text), - ob = op ? asDateObject(obj) : '', - tex = op ? asDateObject(text.substr(op).trim()) : ''; - if (op) { - return operators[text.substr(0, op)](ob, tex); - } else { - return obj.toString().indexOf(text) > -1; - } - - if (text.indexOf('!') === 0) { - return obj.toLowerCase().indexOf(text.substr(1)) <= -1; - } else { - return obj.toLowerCase().indexOf(text) > -1; - } + var obDate = moment(obj, 'DD-MMM-YYYY'), + op = operatorLength(text), + operator = op ? text.substr(0, op) : '==', + textDate = op ? moment(text.substr(op).trim(), 'DD-MMM-YYYY') : moment(text, 'DD-MMM-YYYY'); + return !obDate.isValid() || !textDate.isValid() || operators[operator](obDate.valueOf(), textDate.valueOf()); }, 'boolean': function (obj, text) { return obj === isTrue(text); }, 'numeric': function (obj, text) { - var op = opLength(text); + var op = operatorLength(text); if (op) { return operators[text.substr(0, op)](obj, Number(text.substr(op).trim())); } else { @@ -323,7 +307,7 @@ overlordService.factory('Tokenizer', ['$filter', function ($filter) { return {'Col': comparator.Col, 'Comparator': comparators[comparator.Comparator], 'Value': value}; } - function opLength(operator) { + function operatorLength(operator) { var i, ops = ['<=', '<', '>=', '>', '==', '!=']; for (i = 0; i < ops.length; i++) { diff --git a/brewman/static/scripts/overlord.js b/brewman/static/scripts/overlord.js index cce6c88f..a51afd67 100644 --- a/brewman/static/scripts/overlord.js +++ b/brewman/static/scripts/overlord.js @@ -417,7 +417,7 @@ var overlord = angular.module('overlord', ['overlord.directive', 'overlord.filte }]) .config(['$mdDateLocaleProvider', function ($mdDateLocaleProvider) { $mdDateLocaleProvider.formatDate = function (date) { - return moment(date).format('DD-MMM-YYYY'); + return !angular.isUndefined(date) ? moment(date).format('DD-MMM-YYYY') : ""; }; $mdDateLocaleProvider.parseDate = function (date) { return moment(date, 'DD-MMM-YYYY').toDate(); diff --git a/brewman/static/scripts/recipe.js b/brewman/static/scripts/recipe.js index 613cab06..4bce7a61 100644 --- a/brewman/static/scripts/recipe.js +++ b/brewman/static/scripts/recipe.js @@ -1,8 +1,80 @@ 'use strict'; -var RecipeListController = ['$scope', 'recipes', function ($scope, recipes) { - $scope.info = recipes; -}]; +var RecipeListController = ['$scope', 'recipes', '$location', '$routeParams', 'Tokenizer', function ($scope, recipes, $location, $routeParams, Tokenizer) { + $scope.info = recipes; + $scope.search = $routeParams.q || ''; + + $scope.startDate = function (startDate) { + if (arguments.length === 0) { + return $scope._startDate; + } + $scope._startDate = startDate; + var re = /(('[s]'|"[s]"|[s]+)\s*:\s*('[^']+'|"[^"]+"|[^\s]+))/gi, + matches = $scope.search.match(re), + st = startDate === null ? '' : 's:>=' + moment(startDate).format('DD-MMM-YYYY'); + $scope.search = (matches === null) ? $scope.search.trim() + ' ' + st : $scope.search.replace(re, st); + }; + + $scope.finishDate = function (finishDate) { + if (arguments.length === 0) { + return $scope._finishDate; + } + $scope._finishDate = finishDate; + var re = /(('[f]'|"[f]"|[f]+)\s*:\s*('[^']+'|"[^"]+"|[^\s]+))/gi, + matches = $scope.search.match(re), + st = finishDate === null ? '' : 'f:<=' + moment(finishDate).format('DD-MMM-YYYY'); + $scope.search = (matches === null) ? $scope.search.trim() + ' ' + st : $scope.search.replace(re, st); + }; + + $scope.$watch('search', function (value) { + $scope.filterRecipes(value); + }, true); + + $scope.$on('$destroy', function () { + Tokenizer.doFilter.cache = {}; + }); + + $scope.searchInfo = { + comparator: { + 'n': {'Col': 'Name', 'Comparator': 'text'}, + 's': {'Col': 'ValidFrom', 'Comparator': 'date'}, + 'f': {'Col': 'ValidTo', 'Comparator': 'date'} + }, + def: 'n', + sorter: { + 'n': 'Name', + 's': 'ValidFrom', + 'f': 'ValidTo', + 'c': 'Costing', + 'cp': 'CostPrice', + 'sp': 'SalePrice' + }, + flags: {} + }; + + $scope.filterRecipes = _.debounce(function (q) { + if (q !== $scope._search) { + $scope._search = q; + if (angular.isUndefined(q) || q === '') { + $location.path('/Recipes').search('q', null).replace(); + } else { + $location.path('/Recipes').search({'q': q}).replace(); + } + $scope.$apply(function () { + var matches = Tokenizer.parseFilterString(q, $scope.searchInfo); + $scope.recipes = _.map($scope.info, function (prod) { + var item = angular.copy(prod); + item.Prices = Tokenizer.doFilter(prod.ProductID + ' ' + q, prod.Prices, matches); + return item; + }); + + + }); + } + }, 350); + + }] + ; RecipeListController.resolve = { recipes: ['Recipe', function (Recipe) {