1/* learn.js */ 2 3{ 4 let pref = localStorage.getItem('darkMode'); 5 pref ??= window.matchMedia('prefers-color-scheme: dark').matches ? 'dark' : 'light'; 6 7 document.body.classList.remove('light', 'dark'); 8 document.body.classList.add(pref); 9} 10 11function toggleDarkMode() { 12 if (document.body.classList.contains('dark')) { 13 document.body.classList.remove('dark'); 14 document.body.classList.add('light'); 15 localStorage.setItem('darkMode', 'light'); 16 } else { 17 document.body.classList.remove('light'); 18 document.body.classList.add('dark'); 19 localStorage.setItem('darkMode', 'dark'); 20 } 21 if (typeof setEditorThemes != 'undefined') setEditorThemes(); 22} 23 24if (typeof Q5 != 'undefined') Q5.canvasOptions.alpha = true; 25 26let args = {}; 27 28{ 29 let url = location.href.split('?'); 30 if (url.length > 1) { 31 let params = new URLSearchParams(url[1]); 32 for (let pair of params.entries()) { 33 args[pair[0]] = pair[1]; 34 } 35 } 36} 37 38let pages = document.getElementsByClassName('page'); 39let pageNav = document.getElementById('pageNav'); 40let currentPage = 0, 41 article, 42 trialPages; 43 44function checkTrial(page = 0) { 45 let url = location.pathname; 46 47 trialPages = 48 (!page || page <= 2) && 49 (url.endsWith('learn') || 50 url.endsWith('/') || 51 url.endsWith('index') || 52 url.endsWith('index.html') || 53 url.endsWith('sprite') || 54 url.endsWith('sprite.html') || 55 url.endsWith('group') || 56 url.endsWith('group.html')); 57} 58checkTrial(args.page); 59 60async function start() { 61 article = document.body.children[0]; 62 63 function loadScript(src) { 64 return new Promise(function (resolve) { 65 let script = document.createElement('script'); 66 script.src = src; 67 script.onload = resolve; 68 document.body.appendChild(script); 69 }); 70 } 71 72 async function loadScripts(sources) { 73 for (let src of sources) await loadScript(src); 74 } 75 76 if (navigator.onLine) { 77 await loadScripts([ 78 'https://cdn.jsdelivr.net/npm/[email protected]/src-min-noconflict/ace.min.js', 79 'https://cdn.jsdelivr.net/npm/[email protected]/src-min-noconflict/ext-language_tools.js', 80 'https://cdn.jsdelivr.net/npm/[email protected]/src-min-noconflict/ext-beautify.js' 81 ]); 82 } else { 83 await loadScripts([ 84 '/learn/ace/ace.min.js', 85 '/learn/ace/ext-language_tools.js', 86 '/learn/ace/mode-javascript.js', 87 '/learn/ace/theme-dracula.js', 88 '/learn/ace/theme-xcode.js', 89 'ace/ext-beautify.js' 90 ]); 91 } 92 93 if (pageNav) { 94 let previousPage = document.getElementById('prevPage'); 95 previousPage.onclick = function () { 96 if (currentPage - 1 > -1) { 97 let i = currentPage - 1; 98 let url = `?page=${i}`; 99 history.pushState({}, 'p5play : Sprite : ' + i, url); 100 loadPage(i); 101 } 102 }; 103 104 let nextPage = document.getElementById('nextPage'); 105 nextPage.onclick = function () { 106 if (currentPage + 1 < pages.length) { 107 let i = currentPage + 1; 108 let url = `?page=${i}`; 109 history.pushState({}, 'p5play : Sprite : ' + i, url); 110 loadPage(i); 111 } 112 }; 113 114 if (typeof mie != 'undefined') { 115 (async () => { 116 let data = await fetch('/learn/ace/completions.json'); 117 let json = await data.json(); 118 mie.lang.p5.completions = json; 119 120 mie.load(); 121 })(); 122 } 123 loadPage(); 124 } 125} 126start(); 127 128function loadPage(pageNum) { 129 article.style.display = 'none'; 130 131 pageNum = pageNum ?? args.page ?? 0; 132 133 for (let i = 0; i < pages.length; i++) { 134 let el = pageNav.children[i]; 135 if (el.dataset.page == pageNum) { 136 el.classList.add('active'); 137 } else { 138 el.classList.remove('active'); 139 } 140 } 141 for (let mini of mie) { 142 mini.remove(); 143 } 144 for (let page of pages) { 145 page.style.display = 'none'; 146 } 147 let page = document.getElementById('page-' + pageNum); 148 page.style.display = 'flex'; 149 mie.loadMinis(page); 150 setEditorThemes(); 151 document.body.scrollTop = 0; // for Safari 152 document.documentElement.scrollTop = 0; // Chrome, Firefox, and Opera 153 currentPage = parseInt(pageNum); 154 155 document.getElementById('toc').style.display = 'flex'; 156 157 article.style.display = 'flex'; 158 159 checkTrial(currentPage); 160 161 if (typeof p5playAccount != 'undefined') ad(); 162} 163 164function setEditorThemes() { 165 if (typeof mie == 'undefined') return; 166 if (document.body.className == 'dark') { 167 mie.theme = 'dark'; 168 } else { 169 mie.theme = 'light'; 170 } 171} 172 173window.addEventListener('keydown', function (e) { 174 if ( 175 (e.key == ' ' || 176 e.key == '/' || 177 e.key == 'ArrowUp' || 178 e.key == 'ArrowDown' || 179 e.key == 'ArrowLeft' || 180 e.key == 'ArrowRight') && 181 e.target == document.body 182 ) { 183 e.preventDefault(); 184 } 185}); 186 187window.showUnauthContent = async () => { 188 if (trialPages) return; 189 190 let unauth = await (await fetch('../account/unauth.html')).text(); 191
192 setInterval(() => { 193 if (!document.getElementById('wall')) { 194 document.body.insertAdjacentHTML('beforeend', unauth); 195 } 196 }, 1000); 197}; 198 199function ad() { 200 if (trialPages || p5playAccount.type == 'Student' || p5playAccount.paid) return; 201 202 if (p5playAccount.type == 'Teacher') { 203 // has access through their school 204 if (p5playAccount.classes?.length) return; 205 206 if (document.getElementById('banner')) return; 207 208 let banner = ` 209<div id="banner"> 210 <p>For teacher evaluation only. ðµ <a href="../teach">Want to teach p5play?</a> ð¤©</p> 211</div>`; 212 213 document.body.insertAdjacentHTML('afterbegin', banner); 214 return; 215 } 216 217 addPaywall(); 218} 219 220function addPaywall() { 221 let paywall = ` 222<div id="wall"> 223 <div class="popup"> 224 <div class="navLink active"> 225 <img alt="p5play logo" src="/assets/p5play_logo.svg" class="p5play_logo"> 226 <span>p5play</span> 227 </div> 228 <p>Enjoying p5play? To unlock this content, purchase full access to <em>Learn p5play</em>. ð¤</p> 229 <a id="purchase" class="heroBtns" href="https://ko-fi.com/s/fdf3297d1c">Purchase on Ko-fi</a> 230 <p>Looking for the latest edition? <a href="https://q5play.org/learn"><em>Learn q5play</em></a> is available now!</p> 231 </div> 232</div>`; 233 234 setInterval(() => { 235 if (!document.getElementById('wall')) { 236 document.body.insertAdjacentHTML('beforeend', paywall); 237 } 238 }, 1000); 239} 240 241window.showAuthContent = ad;
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.