scroll-behavior.js (3121B)
1 // TODO(crbug.com/888443): It would be better to listen to the scrollend event 2 // instead of polling the scroll position. 3 function observeScrolling(elements, callback) { 4 if (!Array.isArray(elements)) 5 elements = [elements]; 6 var lastChangedFrame = 0; 7 var lastLeft = new Map(); 8 var lastTop = new Map(); 9 elements.forEach((element) => { 10 lastLeft.set(element, element.scrollLeft); 11 lastTop.set(element, element.scrollTop); 12 }); 13 function tick(frames) { 14 // We requestAnimationFrame either for 5000 frames or until 20 frames with 15 // no change have been observed. (In Chromium, frames may run as frequently 16 // as once per millisecond when threaded compositing is disabled. The limit 17 // of 5000 frames is chosen to be high enough to reasonably ensure any 18 // scroll animation will run to completion.) 19 if (frames >= 5000 || frames - lastChangedFrame > 20) { 20 callback(true); 21 } else { 22 var scrollHappened = elements.some((element) => { 23 return element.scrollLeft != lastLeft.get(element) || element.scrollTop != lastTop.get(element); 24 }); 25 if (scrollHappened) { 26 lastChangedFrame = frames; 27 elements.forEach((element) => { 28 lastLeft.set(element, element.scrollLeft); 29 lastTop.set(element, element.scrollTop); 30 }); 31 callback(false); 32 } 33 requestAnimationFrame(tick.bind(null, frames + 1)); 34 } 35 } 36 tick(0); 37 } 38 39 function waitForScrollEnd(elements) { 40 return new Promise((resolve) => { 41 observeScrolling(elements, (done) => { 42 if (done) 43 resolve(); 44 }); 45 }); 46 } 47 48 function resetScroll(scrollingElement) { 49 // Try various methods to ensure the element position is reset immediately. 50 scrollingElement.scrollLeft = 0; 51 scrollingElement.scrollTop = 0; 52 scrollingElement.scroll({left: 0, top: 0, behavior: "instant"}); 53 } 54 55 function resetScrollForWindow(scrollingWindow) { 56 // Try various methods to ensure the element position is reset immediately. 57 scrollingWindow.document.scrollingElement.scrollLeft = 0; 58 scrollingWindow.document.scrollingElement.scrollTop = 0; 59 scrollingWindow.scroll({left: 0, top: 0, behavior: "instant"}); 60 } 61 62 function setScrollBehavior(styledElement, className) { 63 styledElement.classList.remove("autoBehavior", "smoothBehavior"); 64 styledElement.classList.add(className); 65 } 66 67 function scrollNode(scrollingElement, scrollFunction, behavior, elementToRevealLeft, elementToRevealTop) { 68 var args = {}; 69 if (behavior) 70 args.behavior = behavior; 71 switch (scrollFunction) { 72 case "scrollIntoView": 73 args.inline = "start"; 74 args.block = "start"; 75 elementToReveal.scrollIntoView(args); 76 break; 77 default: 78 args.left = elementToRevealLeft; 79 args.top = elementToRevealTop; 80 scrollingElement[scrollFunction](args); 81 break; 82 } 83 } 84 85 function scrollWindow(scrollingWindow, scrollFunction, behavior, elementToRevealLeft, elementToRevealTop) { 86 var args = {}; 87 if (behavior) 88 args.behavior = behavior; 89 args.left = elementToRevealLeft; 90 args.top = elementToRevealTop; 91 scrollingWindow[scrollFunction](args); 92 }