Bumble.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /**
  2. * The globally-accessible Bumble Object
  3. *
  4. * Here I can store any and all utilities without taking up space in the
  5. * gloabl namespace.
  6. */
  7. var Bumble = {};
  8. /**
  9. * The info panel
  10. *
  11. * The info panel is a utility that allows me to add information to a page
  12. * in such a way that it can easily be closed when the user is done reading
  13. * it.
  14. *
  15. * This aims to improve the SEO of pages by adding as much descriptive
  16. * text as I want, without harming the usability of the page. This takes into
  17. * consideration that most of my pages are, currently, JS games on canvasses.
  18. *
  19. * @param {HTMLElement} panel - An HTML element with the .infopanel class
  20. */
  21. Bumble.InfoPanel = function(panel){
  22. this.panel = panel;
  23. this.head = undefined;
  24. this.body = undefined;
  25. this.title = undefined
  26. this.closer = undefined;
  27. this.icons = {
  28. close: "uil-times-circle",
  29. open: "uil-info-circle"
  30. }
  31. this.isClosed = false;
  32. /**
  33. * Initialzize the info panel
  34. */
  35. this.init = function(){
  36. if(!this.panel){ throw new Error("Panel not found."); }
  37. this.head = this.panel.querySelector('.infopanel-head');
  38. this.body = this.panel.querySelector('.infopanel-body');
  39. this.title = this.head.querySelector('.infopanel-title');
  40. this.closer = this.head.querySelector('.infopanel-closer');
  41. this.isClosed = this.panel.classList.contains('closed');
  42. this.closer.addEventListener("click", ()=>{ this.toggleVisibility(); });
  43. this.toggleCloseButtonIcon();
  44. }
  45. /**
  46. * Close the info panel
  47. */
  48. this.close = function() {
  49. this.panel.classList.add("closed");
  50. this.isClosed = true;
  51. }
  52. /**
  53. * Open the info panel
  54. */
  55. this.open = function() {
  56. this.panel.classList.remove("closed")
  57. this.isClosed = false;
  58. }
  59. /**
  60. * Toggle the info panel's visibility
  61. */
  62. this.toggleVisibility = function() {
  63. if(this.isClosed) { this.open(); }
  64. else { this.close(); }
  65. this.toggleCloseButtonIcon();
  66. }
  67. /**
  68. * Toggle the icon of the info panel's open/close button
  69. */
  70. this.toggleCloseButtonIcon = function() {
  71. if(this.isClosed) {
  72. this.closer.classList.remove(this.icons.close);
  73. this.closer.classList.add(this.icons.open);
  74. }
  75. else {
  76. this.closer.classList.remove(this.icons.open);
  77. this.closer.classList.add(this.icons.close);
  78. }
  79. }
  80. this.init();
  81. }
  82. /**
  83. * A classic modal
  84. *
  85. * @param {string} DOMID - An option string of the DOM ID for premade modal
  86. */
  87. Bumble.Modal = function(DOMID) {
  88. this.overlay = undefined;
  89. this.modal = {
  90. base: undefined,
  91. header: undefined,
  92. title: undefined,
  93. closer: undefined,
  94. body: undefined
  95. };
  96. this.isShown = false;
  97. this.init = function(DOMID) {
  98. // Build the overlay
  99. this.overlay = document.createElement("div");
  100. this.overlay.classList.add("modal-overlay", "hidden");
  101. // Initialize a predefined modal
  102. if(DOMID) {
  103. const elem = document.getElementById(DOMID);
  104. if(!elem){
  105. console.warn("No element found with ID: ", DOMID);
  106. console.warn("Creating modal");
  107. }
  108. else {
  109. this.modal.pane = elem;
  110. this.modal.header = elem.querySelector(".modal-header");
  111. this.modal.title = elem.querySelector(".modal-title");
  112. this.modal.closer = elem.querySelector(".uil-times-circle");
  113. this.modal.body = elem.querySelector(".modal-body");
  114. }
  115. }
  116. // Build the modal from scratch
  117. if(!this.modal.pane) {
  118. this.modal.pane = document.createElement("div");
  119. this.modal.pane.classList.add("modal");
  120. this.modal.header = document.createElement("div");
  121. this.modal.header.classList.add("modal-header");
  122. this.modal.title = document.createElement("div");
  123. this.modal.title.classList.add("modal-title");
  124. const closerContainer = document.createElement("div");
  125. closerContainer.classList.add("modal-closer", "text-right");
  126. this.modal.closer = document.createElement("i");
  127. this.modal.closer.classList.add("uil", "uil-times-circle");
  128. closerContainer.appendChild(this.modal.closer);
  129. this.modal.header.append(this.modal.title, closerContainer);
  130. this.modal.body = document.createElement("div");
  131. this.modal.body.classList.add("modal-body");
  132. this.modal.pane.append(this.modal.header, this.modal.body);
  133. }
  134. // Add event listener to closer button
  135. this.modal.closer.addEventListener("click", this.hide.bind(this));
  136. // Add modal pane to the overlay
  137. this.overlay.appendChild(this.modal.pane);
  138. // Add overlay to body
  139. document.body.appendChild(this.overlay);
  140. return;
  141. }
  142. this.SetTitle = function(title) {
  143. this.modal.title.innerText = title;
  144. }
  145. this.SetBody = function(bodyHTML) {
  146. this.modal.body.innerHTML = bodyHTML;
  147. }
  148. this.show = function() {
  149. this.isShown = true;
  150. this._toggleVisibility();
  151. }
  152. this.hide = function() {
  153. this.isShown = false;
  154. this._toggleVisibility();
  155. }
  156. this._toggleVisibility = function() {
  157. if(this.isShown) {
  158. this.overlay.classList.remove("hidden");
  159. }
  160. else {
  161. this.overlay.classList.add("hidden");
  162. }
  163. }
  164. this.init(DOMID);
  165. }
  166. /**
  167. * Store GET Parameters
  168. *
  169. * A convenient place to store and access GET parameters sent to the page.
  170. */
  171. Bumble._GET = {
  172. /**
  173. * Loads the GET parameters into this object
  174. */
  175. __init: function() {
  176. const params = (new URL(document.location)).searchParams.entries();
  177. for(const entry of params) {
  178. if(entry[0] == "__init"){ continue; }
  179. this[entry[0]] = !isNaN(entry[1]) ? Number(entry[1]) : entry[1];
  180. }
  181. }
  182. }
  183. Bumble.XFN = {
  184. me: "uil-cell",
  185. friend: "uil-user-check",
  186. colleague: "uil-books",
  187. _buildIcon: function(iconClass) {
  188. const icon = document.createElement("i");
  189. icon.classList.add("uil", iconClass);
  190. return icon;
  191. },
  192. init: function() {
  193. const links = document.querySelectorAll("a[rel]");
  194. for(const link of links) {
  195. // Ignore links that only contain images
  196. if (link.childNodes.length == 1 && link.lastChild instanceof HTMLImageElement) { continue; }
  197. const rels = link.rel.split(' ');
  198. let rel = null;
  199. if(rels.indexOf("me") >= 0) {
  200. rel = this.me;
  201. }
  202. else if(rels.indexOf("friend") >= 0) {
  203. rel = this.friend;
  204. }
  205. else if(rels.indexOf("colleague") >= 0) {
  206. rel = this.colleague;
  207. }
  208. if(rel) {
  209. link.insertAdjacentElement("afterbegin", this._buildIcon(rel));
  210. }
  211. }
  212. },
  213. }
  214. /**
  215. * Quotes that either have a lot of meaning to me, or I just really enjoy
  216. */
  217. Bumble.FooterQuotes = {
  218. all_quotes: [
  219. {
  220. "text":"We can't rewind now; we've gone too far",
  221. "source":"The Limousines - Internet Killed The Video Star"
  222. },
  223. {
  224. "text":"There is no justice or no peace, there's only forgiveness",
  225. "source":"John Reuben - There's only Forgiveness"
  226. },
  227. {
  228. "text":"Love is like a circle; there's no easy way to end",
  229. "source":"Oliver Tree - Cowboys Don't Cry"
  230. },
  231. {
  232. "text":"No crime is as bad as meaninglessness",
  233. "source":"Futhermore - Letter To Myself"
  234. },
  235. {
  236. "text":"Independence was the goal, now you miss home sick",
  237. "source":"Futhermore - Letter To Myself"
  238. },
  239. {
  240. "text":"Apathy's a tragedy, and boredom is a crime",
  241. "source":"Bo Burnham - Welcome To The Internet"
  242. },
  243. {
  244. "text":"All I ever wanted was a little bit of everything all of the time",
  245. "source":"Bo Burnham - Welcome To The Internet"
  246. },
  247. {
  248. "text":"The taste of blood; It's murder; This is your fault; You chose this path.",
  249. "source":"Mayhem - It's Murder"
  250. },
  251. {
  252. "text":"So it goes.",
  253. "source":"Kurt Vonnegaut - Slaughter-house Five"
  254. },
  255. {
  256. "text":"He has always pressed it, and he always will. We always let him and we always will let him. The moment is structured that way.",
  257. "source":"Kurt Vonnegaut - Slaughter-house Five"
  258. },
  259. {
  260. "text":"This isn't a man. It's a broken kite.",
  261. "source":"Kurt Vonnegaut - Slaughter-house Five"
  262. },
  263. {
  264. "text":"Why you? Why us for that matter? Why Anything? Because the moment simply is.",
  265. "source":"Kurt Vonnegaut - Slaughter-house Five"
  266. },
  267. {
  268. "text":"Poo-tee-tweet?",
  269. "source":"Kurt Vonnegaut - Slaughter-house Five"
  270. },
  271. {
  272. "text":"Yeah there's nothing left to ruin, yeah we finally got free / How's that for manifesting our destiny",
  273. "source":"Sylvan Esso - PARAD(w/m)E"
  274. },
  275. {
  276. "text":"Where you been? I wonder / We've been waitin so long around here for days, days, days",
  277. "source":"Mr. Gnome - Pixie Dust"
  278. },
  279. {
  280. "text":"We will laugh at the fact that we ever resisted this blissful togetherness",
  281. "source":"Rachel Kann - I Know This"
  282. },
  283. {
  284. "text":"Who mistook the steak for chicken?",
  285. "source":"Moldy Peaches - Steak For Chicken"
  286. },
  287. {
  288. "text":"We're not those kids, sitting on the couch",
  289. "source":"Moldy Peaches - Steak For Chicken"
  290. },
  291. {
  292. "text":"Death will give us back to God / Just like the setting sun is returned to lonesome ocean",
  293. "source":"Bright Eyes - At The Bottom Of Everything"
  294. },
  295. {
  296. "text":"I'm happy just because / I found out I am really no one",
  297. "source":"Bright Eyes - At The Bottom Of Everything"
  298. },
  299. {
  300. "text":"There'll always be a few things, maybe several things / That you're gonna find really difficult to forgive",
  301. "source":"The Mountain Goates - Up The Wolves"
  302. },
  303. {
  304. "text":"It's gonna take you people years to recover from all of the damage",
  305. "source":"The Mountain Goates - Up The Wolves"
  306. },
  307. {
  308. "text":"Your sleepy anarchy... Wake it Up! Wake it up!",
  309. "source":"TeddyLoid Ft. Debra Zeer - D City Rock"
  310. },
  311. {
  312. "text":"I just miss how it felt standing next to you / Wearing matching dresses before the world was big",
  313. "source":"Girlpool - Before The World Was Big"
  314. },
  315. {
  316. "text":"I have to be fucking with something I love if I'm burning both ends of my candle stick",
  317. "source":"Ceschi, Factor Chandelier & Sammus - Middle Earth"
  318. },
  319. {
  320. "text":"Why you tweetin' at the top of your lungs?",
  321. "source":"Lil Darkie - COMFORT IN DISCOMFORT"
  322. },
  323. {
  324. "text":"It's almost over / It's just begun",
  325. "source":"Bo Burnham - All Eyes On Me"
  326. },
  327. {
  328. "text":"You say the whole world's ending, honey, it already did",
  329. "source":"Bo Burnham - All Eyes On Me"
  330. },
  331. {
  332. "text":"You're drowning in the grief of Jupiter's waters",
  333. "source":"Terrance Zdunich - Grief (Alternate Version)"
  334. },
  335. {
  336. "text":"I'd rather nap than wonder, restlessly / Will you ever be impressed by me?",
  337. "source":"Crying - ES"
  338. },
  339. {
  340. "text":"How did you become this way?",
  341. "source":"Crying - ES"
  342. },
  343. {
  344. "text":"I'll embrace dreams again when I can breathe again / And at that point I won't be needing them",
  345. "source":"John Reuben - Chapter 1"
  346. },
  347. {
  348. "text":"The revolution didn't leave you, it never came",
  349. "source":"John Reuben - Chapter 1"
  350. },
  351. {
  352. "text":"When real life is reality TV, no wonder our youth don't believe in anything",
  353. "source":"John Reuben - Chapter 1"
  354. },
  355. {
  356. "text":"There are no heroes, just those of us with high hopes",
  357. "source":"John Reuben - Chapter 1"
  358. },
  359. {
  360. "text":"Puff the magic Jesus floats around the universe; The United States is his favorite place on the whole entire Earth",
  361. "source":"John Reuben - What About Them?"
  362. },
  363. {
  364. "text":"History is best forgotten and even better rewritten / And since there's no forgetting, let's remember it different",
  365. "source":"John Reuben - What About Them?"
  366. },
  367. {
  368. "text":"Four walls with no windows doesn't mean you're it / Four walls with no windows doesn't mean they don't exist",
  369. "source":"John Reuben - What About Them?"
  370. },
  371. {
  372. "text":"Ignore the crying outside the door / Sure, you'll pray for their burdens, but you don't want to make it yours",
  373. "source":"John Reuben - What About Them?"
  374. },
  375. {
  376. "text":"The more you have, the less you care / The less you care, the more you become unaware",
  377. "source":"John Reuben - What About Them?"
  378. },
  379. {
  380. "text":"Try to sell it to God, and see if he buys your sales pitch",
  381. "source":"John Reuben - Sales Pitch"
  382. },
  383. {
  384. "text":"Everyone's got an agenda. Can you tell me what's yours?",
  385. "source":"John Reuben - Sales Pitch"
  386. },
  387. {
  388. "text":"Job well done, Religion. Look what you've created.",
  389. "source":"John Reuben - Sales Pitch"
  390. },
  391. {
  392. "text":"God bless us as we sweep this mess under the rug",
  393. "source":"John Reuben - What About Them?"
  394. },
  395. {
  396. "text":"It's not the way I'm meant to be / It's just the way the operation made me",
  397. "source":"The Dresden Dolls - Girl Anachronism"
  398. },
  399. {
  400. "text":"Behold the world's worst accident / I am the girl anachronism",
  401. "source":"The Dresden Dolls - Girl Anachronism"
  402. },
  403. {
  404. "text":"I don't necessarily believe there is a cure for this, so I might join your century as a doubtful guest",
  405. "source":"The Dresden Dolls - Girl Anachronism"
  406. },
  407. {
  408. "text":"Do you love me? Yes, no, maybe. I'll be seeing Hades soon",
  409. "source":"JACK THE STRIPPER Ft. Byrds - PHANTASM"
  410. },
  411. {
  412. "text":"Define \"terrorist\"",
  413. "source":"Me - On the subject of governments trying to stop \"terrorists\""
  414. },
  415. {
  416. "text":"What goal would justify the suffering of your life",
  417. "source":"Jordan Peterson"
  418. },
  419. {
  420. "text":"The goal is to be wrong in interesting ways",
  421. "source":"Abigail Thorn"
  422. },
  423. {
  424. "text":"God help the outcast with her witchcraft / Some day I'm gonna go home",
  425. "source":"Sherclop Pones - Pinkie's Brew"
  426. },
  427. {
  428. "text":"When I wrote this code, only God and I knew how it worked. Now, only God knows it!",
  429. "source":"Unknown Developer"
  430. },
  431. {
  432. "text":"It's okay to be different things in different places.",
  433. "source":"@alis@fandom.ink - https://fandom.ink/@alis/109545392718134930"
  434. },
  435. {
  436. "text":"You're nobody till somebody wants you dead",
  437. "source":"Saint Motel - You're Nobody Till Somebody Wants You Dead"
  438. },
  439. {
  440. "text":"You ask a silly question, you get a silly answer.",
  441. "source":"Tom Lehrer - New Math"
  442. },
  443. {
  444. "text":"But I don't want to go to sleep; in all my dreams I drown.",
  445. "source":"The Devil's Carnival - In All My Dreams I Drown"
  446. },
  447. {
  448. "text":"We are the life, we are the light / We are the envy of the Gods above",
  449. "source":"The Orion Experience - The Cult of Dionysus"
  450. },
  451. {
  452. "text":"Let's get mischievous, and polyamorous",
  453. "source":"The Orion Experience - The Cult of Dionysus"
  454. },
  455. {
  456. "text":"Don't give up yet, no don't ever quit / There's always a chance for a critical hit.",
  457. "source":"Ghost Mice - Critical Hit"
  458. },
  459. {
  460. "text":"Shut your mouth / Listen up when I talk / I'm a spoiled little brat and I get what I want",
  461. "source":"Underscores - Spoiled Little Brat"
  462. },
  463. {
  464. "text":"In my life, I hope I lie, and tell everyone you were a good wife",
  465. "source":"The Mountain Goats - No Children"
  466. },
  467. {
  468. "text":"I hope you Die / I hope we both die",
  469. "source":"The Mountain Goats - No Children"
  470. },
  471. {
  472. "text":"I hope it stays dark forever / I hope the worst the isn't over",
  473. "source":"The Mountain Goats - No Children"
  474. },
  475. {
  476. "text":"I hope when you think of me years down the line, you can't think of one good thing to say",
  477. "source":"The Mountain Goats - No Children"
  478. },
  479. {
  480. "text":"And I'd hope that if I found the strength to walk out, you'd stay the hell out of my way",
  481. "source":"The Mountain Goats - No Children"
  482. },
  483. {
  484. "text":"I am Drowning / There is no sign of land / You are coming down with me / Hand in unlovable hand",
  485. "source":"The Mountain Goats - No Children"
  486. },
  487. {
  488. "text":"If I had a dime for every man that's stolen mine, I'd be right back where I started",
  489. "source":"Larry and His Flask - Breaking Even"
  490. },
  491. {
  492. "text":"I can't decide whether you should live or die. Oh you'll probably go to Heaven. Please don't hang your head and cry.",
  493. "source":"Scissor Sisters - I Can't Decide"
  494. },
  495. {
  496. "text":"I've got to hand it to you / You played by all the same rules. It takes the truth to fool me, and now you've made me angry.",
  497. "source":"Scissor Sisters - I Can't Decide"
  498. },
  499. {
  500. "text":"A bit of mustard adds reality",
  501. "source":"An advertisement for a rubber hotdog prank"
  502. },
  503. {
  504. "text":"You're closer to a jail cell than you'll ever be to God",
  505. "source":"CALYPSO - The Exorcist"
  506. },
  507. {
  508. "text":"Love thy neighbor, right? Or is it only if they're rich, able-bodied, cis, hetero and white?",
  509. "source":"CALYPSO - The Exorcist"
  510. },
  511. {
  512. "text":"Plenty of time until it's gone. It's alright until it's not.",
  513. "source":"Worthikids - Spinning Wheel"
  514. },
  515. {
  516. "text":"How many times have I looped this song? When did my hair get so long?",
  517. "source":"Worthikids - Spinning Wheel"
  518. },
  519. {
  520. "text":"And the future never comes. What comes is always here, now.",
  521. "source":"Osho, Indian Philosopher"
  522. },
  523. {
  524. "text":"It is a series of nows. One now, another now, but you are always living in the now.",
  525. "source":"Osho, Indian Philosopher"
  526. },
  527. {
  528. "text":"I'm a person among other people, and I deserve at least as much respect as a person among other people",
  529. "source":"Jordan Peterson"
  530. },
  531. {
  532. "text":"I didn't know the Russians had tea!",
  533. "source":"A customer I overheard commenting on my bakery's Russian Tea Biscuits"
  534. },
  535. {
  536. "text":"What is youth, if not a time to be forgiven for one's transgressions?",
  537. "source":"Gale from Baldur's Gate 3"
  538. },
  539. {
  540. "text":"Something's wrong when you regret things that haven't happened yet",
  541. "source":"The Submarines - 1940"
  542. },
  543. {
  544. "text":"Why worry about yesterday's fuckups when you have tomorrow's fuckups to look forward to?",
  545. "source":"@masood_boomgaard@tiktok.com"
  546. },
  547. {
  548. "text":"You will be okay. You have no other option.",
  549. "source":"/u/kristencolby on Reddit"
  550. },
  551. {
  552. "text":"waga baga bobo",
  553. "source":"The jailer has decided to execute you"
  554. },
  555. {
  556. "text":"I don't know what I'm gonna do / I can't keep anything at all from slipping through my raccoon claws",
  557. "source":"Penelope Scott - Soap"
  558. },
  559. {
  560. "text":"I don't know what I'm doing, but I am okay with losing",
  561. "source":"That Handsome Devil - F2F"
  562. },
  563. {
  564. "text":"I don't know what I'm doing, but I'm not afraid of losing",
  565. "source":"That Handsome Devil - F2F"
  566. },
  567. {
  568. "text":"You deserve to get to know the person you're trying your damnedest to let go",
  569. "source":"36 Questions - Hear Me Out"
  570. },
  571. {
  572. "text":"Only you can be the one to say you're through, and walk away",
  573. "source":"36 Questions - Answer 36"
  574. },
  575. {
  576. "text":"I deserve to let you go, and build a better version on my own, somehow",
  577. "source":"36 Questions - Answer 36"
  578. },
  579. {
  580. "text":"It's strange to imagine my everyday without you",
  581. "source":"36 Questions - Answer 36"
  582. },
  583. {
  584. "text":"What's true for you doesn't have to be true forever",
  585. "source":"36 Questions - The Truth"
  586. },
  587. {
  588. "text":"The truth is that the truth doesn't exist in black and white, and some times two sides can both be right",
  589. "source":"36 Questions - The Truth"
  590. },
  591. {
  592. "text":"I know for sure I don't wanna be a rockstar if it makes me what you are",
  593. "source":"Woz - Child Support"
  594. },
  595. {
  596. "text":"Next time your song is playing at the bar I swear I'll go hom. At least I know you won't be there.",
  597. "source":"Woz - Child Support"
  598. },
  599. {
  600. "text":"Daddy's little girl paints the world with her magic wand",
  601. "source":"Jesse Spencer - Molly Smiles"
  602. },
  603. {
  604. "text":"I'm still fixing who you make me / But one day I'll forget it even happened",
  605. "source":"Addison Grace - Manic Pixie Dream Girl"
  606. },
  607. {
  608. "text":"Pity me, I'm almost a human being",
  609. "source":"Aurelio Voltaire - Almost Human"
  610. },
  611. {
  612. "text":"Look at me, I'm almost a human being",
  613. "source":"Aurelio Voltaire - Almost Human"
  614. },
  615. {
  616. "text":"I'm just like you, made by He, despised by They, I'm almost me",
  617. "source":"Aurelio Voltaire - Almost Human"
  618. },
  619. {
  620. "text":"I know money's for managers, but goddamit, art is for amateurs",
  621. "source":"Jam Mechanics, Bug Hunter, The Narcissist Cookbook - Art is for Amateurs"
  622. },
  623. ],
  624. PlaceQuote: function() {
  625. const div = document.getElementById("footer-quote");
  626. if (div) {
  627. quote = this.all_quotes[Math.floor(Math.random() * this.all_quotes.length)];
  628. div.innerText = quote.text;
  629. console.log(`Quote source: ${quote.source}`);
  630. }
  631. },
  632. /**
  633. * Add a quote to the list of possible quotes to display in the footer
  634. *
  635. * @param {string} quote The quote to display in the footer
  636. * @param {string} source The source of the quote that will be logged in the browser's console
  637. */
  638. AddQuote: function(quote, source) {
  639. this.all_quotes.push({
  640. text: quote,
  641. source: source,
  642. });
  643. }
  644. }
  645. function page_init() {
  646. /* Initialize info panels */
  647. const panels = document.querySelectorAll('.infopanel');
  648. for(const panel of panels) {
  649. panel._infoPanel = new Bumble.InfoPanel(panel);
  650. }
  651. Bumble._GET.__init();
  652. Bumble.XFN.init();
  653. Bumble.FooterQuotes.PlaceQuote();
  654. }
  655. if(document.readyState != 'loading') {
  656. page_init();
  657. }
  658. else {
  659. document.addEventListener('DOMContentLoaded', page_init);
  660. }