Bumble.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  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. const rels = link.rel.split(' ');
  196. let rel = null;
  197. if(rels.indexOf("me") >= 0) {
  198. rel = this.me;
  199. }
  200. else if(rels.indexOf("friend") >= 0) {
  201. rel = this.friend;
  202. }
  203. else if(rels.indexOf("colleague") >= 0) {
  204. rel = this.colleague;
  205. }
  206. if(rel) {
  207. link.insertAdjacentElement("afterbegin", this._buildIcon(rel));
  208. }
  209. }
  210. },
  211. }
  212. /**
  213. * Quotes that either have a lot of meaning to me, or I just really enjoy
  214. */
  215. Bumble.FooterQuotes = {
  216. all_quotes: [
  217. {
  218. "text":"We can't rewind now; we've gone too far",
  219. "source":"The Limousines - Internet Killed The Video Star"
  220. },
  221. {
  222. "text":"There is no justice or no peace, there's only forgiveness",
  223. "source":"John Reuben - There's only Forgiveness"
  224. },
  225. {
  226. "text":"Love is like a circle; there's no easy way to end",
  227. "source":"Oliver Tree - Cowboys Don't Cry"
  228. },
  229. {
  230. "text":"No crime is as bad as meaninglessness",
  231. "source":"Futhermore - Letter To Myself"
  232. },
  233. {
  234. "text":"Independence was the goal, now you miss home sick",
  235. "source":"Futhermore - Letter To Myself"
  236. },
  237. {
  238. "text":"Apathy's a tragedy, and boredom is a crime",
  239. "source":"Bo Burnham - Welcome To The Internet"
  240. },
  241. {
  242. "text":"All I ever wanted was a little bit of everything all of the time",
  243. "source":"Bo Burnham - Welcome To The Internet"
  244. },
  245. {
  246. "text":"The taste of blood; It's murder; This is your fault; You chose this path.",
  247. "source":"Mayhem - It's Murder"
  248. },
  249. {
  250. "text":"So it goes.",
  251. "source":"Kurt Vonnegaut - Slaughter-house Five"
  252. },
  253. {
  254. "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.",
  255. "source":"Kurt Vonnegaut - Slaughter-house Five"
  256. },
  257. {
  258. "text":"This isn't a man. It's a broken kite.",
  259. "source":"Kurt Vonnegaut - Slaughter-house Five"
  260. },
  261. {
  262. "text":"Why you? Why us for that matter? Why Anything? Because the moment simply is.",
  263. "source":"Kurt Vonnegaut - Slaughter-house Five"
  264. },
  265. {
  266. "text":"Poo-tee-tweet?",
  267. "source":"Kurt Vonnegaut - Slaughter-house Five"
  268. },
  269. {
  270. "text":"Yeah there's nothing left to ruin, yeah we finally got free / How's that for manifesting our destiny",
  271. "source":"Sylvan Esso - PARAD(w/m)E"
  272. },
  273. {
  274. "text":"Where you been? I wonder / We've been waitin so long around here for days, days, days",
  275. "source":"Mr. Gnome - Pixie Dust"
  276. },
  277. {
  278. "text":"We will laugh at the fact that we ever resisted this blissful togetherness",
  279. "source":"Rachel Kann - I Know This"
  280. },
  281. {
  282. "text":"Who mistook the steak for chicken?",
  283. "source":"Moldy Peaches - Steak For Chicken"
  284. },
  285. {
  286. "text":"We're not those kids, sitting on the couch",
  287. "source":"Moldy Peaches - Steak For Chicken"
  288. },
  289. {
  290. "text":"Death will give us back to God / Just like the setting sun is returned to lonesome ocean",
  291. "source":"Bright Eyes - At The Bottom Of Everything"
  292. },
  293. {
  294. "text":"I'm happy just because / I found out I am really no one",
  295. "source":"Bright Eyes - At The Bottom Of Everything"
  296. },
  297. {
  298. "text":"There'll always be a few things, maybe several things / That you're gonna find really difficult to forgive",
  299. "source":"The Mountain Goates - Up The Wolves"
  300. },
  301. {
  302. "text":"It's gonna take you people years to recover from all of the damage",
  303. "source":"The Mountain Goates - Up The Wolves"
  304. },
  305. {
  306. "text":"Your sleepy anarchy... Wake it Up! Wake it up!",
  307. "source":"TeddyLoid Ft. Debra Zeer - D City Rock"
  308. },
  309. {
  310. "text":"I just miss how it felt standing next to you / Wearing matching dresses before the world was big",
  311. "source":"Girlpool - Before The World Was Big"
  312. },
  313. {
  314. "text":"I have to be fucking with something I love if I'm burning both ends of my candle stick",
  315. "source":"Girlpool - Before The World Was Big"
  316. },
  317. {
  318. "text":"Why you tweetin' at the top of your lungs?",
  319. "source":"Lil Darkie - COMFORT IN DISCOMFORT"
  320. },
  321. {
  322. "text":"It's almost over / It's just begun",
  323. "source":"Bo Burnham - All Eyes On Me"
  324. },
  325. {
  326. "text":"You say the whole world's ending, honey, it already did",
  327. "source":"Bo Burnham - All Eyes On Me"
  328. },
  329. {
  330. "text":"You're drowning in the grief of Jupiter's waters",
  331. "source":"Terrance Zdunich - Grief (Alternate Version)"
  332. },
  333. {
  334. "text":"I'd rather nap than wonder, restlessly / Will you ever be impressed by me?",
  335. "source":"Crying - ES"
  336. },
  337. {
  338. "text":"How did you become this way?",
  339. "source":"Crying - ES"
  340. },
  341. {
  342. "text":"I'll embrace dreams again when I can breathe again / And at that point I won't be needing them",
  343. "source":"John Reuben - Chapter 1"
  344. },
  345. {
  346. "text":"The revolution didn't leave you, it never came",
  347. "source":"John Reuben - Chapter 1"
  348. },
  349. {
  350. "text":"When real life is reality TV, no wonder our youth don't believe in anything",
  351. "source":"John Reuben - Chapter 1"
  352. },
  353. {
  354. "text":"There are no heroes, just those of us with high hopes",
  355. "source":"John Reuben - Chapter 1"
  356. },
  357. {
  358. "text":"Puff the magic Jesus floats around the universe; The United States is his favorite place on the whole entire Earth",
  359. "source":"John Reuben - What About Them?"
  360. },
  361. {
  362. "text":"History is best forgotten and even better rewritten / And since there's no forgetting, let's remember it different",
  363. "source":"John Reuben - What About Them?"
  364. },
  365. {
  366. "text":"Four walls with no windows doesn't mean you're it / Four walls with no windows doesn't mean they don't exist",
  367. "source":"John Reuben - What About Them?"
  368. },
  369. {
  370. "text":"Ignore the crying outside the door / Sure, you'll pray for their burdens, but you don't want to make it yours",
  371. "source":"John Reuben - What About Them?"
  372. },
  373. {
  374. "text":"The more you have, the less you care / The less you care, the more you become unaware",
  375. "source":"John Reuben - What About Them?"
  376. },
  377. {
  378. "text":"Try to sell it to God, and see if he buys your sales pitch",
  379. "source":"John Reuben - Sales Pitch"
  380. },
  381. {
  382. "text":"Everyone's got an agenda. Can you tell me what's yours?",
  383. "source":"John Reuben - Sales Pitch"
  384. },
  385. {
  386. "text":"Job well done, Religion. Look what you've created.",
  387. "source":"John Reuben - Sales Pitch"
  388. },
  389. {
  390. "text":"God bless us as we sweep this mess under the rug",
  391. "source":"John Reuben - What About Them?"
  392. },
  393. {
  394. "text":"It's not the way I'm meant to be / It's just the way the operation made me",
  395. "source":"The Dresden Dolls - Girl Anachronism"
  396. },
  397. {
  398. "text":"Behold the world's worst accident / I am the girl anachronism",
  399. "source":"The Dresden Dolls - Girl Anachronism"
  400. },
  401. {
  402. "text":"I don't necessarily believe there is a cure for this, so I might join your century as a doubtful guest",
  403. "source":"The Dresden Dolls - Girl Anachronism"
  404. },
  405. {
  406. "text":"Do you love me? Yes, no, maybe. I'll be seeing Hades soon",
  407. "source":"JACK THE STRIPPER Ft. Byrds - PHANTASM"
  408. },
  409. {
  410. "text":"Define \"terrorist\"",
  411. "source":"Me - On the subject of governments trying to stop \"terrorists\""
  412. },
  413. {
  414. "text":"What goal would justify the suffering of your life",
  415. "source":"Jordan Peterson"
  416. },
  417. {
  418. "text":"The goal is to be wrong in interesting ways",
  419. "source":"Abigail Thorn"
  420. },
  421. {
  422. "text":"God help the outcast with her witchcraft / Some day I'm gonna go home",
  423. "source":"Sherclop Pones - Pinkie's Brew"
  424. },
  425. {
  426. "text":"When I wrote this code, only God and I knew how it worked. Now, only God knows it!",
  427. "source":"Unknown Developer"
  428. },
  429. {
  430. "text":"It's okay to be different things in different places.",
  431. "source":"@alis@fandom.ink - https://fandom.ink/@alis/109545392718134930"
  432. },
  433. {
  434. "text":"You're nobody till somebody wants you dead",
  435. "source":"Saint Motel - You're Nobody Till Somebody Wants You Dead"
  436. },
  437. {
  438. "text":"You ask a silly question, you get a silly answer.",
  439. "source":"Tom Lehrer - New Math"
  440. },
  441. {
  442. "text":"But I don't want to go to sleep; in all my dreams I drown.",
  443. "source":"The Devil's Carnival - In All My Dreams I Drown"
  444. },
  445. {
  446. "text":"We are the life, we are the light / We are the envy of the Gods above",
  447. "source":"The Orion Experience - The Cult of Dionysus"
  448. },
  449. {
  450. "text":"Let's get mischievous, and polyamorous",
  451. "source":"The Orion Experience - The Cult of Dionysus"
  452. },
  453. {
  454. "text":"Don't give up yet, no don't ever quit / There's always a chance for a critical hit.",
  455. "source":"Ghost Mice - Critical Hit"
  456. },
  457. {
  458. "text":"Shut your mouth / Listen up when I talk / I'm a spoiled little brat and I get what I want",
  459. "source":"Underscores - Spoiled Little Brat"
  460. },
  461. {
  462. "text":"In my life, I hope I lie, and tell everyone you were a good wife",
  463. "source":"The Mountain Goats - No Children"
  464. },
  465. {
  466. "text":"I hope you Die / I hope we both die",
  467. "source":"The Mountain Goats - No Children"
  468. },
  469. {
  470. "text":"I hope it stays dark forever / I hope the worst the isn't over",
  471. "source":"The Mountain Goats - No Children"
  472. },
  473. {
  474. "text":"I hope when you think of me years down the line, you can't think of one good thing to say",
  475. "source":"The Mountain Goats - No Children"
  476. },
  477. {
  478. "text":"And I'd hope that if I found the strength to walk out, you'd stay the hell out of my way",
  479. "source":"The Mountain Goats - No Children"
  480. },
  481. {
  482. "text":"I am Drowning / There is no sign of land / You are coming down with me / Hand in unlovable hand",
  483. "source":"The Mountain Goats - No Children"
  484. },
  485. {
  486. "text":"If I had a dime for every man that's stolen mine, I'd be right back where I started",
  487. "source":"Larry and His Flask - Breaking Even"
  488. },
  489. {
  490. "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.",
  491. "source":"Scissor Sisters - I Can't Decide"
  492. },
  493. {
  494. "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.",
  495. "source":"Scissor Sisters - I Can't Decide"
  496. },
  497. {
  498. "text":"A bit of mustard adds reality",
  499. "source":"An advertisement for a rubber hotdog prank"
  500. },
  501. {
  502. "text":"You're closer to a jail cell than you'll ever be to God",
  503. "source":"CALYPSO - The Exorcist"
  504. },
  505. {
  506. "text":"Love thy neighbor, right? Or is it only if they're rich, able-bodied, cis, hetero and white?",
  507. "source":"CALYPSO - The Exorcist"
  508. },
  509. ],
  510. PlaceQuote: function() {
  511. const div = document.getElementById("footer-quote");
  512. if (div) {
  513. quote = this.all_quotes[Math.floor(Math.random() * this.all_quotes.length)];
  514. div.innerText = quote.text;
  515. console.log(`Quote source: ${quote.source}`);
  516. }
  517. }
  518. }
  519. function page_init() {
  520. /* Initialize info panels */
  521. const panels = document.querySelectorAll('.infopanel');
  522. for(const panel of panels) {
  523. panel._infoPanel = new Bumble.InfoPanel(panel);
  524. }
  525. Bumble._GET.__init();
  526. Bumble.XFN.init();
  527. Bumble.FooterQuotes.PlaceQuote();
  528. }
  529. if(document.readyState != 'loading') {
  530. page_init();
  531. }
  532. else {
  533. document.addEventListener('DOMContentLoaded', page_init);
  534. }