1/* 2 Copyright 2022 Jim "JimOfLeisure" Nelson 3 https://github.com/JimOfLeisure/html5up-phantom-plus | @JimOfLeisure 4 Free for personal and commercial use under the CCA 3.0 license (https://creativecommons.org/licenses/by/3.0/) 5 6 This file is a vanillajs rewrite of main.js from: 7 Phantom by HTML5 UP 8 html5up.net | @ajlkn 9 Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) 10*/ 11 12document.addEventListener("DOMContentLoaded", () => { 13 const body = document.querySelector("body"); 14 enhanceForms(); 15 // enableMenu(body); 16 removePreload(body); 17}); 18 19function wrapInner(parent, wrapper, attribute, attributevalue) { 20 // This function from https://codepen.io/kenjiroart/pen/qBmONJ 21 // It is meant to replace the functionality of jQuery's $.wrapInner 22 if (typeof wrapper === "string") { 23 wrapper = document.createElement(wrapper); 24 } 25 const div = parent.appendChild(wrapper).setAttribute(attribute, attributevalue); 26 27 while (parent.firstChild !== wrapper) { 28 wrapper.appendChild(parent.firstChild); 29 } 30} 31 32function wrapOuter(element, wrapper, attribute, attributevalue) { 33 // Adapting from wrapInner 34 if (typeof wrapper === "string") { 35 wrapper = document.createElement(wrapper); 36 } 37 attribute && wrapper.setAttribute(attribute, attributevalue); 38 // To ensure the wrapper is in the same sibling-related position as element 39 element.parentElement.insertBefore(wrapper, element); 40} 41 42function removePreload(body) { 43 // Play initial animations on page load. 44 // Wait 100ms to remove is-preload to ensure DOM has had time to update 45 setTimeout(() => body.classList.remove("is-preload"), 100); 46} 47 48// Touch? 49// Original sets is-touch based on browser detection 50// Will replace that with @media(hover: none) in scss instead 51 52function enhanceForms() { 53 // Forms. 54 // Find all textareas in forms and loop through each 55 Array.from(document.querySelectorAll("form textarea")).forEach((textarea) => { 56 // Add wrapper div, set some style and attribute 57 wrapOuter(textarea, "div", "class", "textarea-wrapper"); 58 textarea.setAttribute("rows", "1"); 59 textarea.style.overflow = "hidden"; 60 textarea.style.resize = "none"; 61 62 // Trim leading and trailing whitespace in textarea on focus change and ctrl-enter 63 const trimElement = (element) => element.value = element.value.trim(); 64 ["blur", "focus"].forEach((eventName) => textarea.addEventListener(eventName, (event) => trimElement(event.target))); 65 textarea.addEventListener("keydown", (event) => { 66 if (event.code === 13 && event.ctrlKey) { 67 event.preventDefault(); 68 event.stopPropagation(); 69 trimElement(event.target); 70 } 71 }); 72 73 // Auto-size the height of the textarea 74 const setHeight = (element) => { 75 element.style.height = "auto"; 76 element.style.height = `${element.scrollHeight}px`; 77 }; 78 // Set height on initial load 79 setHeight(textarea); 80 // Monitor events to resize 81 ["input", "blur", "focus"].forEach((eventName) => textarea.addEventListener(eventName, (event) => setHeight(event.target))); 82 83 // Select text on tab-out 84 // This is broken, but it's broken in the original code, too 85 // It exits the field and doesn't select 86 // It will select the text if youchange keyup to keydown, 87 // But then the selection is irrelevant when the focus is lost 88 // You can make it work with keydown and event.preventDefault(), 89 // But that prevents you from being able to exit the field with tab 90 textarea.addEventListener("keyup", (event) => { 91 if (event.code === "Tab") { 92 event.target.select(); 93 } 94 }); 95 96 // Limit textarea height for "mobile" 97 // Original code used browser detection; I'll just assume if 98 // it can't hover we'll limit the height 99 if (matchMedia("(hover: none)").matches) { 100 textarea.style["max-height"] = "10em"; 101 textarea.style.overflow = "auto"; 102 } 103 }); 104} 105 106function enableMenu(body) { 107 // Menu. 108 const menu = document.querySelector("#menu"); 109 wrapInner(menu, "div", "class", "inner"); 110 111 let menuIsDebouncing = false;
112 const menuDebounced = () => { 113 if (!menuIsDebouncing) { 114 setTimeout(() => menuIsDebouncing = false, 350); 115 menuIsDebouncing = true; 116 return true; 117 } 118 return false; 119 }; 120 const menuMove = { 121 "hide": () => menuDebounced() && body.classList.remove("is-menu-visible"), 122 "show": () => menuDebounced() && body.classList.add("is-menu-visible"), 123 "toggle": () => menuDebounced() && body.classList.toggle("is-menu-visible") 124 }; 125 126 // The original script moves #menu to the bottom of body 127 // Why though? 128 // Ok, the styles only work right when it's down there 129 // Not sure why it's not just there in the first place 130 body.appendChild(menu); 131 132 // This adds the animated X icon to close the menu 133 // I don't know why it's being added with script 134 // I'm just aping the original code so far 135 const close = document.createElement("a"); 136 close.href = "#menu"; 137 close.classList.add("close"); 138 close.innerText = "Close"; 139 menu.appendChild(close); 140 141 // Add menu toggle to appropriate link targets 142 Array.from(document.querySelectorAll("[href=\"#menu\"]")).forEach((el) => el.addEventListener("click", (event) => { 143 event.preventDefault(); 144 event.stopPropagation(); 145 menuMove.toggle(); 146 })); 147 148 // Prevents unhandled clicks in #menu from propagating to body to close menu 149 menu.addEventListener("click", (event) => { 150 event.stopPropagation(); 151 // The original code on link click stops propagation and changes the 152 // location after a delay. I'm not gonna do that. 153 }); 154 155 // Hides menu when clicking on body 156 body.addEventListener("click", (event) => { 157 menuMove.hide(); 158 }); 159 160 // Close menu on ESC key pressed 161 body.addEventListener("keydown", (event) => { 162 if (event.code === "Escape") { 163 menuMove.hide(); 164 } 165 }); 166}
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.