1/** 2 * Infinite scroller for articles. 3 * Require CSS to support transform using translateX. 4 * This is optimized to use GPU instead og CPU. 5 * (c) Publish Lab AS 2018 6 */ 7 8if (!window.Dac) window.Dac = {} 9var Dac = window.Dac; 10 11Dac.AutoScroller = function(boxContainer, autoscroll, interval) { 12 13 var autoscrollId = null; 14 if (!boxContainer) return; 15 var container = boxContainer.querySelector('ul.articles'); 16 if (!container) return; 17 var articleList = container.children; 18 if (!articleList.length) return; 19 var leftNav = boxContainer.querySelector('span.left'); 20 var rightNav = boxContainer.querySelector('span.right'); 21 var currentIndex = 0; 22 var elementWidth = articleList[0].offsetWidth; 23 var visibleCount = Math.round(container.offsetWidth / elementWidth); 24 var scrollWidth = container.offsetWidth / visibleCount; 25 var intervalPeriod = interval || 4000; 26 27 if (visibleCount >= articleList.length) return; 28 var slots = []; 29 30 var setupSlots = function() { 31 slots = []; 32 for (var i = 0; i < articleList.length; i++) { 33 slots.push(new slot(articleList[i], scrollWidth)); 34 } 35 } 36 37 var resizeObserver; 38 if (window.ResizeObserver) { 39 resizeObserver = new ResizeObserver(entries => { 40 for (let entry of entries) { 41 if (entry.target === container) { 42 var newElementWidth = articleList[0].offsetWidth; 43 if (newElementWidth !== elementWidth) { 44 elementWidth = newElementWidth; 45 scrollWidth = container.offsetWidth / visibleCount; 46 setupSlots(); 47 repositionLast(1); 48 } 49 } 50 } 51 }); 52 } 53 54 var start = function() { 55 setupSlots(); 56 repositionLast(1); 57 if (resizeObserver) { resizeObserver.observe(container); } 58 if (autoscroll) { 59 autoscrollId = window.setInterval(function() { 60 if (!autoscroll) { 61 window.clearInterval(autoscrollId); 62 return; 63 } 64 step(1); 65 }, intervalPeriod); 66 } 67 } 68 69 var dotsContainer = boxContainer.querySelector('ul.dots'); 70 71 72 // Eks: "transition: transform 0.5s;" -> more than 500. 73 // CSS-class "transformHidden" should move the element instantly and hide it. 74 var slot = function(element, slotWidth) { 75 this.element = element; 76 this.slotWidth = slotWidth; 77 this.xPos = 0; 78 79 this.step = function(amount, hidden) { 80 this.xPos -= this.slotWidth * amount; 81 this.move(this.xPos, hidden); 82 } 83 84 this.reset = function() { 85 this.xPos = 0; 86 this.move(0); 87 } 88 89 this.move = function(xPos, hidden) { 90 var el = this.element; 91 if (hidden) { 92 el.classList.add('transformHidden'); 93 } else { 94 el.classList.remove('transformHidden'); 95 } 96 el.style.transform = 'translateX(' + xPos + 'px)'; // transitionend 97 } 98 99 var self = this; 100 return { 101 step: function(amount, hidden) { 102 self.step(amount, hidden); 103 }, 104 reset: function() { 105 self.reset(); 106 } 107 } 108 } 109 110 var step = function(amount, hidden) { 111 var oldIndex = currentIndex; 112 currentIndex += amount; 113 if (Math.abs(currentIndex) >= slots.length) { 114 currentIndex = 0; 115 } 116 slots.forEach(function(obj) { 117 obj.step(amount, hidden); 118 }) 119 if (amount > 0) { 120 repositionFirst(Math.abs(amount)); 121 } else if (amount < 0) { 122 repositionLast(Math.abs(amount)); 123 } 124 updateDots(currentIndex, oldIndex); 125 } 126 127 var repositionFirst = function(count) { 128 var first = slots.shift(); 129 first.step(-2 - slots.length, true); 130 window.setTimeout(function() { 131 first.step(1); 132 }, 50); 133 slots.push(first); 134 count--; 135 if (count > 0) repositionFirst(count); 136 } 137 138 var repositionLast = function(count) { 139 var last = slots.pop(); 140 slots.unshift(last); 141 last.step(slots.length, true); 142 count--; 143 if (count > 0) repositionLast(count); 144 } 145 146 var slideToPrevious = function() { 147 step(-1); 148 autoscroll = false;
149 } 150 151 var slideToNext = function() { 152 step(1); 153 autoscroll = false; 154 } 155 156 if (leftNav) { 157 leftNav.addEventListener('click', slideToPrevious, false); 158 } 159 if (rightNav) { 160 rightNav.addEventListener('click', slideToNext, false); 161 } 162 163 function getIndex(element) { 164 var nodes = Array.prototype.slice.call(element.parentNode.children); 165 return nodes.indexOf(element); 166 } 167 168 function dotClicked(event) { 169 event.preventDefault(); 170 event.stopPropagation(); 171 var index = getIndex(this); 172 if (index > -1) { 173 step(index - currentIndex, true); 174 } 175 autoscroll = false; 176 } 177 178 function updateDots(newIndex, oldIndex) { 179 if (!dotsContainer) return; 180 var oldEl = dotsContainer.children[oldIndex]; 181 if (oldEl) oldEl.classList.remove('selected'); 182 var newEl = dotsContainer.children[newIndex]; 183 if (newEl) newEl.classList.add('selected'); 184 } 185 186 187 if (dotsContainer) { 188 for (var i = 0; i < dotsContainer.children.length; i++) { 189 dotsContainer.children[i].addEventListener('click', dotClicked, false); 190 } 191 updateDots(0); 192 } 193 194 start(); 195}
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.