PageSourceSearch

https://p5play.org/learn/learn.js

js p5play.org collected 2026-10-03 23:13:23 UTC 5,934 bytes, 241 lines download raw bytes

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.