advanced-filter-system 1.0.4 → 1.0.6

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AFS.min.js","sources":["../src/AFS.js"],"sourcesContent":["/**\n * @fileoverview Advanced Filter System for DOM elements\n * @version 1.0.0\n *\n * A flexible and customizable filtering system that supports:\n * - Multiple filtering modes (OR/AND)\n * - Text search with debouncing\n * - Multiple sorting criteria\n * - Range filtering\n * - URL state management\n * - Animation and transitions\n * - Results counter\n */\n\n/**\n * Utility function for debouncing\n * @param {Function} func - Function to debounce\n * @param {number} wait - Delay in milliseconds\n * @returns {Function} Debounced function\n */\nfunction debounce(func, wait) {\n let timeout;\n return function executedFunction(...args) {\n const later = () => {\n clearTimeout(timeout);\n func(...args);\n };\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n };\n}\n\nclass AFS {\n /**\n * @typedef {Object} FilterOptions\n * @property {string} containerSelector - Main container selector\n * @property {string} itemSelector - Items to filter selector\n * @property {string} filterButtonSelector - Filter buttons selector\n * @property {string} [searchInputSelector] - Search input selector\n * @property {string} [counterSelector] - Results counter selector\n * @property {string} [activeClass='active'] - Active state class\n * @property {string} [hiddenClass='hidden'] - Hidden state class\n * @property {number} [animationDuration=300] - Animation duration in ms\n * @property {string} [filterMode='OR'] - Filter mode ('OR' or 'AND')\n * @property {string[]} [searchKeys=['title']] - Data attributes to search in\n * @property {number} [debounceTime=300] - Search debounce delay in ms\n */\n\n /**\n * @param {FilterOptions} options - Filter configuration options\n */\n constructor(options = {}) {\n this.options = {\n containerSelector: \".filter-container\",\n itemSelector: \".filter-item\",\n filterButtonSelector: \".btn-filter\",\n searchInputSelector: \".filter-search\",\n counterSelector: \".filter-counter\",\n activeClass: \"active\",\n hiddenClass: \"hidden\",\n animationDuration: 300,\n filterMode: \"OR\",\n searchKeys: [\"title\"],\n debounceTime: 300,\n ...options,\n };\n\n // Initialize elements\n this.container = document.querySelector(this.options.containerSelector);\n this.items = document.querySelectorAll(this.options.itemSelector);\n this.filterButtons = document.querySelectorAll(\n this.options.filterButtonSelector,\n );\n this.searchInput = document.querySelector(this.options.searchInputSelector);\n this.counter = document.querySelector(this.options.counterSelector);\n\n // Initialize state\n this.currentFilters = new Set([\"*\"]);\n this.currentSearch = \"\";\n this.visibleItems = new Set(this.items);\n this.filterGroups = new Map();\n this.groupMode = \"OR\"; // Default group mode\n\n this.init();\n }\n\n /**\n * Initialize the filter system\n * @private\n */\n init() {\n this.addStyles();\n this.bindEvents();\n this.loadFromURL();\n this.updateCounter();\n }\n\n /**\n * Add required styles to document\n * @private\n */\n addStyles() {\n const styles = `\n .${this.options.hiddenClass} {\n display: none !important;\n }\n\n ${this.options.itemSelector} {\n opacity: 1;\n transform: scale(1);\n transition: opacity ${this.options.animationDuration}ms ease-out,\n transform ${this.options.animationDuration}ms ease-out;\n }\n\n ${this.options.filterButtonSelector} {\n opacity: 0.5;\n transition: opacity ${this.options.animationDuration}ms ease;\n }\n\n ${this.options.filterButtonSelector}.${this.options.activeClass} {\n opacity: 1;\n }\n `;\n\n const styleSheet = document.createElement(\"style\");\n styleSheet.textContent = styles;\n document.head.appendChild(styleSheet);\n }\n\n /**\n * Bind all event listeners\n * @private\n */\n bindEvents() {\n this.filterButtons.forEach((button) => {\n button.addEventListener(\"click\", () => this.handleFilterClick(button));\n });\n\n if (this.searchInput) {\n this.searchInput.addEventListener(\n \"input\",\n debounce((e) => {\n this.search(e.target.value);\n }, this.options.debounceTime),\n );\n }\n\n window.addEventListener(\"popstate\", () => this.loadFromURL());\n }\n\n /**\n * Handle filter button clicks\n * @private\n * @param {HTMLElement} button - Clicked filter button\n */\n handleFilterClick(button) {\n const filterValue = button.dataset.filter;\n\n if (filterValue === \"*\") {\n this.resetFilters();\n } else {\n this.toggleFilter(filterValue, button);\n }\n\n this.filter();\n this.updateURL();\n }\n\n /**\n * Reset all filters to default state\n * @private\n */\n resetFilters() {\n this.filterButtons.forEach((btn) =>\n btn.classList.remove(this.options.activeClass),\n );\n this.currentFilters.clear();\n this.currentFilters.add(\"*\");\n this.filterButtons[0].classList.add(this.options.activeClass);\n this.resetCounter();\n }\n\n /**\n * Reset visible items counter\n * @private\n */\n resetCounter() {\n this.visibleItems = new Set(this.items);\n this.updateCounter();\n }\n\n /**\n * Toggle individual filter state\n * @private\n * @param {string} filterValue - Filter value to toggle\n * @param {HTMLElement} button - Filter button element\n */\n toggleFilter(filterValue, button) {\n this.currentFilters.delete(\"*\");\n this.filterButtons[0].classList.remove(this.options.activeClass);\n\n if (button.classList.contains(this.options.activeClass)) {\n button.classList.remove(this.options.activeClass);\n this.currentFilters.delete(filterValue);\n\n if (this.currentFilters.size === 0) {\n this.resetFilters();\n }\n } else {\n button.classList.add(this.options.activeClass);\n this.currentFilters.add(filterValue);\n }\n }\n\n /**\n * Apply current filters to items\n * @public\n */\n /**\n * Apply current filters to items\n * @public\n */\nfilter() {\n // Store the original filter logic\n const standardFilter = () => {\n this.visibleItems.clear();\n \n this.items.forEach((item) => {\n if (this.currentFilters.has(\"*\")) {\n this.showItem(item);\n this.visibleItems.add(item);\n } else {\n const itemCategories = new Set(\n item.dataset.categories?.split(\" \") || [],\n );\n const matchesFilter =\n this.options.filterMode === \"OR\"\n ? this.matchesAnyFilter(itemCategories)\n : this.matchesAllFilters(itemCategories);\n\n if (matchesFilter) {\n this.showItem(item);\n this.visibleItems.add(item);\n } else {\n this.hideItem(item);\n }\n }\n });\n };\n\n // Check if we should use group filtering or standard filtering\n if (this.filterGroups.size === 0) {\n standardFilter();\n } else {\n this.visibleItems.clear();\n\n this.items.forEach(item => {\n if (this.currentFilters.has(\"*\")) {\n this.showItem(item);\n this.visibleItems.add(item);\n } else {\n const itemCategories = new Set(item.dataset.categories?.split(\" \") || []);\n const matchesGroups = this.matchesFilterGroups(itemCategories);\n\n if (matchesGroups) {\n this.showItem(item);\n this.visibleItems.add(item);\n } else {\n this.hideItem(item);\n }\n }\n });\n }\n\n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n}\n\n /**\n * Add or update a filter group\n * @public\n * @param {string} groupId - Group identifier\n * @param {string[]} filters - Array of filter values\n * @param {string} [operator='OR'] - Operator within group ('AND' or 'OR')\n * @returns {boolean} Success status\n */\n addFilterGroup(groupId, filters, operator = \"OR\") {\n try {\n // Validate inputs\n if (!groupId || !Array.isArray(filters)) {\n console.warn(\"Invalid group parameters\");\n return false;\n }\n\n const validOperator = operator.toUpperCase();\n if (![\"AND\", \"OR\"].includes(validOperator)) {\n console.warn('Invalid operator. Using default \"OR\"');\n operator = \"OR\";\n }\n\n // Create or update group\n this.filterGroups.set(groupId, {\n filters: new Set(filters),\n operator: validOperator,\n });\n\n // Only update if we have active groups\n if (this.filterGroups.size > 0) {\n this.updateFiltersFromGroups();\n this.filter();\n this.updateURL();\n }\n\n return true;\n } catch (error) {\n console.error(\"Error adding filter group:\", error);\n return false;\n }\n }\n\n /**\n * Set how groups combine with each other\n * @public\n * @param {string} mode - Mode for combining groups ('AND' or 'OR')\n */\n setGroupMode(mode) {\n const validMode = mode.toUpperCase();\n if ([\"AND\", \"OR\"].includes(validMode)) {\n this.groupMode = validMode;\n if (this.filterGroups.size > 0) {\n this.filter();\n }\n }\n }\n\n /**\n * Remove a filter group\n * @public\n * @param {string} groupId - Group identifier\n * @returns {boolean} Success status\n */\n removeFilterGroup(groupId) {\n if (this.filterGroups.has(groupId)) {\n this.filterGroups.delete(groupId);\n\n // If no groups left, revert to normal filtering\n if (this.filterGroups.size === 0) {\n this.resetFilters();\n } else {\n this.updateFiltersFromGroups();\n }\n\n this.filter();\n this.updateURL();\n return true;\n }\n return false;\n }\n\n /**\n * Update filters based on groups\n * @private\n */\n updateFiltersFromGroups() {\n // Only process if we have groups\n if (this.filterGroups.size === 0) return;\n\n // Clear current filters except '*'\n if (!this.currentFilters.has(\"*\")) {\n this.currentFilters.clear();\n }\n\n // Combine all group filters\n for (const group of this.filterGroups.values()) {\n group.filters.forEach((filter) => {\n if (filter !== \"*\") {\n this.currentFilters.add(filter);\n }\n });\n }\n }\n\n /**\n * Check if item matches any active filter (OR mode)\n * @private\n * @param {Set} itemCategories - Item's categories\n * @returns {boolean} Whether item matches any filter\n */\n matchesAnyFilter(itemCategories) {\n return [...this.currentFilters].some((filter) => {\n const [type, value] = filter.split(\":\");\n return itemCategories.has(`${type}:${value}`);\n });\n }\n\n /**\n * Check if item matches all active filters (AND mode)\n * @private\n * @param {Set} itemCategories - Item's categories\n * @returns {boolean} Whether item matches all filters\n */\n matchesAllFilters(itemCategories) {\n return [...this.currentFilters].every((filter) => {\n const [type, value] = filter.split(\":\");\n return itemCategories.has(`${type}:${value}`);\n });\n }\n\n /**\n * Show an item with animation\n * @private\n * @param {HTMLElement} item - Item to show\n */\n showItem(item) {\n this.visibleItems.add(item);\n item.classList.remove(this.options.hiddenClass);\n item.style.opacity = \"0\";\n item.style.transform = \"scale(0.95)\";\n\n item.offsetHeight;\n\n requestAnimationFrame(() => {\n item.style.opacity = \"1\";\n item.style.transform = \"scale(1)\";\n });\n }\n\n /**\n * Hide an item with animation\n * @private\n * @param {HTMLElement} item - Item to hide\n */\n hideItem(item) {\n item.style.opacity = \"0\";\n item.style.transform = \"scale(0.95)\";\n\n setTimeout(() => {\n if (item.style.opacity === \"0\") {\n item.classList.add(this.options.hiddenClass);\n this.visibleItems.delete(item);\n }\n }, this.options.animationDuration);\n }\n\n /**\n * Search items by text\n * @public\n * @param {string} query - Search query\n */\n search(query) {\n this.currentSearch = query.toLowerCase().trim();\n let matches = 0;\n\n this.items.forEach((item) => {\n const searchText = this.options.searchKeys\n .map((key) => item.dataset[key] || \"\")\n .join(\" \")\n .toLowerCase();\n\n const matchesSearch =\n this.currentSearch === \"\" || searchText.includes(this.currentSearch);\n\n if (matchesSearch) {\n this.showItem(item);\n matches++;\n } else {\n this.hideItem(item);\n }\n });\n\n this.updateURL();\n\n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n }\n\n /**\n * Sort items by multiple criteria\n * @public\n * @param {Array<{key: string, direction: string}>} criteria - Sort criteria\n */\n sortMultiple(criteria) {\n const items = [...this.items];\n\n items.sort((a, b) => {\n for (const criterion of criteria) {\n const valueA = a.dataset[criterion.key];\n const valueB = b.dataset[criterion.key];\n\n const comparison =\n criterion.direction === \"asc\"\n ? valueA.localeCompare(valueB)\n : valueB.localeCompare(valueA);\n\n if (comparison !== 0) return comparison;\n }\n return 0;\n });\n\n items.forEach((item) => this.container.appendChild(item));\n }\n\n /**\n * Filter items by numeric range\n * @public\n * @param {string} key - Data attribute key\n * @param {number} min - Minimum value\n * @param {number} max - Maximum value\n */\n addRangeFilter(key, min, max) {\n this.items.forEach((item) => {\n const value = parseFloat(item.dataset[key]);\n const inRange = value >= min && value <= max;\n\n if (inRange) {\n this.showItem(item);\n } else {\n this.hideItem(item);\n }\n });\n\n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n }\n\n /**\n * Check if item matches filter groups\n * @private\n * @param {Set} itemCategories - Item's categories\n * @returns {boolean} Whether item matches the group filters\n */\n matchesFilterGroups(itemCategories) {\n const groupMatches = [...this.filterGroups.values()].map((group) => {\n const groupFilters = [...group.filters];\n if (groupFilters.length === 0) return true;\n\n return group.operator === \"OR\"\n ? groupFilters.some((filter) => itemCategories.has(filter))\n : groupFilters.every((filter) => itemCategories.has(filter));\n });\n\n return this.groupMode === \"OR\"\n ? groupMatches.some((matches) => matches)\n : groupMatches.every((matches) => matches);\n }\n\n /**\n * Update URL with current filter state\n * @private\n */\n updateURL() {\n const params = new URLSearchParams(window.location.search);\n\n // Add groups to URL if they exist\n if (this.filterGroups.size > 0) {\n for (const [groupId, group] of this.filterGroups.entries()) {\n params.set(`group_${groupId}`, [...group.filters].join(\",\"));\n params.set(`groupOp_${groupId}`, group.operator.toLowerCase());\n }\n params.set(\"groupMode\", this.groupMode.toLowerCase());\n }\n\n // Séparer les filtres par type\n const filtersByType = {};\n for (const filter of this.currentFilters) {\n if (filter !== \"*\") {\n const [type, value] = filter.split(\":\");\n if (!filtersByType[type]) {\n filtersByType[type] = new Set();\n }\n filtersByType[type].add(value);\n }\n }\n\n // Ajouter chaque type de filtre à l'URL\n Object.entries(filtersByType).forEach(([type, values]) => {\n params.set(type, Array.from(values).join(\",\"));\n });\n\n if (this.currentSearch) {\n params.set(\"search\", this.currentSearch);\n }\n\n const newURL = `${window.location.pathname}${\n params.toString() ? \"?\" + params.toString() : \"\"\n }`;\n window.history.pushState({}, \"\", newURL);\n }\n\n /**\n * Load filter state from URL\n * @private\n */\n loadFromURL() {\n const params = new URLSearchParams(window.location.search);\n\n // Load groups if they exist\n this.filterGroups.clear();\n for (const [key, value] of params.entries()) {\n if (key.startsWith(\"group_\")) {\n const groupId = key.replace(\"group_\", \"\");\n const operator =\n params.get(`groupOp_${groupId}`)?.toUpperCase() || \"OR\";\n const filters = value.split(\",\");\n this.addFilterGroup(groupId, filters, operator);\n }\n }\n\n // Set group mode if present\n const groupMode = params.get(\"groupMode\")?.toUpperCase();\n if (groupMode && [\"AND\", \"OR\"].includes(groupMode)) {\n this.groupMode = groupMode;\n }\n\n this.currentFilters.clear();\n\n // Si aucun filtre n'est présent, utiliser '*'\n let hasFilters = false;\n\n // Parcourir tous les paramètres\n for (const [type, values] of params.entries()) {\n if (type !== \"search\") {\n hasFilters = true;\n values.split(\",\").forEach((value) => {\n this.currentFilters.add(`${type}:${value}`);\n });\n }\n }\n\n if (!hasFilters) {\n this.currentFilters.add(\"*\");\n }\n\n // Update active buttons\n this.filterButtons.forEach((button) => {\n const filterValue = button.dataset.filter;\n if (\n this.currentFilters.has(filterValue) ||\n (filterValue === \"*\" && this.currentFilters.has(\"*\"))\n ) {\n button.classList.add(this.options.activeClass);\n } else {\n button.classList.remove(this.options.activeClass);\n }\n });\n\n // Load search\n const search = params.get(\"search\") || \"\";\n if (this.searchInput) {\n this.searchInput.value = search;\n }\n\n this.filter();\n if (search) {\n this.search(search);\n }\n }\n\n /**\n * Update results counter\n * @private\n * @returns {{total: number, visible: number}}\n */\n updateCounter() {\n const total = this.items.length;\n const visible = this.visibleItems.size;\n\n if (this.counter) {\n this.counter.textContent = `Showing ${visible} of ${total}`;\n }\n\n return { total, visible };\n }\n\n /**\n * Set animation options\n * @public\n * @param {Object} options - Animation options\n */\n setAnimationOptions(options = {}) {\n this.options.animationDuration =\n options.duration || this.options.animationDuration;\n this.options.animationType = options.type || \"ease-out\";\n this.addStyles(); // Refresh styles with new options\n }\n\n /**\n * Event handling system\n */\n addEventSystem() {\n this.events = {};\n\n this.on = (eventName, callback) => {\n if (!this.events[eventName]) {\n this.events[eventName] = [];\n }\n this.events[eventName].push(callback);\n };\n\n this.emit = (eventName, data) => {\n if (this.events[eventName]) {\n this.events[eventName].forEach((callback) => callback(data));\n }\n };\n }\n\n /**\n * Add pagination\n * @public\n * @param {number} itemsPerPage - Number of items per page\n */\n setPagination(itemsPerPage) {\n this.pagination = {\n currentPage: 1,\n itemsPerPage: itemsPerPage,\n totalPages: Math.ceil(this.visibleItems.size / itemsPerPage),\n };\n this.updatePagination();\n }\n\n updatePagination() {\n const start =\n (this.pagination.currentPage - 1) * this.pagination.itemsPerPage;\n const end = start + this.pagination.itemsPerPage;\n\n [...this.visibleItems].forEach((item, index) => {\n if (index >= start && index < end) {\n this.showItem(item);\n } else {\n this.hideItem(item);\n }\n });\n }\n\n /**\n * Enable analytics tracking\n * @public\n * @param {Function} callback - Analytics callback function\n */\n enableAnalytics(callback) {\n this.analyticsCallback = callback;\n this.on(\"filter\", (data) => {\n this.analyticsCallback({\n type: \"filter\",\n filters: [...this.currentFilters],\n visibleItems: this.visibleItems.size,\n timestamp: new Date().toISOString(),\n });\n });\n }\n\n /**\n * Sort with custom comparator\n * @public\n * @param {string} key - Data attribute key\n * @param {Function} comparator - Custom comparison function\n */\n sortWithComparator(key, comparator) {\n const items = [...this.items];\n items.sort((a, b) => {\n const valueA = a.dataset[key];\n const valueB = b.dataset[key];\n return comparator(valueA, valueB);\n });\n items.forEach((item) => this.container.appendChild(item));\n }\n\n /**\n * Add responsive behavior\n * @public\n * @param {Object} breakpoints - Breakpoint configurations\n */\n setResponsiveOptions(breakpoints) {\n window.addEventListener(\n \"resize\",\n debounce(() => {\n const width = window.innerWidth;\n for (const [breakpoint, options] of Object.entries(breakpoints)) {\n if (width <= parseInt(breakpoint)) {\n Object.assign(this.options, options);\n this.filter();\n break;\n }\n }\n }, 250),\n );\n }\n\n /**\n * Enable keyboard navigation\n * @public\n */\n enableKeyboardNavigation() {\n document.addEventListener(\"keydown\", (e) => {\n if (\n e.key === \"Enter\" &&\n document.activeElement.classList.contains(\n this.options.filterButtonSelector.slice(1),\n )\n ) {\n document.activeElement.click();\n }\n });\n }\n\n /**\n * Export current filter state\n * @public\n * @returns {Object} Filter state\n */\n exportState() {\n return {\n filters: [...this.currentFilters],\n search: this.currentSearch,\n mode: this.options.filterMode,\n timestamp: new Date().toISOString(),\n };\n }\n\n /**\n * Import filter state\n * @public\n * @param {Object} state - Filter state to import\n */\n importState(state) {\n if (state.filters) {\n this.currentFilters = new Set(state.filters);\n this.currentSearch = state.search || \"\";\n this.options.filterMode = state.mode || \"OR\";\n this.filter();\n this.updateURL();\n }\n }\n\n /**\n * Save current filter state as preset\n * @public\n * @param {string} presetName - Name of the preset\n */\n savePreset(presetName) {\n const preset = {\n filters: [...this.currentFilters],\n search: this.currentSearch,\n mode: this.options.filterMode,\n };\n localStorage.setItem(`afs_preset_${presetName}`, JSON.stringify(preset));\n }\n\n /**\n * Load filter preset\n * @public\n * @param {string} presetName - Name of the preset to load\n */\n loadPreset(presetName) {\n const preset = JSON.parse(localStorage.getItem(`afs_preset_${presetName}`));\n if (preset) {\n this.currentFilters = new Set(preset.filters);\n this.currentSearch = preset.search;\n this.options.filterMode = preset.mode;\n this.filter();\n this.updateURL();\n }\n }\n\n /**\n * Set filter logic mode (alias for setFilterMode)\n * @public\n * @param {string} logic - New filter logic ('AND' or 'OR')\n */\n setLogic(logic) {\n if (typeof logic === \"boolean\") {\n // Handle boolean input (true = AND, false = OR)\n this.options.filterMode = logic ? \"AND\" : \"OR\";\n this.filter();\n return;\n }\n\n const mode = logic.toUpperCase();\n if ([\"OR\", \"AND\"].includes(mode)) {\n this.options.filterMode = mode;\n this.filter();\n }\n }\n\n /**\n * Change filter mode\n * @public\n * @param {string} mode - New filter mode ('OR' or 'AND')\n */\n setFilterMode(mode) {\n if ([\"OR\", \"AND\"].includes(mode.toUpperCase())) {\n this.options.filterMode = mode.toUpperCase();\n this.filter();\n }\n }\n\n /**\n * Add filter by type and value\n * @public\n * @param {string} type - Filter type\n * @param {string} value - Filter value\n */\n addFilter(type, value) {\n this.currentFilters.add(`${type}:${value}`);\n this.filter();\n this.updateURL();\n }\n\n /**\n * Remove filter by type and value\n * @public\n * @param {string} type - Filter type\n */\n removeFilter(type, value) {\n this.currentFilters.delete(`${type}:${value}`);\n if (this.currentFilters.size === 0) {\n this.currentFilters.add(\"*\");\n }\n this.filter();\n this.updateURL();\n }\n\n /**\n * Get active filters by type\n * @public\n * @param {string} type - Filter type\n */\n getActiveFiltersByType(type) {\n return [...this.currentFilters]\n .filter((filter) => filter.startsWith(`${type}:`))\n .map((filter) => filter.split(\":\")[1]);\n }\n}\n\nexport { AFS };\n"],"names":["debounce","func","wait","timeout","_len","arguments","length","args","Array","_key","clearTimeout","setTimeout","later","constructor","options","undefined","this","containerSelector","itemSelector","filterButtonSelector","searchInputSelector","counterSelector","activeClass","hiddenClass","animationDuration","filterMode","searchKeys","debounceTime","container","document","querySelector","items","querySelectorAll","filterButtons","searchInput","counter","currentFilters","Set","currentSearch","visibleItems","filterGroups","Map","groupMode","init","addStyles","bindEvents","loadFromURL","updateCounter","styles","styleSheet","createElement","textContent","head","appendChild","forEach","button","addEventListener","handleFilterClick","e","search","target","value","window","filterValue","dataset","filter","resetFilters","toggleFilter","updateURL","btn","classList","remove","clear","add","resetCounter","delete","contains","size","standardFilter","item","has","showItem","itemCategories","categories","split","matchesAnyFilter","matchesAllFilters","hideItem","matchesFilterGroups","addFilterGroup","groupId","filters","operator","isArray","console","warn","validOperator","toUpperCase","includes","set","updateFiltersFromGroups","error","setGroupMode","mode","validMode","removeFilterGroup","group","values","some","type","every","style","opacity","transform","offsetHeight","requestAnimationFrame","query","toLowerCase","trim","searchText","map","key","join","sortMultiple","criteria","sort","a","b","criterion","valueA","valueB","comparison","direction","localeCompare","addRangeFilter","min","max","parseFloat","groupMatches","groupFilters","matches","params","URLSearchParams","location","entries","filtersByType","Object","_ref","from","newURL","pathname","toString","history","pushState","startsWith","replace","get","hasFilters","total","visible","setAnimationOptions","duration","animationType","addEventSystem","events","on","eventName","callback","push","emit","data","setPagination","itemsPerPage","pagination","currentPage","totalPages","Math","ceil","updatePagination","start","end","index","enableAnalytics","analyticsCallback","timestamp","Date","toISOString","sortWithComparator","comparator","setResponsiveOptions","breakpoints","width","innerWidth","breakpoint","parseInt","assign","enableKeyboardNavigation","activeElement","slice","click","exportState","importState","state","savePreset","presetName","preset","localStorage","setItem","JSON","stringify","loadPreset","parse","getItem","setLogic","logic","setFilterMode","addFilter","removeFilter","getActiveFiltersByType"],"mappings":"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"}
1
+ {"version":3,"file":"AFS.min.js","sources":["../src/AFS.js"],"sourcesContent":["/**\n * @fileoverview Advanced Filter System for DOM elements\n * @version 1.0.6\n *\n * A flexible and customizable filtering system that supports:\n * - Multiple filtering modes (OR/AND)\n * - Text search with debouncing\n * - Multiple sorting criteria\n * - Range filtering\n * - URL state management\n * - Animation and transitions\n * - Results counter\n */\n\n/**\n * Utility function for debouncing\n * @param {Function} func - Function to debounce\n * @param {number} wait - Delay in milliseconds\n * @returns {Function} Debounced function\n */\nfunction debounce(func, wait) {\n let timeout;\n return function executedFunction(...args) {\n const later = () => {\n clearTimeout(timeout);\n func(...args);\n };\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n };\n}\n\nclass AFS {\n /**\n * @typedef {Object} FilterOptions\n * @property {string} containerSelector - Main container selector\n * @property {string} itemSelector - Items to filter selector\n * @property {string} filterButtonSelector - Filter buttons selector\n * @property {string} [searchInputSelector] - Search input selector\n * @property {string} [counterSelector] - Results counter selector\n * @property {string} [activeClass='active'] - Active state class\n * @property {string} [hiddenClass='hidden'] - Hidden state class\n * @property {number} [animationDuration=300] - Animation duration in ms\n * @property {string} [filterMode='OR'] - Filter mode ('OR' or 'AND')\n * @property {string[]} [searchKeys=['title']] - Data attributes to search in\n * @property {number} [debounceTime=300] - Search debounce delay in ms\n */\n\n /**\n * @param {FilterOptions} options - Filter configuration options\n */\n constructor(options = {}) {\n this.options = {\n containerSelector: \".filter-container\",\n itemSelector: \".filter-item\",\n filterButtonSelector: \".btn-filter\",\n searchInputSelector: \".filter-search\",\n counterSelector: \".filter-counter\",\n activeClass: \"active\",\n hiddenClass: \"hidden\",\n animationDuration: 300,\n filterMode: \"OR\",\n searchKeys: [\"title\"],\n debounceTime: 300,\n debug: false,\n logLevel: 'info',\n ...options,\n };\n\n // Define logging levels hierarchy\n this.logLevels = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3\n };\n\n // Initialize elements\n this.container = document.querySelector(this.options.containerSelector);\n this.items = document.querySelectorAll(this.options.itemSelector);\n this.sortOrders = {};\n this.filterButtons = document.querySelectorAll(\n this.options.filterButtonSelector,\n );\n this.searchInput = document.querySelector(this.options.searchInputSelector);\n this.counter = document.querySelector(this.options.counterSelector);\n\n // Initialize state\n this.currentFilters = new Set([\"*\"]);\n this.currentSearch = \"\";\n this.visibleItems = new Set(this.items);\n this.filterGroups = new Map();\n this.groupMode = \"OR\"; // Default group mode\n\n this.log('debug', 'Initializing AFS with options:', this.options);\n this.init();\n }\n\n /**\n * Internal logging method\n * Handles debug message output based on current log level\n * \n * @private\n * @param {string} level - Log level ('error', 'warn', 'info', 'debug')\n * @param {...any} args - Arguments to log\n */\n log(level, ...args) {\n if (!this.options.debug) return;\n \n const currentLevelValue = this.logLevels[this.options.logLevel];\n const messageLevel = this.logLevels[level];\n\n if (messageLevel <= currentLevelValue) {\n const timestamp = new Date().toISOString();\n const prefix = `[AFS ${level.toUpperCase()}] ${timestamp}`;\n\n switch (level) {\n case 'error':\n console.error(prefix, ...args);\n break;\n case 'warn':\n console.warn(prefix, ...args);\n break;\n case 'info':\n console.info(prefix, ...args);\n break;\n case 'debug':\n console.debug(prefix, ...args);\n break;\n }\n }\n }\n\n /**\n * Configure debug mode settings\n * \n * @public\n * @param {boolean} enabled - Enable or disable debug mode\n * @param {string} [level='info'] - Log level ('error', 'warn', 'info', 'debug')\n */\n setDebugMode(enabled, level = 'info') {\n this.options.debug = enabled;\n if (this.logLevels.hasOwnProperty(level)) {\n this.options.logLevel = level;\n }\n this.log('info', `Debug mode ${enabled ? 'enabled' : 'disabled'} with level: ${level}`);\n }\n\n /**\n * Initialize the filter system\n * Sets up styles, events, and initial state\n * \n * @private\n */\n init() {\n this.log('debug', 'Starting initialization');\n \n if (!this.container) {\n this.log('error', `Container not found: ${this.options.containerSelector}`);\n return;\n }\n\n this.addStyles();\n this.bindEvents();\n this.loadFromURL();\n this.updateCounter();\n \n this.log('info', 'Initialization complete');\n }\n\n /**\n * Add required styles to document\n * @private\n */\n addStyles() {\n const styles = `\n .${this.options.hiddenClass} {\n display: none !important;\n }\n\n ${this.options.itemSelector} {\n opacity: 1;\n transform: scale(1);\n transition: opacity ${this.options.animationDuration}ms ease-out,\n transform ${this.options.animationDuration}ms ease-out;\n }\n\n ${this.options.filterButtonSelector} {\n opacity: 0.5;\n transition: opacity ${this.options.animationDuration}ms ease;\n }\n\n ${this.options.filterButtonSelector}.${this.options.activeClass} {\n opacity: 1;\n }\n `;\n\n const styleSheet = document.createElement(\"style\");\n styleSheet.textContent = styles;\n document.head.appendChild(styleSheet);\n this.log('debug', 'Styles added to document');\n }\n\n /**\n * Bind all event listeners\n * @private\n */\n bindEvents() {\n this.log('debug', 'Binding events');\n\n this.filterButtons.forEach((button) => {\n button.addEventListener(\"click\", () => this.handleFilterClick(button));\n });\n\n if (this.searchInput) {\n this.searchInput.addEventListener(\n \"input\",\n debounce((e) => {\n this.search(e.target.value);\n }, this.options.debounceTime),\n );\n }\n\n window.addEventListener(\"popstate\", () => this.loadFromURL());\n\n this.log('debug', 'Events bound successfully');\n }\n\n /**\n * Handle filter button clicks\n * @private\n * @param {HTMLElement} button - Clicked filter button\n */\n handleFilterClick(button) {\n const filterValue = button.dataset.filter;\n this.log('debug', 'Filter button clicked:', filterValue);\n\n if (filterValue === \"*\") {\n this.resetFilters();\n } else {\n this.toggleFilter(filterValue, button);\n }\n\n this.filter();\n this.updateURL();\n }\n\n /**\n * Reset all filters to default state\n * @private\n */\n resetFilters() {\n this.log('debug', 'Resetting filters');\n\n this.filterButtons.forEach((btn) =>\n btn.classList.remove(this.options.activeClass),\n );\n this.currentFilters.clear();\n this.currentFilters.add(\"*\");\n this.filterButtons[0].classList.add(this.options.activeClass);\n this.resetCounter();\n }\n\n /**\n * Reset visible items counter\n * @private\n */\n resetCounter() {\n this.visibleItems = new Set(this.items);\n this.updateCounter();\n }\n\n /**\n * Toggle individual filter state\n * @private\n * @param {string} filterValue - Filter value to toggle\n * @param {HTMLElement} button - Filter button element\n */\n toggleFilter(filterValue, button) {\n this.log('debug', `Toggling filter: ${filterValue}`);\n\n this.currentFilters.delete(\"*\");\n this.filterButtons[0].classList.remove(this.options.activeClass);\n\n if (button.classList.contains(this.options.activeClass)) {\n button.classList.remove(this.options.activeClass);\n this.currentFilters.delete(filterValue);\n\n // If no filters are selected, reset to default state and clear URL\n if (this.currentFilters.size === 0) {\n this.resetFilters();\n window.history.pushState({}, \"\", window.location.pathname);\n return;\n }\n } else {\n button.classList.add(this.options.activeClass);\n this.currentFilters.add(filterValue);\n }\n }\n\n /**\n * Sort items based on auto-detecting ASC or DESC for each key\n * @public\n * @param {string} key - The data attribute key to sort by (e.g., 'title', 'price', 'date')\n */\n sortWithOrder(key) {\n const items = [...this.items];\n\n // Check if the current sort order is ASC, default to ASC if undefined\n const currentOrder = this.sortOrders[key] || \"asc\";\n const newOrder = currentOrder === \"asc\" ? \"desc\" : \"asc\"; // Toggle order\n\n // Sort items based on the new order\n items.sort((a, b) => {\n let valueA = a.dataset[key];\n let valueB = b.dataset[key];\n\n // Check if values are numeric and convert them to numbers if they are\n const isNumeric = !isNaN(valueA) && !isNaN(valueB);\n if (isNumeric) {\n valueA = parseFloat(valueA);\n valueB = parseFloat(valueB);\n }\n\n if (newOrder === \"asc\") {\n return isNumeric ? valueA - valueB : valueA.localeCompare(valueB);\n } else {\n return isNumeric ? valueB - valueA : valueB.localeCompare(valueA);\n }\n });\n\n // Update the current sort order for the key\n this.sortOrders[key] = newOrder;\n\n // Reorder items in the DOM\n items.forEach((item) => this.container.appendChild(item));\n\n this.log('debug', `Sorting items by ${key} in ${newOrder} order`);\n }\n\n /**\n * Shuffle items randomly and display in the container\n * @public\n */\n shuffle() {\n const itemsArray = [...this.items];\n\n // Shuffle the itemsArray using Fisher-Yates algorithm\n for (let i = itemsArray.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [itemsArray[i], itemsArray[j]] = [itemsArray[j], itemsArray[i]];\n }\n\n // Re-append the shuffled items to the container\n itemsArray.forEach((item) => this.container.appendChild(item));\n\n this.log('debug', 'Shuffling items');\n }\n\n /**\n * Apply current filters to items\n * @public\n */\n /**\n * Apply current filters to items\n * @public\n */\n filter() {\n // Store the original filter logic\n const standardFilter = () => {\n this.log('debug', 'Applying filters');\n\n this.visibleItems.clear();\n\n this.items.forEach((item) => {\n if (this.currentFilters.has(\"*\")) {\n this.showItem(item);\n this.visibleItems.add(item);\n } else {\n const itemCategories = new Set(\n item.dataset.categories?.split(\" \") || [],\n );\n const matchesFilter =\n this.options.filterMode === \"OR\"\n ? this.matchesAnyFilter(itemCategories)\n : this.matchesAllFilters(itemCategories);\n\n if (matchesFilter) {\n this.showItem(item);\n this.visibleItems.add(item);\n } else {\n this.hideItem(item);\n }\n }\n });\n };\n\n // Check if we should use group filtering or standard filtering\n if (this.filterGroups.size === 0) {\n standardFilter();\n } else {\n this.visibleItems.clear();\n\n this.items.forEach((item) => {\n if (this.currentFilters.has(\"*\")) {\n this.showItem(item);\n this.visibleItems.add(item);\n } else {\n const itemCategories = new Set(\n item.dataset.categories?.split(\" \") || [],\n );\n const matchesGroups = this.matchesFilterGroups(itemCategories);\n\n if (matchesGroups) {\n this.showItem(item);\n this.visibleItems.add(item);\n } else {\n this.hideItem(item);\n }\n }\n });\n }\n\n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n\n this.log('info', `Filter applied. Visible items: ${this.visibleItems.size}`);\n }\n\n /**\n * Add or update a filter group\n * @public\n * @param {string} groupId - Group identifier\n * @param {string[]} filters - Array of filter values\n * @param {string} [operator='OR'] - Operator within group ('AND' or 'OR')\n * @returns {boolean} Success status\n */\n addFilterGroup(groupId, filters, operator = \"OR\") {\n try {\n // Validate inputs\n if (!groupId || !Array.isArray(filters)) {\n this.log('error', 'Invalid group ID or filters');\n return false;\n }\n\n const validOperator = operator.toUpperCase();\n if (![\"AND\", \"OR\"].includes(validOperator)) {\n this.log('error', 'Invalid operator:', operator);\n operator = \"OR\";\n }\n\n // Create or update group\n this.filterGroups.set(groupId, {\n filters: new Set(filters),\n operator: validOperator,\n });\n\n // Only update if we have active groups\n if (this.filterGroups.size > 0) {\n this.updateFiltersFromGroups();\n this.filter();\n this.updateURL();\n }\n\n return true;\n } catch (error) {\n this.log('error', 'Error adding filter group:', error);\n return false;\n }\n }\n\n /**\n * Set how groups combine with each other\n * @public\n * @param {string} mode - Mode for combining groups ('AND' or 'OR')\n */\n setGroupMode(mode) {\n const validMode = mode.toUpperCase();\n if ([\"AND\", \"OR\"].includes(validMode)) {\n this.groupMode = validMode;\n if (this.filterGroups.size > 0) {\n this.filter();\n }\n }\n }\n\n /**\n * Remove a filter group\n * @public\n * @param {string} groupId - Group identifier\n * @returns {boolean} Success status\n */\n removeFilterGroup(groupId) {\n if (this.filterGroups.has(groupId)) {\n this.filterGroups.delete(groupId);\n\n // If no groups left, revert to normal filtering\n if (this.filterGroups.size === 0) {\n this.resetFilters();\n } else {\n this.updateFiltersFromGroups();\n }\n\n this.filter();\n this.updateURL();\n return true;\n }\n return false;\n }\n\n /**\n * Update filters based on groups\n * @private\n */\n updateFiltersFromGroups() {\n // Only process if we have groups\n if (this.filterGroups.size === 0) return;\n\n // Clear current filters except '*'\n if (!this.currentFilters.has(\"*\")) {\n this.currentFilters.clear();\n }\n\n // Combine all group filters\n for (const group of this.filterGroups.values()) {\n group.filters.forEach((filter) => {\n if (filter !== \"*\") {\n this.currentFilters.add(filter);\n }\n });\n }\n }\n\n /**\n * Check if item matches any active filter (OR mode)\n * @private\n * @param {Set} itemCategories - Item's categories\n * @returns {boolean} Whether item matches any filter\n */\n matchesAnyFilter(itemCategories) {\n return [...this.currentFilters].some((filter) => {\n const [type, value] = filter.split(\":\");\n return itemCategories.has(`${type}:${value}`);\n });\n }\n\n /**\n * Check if item matches all active filters (AND mode)\n * @private\n * @param {Set} itemCategories - Item's categories\n * @returns {boolean} Whether item matches all filters\n */\n matchesAllFilters(itemCategories) {\n return [...this.currentFilters].every((filter) => {\n const [type, value] = filter.split(\":\");\n return itemCategories.has(`${type}:${value}`);\n });\n }\n\n /**\n * Show an item with animation\n * @private\n * @param {HTMLElement} item - Item to show\n */\n showItem(item) {\n this.visibleItems.add(item);\n item.classList.remove(this.options.hiddenClass);\n item.style.opacity = \"0\";\n item.style.transform = \"scale(0.95)\";\n\n item.offsetHeight;\n\n requestAnimationFrame(() => {\n item.style.opacity = \"1\";\n item.style.transform = \"scale(1)\";\n });\n }\n\n /**\n * Hide an item with animation\n * @private\n * @param {HTMLElement} item - Item to hide\n */\n hideItem(item) {\n item.style.opacity = \"0\";\n item.style.transform = \"scale(0.95)\";\n\n setTimeout(() => {\n if (item.style.opacity === \"0\") {\n item.classList.add(this.options.hiddenClass);\n this.visibleItems.delete(item);\n }\n }, this.options.animationDuration);\n }\n\n /**\n * Search items by text\n * @public\n * @param {string} query - Search query\n */\n search(query) {\n this.log('debug', 'Performing search with query:', query);\n\n this.currentSearch = query.toLowerCase().trim();\n let matches = 0;\n\n this.items.forEach((item) => {\n const searchText = this.options.searchKeys\n .map((key) => item.dataset[key] || \"\")\n .join(\" \")\n .toLowerCase();\n\n const matchesSearch =\n this.currentSearch === \"\" || searchText.includes(this.currentSearch);\n\n if (matchesSearch) {\n this.showItem(item);\n matches++;\n } else {\n this.hideItem(item);\n }\n });\n\n this.updateURL();\n this.log('info', `Search complete. Found ${matches} matches`);\n\n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n }\n\n /**\n * Sort items by multiple criteria\n * @public\n * @param {Array<{key: string, direction: string}>} criteria - Sort criteria\n */\n sortMultiple(criteria) {\n const items = [...this.items];\n\n items.sort((a, b) => {\n for (const criterion of criteria) {\n const valueA = a.dataset[criterion.key];\n const valueB = b.dataset[criterion.key];\n\n const comparison =\n criterion.direction === \"asc\"\n ? valueA.localeCompare(valueB)\n : valueB.localeCompare(valueA);\n\n if (comparison !== 0) return comparison;\n }\n return 0;\n });\n\n items.forEach((item) => this.container.appendChild(item));\n\n this.log('debug', 'Sorting items by multiple criteria:', criteria);\n }\n\n /**\n * Filter items by numeric range\n * @public\n * @param {string} key - Data attribute key\n * @param {number} min - Minimum value\n * @param {number} max - Maximum value\n */\n addRangeFilter(key, min, max) {\n this.items.forEach((item) => {\n const value = parseFloat(item.dataset[key]);\n const inRange = value >= min && value <= max;\n\n if (inRange) {\n this.showItem(item);\n } else {\n this.hideItem(item);\n }\n });\n\n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n\n this.log('debug', `Filtering items by range: ${key} between ${min} and ${max}`);\n }\n\n /**\n * Check if item matches filter groups\n * @private\n * @param {Set} itemCategories - Item's categories\n * @returns {boolean} Whether item matches the group filters\n */\n matchesFilterGroups(itemCategories) {\n const groupMatches = [...this.filterGroups.values()].map((group) => {\n const groupFilters = [...group.filters];\n if (groupFilters.length === 0) return true;\n\n return group.operator === \"OR\"\n ? groupFilters.some((filter) => itemCategories.has(filter))\n : groupFilters.every((filter) => itemCategories.has(filter));\n });\n\n return this.groupMode === \"OR\"\n ? groupMatches.some((matches) => matches)\n : groupMatches.every((matches) => matches);\n }\n\n /**\n * Update URL with current filter state\n * @private\n */\n updateURL() {\n this.log('debug', 'Updating URL');\n\n // If only \"*\" filter is active or no filters are active, clear the URL\n if (\n this.currentFilters.size === 0 ||\n (this.currentFilters.size === 1 && this.currentFilters.has(\"*\"))\n ) {\n window.history.pushState({}, \"\", window.location.pathname);\n return;\n }\n\n const params = new URLSearchParams(window.location.search);\n\n // Add groups to URL if they exist\n if (this.filterGroups.size > 0) {\n for (const [groupId, group] of this.filterGroups.entries()) {\n params.set(`group_${groupId}`, [...group.filters].join(\",\"));\n params.set(`groupOp_${groupId}`, group.operator.toLowerCase());\n }\n params.set(\"groupMode\", this.groupMode.toLowerCase());\n }\n\n // Separate filters by type\n const filtersByType = {};\n for (const filter of this.currentFilters) {\n if (filter !== \"*\") {\n const [type, value] = filter.split(\":\");\n if (!filtersByType[type]) {\n filtersByType[type] = new Set();\n }\n filtersByType[type].add(value);\n }\n }\n\n // Add each filter type to the URL\n Object.entries(filtersByType).forEach(([type, values]) => {\n params.set(type, Array.from(values).join(\",\"));\n });\n\n if (this.currentSearch) {\n params.set(\"search\", this.currentSearch);\n }\n\n const newURL = `${window.location.pathname}${\n params.toString() ? \"?\" + params.toString() : \"\"\n }`;\n window.history.pushState({}, \"\", newURL);\n this.log('debug', 'URL updated:', newURL);\n }\n\n /**\n * Load filter state from URL\n * @private\n */\n loadFromURL() {\n this.log('debug', 'Loading state from URL');\n const params = new URLSearchParams(window.location.search);\n\n // Load groups if they exist\n this.filterGroups.clear();\n for (const [key, value] of params.entries()) {\n if (key.startsWith(\"group_\")) {\n const groupId = key.replace(\"group_\", \"\");\n const operator =\n params.get(`groupOp_${groupId}`)?.toUpperCase() || \"OR\";\n const filters = value.split(\",\");\n this.addFilterGroup(groupId, filters, operator);\n }\n }\n\n // Set group mode if present\n const groupMode = params.get(\"groupMode\")?.toUpperCase();\n if (groupMode && [\"AND\", \"OR\"].includes(groupMode)) {\n this.groupMode = groupMode;\n }\n\n this.currentFilters.clear();\n\n // Si aucun filtre n'est présent, utiliser '*'\n let hasFilters = false;\n\n // Parcourir tous les paramètres\n for (const [type, values] of params.entries()) {\n if (type !== \"search\") {\n hasFilters = true;\n values.split(\",\").forEach((value) => {\n this.currentFilters.add(`${type}:${value}`);\n });\n }\n }\n\n if (!hasFilters) {\n this.currentFilters.add(\"*\");\n }\n\n // Update active buttons\n this.filterButtons.forEach((button) => {\n const filterValue = button.dataset.filter;\n if (\n this.currentFilters.has(filterValue) ||\n (filterValue === \"*\" && this.currentFilters.has(\"*\"))\n ) {\n button.classList.add(this.options.activeClass);\n } else {\n button.classList.remove(this.options.activeClass);\n }\n });\n\n // Load search\n const search = params.get(\"search\") || \"\";\n if (this.searchInput) {\n this.searchInput.value = search;\n }\n\n this.filter();\n if (search) {\n this.search(search);\n }\n\n this.log('info', 'State loaded from URL');\n }\n\n /**\n * Update results counter\n * @private\n * @returns {{total: number, visible: number}}\n */\n updateCounter() {\n const total = this.items.length;\n const visible = this.visibleItems.size;\n\n if (this.counter) {\n this.counter.textContent = `Showing ${visible} of ${total}`;\n }\n \n this.log('debug', `Counter updated: ${visible}/${total}`);\n return { total, visible };\n }\n\n /**\n * Set animation options\n * @public\n * @param {Object} options - Animation options\n */\n setAnimationOptions(options = {}) {\n this.options.animationDuration =\n options.duration || this.options.animationDuration;\n this.options.animationType = options.type || \"ease-out\";\n this.addStyles(); // Refresh styles with new options\n }\n\n /**\n * Event handling system\n */\n addEventSystem() {\n this.events = {};\n\n this.on = (eventName, callback) => {\n if (!this.events[eventName]) {\n this.events[eventName] = [];\n }\n this.events[eventName].push(callback);\n };\n\n this.emit = (eventName, data) => {\n if (this.events[eventName]) {\n this.events[eventName].forEach((callback) => callback(data));\n }\n };\n }\n\n /**\n * Add pagination\n * @public\n * @param {number} itemsPerPage - Number of items per page\n */\n setPagination(itemsPerPage) {\n this.pagination = {\n currentPage: 1,\n itemsPerPage: itemsPerPage,\n totalPages: Math.ceil(this.visibleItems.size / itemsPerPage),\n };\n this.updatePagination();\n }\n\n updatePagination() {\n const start =\n (this.pagination.currentPage - 1) * this.pagination.itemsPerPage;\n const end = start + this.pagination.itemsPerPage;\n\n [...this.visibleItems].forEach((item, index) => {\n if (index >= start && index < end) {\n this.showItem(item);\n } else {\n this.hideItem(item);\n }\n });\n }\n\n /**\n * Enable analytics tracking\n * @public\n * @param {Function} callback - Analytics callback function\n */\n enableAnalytics(callback) {\n this.analyticsCallback = callback;\n this.on(\"filter\", (data) => {\n this.analyticsCallback({\n type: \"filter\",\n filters: [...this.currentFilters],\n visibleItems: this.visibleItems.size,\n timestamp: new Date().toISOString(),\n });\n });\n }\n\n /**\n * Sort with custom comparator\n * @public\n * @param {string} key - Data attribute key\n * @param {Function} comparator - Custom comparison function\n */\n sortWithComparator(key, comparator) {\n const items = [...this.items];\n items.sort((a, b) => {\n const valueA = a.dataset[key];\n const valueB = b.dataset[key];\n return comparator(valueA, valueB);\n });\n items.forEach((item) => this.container.appendChild(item));\n }\n\n /**\n * Add responsive behavior\n * @public\n * @param {Object} breakpoints - Breakpoint configurations\n */\n setResponsiveOptions(breakpoints) {\n window.addEventListener(\n \"resize\",\n debounce(() => {\n const width = window.innerWidth;\n for (const [breakpoint, options] of Object.entries(breakpoints)) {\n if (width <= parseInt(breakpoint)) {\n Object.assign(this.options, options);\n this.filter();\n break;\n }\n }\n }, 250),\n );\n }\n\n /**\n * Enable keyboard navigation\n * @public\n */\n enableKeyboardNavigation() {\n document.addEventListener(\"keydown\", (e) => {\n if (\n e.key === \"Enter\" &&\n document.activeElement.classList.contains(\n this.options.filterButtonSelector.slice(1),\n )\n ) {\n document.activeElement.click();\n }\n });\n }\n\n /**\n * Export current filter state\n * @public\n * @returns {Object} Filter state\n */\n exportState() {\n return {\n filters: [...this.currentFilters],\n search: this.currentSearch,\n mode: this.options.filterMode,\n timestamp: new Date().toISOString(),\n };\n }\n\n /**\n * Import filter state\n * @public\n * @param {Object} state - Filter state to import\n */\n importState(state) {\n if (state.filters) {\n this.currentFilters = new Set(state.filters);\n this.currentSearch = state.search || \"\";\n this.options.filterMode = state.mode || \"OR\";\n this.filter();\n this.updateURL();\n }\n }\n\n /**\n * Save current filter state as preset\n * @public\n * @param {string} presetName - Name of the preset\n */\n savePreset(presetName) {\n const preset = {\n filters: [...this.currentFilters],\n search: this.currentSearch,\n mode: this.options.filterMode,\n };\n localStorage.setItem(`afs_preset_${presetName}`, JSON.stringify(preset));\n\n this.log('info', `Preset saved: ${presetName}`);\n }\n\n /**\n * Load filter preset\n * @public\n * @param {string} presetName - Name of the preset to load\n */\n loadPreset(presetName) {\n const preset = JSON.parse(localStorage.getItem(`afs_preset_${presetName}`));\n if (preset) {\n this.currentFilters = new Set(preset.filters);\n this.currentSearch = preset.search;\n this.options.filterMode = preset.mode;\n this.filter();\n this.updateURL();\n }\n }\n\n /**\n * Set filter logic mode (alias for setFilterMode)\n * @public\n * @param {string} logic - New filter logic ('AND' or 'OR')\n */\n setLogic(logic) {\n if (typeof logic === \"boolean\") {\n // Handle boolean input (true = AND, false = OR)\n this.options.filterMode = logic ? \"AND\" : \"OR\";\n this.filter();\n return;\n }\n\n const mode = logic.toUpperCase();\n if ([\"OR\", \"AND\"].includes(mode)) {\n this.options.filterMode = mode;\n this.filter();\n }\n }\n\n /**\n * Change filter mode\n * @public\n * @param {string} mode - New filter mode ('OR' or 'AND')\n */\n setFilterMode(mode) {\n if ([\"OR\", \"AND\"].includes(mode.toUpperCase())) {\n this.options.filterMode = mode.toUpperCase();\n this.filter();\n }\n }\n\n /**\n * Add filter by type and value\n * @public\n * @param {string} type - Filter type\n * @param {string} value - Filter value\n */\n addFilter(type, value) {\n this.currentFilters.add(`${type}:${value}`);\n this.filter();\n this.updateURL();\n }\n\n /**\n * Remove filter by type and value\n * @public\n * @param {string} type - Filter type\n */\n removeFilter(type, value) {\n this.currentFilters.delete(`${type}:${value}`);\n if (this.currentFilters.size === 0) {\n this.currentFilters.add(\"*\");\n }\n this.filter();\n this.updateURL();\n }\n\n /**\n * Get active filters by type\n * @public\n * @param {string} type - Filter type\n */\n getActiveFiltersByType(type) {\n return [...this.currentFilters]\n .filter((filter) => filter.startsWith(`${type}:`))\n .map((filter) => filter.split(\":\")[1]);\n }\n\n /**\n * Clear all filters, url and search\n *\n * @public\n */\n clearAllFilters() {\n this.currentFilters.clear();\n this.currentFilters.add(\"*\");\n this.filter();\n this.updateURL();\n\n // Uncheck all checkboxes if any with activeClass\n const checkboxes = document.querySelectorAll('input[type=\"checkbox\"]');\n checkboxes.forEach((checkbox) => {\n if (checkbox.classList.contains(this.options.activeClass)) {\n checkbox.checked = false;\n checkbox.classList.remove(this.options.activeClass);\n }\n });\n\n // Clear active on buttons\n this.filterButtons.forEach((btn) => {\n btn.classList.remove(this.options.activeClass);\n });\n\n // Clear search input\n if (this.searchInput) {\n this.searchInput.value = \"\";\n }\n\n this.log('info', 'All filters cleared');\n }\n}\n\nexport { AFS };\n"],"names":["debounce","func","wait","timeout","_len","arguments","length","args","Array","_key","clearTimeout","setTimeout","later","constructor","options","undefined","this","containerSelector","itemSelector","filterButtonSelector","searchInputSelector","counterSelector","activeClass","hiddenClass","animationDuration","filterMode","searchKeys","debounceTime","debug","logLevel","logLevels","error","warn","info","container","document","querySelector","items","querySelectorAll","sortOrders","filterButtons","searchInput","counter","currentFilters","Set","currentSearch","visibleItems","filterGroups","Map","groupMode","log","init","level","currentLevelValue","timestamp","Date","toISOString","prefix","toUpperCase","_len2","_key2","console","setDebugMode","enabled","hasOwnProperty","addStyles","bindEvents","loadFromURL","updateCounter","styles","styleSheet","createElement","textContent","head","appendChild","forEach","button","addEventListener","handleFilterClick","e","search","target","value","window","filterValue","dataset","filter","resetFilters","toggleFilter","updateURL","btn","classList","remove","clear","add","resetCounter","delete","contains","size","history","pushState","location","pathname","sortWithOrder","key","newOrder","sort","a","b","valueA","valueB","isNumeric","isNaN","parseFloat","localeCompare","item","shuffle","itemsArray","i","j","Math","floor","random","standardFilter","has","showItem","itemCategories","categories","split","matchesAnyFilter","matchesAllFilters","hideItem","matchesFilterGroups","addFilterGroup","groupId","filters","operator","isArray","validOperator","includes","set","updateFiltersFromGroups","setGroupMode","mode","validMode","removeFilterGroup","group","values","some","type","every","style","opacity","transform","offsetHeight","requestAnimationFrame","query","toLowerCase","trim","matches","searchText","map","join","sortMultiple","criteria","criterion","comparison","direction","addRangeFilter","min","max","groupMatches","groupFilters","params","URLSearchParams","entries","filtersByType","Object","_ref","from","newURL","toString","startsWith","replace","get","hasFilters","total","visible","setAnimationOptions","duration","animationType","addEventSystem","events","on","eventName","callback","push","emit","data","setPagination","itemsPerPage","pagination","currentPage","totalPages","ceil","updatePagination","start","end","index","enableAnalytics","analyticsCallback","sortWithComparator","comparator","setResponsiveOptions","breakpoints","width","innerWidth","breakpoint","parseInt","assign","enableKeyboardNavigation","activeElement","slice","click","exportState","importState","state","savePreset","presetName","preset","localStorage","setItem","JSON","stringify","loadPreset","parse","getItem","setLogic","logic","setFilterMode","addFilter","removeFilter","getActiveFiltersByType","clearAllFilters","checkbox","checked"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "advanced-filter-system",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Advanced filtering system for DOM elements with multiple features",
5
5
  "main": "dist/AFS.js",
6
6
  "module": "dist/AFS.esm.js",