function Columns(q, setup) { var itemFnClass = "columns-col" var dafaultSetup = { count: 4, gap: [12, 12], imageLoad: true, } if (typeof setup == "undefined") { setup = dafaultSetup } var el = document.querySelectorAll(q); el.forEach(function (holder) { holder.style.position = "relative" holder.style.display = "block" if (typeof setup == "undefined" || typeof setup.imageLoad == "undefined" || setup.imageLoad == true) { var columnImgs = document.querySelectorAll("img"); if (columnImgs.length > 0) { columnImgs.forEach(function (columnImg) { if (!columnImg.complete) { columnImg.addEventListener("load", function () { alignColsItems() }); } }) } } }) window.addEventListener('resize', alignColsItems); alignColsItems() function alignColsItems() { el.forEach(function (holder, index) { var items = holder.querySelectorAll(setup.itemClass ? "." + setup.itemClass : ":scope > *"), holderWidth = holder.clientWidth, cols = (!setup.count) ? dafaultSetup.count : setup.count, gap = (!setup.gap) ? [...dafaultSetup.gap] : (typeof setup.gap === 'number') ? [setup.gap, setup.gap] : [...setup.gap], currentView = 0, colWidth if (items.length > 0) { if (typeof setup.breakpoints === 'object') { var viewpoints = Object.keys(setup.breakpoints) if (viewpoints.length > 0) for (i = 0; i < viewpoints.length; i++) { if (window.innerWidth >= parseInt(viewpoints[i])) { currentView = i + 1 if (setup.breakpoints[viewpoints[i]].count) { cols = setup.breakpoints[viewpoints[i]].count } if (typeof setup.breakpoints[viewpoints[i]].gap === 'object') { gap = [...setup.breakpoints[viewpoints[i]].gap] } else if (typeof setup.breakpoints[viewpoints[i]].gap === 'number') { gap = [setup.breakpoints[viewpoints[i]].gap, setup.breakpoints[viewpoints[i]].gap] } } } } // console.log("currentView", currentView, "gap", gap, "col", cols) colWidth = (holderWidth - ((cols - 1) * gap[0])) / cols resetItems() // ================================ items foreach START ================================ items.forEach(function (item, index) { // console.log("item index", index) if (item.style.display === "none") return var itemCol = 0, itemSpan = 1, itemStyle = {} if (item.getAttribute("data-col-span")) { if (item.dataset.colSpan === "full") itemSpan = cols else { var itemsCountSet = item.dataset.colSpan.split(',') if (!itemsCountSet[currentView]) itemSpan = parseInt(itemsCountSet[itemsCountSet.length - 1]) else itemSpan = parseInt(itemsCountSet[currentView]) itemSpan = (itemSpan > cols) ? cols : itemSpan } } // console.log("itemSpan", itemSpan) if (itemSpan == 1) { // console.log("itemSpan", itemSpan) for (var i = 0; i < cols; i++) { if (colHeight(i) == 0) { itemCol = i break; } else if (colHeight(i) < colHeight(itemCol)) { itemCol = i; } } // console.log(colHeight(itemCol)) itemStyle = { top: colHeight(itemCol), left: (colWidth + gap[0]) * itemCol, width: colWidth, class: itemFnClass + "-" + (itemCol + 1) } } else { if (itemSpan == cols) { itemStyle.width = holderWidth; itemStyle.top = colHeight(itemCol); itemStyle.left = 0; itemStyle.classes = []; for (var i = 0; i < cols; i++) { if (itemStyle.top < colHeight(i)) { itemStyle.top = colHeight(i) } itemStyle.classes.push(itemFnClass + "-" + (itemCol + 1 + i)) } } else { var t = false for (var i = 0; i < cols - itemSpan + 1; i++) { var setHeight = colHeight(i) if (itemSpan < cols && setHeight == 0) { itemCol = i break; } for (var j = 0; j < itemSpan; j++) { var shdCheck = i + j if (setHeight < colHeight(shdCheck)) setHeight = colHeight(shdCheck) } if (!t || setHeight < t) { t = setHeight itemCol = i itemStyle.top = setHeight } } itemStyle.left = (colWidth + gap[0]) * itemCol itemStyle.width = colWidth * itemSpan + (gap[0] * (itemSpan - 1)) itemStyle.classes = [] for (var i = 0; i < itemSpan; i++) { itemStyle.classes.push(itemFnClass + "-" + (itemCol + 1 + i)) } } if (setup.autoHeight == true && index + itemSpan > cols && itemSpan > 1) { // console.log("Current item-" + (index + 1) + " classes: ", itemStyle.classes) blankCols = [] itemStyle.classes.forEach(function (broClass) { var broItems = holder.querySelectorAll("." + broClass), lastBro = broItems[broItems.length - 1] if (typeof lastBro != "undefined") { var lastBroCol = parseInt(lastBro.dataset.itemCol), lastBroSpan = parseInt(lastBro.dataset.colSpanCurrent) // console.log("brother item ", parseInt(lastBro.dataset.itemIndex) + 1 + " ---- column: ", lastBroCol, "; span: ", lastBroSpan) if (lastBroSpan > 1) { if ((lastBroCol - 1) + lastBroSpan < itemCol + itemSpan) { var shdResize = true, blankCol = [] for (var i = lastBroCol; i < lastBroCol + lastBroSpan; i++) { if (colLastItem(i).dataset.itemIndex != lastBro.dataset.itemIndex) shdResize = false else { if (setup.fillBlocker) blankCol.push(i) } } if (shdResize) { lastBro.style.height = (itemStyle.top - lastBro.getBoundingClientRect().top + holder.getBoundingClientRect().top) + "px" } else if (setup.fillBlocker) { blankCols.push(blankCol) } } } else { lastBro.style.height = (itemStyle.top - lastBro.getBoundingClientRect().top + holder.getBoundingClientRect().top) + "px" } } }) // if (setup.fillBlocker && blankCols.length) { // console.log(blankCols) // } } } item.dataset.itemIndex = index item.dataset.colSpanCurrent = itemSpan item.dataset.itemCol = itemCol item.style.position = "absolute" item.style.top = (isColFirst() ? 0 : itemStyle.top + gap[1]) + "px" item.style.left = itemStyle.left + "px" item.style.width = itemStyle.width + "px" if (typeof itemStyle.classes == "object") { itemStyle.classes.forEach(function (itemClass) { item.classList.add(itemClass) }) } else item.classList.add(itemStyle.class) function isColFirst() { return (holder.querySelectorAll("." + itemFnClass + "-" + (itemCol + 1)).length == 0) } function colLastItem(col) { var colItems = holder.querySelectorAll("." + itemFnClass + "-" + (col + 1)) if (!colItems[colItems.length - 1]) { return false } else { return colItems[colItems.length - 1] } } }) // ================================ items foreach END ================================ var holderHeight = colHeight(0) for (var i = 1; i < cols; i++) { if (holderHeight < colHeight(i)) holderHeight = colHeight(i) } holder.style.height = (holderHeight) ? holderHeight + "px" : null // ================================ Common function START ================================ function colHeight(col) { var colItems = holder.querySelectorAll("." + itemFnClass + "-" + (col + 1)) if (colItems.length == 0) return 0 var colLastItems = colItems[colItems.length - 1], holderOffset = holder.getBoundingClientRect().top return colLastItems.getBoundingClientRect().bottom - holderOffset } function resetItems() { items.forEach(function (item) { item.dataset.colSpanCurrent = null item.dataset.itemCol = null item.style.top = null item.style.left = null item.style.width = null item.style.height = null for (var i = 0; i < cols; i++) { item.classList.remove(itemFnClass + "-" + (i + 1)); } }) } // ================================ Common function END ================================ } }) } function destroy() { document.querySelectorAll(q).forEach(function (holder) { holder.style.position = null holder.style.display = null }) } return { "Columns": setup, "updateItems": alignColsItems, "destroy": destroy } }