PageSourceSearch

https://copenhagenbamboo.se/cdn/shop/t/108/assets/items-scroll.js?v=124158216695031153151789967996

js copenhagenbamboo.se collected 2026-09-27 06:36:44 UTC 9,755 bytes, 5 lines download raw bytes

1/*! Copyright (c) Safe As Milk. All rights reserved. */import{BREAKPOINTS,debounce}from"utils";class ItemsScroll extends HTMLElement{items;scrollBar;scrollBarTrack;navigationContainer;navigationPrevButton;navigationNextButton;pageNavigationContainer;#isScrollBarDragged;#boundScrollStart;#boundScrollEnd;#itemsPerPage;#controlsListenersEnabled;#boundPrevNavigationAction;#boundNextNavigationAction;#isNavigating=!1;#scrollPosition=0;#navigationStateControlObserver;#itemsMutationObserver;#resizeObserver;#imageContainerRatio;static observedAttributes=["scrollable"];constructor(){super(),this.items=this.querySelector("[data-items]"),this.breakpointMin=Object.keys(BREAKPOINTS).includes(this.getAttribute("breakpoint-min"))?BREAKPOINTS[this.getAttribute("breakpoint-min")]:Number(this.getAttribute("breakpoint-min")||"0"),this.breakpointMax=Object.keys(BREAKPOINTS).includes(this.getAttribute("breakpoint-max"))?BREAKPOINTS[this.getAttribute("breakpoint-max")]:Number(this.getAttribute("breakpoint-max")||"Infinity"),this.pageNavigationWrapper=null,this.navigationContainer=null,this.navigationPrevButton=null,this.navigationNextButton=null,this.snap=this.getAttribute("snap"),this.#boundPrevNavigationAction=null,this.#boundNextNavigationAction=null,this.#controlsListenersEnabled=!1,this.#navigationStateControlObserver=null,this.#itemsMutationObserver=null,this.#resizeObserver=null,this.#boundScrollStart=this.#handleScrollStart.bind(this),this.#boundScrollEnd=this.#handleScrollEnd.bind(this)}connectedCallback(){if(!this.items)throw Error("Items container missing");this.#scrollPosition=this.items.scrollLeft,this.#resizeObserver=new ResizeObserver(debounce((()=>{this.#updateControls()})),50),this.#resizeObserver.observe(this.items),this.#navigationStateControlObserver||this.#setUpNavigationStateControl(),this.#itemsMutationObserver||this.#setUpItemsMutationObserver(),this.#imageContainerRatio=this.getAttribute("image-container-ratio"),this.items.addEventListener("scroll",this.#boundScrollStart,{once:!0}),this.items.addEventListener("scrollend",this.#boundScrollEnd)}disconnectedCallback(){this.items.removeEventListener("scroll",this.#boundScrollStart),this.items.removeEventListener("scrollend",this.#boundScrollEnd),this.#navigationStateControlObserver&&(this.#navigationStateControlObserver.disconnect(),this.#navigationStateControlObserver=null),this.#itemsMutationObserver&&(this.#itemsMutationObserver.disconnect(),this.#itemsMutationObserver=null),this.#resizeObserver&&(this.#resizeObserver.disconnect(),this.#resizeObserver=null)}attributeChangedCallback(name,oldValue,newValue){name==="scrollable"&&oldValue!==newValue&&this.dispatchEvent(new CustomEvent("on:items-scroll:change-state",{detail:{scrollable:this.hasAttribute("scrollable")}}))}get isNavigating(){return this.#isNavigating}get itemAtScroll(){return this.#getItemAtScroll()}get itemsPerPage(){return this.#itemsPerPage}#getItemAtScroll(){const itemsComputedStyle=window.getComputedStyle(this.items),itemsGap=Number(itemsComputedStyle.getPropertyValue("column-gap").replace("px","")),itemComputedStyle=window.getComputedStyle(this.items.firstElementChild),itemMarginLeft=Number(itemComputedStyle.getPropertyValue("margin-left").replace("px","")),itemMarginRight=Number(itemComputedStyle.getPropertyValue("margin-right").replace("px",""));return Array.from(this.items.children)[Math.round(this.items.scrollLeft/(itemMarginLeft+this.items.firstElementChild.getBoundingClientRect().width+itemMarginRight+itemsGap))]}#createNavigation(){const navigationContainer=document.createElement("div");navigationContainer.classList.add("navigation"),navigationContainer.innerHTML=`
2      <button type="button" class="navigation__button navigation__button--prev" data-navigation-prev aria-label="Previous page"></button>
3      <button type="button" class="navigation__button navigation__button--next" data-navigation-next aria-label="Next page"></button>
4    `,this.appendChild(navigationContainer),this.navigationContainer=navigationContainer,this.navigationPrevButton=navigationContainer.querySelector("[data-navigation-prev]"),this.navigationNextButton=navigationContainer.querySelector("[data-navigation-next]");const arrowPreviousSVG=document.getElementById("template-icon-chevron").content.cloneNode(!0).firstElementChild;arrowPreviousSVG.classList.add("icon--left"),this.navigationPrevButton.append(arrowPreviousSVG);const arrowNextSVG=document.getElementById("template-icon-chevron").content.cloneNode(!0).firstElementChild;this.navigationNextButton.append(arrowNextSVG)}#handlePrevNavigationAction(e){if(e.preventDefault(),this.#isNavigating)return;const previousItem=this.#getItemAtScroll().previousElementSibling;previousItem&&this.smoothScrollItems(previousItem.offsetLeft)}#handleNextNavigationAction(e){if(e.preventDefault(),this.#isNavigating)return;const nextItem=this.#getItemAtScroll().nextElementSibling;nextItem&&this.smoothScrollItems(nextItem.offsetLeft)}#handleScrollStart(){const direction=this.items.scrollLeft>this.#scrollPosition?"FORWARD":"BACKWARD";this.#isNavigating=!0,this.classList.add("is-scrolling"),this.dispatchEvent(new CustomEvent("on:items-scroll:scroll-start",{detail:{direction}}))}#handleScrollEnd(){const position=this.items.scrollLeft,direction=position>this.#scrollPosition?"FORWARD":"BACKWARD";this.#isNavigating=!1,this.classList.remove("is-scrolling"),this.dispatchEvent(new CustomEvent("on:items-scroll:scroll-end",{detail:{direction,position}})),this.#scrollPosition=position,this.items.addEventListener("scroll",this.#boundScrollStart,{once:!0})}#enableControlsListeners(){this.#controlsListenersEnabled||(this.#boundPrevNavigationAction=this.#handlePrevNavigationAction.bind(this),this.#boundNextNavigationAction=this.#handleNextNavigationAction.bind(this),this.navigationPrevButton.addEventListener("click",this.#boundPrevNavigationAction),this.navigationNextButton.addEventListener("click",this.#boundNextNavigationAction),this.#controlsListenersEnabled=!0)}#disableControlsListeners(){this.#controlsListenersEnabled&&(this.navigationPrevButton.removeEventListener("click",this.#boundPrevNavigationAction),this.navigationNextButton.removeEventListener("click",this.#boundNextNavigationAction),this.#controlsListenersEnabled=!1)}#updateControls(){const getNavigationRatio=(imageContainerRatio,itemsPerPage)=>{const[imageContainerWidth,imageContainerHeight]=imageContainerRatio.split(":").map((string=>Number(string))),gap=Number(window.getComputedStyle(this.items).getPropertyValue("column-gap").replace("px","")||0),findGcd=(a,b)=>b?findGcd(b,a%b):a,gcd=findGcd(imageContainerHeight,Math.round(this.items.offsetHeight));return`${imageContainerWidth*itemsPerPage*Math.round(this.items.offsetHeight)/gcd+gap*(itemsPerPage-1)*imageContainerHeight/gcd} / ${imageContainerHeight*Math.round(this.items.offsetHeight)/gcd}`};if(this.items.children.length>0){const itemsPerPage=Math.floor(this.items.offsetWidth/this.items.children[0].offsetWidth);itemsPerPage&&(this.#itemsPerPage=itemsPerPage)}document.body.offsetWidth>this.breakpointMin&&document.body.offsetWidth<=this.breakpointMax?this.setAttribute("scroll-enabled",""):this.removeAttribute("scroll-enabled"),this.hasAttribute("scroll-enabled")&&this.items.scrollWidth>this.items.offsetWidth+10?(this.setAttribute("scrollable",""),this.navigationContainer||this.#createNavigation(),this.snap||(this.items.children.length>0&&this.items.children[0].offsetWidth>this.items.offsetWidth/2?this.setAttribute("snap","center"):this.setAttribute("snap","start")),this.#enableControlsListeners()):(this.navigationContainer&&this.#disableControlsListeners(),this.removeAttribute("scrollable","")),this.#imageContainerRatio&&this.#imageContainerRatio.toLowerCase()!=="natural"&&this.style.setProperty("--navigation-ratio",getNavigationRatio(this.#imageContainerRatio,this.#itemsPerPage)),this.items.classList.contains("grid-layout")&&(this.items.children.length<this.#itemsPerPage?this.items.classList.add("grid-layout--align-center"):this.items.classList.remove("grid-layout--align-center"))}#setUpItemsMutationObserver(){const config={attributes:!1,childList:!0,subtree:!1};this.#itemsMutationObserver=new MutationObserver((mutationList=>{mutationList.forEach((mutation=>{mutation.type==="childList"&&(this.#updateControls(),this.#setUpNavigationStateControl())}))})),this.#itemsMutationObserver.observe(this.items,config)}#setUpNavigationStateControl(){if(!this.items.firstElementChild)return;const options={root:this.items,rootMargin:"0px",threshold:.75};this.#navigationStateControlObserver&&this.#navigationStateControlObserver.disconnect(),this.#navigationStateControlObserver=new IntersectionObserver((entries=>
4{this.navigationContainer&&entries.forEach((({target,isIntersecting})=>{target.previousElementSibling||(this.navigationPrevButton.disabled=isIntersecting),target.nextElementSibling||(this.navigationNextButton.disabled=isIntersecting)}))}),options),this.#navigationStateControlObserver.observe(this.items.firstElementChild),this.#navigationStateControlObserver.observe(this.items.lastElementChild)}smoothScrollItems(position){return new Promise(((resolve,reject)=>{let same=0,lastPos=null;const check=()=>{const newPos=this.items.scrollLeft;if(this.#isScrollBarDragged)return reject(newPos);if(newPos===lastPos){if(same+=1,same>2)return resolve(position)}else same=0,lastPos=newPos;return window.requestAnimationFrame(check),null};this.items.scrollTo({left:position,behavior:window.matchMedia("(prefers-reduced-motion: reduce)").matches?"instant":"smooth"}),window.requestAnimationFrame(check)}))}}customElements.define("items-scroll",ItemsScroll);export default ItemsScroll;
5//# sourceMappingURL=/cdn/shop/t/108/assets/items-scroll.js.map?v=124158216695031153151789967996

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.