Blog Filters

Category Filter

Filter by Category
All Categories
AI
Cloud
Company
Customer Stories
Design
Development
Digital Signatures
Insights
Integrations
Learning
Low-Code
News
Performance
Productivity
Products
Releases
SDK
Security
Solutions
Tutorials
Web
Workflow
visionOS
'; return; } // Batch DOM operations using DocumentFragment and DRY utilities filteredOptions.forEach((option) => { const optionEl = OptionCreator.createOption(option); fragment.appendChild(optionEl); }); // Single DOM update for better performance dropdown.innerHTML = ""; dropdown.appendChild(fragment); } // Add a tag function addTag(value) { const option = Array.from(select.options).find( (opt) => opt.value === value, ); if (option) { option.selected = true; } updateSelectedTags(); updateURL(); } // Remove a tag function removeTag(value) { const option = Array.from(select.options).find( (opt) => opt.value === value, ); if (option) { option.selected = false; } updateSelectedTags(); updateURL(); // Refresh the dropdown to show the newly available tag populateDropdown( document.querySelector(".tag-multi-select-input")?.value || "", ); // If the input is focused, make sure the dropdown stays visible const input = document.querySelector(".tag-multi-select-input"); if (input && document.activeElement === input) { dropdownManager.show("tags"); } } // Update the URL with selected tags function updateURL() { const selectedValues = Array.from(select.selectedOptions).map( (option) => option.value, ); // Get current URL and params const url = new URL(window.location.href); const pathParts = url.pathname.split("/").filter(Boolean); // If we're on an overview page and tags are selected, redirect to the category page if (isOverviewPageValue && selectedValues.length > 0) { // Get the category name from the current URL path const categoryFromPath = pathParts[pathParts.length - 1]; // Create the new URL for the categories page const newUrl = new URL(window.location.origin); newUrl.pathname = `/blog/categories/${categoryFromPath}/`; if (selectedValues.length > 0) { // Convert tags to URL-friendly format const tagsValue = selectedValues .map((tag) => encodeURIComponent(tag)) .join(","); newUrl.searchParams.set("tags", tagsValue); } // Force a page reload to the new URL window.location.replace(newUrl.toString()); return; // Stop here since we're redirecting } // For non-overview pages, just update the URL if (selectedValues.length > 0) { // Convert tags to URL-friendly format const tagsValue = selectedValues .map((tag) => encodeURIComponent(tag)) .join(","); url.searchParams.set("tags", tagsValue); } else { url.searchParams.delete("tags"); } // Update the URL without refreshing the page window.history.pushState({}, "", url.toString()); // Update post visibility based on selected tags updatePostVisibility(selectedValues); // Dispatch a custom event to notify that tags have changed const event = new CustomEvent("tagsChanged", { detail: { tags: selectedValues, category: pathParts[pathParts.length - 1] || "", }, }); document.dispatchEvent(event); } // Function to update post visibility based on selected tags function updatePostVisibility(selectedTags) { // Find all blog post list containers const containers = document.querySelectorAll("[id^='blog-post-list-']"); containers.forEach((container) => { const componentId = container.id; const showMoreButton = document.getElementById( `${componentId}-show-more`, ); const showAllButton = document.getElementById( `${componentId}-show-all`, ); const noMoreMessage = document.getElementById(`${componentId}-no-more`); const allPosts = container.querySelectorAll(".post-item"); // If no tags selected, reset to initial infinite scroll state if (selectedTags.length === 0) { const itemsPerPage = showMoreButton ? parseInt( showMoreButton.getAttribute("data-items-per-page") || "12", 10, ) : 12; // Batch DOM operations for better performance const postsToShow = Array.from(allPosts).slice(0, itemsPerPage); const postsToHide = Array.from(allPosts).slice(itemsPerPage); requestAnimationFrame(() => { postsToShow.forEach((post) => post.classList.remove("hidden-post")); postsToHide.forEach((post) => post.classList.add("hidden-post")); }); // Reset buttons if (showMoreButton) { showMoreButton.style.display = allPosts.length > itemsPerPage ? "inline-block" : "none"; showMoreButton.setAttribute("data-current-page", "1"); } if (showAllButton) { showAllButton.style.display = allPosts.length > itemsPerPage ? "inline-block" : "none"; } if (noMoreMessage) { noMoreMessage.classList.add("hidden"); } return; } // Convert selected tags to lowercase for comparison const selectedTagsLower = selectedTags.map((tag) => tag.toLowerCase()); // Batch DOM operations using requestAnimationFrame for better performance const postsToShow = []; const postsToHide = []; // First pass: determine which posts to show/hide without DOM manipulation allPosts.forEach((post) => { const postTagsAttr = post .querySelector("[data-tags]") ?.getAttribute("data-tags"); if (!postTagsAttr) return; try { const postTags = JSON.parse(postTagsAttr).map((tag) => tag.toLowerCase(), ); const hasMatchingTag = postTags.some((tag) => selectedTagsLower.includes(tag), ); if (hasMatchingTag) { postsToShow.push(post); } else { postsToHide.push(post); } } catch (e) { console.error("Error parsing post tags:", e); } }); // Second pass: batch apply changes in requestAnimationFrame requestAnimationFrame(() => { postsToShow.forEach((post) => post.classList.remove("hidden-post")); postsToHide.forEach((post) => post.classList.add("hidden-post")); }); // Update button visibility if (showMoreButton) showMoreButton.style.display = "none"; if (showAllButton) showAllButton.style.display = "none"; if (noMoreMessage) noMoreMessage.classList.remove("hidden"); }); } } })();


blog archive

View all blog posts