|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict" |
|
6 |
|
7 this.EXPORTED_SYMBOLS = ['ActivitiesServiceFilter']; |
|
8 |
|
9 this.ActivitiesServiceFilter = { |
|
10 match: function(aValues, aFilters) { |
|
11 |
|
12 function matchValue(aValue, aFilter, aFilterObj) { |
|
13 if (aFilter !== null) { |
|
14 // Custom functions for the different types. |
|
15 switch (typeof(aFilter)) { |
|
16 case 'boolean': |
|
17 return aValue === aFilter; |
|
18 |
|
19 case 'number': |
|
20 return Number(aValue) === aFilter; |
|
21 |
|
22 case 'string': |
|
23 return String(aValue) === aFilter; |
|
24 |
|
25 default: // not supported |
|
26 return false; |
|
27 } |
|
28 } |
|
29 |
|
30 // Pattern. |
|
31 if (('pattern' in aFilterObj)) { |
|
32 var pattern = String(aFilterObj.pattern); |
|
33 |
|
34 var patternFlags = ''; |
|
35 if (('patternFlags' in aFilterObj)) { |
|
36 patternFlags = String(aFilterObj.patternFlags); |
|
37 } |
|
38 |
|
39 var re = new RegExp('^(?:' + pattern + ')$', patternFlags); |
|
40 return re.test(aValue); |
|
41 } |
|
42 |
|
43 // Validation of the min/Max. |
|
44 if (('min' in aFilterObj) || ('max' in aFilterObj)) { |
|
45 // Min value. |
|
46 if (('min' in aFilterObj) && |
|
47 aFilterObj.min > aValue) { |
|
48 return false; |
|
49 } |
|
50 |
|
51 // Max value. |
|
52 if (('max' in aFilterObj) && |
|
53 aFilterObj.max < aValue) { |
|
54 return false; |
|
55 } |
|
56 } |
|
57 |
|
58 return true; |
|
59 } |
|
60 |
|
61 // this function returns true if the value matches with the filter object |
|
62 function matchObject(aValue, aFilterObj) { |
|
63 |
|
64 // Let's consider anything an array. |
|
65 let filters = ('value' in aFilterObj) |
|
66 ? (Array.isArray(aFilterObj.value) |
|
67 ? aFilterObj.value |
|
68 : [aFilterObj.value]) |
|
69 : [ null ]; |
|
70 let values = Array.isArray(aValue) ? aValue : [aValue]; |
|
71 |
|
72 for (var filterId = 0; filterId < filters.length; ++filterId) { |
|
73 for (var valueId = 0; valueId < values.length; ++valueId) { |
|
74 if (matchValue(values[valueId], filters[filterId], aFilterObj)) { |
|
75 return true; |
|
76 } |
|
77 } |
|
78 } |
|
79 |
|
80 return false; |
|
81 } |
|
82 |
|
83 // Creation of a filter map useful to know what has been |
|
84 // matched and what is not. |
|
85 let filtersMap = {} |
|
86 for (let filter in aFilters) { |
|
87 // Convert this filter in an object if needed |
|
88 let filterObj = aFilters[filter]; |
|
89 |
|
90 if (Array.isArray(filterObj) || typeof(filterObj) !== 'object') { |
|
91 filterObj = { |
|
92 required: false, |
|
93 value: filterObj |
|
94 } |
|
95 } |
|
96 |
|
97 filtersMap[filter] = { filter: filterObj, |
|
98 found: false }; |
|
99 } |
|
100 |
|
101 // For any incoming property. |
|
102 for (let prop in aValues) { |
|
103 // If this is unknown for the app, let's continue. |
|
104 if (!(prop in filtersMap)) { |
|
105 continue; |
|
106 } |
|
107 |
|
108 if (Array.isArray(aValues[prop]) && aValues[prop].length == 0) { |
|
109 continue; |
|
110 } |
|
111 |
|
112 // Otherwise, let's check the value against the filter. |
|
113 if (!matchObject(aValues[prop], filtersMap[prop].filter)) { |
|
114 return false; |
|
115 } |
|
116 |
|
117 filtersMap[prop].found = true; |
|
118 } |
|
119 |
|
120 // Required filters: |
|
121 for (let filter in filtersMap) { |
|
122 if (filtersMap[filter].filter.required && !filtersMap[filter].found) { |
|
123 return false; |
|
124 } |
|
125 } |
|
126 |
|
127 return true; |
|
128 } |
|
129 } |