1// https://benfrain.com/a-horizontal-scrolling-navigation-pattern-for-touch-and-mouse-with-moving-current-indicator/#h-H2_8 2 3$(document).ready(function() { 4 5 let boxes = {}; 6 var ticking = false; //May need to be box specific 7 8 //Initialise each scrollbox 9 $("[id^=scrollbox]").each(function() { 10 let uid = parse_uid(this.id); 11 boxes[uid] = {}; 12 let current_box = boxes[uid]; 13 14 current_box["uid"] = uid; 15 current_box["data_overflowing"] = "right" 16 current_box["SETTINGS"] = { 17 navBarTravelling: false, 18 navBarDirection: "", 19 navBarTravelDistance: 372 20 }; 21 22 current_box["last_known_scroll_position"] = 0; 23 current_box["sb"] = $(`#scrollbox_${uid}`)[0]; 24 current_box["sb_contents"] = $(`#scrollbox_contents_${uid}`)[0]; 25 update_overflow_attr(current_box); 26 }); 27 28 function update_overflow_attr(box) { 29 $(`#scrollbox_${box["uid"]}`).attr("data-overflowing", determineOverflow(box["sb_contents"], box["sb"])); 30 box["data_overflowing"] = determineOverflow(box["sb_contents"], box["sb"]); 31 update_arrow_display(box["data_overflowing"], box["uid"]); 32 }; 33 34 function update_arrow_display(data_overflow, uid) { 35 switch (data_overflow) { 36 case "right": 37 $(`#pnAdvancerLeft_${uid}`).addClass("pn-Advancer_hidden"); 38 $(`#pnAdvancerRight_${uid}`).removeClass("pn-Advancer_hidden"); 39 break; 40 case "left": 41 $(`#pnAdvancerLeft_${uid}`).removeClass("pn-Advancer_hidden"); 42 $(`#pnAdvancerRight_${uid}`).addClass("pn-Advancer_hidden"); 43 break; 44 case "both": 45 $(`#pnAdvancerLeft_${uid}`).removeClass("pn-Advancer_hidden"); 46 $(`#pnAdvancerRight_${uid}`).removeClass("pn-Advancer_hidden"); 47 break; 48 } 49 } 50 51 $("[id^=scrollbox_contents]").on('webkitTransitionEnd oTransitionEnd transitionend msTransitionEnd', function() { 52 let uid = parse_uid(this.id); 53 // get the value of the transform, apply that to the current scroll position (so get the scroll pos first) and then remove the transform 54 var styleOfTransform = window.getComputedStyle(boxes[uid]["sb_contents"], null); 55 var tr = styleOfTransform.getPropertyValue("-webkit-transform") || styleOfTransform.getPropertyValue("transform"); 56 // If there is no transition we want to default to 0 and not null 57 var amount = Math.abs(parseInt(tr.split(",")[4]) || 0); 58 boxes[uid]["sb_contents"].style.transform = "none"; 59 boxes[uid]["sb_contents"].classList.add("scrollbox_contents-no-transition"); 60 // Now lets set the scroll position 61 if (boxes[uid]["SETTINGS"].navBarTravelDirection === "left") { 62 boxes[uid]["sb"].scrollLeft = boxes[uid]["sb"].scrollLeft - amount; 63 } else { 64 boxes[uid]["sb"].scrollLeft = boxes[uid]["sb"].scrollLeft + amount; 65 } 66 boxes[uid]["SETTINGS"].navBarTravelling = false; 67 }); 68 69 70 71 $("[id^=scrollbox]").scroll(function() { 72 let uid = parse_uid(this.id); 73 boxes[uid]["last_known_scroll_position"] = window.scrollY; 74 if (!ticking) { 75 window.requestAnimationFrame(function() { 76 update_overflow_attr(boxes[uid]); 77 ticking = false; 78 }); 79 } 80 ticking = true; 81 }); 82 83 $("[id^=pnAdvancerLeft]").click(function() { 84 let uid = parse_uid(this.id); 85 // If in the middle of a move return 86 if (boxes[uid]["SETTINGS"].navBarTravelling === true) { 87 // console.log("Navbar is travelling"); 88 return; 89 } 90 // If we have content overflowing both sides or on the left 91 let overflow = determineOverflow(boxes[uid]["sb_contents"], boxes[uid]["sb"]); 92 if (overflow === "left" || overflow === "both") { 93 // Find how far this panel has been scrolled 94 var availableScrollLeft = boxes[uid]["sb"].scrollLeft; 95 // If the space available is less than our desired distance, just move the whole amount 96 // otherwise, move by the amount in the settings 97 if (availableScrollLeft < boxes[uid]["SETTINGS"].navBarTravelDistance * 1.5) { 98 boxes[uid]["sb_contents"].style.transform = "translateX(" + availableScrollLeft + "px)"; 99 } else { 100 boxes[uid]["sb_contents"].style.transform = "translateX("
100+ boxes[uid]["SETTINGS"].navBarTravelDistance + "px)"; 101 } 102 // We do want a transition (this is set in CSS) when moving so remove the class that would prevent that 103 boxes[uid]["sb_contents"].classList.remove("scrollbox_contents-no-transition"); 104 // Update our settings 105 boxes[uid]["SETTINGS"].navBarTravelDirection = "left"; 106 boxes[uid]["SETTINGS"].navBarTravelling = true; 107 } 108 // Now update the attribute in the DOM 109 update_overflow_attr(boxes[uid]); 110 }); 111 112 $("[id^=pnAdvancerRight]").click(function() { 113 let uid = parse_uid(this.id); 114 // If in the middle of a move return 115 if (boxes[uid]["SETTINGS"].navBarTravelling === true) { 116 // console.log("Navbar is travelling") 117 return; 118 } 119 120 // If we have content overflowing both sides or on the right 121 let overflow = determineOverflow(boxes[uid]["sb_contents"], boxes[uid]["sb"]); 122 if (overflow === "right" || overflow === "both") { 123 // Get the right edge of the container and content 124 var navBarRightEdge = boxes[uid]["sb_contents"].getBoundingClientRect().right; 125 var navBarScrollerRightEdge = boxes[uid]["sb"].getBoundingClientRect().right; 126 // Now we know how much space we have available to scroll 127 var availableScrollRight = Math.ceil(navBarRightEdge - navBarScrollerRightEdge); 128 // If the space available is less than our desired distance, just move the whole amount 129 // otherwise, move by the amount in the settings 130 if (availableScrollRight < boxes[uid]["SETTINGS"].navBarTravelDistance * 1.5) { 131 boxes[uid]["sb_contents"].style.transform = "translateX(-" + availableScrollRight + "px)"; 132 } else { 133 boxes[uid]["sb_contents"].style.transform = "translateX(-" + boxes[uid]["SETTINGS"].navBarTravelDistance + "px)"; 134 } 135 // We do want a transition (this is set in CSS) when moving so remove the class that would prevent that 136 boxes[uid]["sb_contents"].classList.remove("scrollbox_contents-no-transition"); 137 // Update our settings 138 boxes[uid]["SETTINGS"].navBarTravelDirection = "right"; 139 boxes[uid]["SETTINGS"].navBarTravelling = true; 140 } 141 // Now update the attribute in the DOM 142 update_overflow_attr(boxes[uid]); 143 }); 144 145 function determineOverflow(content, container) { 146 var containerMetrics = container.getBoundingClientRect(); 147 var containerMetricsRight = Math.floor(containerMetrics.right); 148 var containerMetricsLeft = Math.floor(containerMetrics.left); 149 var contentMetrics = content.getBoundingClientRect(); 150 var contentMetricsRight = Math.floor(contentMetrics.right); 151 var contentMetricsLeft = Math.floor(contentMetrics.left); 152 153 if (containerMetricsLeft > contentMetricsLeft && containerMetricsRight < contentMetricsRight) { 154 return "both"; 155 } else if (contentMetricsLeft < containerMetricsLeft) { 156 return "left"; 157 } else if (contentMetricsRight > containerMetricsRight) { 158 return "right"; 159 } else { 160 return "none"; 161 } 162 }; 163 164 //Parse uid of an element 165 function parse_uid(element_id) { 166 return (element_id.substring(element_id.lastIndexOf("_") + 1)); 167 } 168});
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.