github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/witch/webroot/filters.html (about) 1 <script type="text/x-template" id="filters-template"> 2 <div> 3 <h4>Filters<i class="el-icon-refresh" style="cursor: pointer" @click="clearFilters()"></i></h4> 4 <el-select v-model="editingFilter.propKey" 5 allow-create 6 filterable 7 placeholder="Property..."> 8 <el-option 9 v-for="propKey in propKeys" 10 :key="propKey" 11 :label="propKey" 12 :value="propKey"> 13 </el-option> 14 </el-select> 15 <el-select v-model="editingFilter.operator" filterable placeholder="Operator..." style="margin-top: 8px;"> 16 <el-option 17 v-for="operator in operators" 18 :key="operator[1]" 19 :label="operator[0]" 20 :value="operator[1]"> 21 </el-option> 22 </el-select> 23 <el-select 24 v-model="editingFilter.operand" 25 filterable 26 allow-create 27 placeholder="Value..." style="margin-top: 8px;"> 28 <el-option 29 v-for="propValue in editingPropValues" 30 :key="propValue" 31 :label="propValue" 32 :value="propValue"> 33 </el-option> 34 </el-select> 35 <el-button style="margin-top: 8px;" @click="addFilter()">Add Filter</el-button> 36 <div v-for="(filter, index) in editableFilters" :key="filter.key" 37 style="margin-top: 8px; word-wrap: break-word; line-height: 2em;"> 38 <i class="el-icon-circle-close-outline" style="cursor: pointer" @click="removeFilter(index)"></i> 39 {{ filter.propKey }} {{ filter.operator}} {{ formatOperand(filter.operand) }} 40 </div> 41 </div> 42 </script> 43 <script> 44 Vue.component('filters', { 45 template: '#filters-template', 46 props: ['propValues', 'filters'], 47 data: function () { 48 var editableFilters = []; 49 var persistedModel = localStorage.getItem('filters::persistedModel'); 50 if (persistedModel) { 51 var model = JSON.parse(persistedModel); 52 editableFilters = model.editableFilters || []; 53 } 54 return { 55 editingFilter: { 56 propKey: '', 57 operator: 'equals', 58 operand: '' 59 }, 60 operators: [ 61 ['Equals', 'equals'], 62 ['Contains', 'contains'], 63 ['Not Equals', 'not-equals'], 64 ['Not Contains', 'not-contains'] 65 ], 66 editableFilters: editableFilters 67 } 68 }, 69 watch: { 70 editableFilters: function (val) { 71 this.onEditableFiltersUpdated(); 72 } 73 }, 74 mounted: function() { 75 this.onEditableFiltersUpdated(); 76 }, 77 computed: { 78 propKeys: function() { 79 var propKeys = []; 80 for (var propKey in this.propValues) { 81 propKeys.push(propKey); 82 } 83 return propKeys; 84 }, 85 editingPropValues: function() { 86 if (!this.editingFilter.propKey) { 87 return []; 88 } 89 return this.propValues[this.editingFilter.propKey]; 90 } 91 }, 92 methods: { 93 clearFilters: function() { 94 this.editingFilter = { 95 propKey: '', 96 operator: 'equals', 97 operand: '' 98 }; 99 this.editableFilters = []; 100 this.$notify.info({ 101 title: 'info', 102 message: 'filters cleared' 103 }); 104 }, 105 onEditableFiltersUpdated: function() { 106 var whitelist = {}; 107 var blacklist = {}; 108 for (var i in this.editableFilters) { 109 var editableFilter = this.editableFilters[i]; 110 if (editableFilter.operator.indexOf('not-') === 0) { 111 blacklist[editableFilter.propKey] = createFilterFunc( 112 editableFilter, blacklist[editableFilter.propKey]); 113 } else { 114 whitelist[editableFilter.propKey] = createFilterFunc( 115 editableFilter, whitelist[editableFilter.propKey]); 116 } 117 } 118 var filters = { 119 cacheKey: '__filtered_by_' + new Date().getTime(), 120 filterFunc: mergeWhitelistAndBlacklist(whitelist, blacklist) 121 }; 122 this.$emit('update:filters', filters); 123 localStorage.setItem('filters::persistedModel', JSON.stringify({ 124 'editableFilters': this.editableFilters 125 })); 126 }, 127 addFilter: function(propKey, operator, operand) { 128 propKey = propKey || this.editingFilter.propKey; 129 operator = operator || this.editingFilter.operator; 130 operand = operand || this.editingFilter.operand; 131 if (!(propKey)) { 132 $vue.$notify.error({ 133 title: 'Add filter missing parameter', 134 message: 'Property not specified' 135 }); 136 return; 137 } 138 if (!(operand)) { 139 $vue.$notify.error({ 140 title: 'Add filter missing parameter', 141 message: 'Filter operand not specified' 142 }); 143 return; 144 } 145 this.editableFilters.push({ 146 propKey: propKey, 147 operator: operator, 148 operand: operand, 149 key: new Date().getTime() 150 }); 151 this.editingFilter.propKey = ''; 152 this.editingFilter.operand = ''; 153 }, 154 removeFilter: function(index) { 155 this.editableFilters.splice(index, 1); 156 }, 157 formatTimestamp: function(val) { 158 var d = new Date(val / 1000000); 159 return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + '.' + d.getMilliseconds(); 160 }, 161 formatOperand: function(operand) { 162 if (Array.isArray(operand)) { 163 return this.formatTimestamp(operand[0]) + ' ~ ' + this.formatTimestamp(operand[1]); 164 } else { 165 return operand; 166 } 167 } 168 } 169 }); 170 171 function mergeWhitelistAndBlacklist(whitelist, blacklist) { 172 return function(event) { 173 // if blacklist, do not show 174 for (var propKey in blacklist) { 175 var filterFunc = blacklist[propKey]; 176 var propValue = event[propKey]; 177 if (propValue && !filterFunc(propValue)) { 178 return false; 179 } 180 } 181 // if no whitelist, show by default 182 if (Object.keys(whitelist).length === 0) { 183 return true; 184 } 185 // test if whitelist matched 186 for (var propKey in whitelist) { 187 var filterFunc = whitelist[propKey]; 188 var propValue = event[propKey]; 189 if (propValue && filterFunc(propValue)) { 190 return true; 191 } 192 } 193 // if not covered by whitelist, do not show 194 return false; 195 } 196 } 197 198 function createFilterFunc(editableFilter, previousFunc) { 199 switch (editableFilter.operator) { 200 case 'contains': 201 return function(val) { 202 if (val.indexOf(editableFilter.operand) !== -1) { 203 return true; 204 } 205 if (previousFunc) { 206 return previousFunc(val) 207 } else { 208 return false; 209 } 210 }; 211 case 'not-contains': 212 return function(val) { 213 var myResult = val.indexOf(editableFilter.operand) === -1; 214 if (previousFunc) { 215 return myResult && previousFunc(val) 216 } 217 return myResult; 218 }; 219 case 'equals': 220 return function(val) { 221 if (val === editableFilter.operand) { 222 return true; 223 } 224 if (previousFunc) { 225 return previousFunc(val) 226 } else { 227 return false; 228 } 229 }; 230 case 'not-equals': 231 return function(val) { 232 var myResult = val !== editableFilter.operand; 233 if (previousFunc) { 234 return myResult && previousFunc(val) 235 } 236 return myResult; 237 }; 238 case 'between': 239 return function(val) { 240 if (val >= editableFilter.operand[0] && val <= editableFilter.operand[1]) { 241 return true; 242 } 243 if (previousFunc) { 244 return previousFunc(val) 245 } else { 246 return false; 247 } 248 }; 249 default: 250 console.log('unknown filter operator: ' + editableFilter.operator); 251 return function(val) { return false; } 252 } 253 } 254 </script>