advanced-filter-system 1.0.4 β 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +208 -108
- package/dist/AFS.esm.js +15 -6
- package/dist/AFS.esm.js.map +1 -1
- package/dist/AFS.js +15 -6
- package/dist/AFS.js.map +1 -1
- package/dist/AFS.min.js +1 -1
- package/dist/AFS.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
|
-
|
|
2
1
|
# Advanced Filter System
|
|
3
2
|
|
|
4
|
-
A
|
|
3
|
+
A powerful and flexible JavaScript library for filtering DOM elements with comprehensive search, sorting, and filtering capabilities.
|
|
5
4
|
|
|
6
5
|
## Features
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
### Core Filtering
|
|
8
|
+
|
|
9
|
+
- π Multiple filter types (category, price, status, etc.)
|
|
10
|
+
- π Flexible filter modes (AND/OR logic)
|
|
11
|
+
- π₯ Filter groups with independent logic
|
|
10
12
|
- π Multi-criteria sorting
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
+
- π Text search with debouncing
|
|
14
|
+
- π± Responsive design support
|
|
15
|
+
- β¨ Smooth animations and transitions
|
|
13
16
|
- π’ Results counter
|
|
14
|
-
-
|
|
17
|
+
- π URL state management
|
|
18
|
+
|
|
19
|
+
### Advanced Features
|
|
20
|
+
|
|
21
|
+
- π Pagination support
|
|
22
|
+
- π Range-based filtering
|
|
23
|
+
- πΎ Filter presets (save/load)
|
|
24
|
+
- π Analytics integration
|
|
25
|
+
- β¨οΈ Keyboard navigation
|
|
26
|
+
- π Custom sort comparators
|
|
27
|
+
- π― Event system
|
|
28
|
+
- π± Responsive breakpoints
|
|
29
|
+
- π Multiple search keys
|
|
30
|
+
- π¨ Customizable animations
|
|
15
31
|
|
|
16
32
|
## Installation
|
|
17
33
|
|
|
@@ -21,36 +37,39 @@ A flexible and powerful JavaScript library for filtering DOM elements with searc
|
|
|
21
37
|
npm install advanced-filter-system
|
|
22
38
|
```
|
|
23
39
|
|
|
40
|
+
### Via yarn
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
yarn add advanced-filter-system
|
|
44
|
+
```
|
|
45
|
+
|
|
24
46
|
### Direct Download
|
|
25
47
|
|
|
26
48
|
Download `src/AFS.js` from this repository and include it in your project.
|
|
27
49
|
|
|
28
|
-
##
|
|
50
|
+
## Usage Guide
|
|
29
51
|
|
|
30
|
-
###
|
|
52
|
+
### Basic Setup
|
|
31
53
|
|
|
32
54
|
```html
|
|
33
55
|
<div class="filter-container">
|
|
34
|
-
<!-- Filter buttons
|
|
56
|
+
<!-- Filter buttons -->
|
|
35
57
|
<div class="filters">
|
|
36
58
|
<button class="btn-filter" data-filter="*">All</button>
|
|
37
59
|
<button class="btn-filter" data-filter="category:web">Web</button>
|
|
38
60
|
<button class="btn-filter" data-filter="category:design">Design</button>
|
|
39
|
-
<button class="btn-filter" data-filter="price:low">Low Price</button>
|
|
40
61
|
</div>
|
|
41
62
|
|
|
42
|
-
<!--
|
|
63
|
+
<!-- Optional components -->
|
|
43
64
|
<input type="text" class="filter-search" placeholder="Search...">
|
|
44
|
-
|
|
45
|
-
<!-- Counter (optional) -->
|
|
46
65
|
<div class="filter-counter"></div>
|
|
47
66
|
|
|
48
67
|
<!-- Filterable items -->
|
|
49
68
|
<div class="items">
|
|
50
69
|
<div class="filter-item"
|
|
51
|
-
data-categories="category:web
|
|
70
|
+
data-categories="category:web"
|
|
52
71
|
data-title="Project 1"
|
|
53
|
-
data-price="
|
|
72
|
+
data-price="599"
|
|
54
73
|
data-year="2023">
|
|
55
74
|
<!-- Content -->
|
|
56
75
|
</div>
|
|
@@ -58,7 +77,7 @@ Download `src/AFS.js` from this repository and include it in your project.
|
|
|
58
77
|
</div>
|
|
59
78
|
```
|
|
60
79
|
|
|
61
|
-
### JavaScript Initialization
|
|
80
|
+
### Basic JavaScript Initialization
|
|
62
81
|
|
|
63
82
|
```javascript
|
|
64
83
|
import { AFS } from 'advanced-filter-system';
|
|
@@ -70,135 +89,216 @@ const filter = new AFS({
|
|
|
70
89
|
});
|
|
71
90
|
```
|
|
72
91
|
|
|
73
|
-
##
|
|
92
|
+
## Feature Documentation
|
|
93
|
+
|
|
94
|
+
### 1. Filter Modes
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
// Set filter logic mode
|
|
98
|
+
filter.setFilterMode('AND'); // Items must match all selected filters
|
|
99
|
+
filter.setFilterMode('OR'); // Items must match any selected filter
|
|
100
|
+
|
|
101
|
+
// Alternative method
|
|
102
|
+
filter.setLogic('AND');
|
|
103
|
+
filter.setLogic(true); // true = AND, false = OR
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 2. Filter Groups
|
|
107
|
+
|
|
108
|
+
Groups allow complex filtering logic with independent AND/OR operations.
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
// Add filter groups
|
|
112
|
+
filter.addFilterGroup('categories', ['category:tech', 'category:web'], 'OR');
|
|
113
|
+
filter.addFilterGroup('price', ['price:low', 'price:medium'], 'AND');
|
|
114
|
+
|
|
115
|
+
// Set how groups combine
|
|
116
|
+
filter.setGroupMode('AND'); // Items must match all groups
|
|
117
|
+
filter.setGroupMode('OR'); // Items must match any group
|
|
118
|
+
|
|
119
|
+
// Remove groups
|
|
120
|
+
filter.removeFilterGroup('price');
|
|
121
|
+
```
|
|
74
122
|
|
|
75
|
-
###
|
|
123
|
+
### 3. Search Functionality
|
|
76
124
|
|
|
77
125
|
```javascript
|
|
126
|
+
// Configure search
|
|
78
127
|
const filter = new AFS({
|
|
79
|
-
// Required
|
|
80
|
-
containerSelector: '.filter-container',
|
|
81
|
-
itemSelector: '.filter-item',
|
|
82
|
-
filterButtonSelector: '.btn-filter',
|
|
83
|
-
|
|
84
|
-
// Optional (default values)
|
|
85
128
|
searchInputSelector: '.filter-search',
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
hiddenClass: 'hidden',
|
|
89
|
-
animationDuration: 300,
|
|
90
|
-
filterMode: 'OR',
|
|
91
|
-
searchKeys: ['title'],
|
|
92
|
-
debounceTime: 300
|
|
129
|
+
searchKeys: ['title', 'description'], // Data attributes to search in
|
|
130
|
+
debounceTime: 300 // Milliseconds
|
|
93
131
|
});
|
|
132
|
+
|
|
133
|
+
// Programmatic search
|
|
134
|
+
filter.search('query');
|
|
94
135
|
```
|
|
95
136
|
|
|
96
|
-
###
|
|
137
|
+
### 4. Sorting
|
|
97
138
|
|
|
98
139
|
```javascript
|
|
99
|
-
//
|
|
100
|
-
filter.
|
|
101
|
-
|
|
140
|
+
// Multi-criteria sorting
|
|
141
|
+
filter.sortMultiple([
|
|
142
|
+
{ key: 'year', direction: 'desc' },
|
|
143
|
+
{ key: 'title', direction: 'asc' }
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
// Custom comparator
|
|
147
|
+
filter.sortWithComparator('price', (a, b) => parseFloat(a) - parseFloat(b));
|
|
148
|
+
```
|
|
102
149
|
|
|
103
|
-
|
|
104
|
-
filter.removeFilter('category', 'web');
|
|
150
|
+
### 5. Range Filtering
|
|
105
151
|
|
|
106
|
-
|
|
107
|
-
|
|
152
|
+
```javascript
|
|
153
|
+
// Filter by numeric range
|
|
154
|
+
filter.addRangeFilter('price', 100, 500);
|
|
155
|
+
```
|
|
108
156
|
|
|
109
|
-
|
|
110
|
-
filter.addFilterGroup('categories', ['category:tech', 'category:fashion'], 'OR');
|
|
111
|
-
filter.addFilterGroup('price', ['price:low', 'price:medium'], 'AND');
|
|
157
|
+
### 6. Pagination
|
|
112
158
|
|
|
113
|
-
|
|
114
|
-
|
|
159
|
+
```javascript
|
|
160
|
+
// Enable pagination
|
|
161
|
+
filter.setPagination(12); // 12 items per page
|
|
162
|
+
```
|
|
115
163
|
|
|
116
|
-
|
|
117
|
-
|
|
164
|
+
### 7. State Management
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
// URL State
|
|
168
|
+
// Automatically managed, creates URLs like:
|
|
169
|
+
// ?category=web,design&price=low,medium&search=project
|
|
170
|
+
|
|
171
|
+
// Export/Import State
|
|
172
|
+
const state = filter.exportState();
|
|
173
|
+
filter.importState(state);
|
|
174
|
+
|
|
175
|
+
// Presets
|
|
176
|
+
filter.savePreset('myFilters');
|
|
177
|
+
filter.loadPreset('myFilters');
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 8. Analytics
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
filter.enableAnalytics((data) => {
|
|
184
|
+
console.log('Filter event:', data);
|
|
185
|
+
// { type: 'filter', filters: [...], visibleItems: 10, timestamp: '...' }
|
|
186
|
+
});
|
|
118
187
|
```
|
|
119
188
|
|
|
120
|
-
###
|
|
189
|
+
### 9. Responsive Design
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
filter.setResponsiveOptions({
|
|
193
|
+
'768': {
|
|
194
|
+
animationDuration: 200,
|
|
195
|
+
itemsPerPage: 8
|
|
196
|
+
},
|
|
197
|
+
'480': {
|
|
198
|
+
animationDuration: 0,
|
|
199
|
+
itemsPerPage: 4
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
```
|
|
121
203
|
|
|
122
|
-
|
|
204
|
+
### 10. Animation Configuration
|
|
123
205
|
|
|
124
206
|
```javascript
|
|
125
|
-
|
|
126
|
-
|
|
207
|
+
filter.setAnimationOptions({
|
|
208
|
+
duration: 300,
|
|
209
|
+
type: 'ease-out'
|
|
210
|
+
});
|
|
127
211
|
```
|
|
128
212
|
|
|
129
|
-
|
|
213
|
+
### 11. Event System
|
|
130
214
|
|
|
131
|
-
|
|
215
|
+
```javascript
|
|
216
|
+
filter.on('filter', (data) => {
|
|
217
|
+
console.log('Filter changed:', data);
|
|
218
|
+
});
|
|
219
|
+
```
|
|
132
220
|
|
|
133
|
-
|
|
134
|
-
<div class="portfolio filter-container">
|
|
135
|
-
<div class="filters">
|
|
136
|
-
<button class="btn-filter" data-filter="*">All</button>
|
|
137
|
-
<button class="btn-filter" data-filter="type:web">Web</button>
|
|
138
|
-
<button class="btn-filter" data-filter="type:app">Apps</button>
|
|
139
|
-
<button class="btn-filter" data-filter="tech:react">React</button>
|
|
140
|
-
<button class="btn-filter" data-filter="tech:vue">Vue</button>
|
|
141
|
-
</div>
|
|
221
|
+
### 12. Keyboard Navigation
|
|
142
222
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
data-title="React Project">
|
|
147
|
-
<h3>React Web Project</h3>
|
|
148
|
-
<p>Description...</p>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
</div>
|
|
223
|
+
```javascript
|
|
224
|
+
filter.enableKeyboardNavigation();
|
|
225
|
+
```
|
|
152
226
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
227
|
+
## Browser Compatibility
|
|
228
|
+
|
|
229
|
+
- β
Chrome
|
|
230
|
+
- β
Firefox
|
|
231
|
+
- β
Safari
|
|
232
|
+
- β
Edge
|
|
233
|
+
- β
IE11 (with polyfills)
|
|
234
|
+
|
|
235
|
+
## Full Configuration Options
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
const filter = new AFS({
|
|
239
|
+
// Required
|
|
240
|
+
containerSelector: '.filter-container',
|
|
156
241
|
itemSelector: '.filter-item',
|
|
157
242
|
filterButtonSelector: '.btn-filter',
|
|
158
|
-
|
|
243
|
+
|
|
244
|
+
// Optional (with defaults)
|
|
245
|
+
searchInputSelector: '.filter-search',
|
|
246
|
+
counterSelector: '.filter-counter',
|
|
247
|
+
activeClass: 'active',
|
|
248
|
+
hiddenClass: 'hidden',
|
|
249
|
+
animationDuration: 300,
|
|
250
|
+
filterMode: 'OR',
|
|
251
|
+
searchKeys: ['title'],
|
|
252
|
+
debounceTime: 300
|
|
159
253
|
});
|
|
160
|
-
</script>
|
|
161
254
|
```
|
|
162
255
|
|
|
163
|
-
|
|
256
|
+
## API Methods Reference
|
|
164
257
|
|
|
165
|
-
|
|
166
|
-
<div class="products filter-container">
|
|
167
|
-
<!-- Filters by type -->
|
|
168
|
-
<div class="filters">
|
|
169
|
-
<button class="btn-filter" data-filter="*">All</button>
|
|
170
|
-
<button class="btn-filter" data-filter="category:electronics">Electronics</button>
|
|
171
|
-
<button class="btn-filter" data-filter="price:low">Low Price</button>
|
|
172
|
-
<button class="btn-filter" data-filter="price:medium">Medium Price</button>
|
|
173
|
-
<button class="btn-filter" data-filter="stock:available">In Stock</button>
|
|
174
|
-
</div>
|
|
258
|
+
### Filter Management
|
|
175
259
|
|
|
176
|
-
|
|
177
|
-
|
|
260
|
+
- `addFilter(type, value)`
|
|
261
|
+
- `removeFilter(type, value)`
|
|
262
|
+
- `getActiveFiltersByType(type)`
|
|
263
|
+
- `setFilterMode(mode)`
|
|
264
|
+
- `resetFilters()`
|
|
178
265
|
|
|
179
|
-
|
|
180
|
-
<div class="filter-item"
|
|
181
|
-
data-categories="category:electronics price:low stock:available"
|
|
182
|
-
data-title="Smartphone"
|
|
183
|
-
data-price="599">
|
|
184
|
-
<!-- Product content -->
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
```
|
|
266
|
+
### Filter Groups
|
|
189
267
|
|
|
190
|
-
|
|
268
|
+
- `addFilterGroup(groupId, filters, operator)`
|
|
269
|
+
- `removeFilterGroup(groupId)`
|
|
270
|
+
- `setGroupMode(mode)`
|
|
271
|
+
|
|
272
|
+
### Search and Sort
|
|
273
|
+
|
|
274
|
+
- `search(query)`
|
|
275
|
+
- `sortMultiple(criteria)`
|
|
276
|
+
- `sortWithComparator(key, comparator)`
|
|
277
|
+
- `addRangeFilter(key, min, max)`
|
|
278
|
+
|
|
279
|
+
### State Management
|
|
280
|
+
|
|
281
|
+
- `exportState()`
|
|
282
|
+
- `importState(state)`
|
|
283
|
+
- `savePreset(presetName)`
|
|
284
|
+
- `loadPreset(presetName)`
|
|
285
|
+
|
|
286
|
+
### UI and Display
|
|
287
|
+
|
|
288
|
+
- `setPagination(itemsPerPage)`
|
|
289
|
+
- `setAnimationOptions(options)`
|
|
290
|
+
- `setResponsiveOptions(breakpoints)`
|
|
291
|
+
- `enableKeyboardNavigation()`
|
|
292
|
+
|
|
293
|
+
### Events and Analytics
|
|
191
294
|
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
- Safari
|
|
195
|
-
- Edge
|
|
196
|
-
- IE11 (with polyfills)
|
|
295
|
+
- `on(eventName, callback)`
|
|
296
|
+
- `enableAnalytics(callback)`
|
|
197
297
|
|
|
198
|
-
##
|
|
298
|
+
## Contributing
|
|
199
299
|
|
|
200
|
-
Contributions are welcome!
|
|
300
|
+
Contributions are welcome! Please feel free to submit issues and pull requests.
|
|
201
301
|
|
|
202
302
|
## License
|
|
203
303
|
|
|
204
|
-
MIT License
|
|
304
|
+
MIT License - feel free to use this in your projects!
|
package/dist/AFS.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Advanced Filter System for DOM elements
|
|
3
|
-
* @version 1.0.
|
|
3
|
+
* @version 1.0.5
|
|
4
4
|
*
|
|
5
5
|
* A flexible and customizable filtering system that supports:
|
|
6
6
|
* - Multiple filtering modes (OR/AND)
|
|
@@ -192,8 +192,12 @@ class AFS {
|
|
|
192
192
|
if (button.classList.contains(this.options.activeClass)) {
|
|
193
193
|
button.classList.remove(this.options.activeClass);
|
|
194
194
|
this.currentFilters.delete(filterValue);
|
|
195
|
+
|
|
196
|
+
// If no filters are selected, reset to default state and clear URL
|
|
195
197
|
if (this.currentFilters.size === 0) {
|
|
196
198
|
this.resetFilters();
|
|
199
|
+
window.history.pushState({}, "", window.location.pathname);
|
|
200
|
+
return;
|
|
197
201
|
}
|
|
198
202
|
} else {
|
|
199
203
|
button.classList.add(this.options.activeClass);
|
|
@@ -206,9 +210,9 @@ class AFS {
|
|
|
206
210
|
* @public
|
|
207
211
|
*/
|
|
208
212
|
/**
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
* Apply current filters to items
|
|
214
|
+
* @public
|
|
215
|
+
*/
|
|
212
216
|
filter() {
|
|
213
217
|
// Store the original filter logic
|
|
214
218
|
const standardFilter = () => {
|
|
@@ -500,6 +504,11 @@ class AFS {
|
|
|
500
504
|
* @private
|
|
501
505
|
*/
|
|
502
506
|
updateURL() {
|
|
507
|
+
// If only "*" filter is active or no filters are active, clear the URL
|
|
508
|
+
if (this.currentFilters.size === 0 || this.currentFilters.size === 1 && this.currentFilters.has("*")) {
|
|
509
|
+
window.history.pushState({}, "", window.location.pathname);
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
503
512
|
const params = new URLSearchParams(window.location.search);
|
|
504
513
|
|
|
505
514
|
// Add groups to URL if they exist
|
|
@@ -511,7 +520,7 @@ class AFS {
|
|
|
511
520
|
params.set("groupMode", this.groupMode.toLowerCase());
|
|
512
521
|
}
|
|
513
522
|
|
|
514
|
-
//
|
|
523
|
+
// Separate filters by type
|
|
515
524
|
const filtersByType = {};
|
|
516
525
|
for (const filter of this.currentFilters) {
|
|
517
526
|
if (filter !== "*") {
|
|
@@ -523,7 +532,7 @@ class AFS {
|
|
|
523
532
|
}
|
|
524
533
|
}
|
|
525
534
|
|
|
526
|
-
//
|
|
535
|
+
// Add each filter type to the URL
|
|
527
536
|
Object.entries(filtersByType).forEach(_ref => {
|
|
528
537
|
let [type, values] = _ref;
|
|
529
538
|
params.set(type, Array.from(values).join(","));
|