leilukin-site/assets/js/gvKiDZvbYN.js

1292 lines
59 KiB
JavaScript
Raw Permalink Normal View History

/**
* Author: Vera Konigin
* Site: https://groundedwren.neocities.org
* Contact: vera@groundedwren.com
*
* File Description: A web component to site SVG icons easily
*/
/**
* By default, any JavaScript code written is defined in the global namespace, which means it's accessible directly under the "window" element.
* If you have a lot of scripts, this can lead to clutter and naming collisions (what if two different scripts use a variable called "i"? They can inadvertently mess each other up).
* To get around this, we define the registerNamespace function in the global namespace, which just confines all the code in the function passed to it to a property under window.
* That property is represented as the "path" parameter. It is passed to the function for ease of access.
*/
function registerNamespace(path, nsFunc)
{
var ancestors = path.split(".");
var ns = window;
for(var i = 0; i < ancestors.length; i++)
{
ns[ancestors[i]] = ns[ancestors[i]] || {};
ns = ns[ancestors[i]];
}
nsFunc(ns);
}
registerNamespace("GW.Controls.SVGLib", function(ns) {
const XML_NAMESPACE = "http://www.w3.org/2000/svg";
/**
* https://www.w3.org/TR/SVG/eltindex.html
*/
ns.ElementTypes = {
svg: "svg", //viewBox, preserveAspectRatio, zoomAndPan, transform - https://www.w3.org/TR/SVG/struct.html#SVGElement
circle: "circle", //cx, cy, r - https://www.w3.org/TR/SVG/shapes.html#CircleElement
linearGradient: "linearGradient", //x1, y1, x2, y2, gradientUnits, gradientTransform, spreadMethod, href - https://www.w3.org/TR/SVG/pservers.html#LinearGradientElement
stop: "stop", //offset, stop-color https://www.w3.org/TR/SVG/pservers.html#StopElement
defs: "defs", //https://www.w3.org/TR/SVG/struct.html#DefsElement
rect: "rect", //x, y, width, height, rx, ry - https://www.w3.org/TR/SVG/shapes.html#RectElement
text: "text", //x, y, dominant-baseline, text-anchor, fill - https://www.w3.org/TR/SVG/text.html#TextElement
a: "a", //href, target - https://developer.mozilla.org/en-US/docs/Web/SVG/Element/a
path: "path", //d, pathLength - https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path
title: "title", // - https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title
desc: "desc", // - https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc
foreignObject: "foreignObject", // - https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject
};
/**
* Shortcut to create an SVG element and append it to a parent
* @param parent the parent element
* ... see ns.createElement
*/
function createChildElement(parent, elementType, attributes, innerHTML)
{
var childEl = createElement(elementType, attributes, innerHTML);
parent.appendChild(childEl);
return childEl;
}
ns.createChildElement = createChildElement;
/**
* Creates an SVG element to spec
* @param elementType type of SVG element (see ns.ElementTypes)
* @param attributes object of attributes and values
* @param innerHTML inner HTML
*/
function createElement(elementType, attributes, innerHTML)
{
var el = document.createElementNS(XML_NAMESPACE, elementType);
Object.keys(attributes || {}).forEach((attr) => el.setAttributeNS(null, attr, attributes[attr]));
el.innerHTML = innerHTML || null;
return el;
}
ns.createElement = createElement;
//#region Icons
const ICON_CITATION = "<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->";
const ICON_CLASS = "icon";
/**
* Icon SVG path definitions
*/
ns.Icons = {
"circle-info": {
title: "info",
viewBox: "0 0 512 512",
d: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"
},
"play": {
title: "play",
viewBox: "0 0 384 512",
d: "M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"
},
"backward-step": {
title: "backward step",
viewBox: "0 0 320 512",
d: "M267.5 440.6c9.5 7.9 22.8 9.7 34.1 4.4s18.4-16.6 18.4-29V96c0-12.4-7.2-23.7-18.4-29s-24.5-3.6-34.1 4.4l-192 160L64 241V96c0-17.7-14.3-32-32-32S0 78.3 0 96V416c0 17.7 14.3 32 32 32s32-14.3 32-32V271l11.5 9.6 192 160z"
},
"forward-step": {
title: "forward step",
viewBox: "0 0 320 512",
d: "M52.5 440.6c-9.5 7.9-22.8 9.7-34.1 4.4S0 428.4 0 416V96C0 83.6 7.2 72.3 18.4 67s24.5-3.6 34.1 4.4l192 160L256 241V96c0-17.7 14.3-32 32-32s32 14.3 32 32V416c0 17.7-14.3 32-32 32s-32-14.3-32-32V271l-11.5 9.6-192 160z"
},
"pause": {
title: "pause",
viewBox: "0 0 320 512",
d: "M48 64C21.5 64 0 85.5 0 112V400c0 26.5 21.5 48 48 48H80c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H48zm192 0c-26.5 0-48 21.5-48 48V400c0 26.5 21.5 48 48 48h32c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H240z"
},
"triangle-exclamation": {
title: "warning",
viewBox: "0 0 512 512",
d: "M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480H40c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24V296c0 13.3 10.7 24 24 24s24-10.7 24-24V184c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"
},
"laptop-code": {
title: "coding",
viewBox: "0 0 640 512",
d: "M64 96c0-35.3 28.7-64 64-64H512c35.3 0 64 28.7 64 64V352H512V96H128V352H64V96zM0 403.2C0 392.6 8.6 384 19.2 384H620.8c10.6 0 19.2 8.6 19.2 19.2c0 42.4-34.4 76.8-76.8 76.8H76.8C34.4 480 0 445.6 0 403.2zM281 209l-31 31 31 31c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-48-48c-9.4-9.4-9.4-24.6 0-33.9l48-48c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9zM393 175l48 48c9.4 9.4 9.4 24.6 0 33.9l-48 48c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l31-31-31-31c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0z"
},
"guitar": {
title: "guitar",
viewBox: "0 0 512 512",
d: "M465 7c-9.4-9.4-24.6-9.4-33.9 0L383 55c-2.4 2.4-4.3 5.3-5.5 8.5l-15.4 41-77.5 77.6c-45.1-29.4-99.3-30.2-131 1.6c-11 11-18 24.6-21.4 39.6c-3.7 16.6-19.1 30.7-36.1 31.6c-25.6 1.3-49.3 10.7-67.3 28.6C-16 328.4-7.6 409.4 47.5 464.5s136.1 63.5 180.9 18.7c17.9-17.9 27.4-41.7 28.6-67.3c.9-17 15-32.3 31.6-36.1c15-3.4 28.6-10.5 39.6-21.4c31.8-31.8 31-85.9 1.6-131l77.6-77.6 41-15.4c3.2-1.2 6.1-3.1 8.5-5.5l48-48c9.4-9.4 9.4-24.6 0-33.9L465 7zM208 256a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"
},
"pen-fancy": {
title: "pen",
viewBox: "0 0 512 512",
d: "M373.5 27.1C388.5 9.9 410.2 0 433 0c43.6 0 79 35.4 79 79c0 22.8-9.9 44.6-27.1 59.6L277.7 319l-10.3-10.3-64-64L193 234.3 373.5 27.1zM170.3 256.9l10.4 10.4 64 64 10.4 10.4-19.2 83.4c-3.9 17.1-16.9 30.7-33.8 35.4L24.4 510.3l95.4-95.4c2.6 .7 5.4 1.1 8.3 1.1c17.7 0 32-14.3 32-32s-14.3-32-32-32s-32 14.3-32 32c0 2.9 .4 5.6 1.1 8.3L1.7 487.6 51.5 310c4.7-16.9 18.3-29.9 35.4-33.8l83.4-19.2z"
},
"glasses": {
title: "glasses",
viewBox: "0 0 576 512",
d: "M118.6 80c-11.5 0-21.4 7.9-24 19.1L57 260.3c20.5-6.2 48.3-12.3 78.7-12.3c32.3 0 61.8 6.9 82.8 13.5c10.6 3.3 19.3 6.7 25.4 9.2c3.1 1.3 5.5 2.4 7.3 3.2c.9 .4 1.6 .7 2.1 1l.6 .3 .2 .1 .1 0 0 0 0 0s0 0-6.3 12.7h0l6.3-12.7c5.8 2.9 10.4 7.3 13.5 12.7h40.6c3.1-5.3 7.7-9.8 13.5-12.7l6.3 12.7h0c-6.3-12.7-6.3-12.7-6.3-12.7l0 0 0 0 .1 0 .2-.1 .6-.3c.5-.2 1.2-.6 2.1-1c1.8-.8 4.2-1.9 7.3-3.2c6.1-2.6 14.8-5.9 25.4-9.2c21-6.6 50.4-13.5 82.8-13.5c30.4 0 58.2 6.1 78.7 12.3L481.4 99.1c-2.6-11.2-12.6-19.1-24-19.1c-3.1 0-6.2 .6-9.2 1.8L416.9 94.3c-12.3 4.9-26.3-1.1-31.2-13.4s1.1-26.3 13.4-31.2l31.3-12.5c8.6-3.4 17.7-5.2 27-5.2c33.8 0 63.1 23.3 70.8 56.2l43.9 188c1.7 7.3 2.9 14.7 3.5 22.1c.3 1.9 .5 3.8 .5 5.7v6.7V352v16c0 61.9-50.1 112-112 112H419.7c-59.4 0-108.5-46.4-111.8-105.8L306.6 352H269.4l-1.2 22.2C264.9 433.6 215.8 480 156.3 480H112C50.1 480 0 429.9 0 368V352 310.7 304c0-1.9 .2-3.8 .5-5.7c.6-7.4 1.8-14.8 3.5-22.1l43.9-188C55.5 55.3 84.8 32 118.6 32c9.2 0 18.4 1.8 27 5.2l31.3 12.5c12.3 4.9 18.3 18.9 13.4 31.2s-18.9 18.3-31.2 13.4L127.8 81.8c-2.9-1.2-6-1.8-9.2-1.8zM64 325.4V368c0 26.5 21.5 48 48 48h44.3c25.5 0 46.5-19.9 47.9-45.3l2.5-45.6c-2.3-.8-4.9-1.7-7.5-2.5c-17.2-5.4-39.9-10.5-63.6-10.5c-23.7 0-46.2 5.1-63.2 10.5c-3.1 1-5.9 1.9-8.5 2.9zM512 368V325.4c-2.6-.9-5.5-1.9-8.5-2.9c-17-5.4-39.5-10.5-63.2-10.5c-23.7 0-46.4 5.1-63.6 10.5c-2.7 .8-5.2 1.7-7.5 2.5l2.5 45.6c1.4 25.4 22.5 45.3 47.9 45.3H464c26.5 0 48-21.5 48-48z"
},
"clock": {
title: "glasses",
viewBox: "0 0 512 512",
d: "M256 0a256 256 0 1 1 0 512A256 256 0 1 1 256 0zM232 120V256c0 8 4 15.5 10.7 20l96 64c11 7.4 25.9 4.4 33.3-6.7s4.4-25.9-6.7-33.3L280 243.2V120c0-13.3-10.7-24-24-24s-24 10.7-24 24z"
},
"envelope": {
title: "envelope",
viewBox: "0 0 512 512",
d: "M48 64C21.5 64 0 85.5 0 112c0 15.1 7.1 29.3 19.2 38.4L236.8 313.6c11.4 8.5 27 8.5 38.4 0L492.8 150.4c12.1-9.1 19.2-23.3 19.2-38.4c0-26.5-21.5-48-48-48H48zM0 176V384c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V176L294.4 339.2c-22.8 17.1-54 17.1-76.8 0L0 176z"
},
"discord": {
title: "discord",
viewBox: "0 0 640 512",
d: "M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"
},
"plus": {
title: "plus",
viewBox: "0 0 448 512",
d: "M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H48c-17.7 0-32 14.3-32 32s14.3 32 32 32H192V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H400c17.7 0 32-14.3 32-32s-14.3-32-32-32H256V80z"
},
"circle-check": {
title: "done",
viewBox: "0 0 512 512",
d: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"
},
"delete-left": {
title: "delete",
viewBox: "0 0 576 512",
d: "M576 128c0-35.3-28.7-64-64-64H205.3c-17 0-33.3 6.7-45.3 18.7L9.4 233.4c-6 6-9.4 14.1-9.4 22.6s3.4 16.6 9.4 22.6L160 429.3c12 12 28.3 18.7 45.3 18.7H512c35.3 0 64-28.7 64-64V128zM271 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"
},
"link": {
title: "link",
viewBox: "0 0 640 512",
d: "M579.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-128.8-56.5-186.3-15.4l-1.6 1.1c-14.4 10.3-17.7 30.3-7.4 44.6s30.3 17.7 44.6 7.4l1.6-1.1c32.1-22.9 76-19.3 103.8 8.6c31.5 31.5 31.5 82.5 0 114L422.3 334.8c-31.5 31.5-82.5 31.5-114 0c-27.9-27.9-31.5-71.8-8.6-103.8l1.1-1.6c10.3-14.4 6.9-34.4-7.4-44.6s-34.4-6.9-44.6 7.4l-1.1 1.6C206.5 251.2 213 330 263 380c56.5 56.5 148 56.5 204.5 0L579.8 267.7zM60.2 244.3c-56.5 56.5-56.5 148 0 204.5c50 50 128.8 56.5 186.3 15.4l1.6-1.1c14.4-10.3 17.7-30.3 7.4-44.6s-30.3-17.7-44.6-7.4l-1.6 1.1c-32.1 22.9-76 19.3-103.8-8.6C74 372 74 321 105.5 289.5L217.7 177.2c31.5-31.5 82.5-31.5 114 0c27.9 27.9 31.5 71.8 8.6 103.9l-1.1 1.6c-10.3 14.4-6.9 34.4 7.4 44.6s34.4 6.9 44.6-7.4l1.1-1.6C433.5 260.8 427 182 377 132c-56.5-56.5-148-56.5-204.5 0L60.2 244.3z"
},
"xmark": {
title: "close",
viewBox: "0 0 384 512",
d: "M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"
},
"trash": {
title: "trash",
viewBox: "0 0 448 512",
d: "M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"
},
"thumbtack": {
title: "trash",
viewBox: "0 0 384 512",
d: "M32 32C32 14.3 46.3 0 64 0H320c17.7 0 32 14.3 32 32s-14.3 32-32 32H290.5l11.4 148.2c36.7 19.9 65.7 53.2 79.5 94.7l1 3c3.3 9.8 1.6 20.5-4.4 28.8s-15.7 13.3-26 13.3H32c-10.3 0-19.9-4.9-26-13.3s-7.7-19.1-4.4-28.8l1-3c13.8-41.5 42.8-74.8 79.5-94.7L93.5 64H64C46.3 64 32 49.7 32 32zM160 384h64v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V384z"
},
"pen-to-square": {
title: "edit",
viewBox: "0 0 512 512",
d: "M471.6 21.7c-21.9-21.9-57.3-21.9-79.2 0L362.3 51.7l97.9 97.9 30.1-30.1c21.9-21.9 21.9-57.3 0-79.2L471.6 21.7zm-299.2 220c-6.1 6.1-10.8 13.6-13.5 21.9l-29.6 88.8c-2.9 8.6-.6 18.1 5.8 24.6s15.9 8.7 24.6 5.8l88.8-29.6c8.2-2.7 15.7-7.4 21.9-13.5L437.7 172.3 339.7 74.3 172.4 241.7zM96 64C43 64 0 107 0 160V416c0 53 43 96 96 96H352c53 0 96-43 96-96V320c0-17.7-14.3-32-32-32s-32 14.3-32 32v96c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V160c0-17.7 14.3-32 32-32h96c17.7 0 32-14.3 32-32s-14.3-32-32-32H96z"
},
"book": {
title: "book",
viewBox: "0 0 448 512",
d: "M96 0C43 0 0 43 0 96V416c0 53 43 96 96 96H384h32c17.7 0 32-14.3 32-32s-14.3-32-32-32V384c17.7 0 32-14.3 32-32V32c0-17.7-14.3-32-32-32H384 96zm0 384H352v64H96c-17.7 0-32-14.3-32-32s14.3-32 32-32zm32-240c0-8.8 7.2-16 16-16H336c8.8 0 16 7.2 16 16s-7.2 16-16 16H144c-8.8 0-16-7.2-16-16zm16 48H336c8.8 0 16 7.2 16 16s-7.2 16-16 16H144c-8.8 0-16-7.2-16-16s7.2-16 16-16z"
},
"gamepad": {
title: "game",
viewBox: "0 0 640 512",
d: "M192 64C86 64 0 150 0 256S86 448 192 448H448c106 0 192-86 192-192s-86-192-192-192H192zM496 168a40 40 0 1 1 0 80 40 40 0 1 1 0-80zM392 304a40 40 0 1 1 80 0 40 40 0 1 1 -80 0zM168 200c0-13.3 10.7-24 24-24s24 10.7 24 24v32h32c13.3 0 24 10.7 24 24s-10.7 24-24 24H216v32c0 13.3-10.7 24-24 24s-24-10.7-24-24V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h32V200z"
},
"hammer": {
title: "game",
viewBox: "0 0 576 512",
d: "M413.5 237.5c-28.2 4.8-58.2-3.6-80-25.4l-38.1-38.1C280.4 159 272 138.8 272 117.6V105.5L192.3 62c-5.3-2.9-8.6-8.6-8.3-14.7s3.9-11.5 9.5-14l47.2-21C259.1 4.2 279 0 299.2 0h18.1c36.7 0 72 14 98.7 39.1l44.6 42c24.2 22.8 33.2 55.7 26.6 86L503 183l8-8c9.4-9.4 24.6-9.4 33.9 0l24 24c9.4 9.4 9.4 24.6 0 33.9l-88 88c-9.4 9.4-24.6 9.4-33.9 0l-24-24c-9.4-9.4-9.4-24.6 0-33.9l8-8-17.5-17.5zM27.4 377.1L260.9 182.6c3.5 4.9 7.5 9.6 11.8 14l38.1 38.1c6 6 12.4 11.2 19.2 15.7L134.9 484.6c-14.5 17.4-36 27.4-58.6 27.4C34.1 512 0 477.8 0 435.7c0-22.6 10.1-44.1 27.4-58.6z"
},
"location-dot": {
title: "location",
viewBox: "0 0 384 512",
d: "M215.7 499.2C267 435 384 279.4 384 192C384 86 298 0 192 0S0 86 0 192c0 87.4 117 243 168.3 307.2c12.3 15.3 35.1 15.3 47.4 0zM192 128a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"
},
"box-open": {
title: "box",
viewBox: "0 0 640 512",
d: "M58.9 42.1c3-6.1 9.6-9.6 16.3-8.7L320 64 564.8 33.4c6.7-.8 13.3 2.7 16.3 8.7l41.7 83.4c9 17.9-.6 39.6-19.8 45.1L439.6 217.3c-13.9 4-28.8-1.9-36.2-14.3L320 64 236.6 203c-7.4 12.4-22.3 18.3-36.2 14.3L37.1 170.6c-19.3-5.5-28.8-27.2-19.8-45.1L58.9 42.1zM321.1 128l54.9 91.4c14.9 24.8 44.6 36.6 72.5 28.6L576 211.6v167c0 22-15 41.2-36.4 46.6l-204.1 51c-10.2 2.6-20.9 2.6-31 0l-204.1-51C79 419.7 64 400.5 64 378.5v-167L191.6 248c27.8 8 57.6-3.8 72.5-28.6L318.9 128h2.2z"
},
"calendar": {
title: "box",
viewBox: "0 0 448 512",
d: "M128 0c17.7 0 32 14.3 32 32V64H288V32c0-17.7 14.3-32 32-32s32 14.3 32 32V64h48c26.5 0 48 21.5 48 48v48H0V112C0 85.5 21.5 64 48 64H96V32c0-17.7 14.3-32 32-32zM0 192H448V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V192zm64 80v32c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V272c0-8.8-7.2-16-16-16H80c-8.8 0-16 7.2-16 16zm128 0v32c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V272c0-8.8-7.2-16-16-16H208c-8.8 0-16 7.2-16 16zm144-16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V272c0-8.8-7.2-16-16-16H336zM64 400v32c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V400c0-8.8-7.2-16-16-16H80c-8.8 0-16 7.2-16 16zm144-16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V400c0-8.8-7.2-16-16-16H208zm112 16v32c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16V400c0-8.8-7.2-16-16-16H336c-8.8 0-16 7.2-16 16z"
},
"people-group": {
title: "people",
viewBox: "0 0 640 512",
d: "M72 88a56 56 0 1 1 112 0A56 56 0 1 1 72 88zM64 245.7C54 256.9 48 271.8 48 288s6 31.1 16 42.3V245.7zm144.4-49.3C178.7 222.7 160 261.2 160 304c0 34.3 12 65.8 32 90.5V416c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V389.2C26.2 371.2 0 332.7 0 288c0-61.9 50.1-112 112-112h32c24 0 46.2 7.5 64.4 20.3zM448 416V394.5c20-24.7 32-56.2 32-90.5c0-42.8-18.7-81.3-48.4-107.7C449.8 183.5 472 176 496 176h32c61.9 0 112 50.1 112 112c0 44.7-26.2 83.2-64 101.2V416c0 17.7-14.3 32-32 32H480c-17.7 0-32-14.3-32-32zm8-328a56 56 0 1 1 112 0A56 56 0 1 1 456 88zM576 245.7v84.7c10-11.3 16-26.1 16-42.3s-6-31.1-16-42.3zM320 32a64 64 0 1 1 0 128 64 64 0 1 1 0-128zM240 304c0 16.2 6 31 16 42.3V261.7c-10 11.3-16 26.1-16 42.3zm144-42.3v84.7c10-11.3 16-26.1 16-42.3s-6-31.1-16-42.3zM448 304c0 44.7-26.2 83.2-64 101.2V448c0 17.7-14.3 32-32 32H288c-17.7 0-32-14.3-32-32V405.2c-37.8-18-64-56.5-64-101.2c0-61.9 50.1-112 112-112h32c61.9 0 112 50.1 112 112z"
},
"comments": {
title: "comments",
viewBox: "0 0 640 512",
d: "M208 352c114.9 0 208-78.8 208-176S322.9 0 208 0S0 78.8 0 176c0 38.6 14.7 74.3 39.6 103.4c-3.5 9.4-8.7 17.7-14.2 24.7c-4.8 6.2-9.7 11-13.3 14.3c-1.8 1.6-3.3 2.9-4.3 3.7c-.5 .4-.9 .7-1.1 .8l-.2 .2 0 0 0 0C1 327.2-1.4 334.4 .8 340.9S9.1 352 16 352c21.8 0 43.8-5.6 62.1-12.5c9.2-3.5 17.8-7.4 25.3-11.4C134.1 343.3 169.8 352 208 352zM448 176c0 112.3-99.1 196.9-216.5 207C255.8 457.4 336.4 512 432 512c38.2 0 73.9-8.7 104.7-23.9c7.5 4 16 7.9 25.2 11.4c18.3 6.9 40.3 12.5 62.1 12.5c6.9 0 13.1-4.5 15.2-11.1c2.1-6.6-.2-13.8-5.8-17.9l0 0 0 0-.2-.2c-.2-.2-.6-.4-1.1-.8c-1-.8-2.5-2-4.3-3.7c-3.6-3.3-8.5-8.1-13.3-14.3c-5.5-7-10.7-15.4-14.2-24.7c24.9-29 39.6-64.7 39.6-103.4c0-92.8-84.9-168.9-192.6-175.5c.4 5.1 .6 10.3 .6 15.5z"
},
"clipboard-check": {
title: "clipboard",
viewBox: "0 0 384 512",
d: "M192 0c-41.8 0-77.4 26.7-90.5 64H64C28.7 64 0 92.7 0 128V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V128c0-35.3-28.7-64-64-64H282.5C269.4 26.7 233.8 0 192 0zm0 64a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM305 273L177 401c-9.4 9.4-24.6 9.4-33.9 0L79 337c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L271 239c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"
},
"user": {
title: "clipboard",
viewBox: "0 0 448 512",
d: "M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"
},
"door-open": {
title: "open door",
viewBox: "0 0 576 512",
d: "M320 32c0-9.9-4.5-19.2-12.3-25.2S289.8-1.4 280.2 1l-179.9 45C79 51.3 64 70.5 64 92.5V448H32c-17.7 0-32 14.3-32 32s14.3 32 32 32H96 288h32V480 32zM256 256c0 17.7-10.7 32-24 32s-24-14.3-24-32s10.7-32 24-32s24 14.3 24 32zm96-128h96V480c0 17.7 14.3 32 32 32h64c17.7 0 32-14.3 32-32s-14.3-32-32-32H512V128c0-35.3-28.7-64-64-64H352v64z"
},
"scroll": {
title: "scroll",
viewBox: "0 0 576 512",
d: "M0 80v48c0 17.7 14.3 32 32 32H48 96V80c0-26.5-21.5-48-48-48S0 53.5 0 80zM112 32c10 13.4 16 30 16 48V384c0 35.3 28.7 64 64 64s64-28.7 64-64v-5.3c0-32.4 26.3-58.7 58.7-58.7H480V128c0-53-43-96-96-96H112zM464 480c61.9 0 112-50.1 112-112c0-8.8-7.2-16-16-16H314.7c-14.7 0-26.7 11.9-26.7 26.7V384c0 53-43 96-96 96H368h96z"
},
"star": {
title: "star",
viewBox: "0 0 576 512",
d: "M316.9 18C311.6 7 300.4 0 288.1 0s-23.4 7-28.8 18L195 150.3 51.4 171.5c-12 1.8-22 10.2-25.7 21.7s-.7 24.2 7.9 32.7L137.8 329 113.2 474.7c-2 12 3 24.2 12.9 31.3s23 8 33.8 2.3l128.3-68.5 128.3 68.5c10.8 5.7 23.9 4.9 33.8-2.3s14.9-19.3 12.9-31.3L438.5 329 542.7 225.9c8.6-8.5 11.7-21.2 7.9-32.7s-13.7-19.9-25.7-21.7L381.2 150.3 316.9 18z"
},
"boxes-stacked": {
title: "stacked boxes",
viewBox: "0 0 576 512",
d: "M248 0H208c-26.5 0-48 21.5-48 48V160c0 35.3 28.7 64 64 64H352c35.3 0 64-28.7 64-64V48c0-26.5-21.5-48-48-48H328V80c0 8.8-7.2 16-16 16H264c-8.8 0-16-7.2-16-16V0zM64 256c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H224c35.3 0 64-28.7 64-64V320c0-35.3-28.7-64-64-64H184v80c0 8.8-7.2 16-16 16H120c-8.8 0-16-7.2-16-16V256H64zM352 512H512c35.3 0 64-28.7 64-64V320c0-35.3-28.7-64-64-64H472v80c0 8.8-7.2 16-16 16H408c-8.8 0-16-7.2-16-16V256H352c-15 0-28.8 5.1-39.7 13.8c4.9 10.4 7.7 22 7.7 34.2V464c0 12.2-2.8 23.8-7.7 34.2C323.2 506.9 337 512 352 512z"
},
"person-running": {
title: "person running",
viewBox: "0 0 448 512",
d: "M320 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM125.7 175.5c9.9-9.9 23.4-15.5 37.5-15.5c1.9 0 3.8 .1 5.6 .3L137.6 254c-9.3 28 1.7 58.8 26.8 74.5l86.2 53.9-25.4 88.8c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l28.7-100.4c5.9-20.6-2.6-42.6-20.7-53.9L238 299l30.9-82.4 5.1 12.3C289 264.7 323.9 288 362.7 288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H362.7c-12.9 0-24.6-7.8-29.5-19.7l-6.3-15c-14.6-35.1-44.1-61.9-80.5-73.1l-48.7-15c-11.1-3.4-22.7-5.2-34.4-5.2c-31 0-60.8 12.3-82.7 34.3L57.4 153.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l23.1-23.1zM91.2 352H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h69.6c19 0 36.2-11.2 43.9-28.5L157 361.6l-9.5-6c-17.5-10.9-30.5-26.8-37.9-44.9L91.2 352z"
},
"handshake": {
title: "handshake",
viewBox: "0 0 640 512",
d: "M323.4 85.2l-96.8 78.4c-16.1 13-19.2 36.4-7 53.1c12.9 17.8 38 21.3 55.3 7.8l99.3-77.2c7-5.4 17-4.2 22.5 2.8s4.2 17-2.8 22.5l-20.9 16.2L550.2 352H592c26.5 0 48-21.5 48-48V176c0-26.5-21.5-48-48-48H516h-4-.7l-3.9-2.5L434.8 79c-15.3-9.8-33.2-15-51.4-15c-21.8 0-43 7.5-60 21.2zm22.8 124.4l-51.7 40.2C263 274.4 217.3 268 193.7 235.6c-22.2-30.5-16.6-73.1 12.7-96.8l83.2-67.3c-11.6-4.9-24.1-7.4-36.8-7.4C234 64 215.7 69.6 200 80l-72 48H48c-26.5 0-48 21.5-48 48V304c0 26.5 21.5 48 48 48H156.2l91.4 83.4c19.6 17.9 49.9 16.5 67.8-3.1c5.5-6.1 9.2-13.2 11.1-20.6l17 15.6c19.5 17.9 49.9 16.6 67.8-2.9c4.5-4.9 7.8-10.6 9.9-16.5c19.4 13 45.8 10.3 62.1-7.5c17.9-19.5 16.6-49.9-2.9-67.8l-134.2-123z"
},
"reply": {
title: "reply",
viewBox: "0 0 512 512",
d: "M205 34.8c11.5 5.1 19 16.6 19 29.2v64H336c97.2 0 176 78.8 176 176c0 113.3-81.5 163.9-100.2 174.1c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-7.5 4.3-14.4 9.8-19.5c9.4-8.8 22.2-26.4 22.2-56.7c0-53-43-96-96-96H224v64c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4z"
},
"d20": {
title: "d20",
viewBox: "0 0 512 512",
d: "M48.7 125.8l53.2 31.9c7.8 4.7 17.8 2 22.2-5.9L201.6 12.1c3-5.4-.9-12.1-7.1-12.1c-1.6 0-3.2 .5-4.6 1.4L47.9 98.8c-9.6 6.6-9.2 20.9 .8 26.9zM16 171.7V295.3c0 8 10.4 11 14.7 4.4l60-92c5-7.6 2.6-17.8-5.2-22.5L40.2 158C29.6 151.6 16 159.3 16 171.7zM310.4 12.1l77.6 139.6c4.4 7.9 14.5 10.6 22.2 5.9l53.2-31.9c10-6 10.4-20.3 .8-26.9L322.1 1.4c-1.4-.9-3-1.4-4.6-1.4c-6.2 0-10.1 6.7-7.1 12.1zM496 171.7c0-12.4-13.6-20.1-24.2-13.7l-45.3 27.2c-7.8 4.7-10.1 14.9-5.2 22.5l60 92c4.3 6.7 14.7 3.6 14.7-4.4V171.7zm-49.3 246L286.1 436.6c-8.1 .9-14.1 7.8-14.1 15.9v52.8c0 3.7 3 6.8 6.8 6.8c.8 0 1.6-.1 2.4-.4l172.7-64c6.1-2.2 10.1-8 10.1-14.5c0-9.3-8.1-16.5-17.3-15.4zM233.2 512c3.7 0 6.8-3 6.8-6.8V452.6c0-8.1-6.1-14.9-14.1-15.9l-160.6-19c-9.2-1.1-17.3 6.1-17.3 15.4c0 6.5 4 12.3 10.1 14.5l172.7 64c.8 .3 1.6 .4 2.4 .4zM41.7 382.9l170.9 20.2c7.8 .9 13.4-7.5 9.5-14.3l-85.7-150c-5.9-10.4-20.7-10.8-27.3-.8L30.2 358.2c-6.5 9.9-.3 23.3 11.5 24.7zm439.6-24.8L402.9 238.1c-6.5-10-21.4-9.6-27.3 .8L290.2 388.5c-3.9 6.8 1.6 15.2 9.5 14.3l170.1-20c11.8-1.4 18-14.7 11.5-24.6zm-216.9 11l78.4-137.2c6.1-10.7-1.6-23.9-13.9-23.9H183.1c-12.3 0-20 13.3-13.9 23.9l78.4 137.2c3.7 6.4 13 6.4 16.7 0zM174.4 176H337.6c12.2 0 19.9-13.1 14-23.8l-80-144c-2.8-5.1-8.2-8.2-14-8.2h-3.2c-5.8 0-11.2 3.2-14 8.2l-80 144c-5.9 10.7 1.8 23.8 14 23.8z"
},
"screwdriver-wrench": {
title: "settings",
viewBox: "0 0 512 512",
d: "M78.6 5C69.1-2.4 55.6-1.5 47 7L7 47c-8.5 8.5-9.4 22-2.1 31.6l80 104c4.5 5.9 11.6 9.4 19 9.4h54.1l109 109c-14.7 29-10 65.4 14.3 89.6l112 112c12.5 12.5 32.8 12.5 45.3 0l64-64c12.5-12.5 12.5-32.8 0-45.3l-112-112c-24.2-24.2-60.6-29-89.6-14.3l-109-109V104c0-7.5-3.5-14.5-9.4-19L78.6 5zM19.9 396.1C7.2 408.8 0 426.1 0 444.1C0 481.6 30.4 512 67.9 512c18 0 35.3-7.2 48-19.9L233.7 374.3c-7.8-20.9-9-43.6-3.6-65.1l-61.7-61.7L19.9 396.1zM512 144c0-10.5-1.1-20.7-3.2-30.5c-2.4-11.2-16.1-14.1-24.2-6l-63.9 63.9c-3 3-7.1 4.7-11.3 4.7H352c-8.8 0-16-7.2-16-16V102.6c0-4.2 1.7-8.3 4.7-11.3l63.9-63.9c8.1-8.1 5.2-21.8-6-24.2C388.7 1.1 378.5 0 368 0C288.5 0 224 64.5 224 144l0 .8 85.3 85.3c36-9.1 75.8 .5 104 28.7L429 274.5c49-23 83-72.8 83-130.5zM56 432a24 24 0 1 1 48 0 24 24 0 1 1 -48 0z"
},
"dumbbell": {
title: "dumbbell",
viewBox: "0 0 640 512",
d: "M96 64c0-17.7 14.3-32 32-32h32c17.7 0 32 14.3 32 32V224v64V448c0 17.7-14.3 32-32 32H128c-17.7 0-32-14.3-32-32V384H64c-17.7 0-32-14.3-32-32V288c-17.7 0-32-14.3-32-32s14.3-32 32-32V160c0-17.7 14.3-32 32-32H96V64zm448 0v64h32c17.7 0 32 14.3 32 32v64c17.7 0 32 14.3 32 32s-14.3 32-32 32v64c0 17.7-14.3 32-32 32H544v64c0 17.7-14.3 32-32 32H480c-17.7 0-32-14.3-32-32V288 224 64c0-17.7 14.3-32 32-32h32c17.7 0 32 14.3 32 32zM416 224v64H224V224H416z"
},
"chevron-down": {
title: "chevron down",
viewBox: "0 0 512 512",
d: "M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"
},
"chevron-up": {
title: "chevron up",
viewBox: "0 0 512 512",
d: "M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"
},
"chevron-left": {
title: "chevron left",
viewBox: "0 0 320 512",
d: "M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"
},
"chevron-right": {
title: "chevron right",
viewBox: "0 0 320 512",
d: "M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"
},
};
ns.createIcon = function createIcon(iconDef, title, desc, classes, style)
{
var iconEl = createElement(
ns.ElementTypes.svg,
{
"viewBox": iconDef.viewBox,
"class": `${ICON_CLASS} ${classes}`,
"role": "img",
"style": style || ""
},
ICON_CITATION
);
iconEl.insertAdjacentHTML("afterbegin",
`<style>
.icon {
fill: black; /*Default color*/
fill: var(--icon-color);
width: 16px;
height: 16px;
}
</style>`
);
createChildElement(
iconEl,
ns.ElementTypes.title,
{},
title || iconDef.title
);
if (desc)
{
createChildElement(
iconEl,
ns.ElementTypes.desc,
{},
desc
);
}
createChildElement(
iconEl,
ns.ElementTypes.path,
{
"d": iconDef.d
}
);
return iconEl;
};
//#endregion
});
registerNamespace("GW.Controls", function(ns) {
ns.IconEl = class IconEl extends HTMLElement
{
//#region staticProperties
static observedAttributes = [];
static instanceCount = 0;
static instanceMap = {};
//#endregion
//#region instance properties
instanceId;
iconObj;
titleText;
isInitialized;
//#region element properties
//#endregion
//#endregion
constructor()
{
super();
this.instanceId = IconEl.instanceCount++;
IconEl.instanceMap[this.instanceId] = this;
}
get idKey()
{
return `gw-icon-${this.instanceId}`;
}
//#region HTMLElement implementation
connectedCallback()
{
if (this.isInitialized) { return; }
this.iconObj = ns.SVGLib.Icons[this.getAttribute("iconKey")];
this.titleText = this.getAttribute("title");
if (this.hasAttribute("titleId"))
{
const titleEl = document.getElementById(this.getAttribute("titleId"));
this.titleText = titleEl.innerText;
titleEl.remove();
}
this.iconDescription = this.getAttribute("description");
this.iconClasses = this.getAttribute("iconClasses");
this.iconStyle = this.getAttribute("iconStyle");
this.renderContent();
this.isInitialized = true;
}
//#endregion
renderContent()
{
if (!this.iconObj)
{
debugger;
return;
}
//Markup
this.insertAdjacentHTML("beforebegin",
`<style>
gw-icon {
display: inline-flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
</style>`
);
this.appendChild(
ns.SVGLib.createIcon(
this.iconObj,
this.titleText,
this.iconDescription,
this.iconClasses,
this.iconStyle,
)
);
//element properties
}
};
customElements.define("gw-icon", ns.IconEl);
});
/**
* Author: Vera Konigin
* Site: https://groundedwren.neocities.org
* Contact: vera@groundedwren.com
*
* File Description: Gizmo for reading from Google Sheets.
* Neocities editor users will see a lot of linter errors in this file, but none of them are real errors. The linter just doesn't understand some modern JS.
*/
/**
* By default, any JavaScript code written is defined in the global namespace, which means it's accessible directly under the "window" element.
* If you have a lot of scripts, this can lead to clutter and naming collisions (what if two different scripts use a variable called "i"? They can inadvertently mess each other up).
* To get around this, we define the registerNamespace function in the global namespace, which just confines all the code in the function passed to it to a property under window.
* That property is represented as the "path" parameter. It is passed to the function for ease of access.
*/
function registerNamespace(path, nsFunc)
{
var ancestors = path.split(".");
var ns = window;
for(var i = 0; i < ancestors.length; i++)
{
ns[ancestors[i]] = ns[ancestors[i]] || {};
ns = ns[ancestors[i]];
}
nsFunc(ns);
}
registerNamespace("GW.Gizmos", function(ns) {
/**
* A class to read from one page in a google sheet document
*/
ns.GoogleSheetsReader = class GoogleSheetsReader
{
//setResponse is intended for React - it's how google responds to our GET. Fortunately valid JSON is inside this call, so we can just parse it out.
static #RESPONSE_PREFIX = "setResponse(";
static #RESPONSE_SUFFIX = ");";
//Here we can define any custom types based on column label. "Timestamp" is intended for ISO 8601 format date/time strings.
static #CUSTOM_LABEL_TYPES = {
"Timestamp": "timestamp"
};
spreadsheetId; //The ID of the spreadsheet. This is the part just after /d/ in the docs.google.com URL
sheetName; //The name of the particular sheet we're after
#sheetURL; //Composed request URL
loadPromise = null; //A promise created when loading begins and which resolves when data has finished loading.
tableJSON = null; //Raw JS Object version of the returned JSON.
rowData = null; //Parsed row data
colData = null; //A shortcut to the the column data in tableJSON
colIndex = null; //An index from column label to its metadata, plus array position
/**
* Constructs a GoogleSheetsReader object
* spreadsheetId is the part of the docs.google.com URL just after /d/
* sheetName is the name of the particular page
*/
constructor(spreadsheetId, sheetName)
{
this.spreadsheetId = spreadsheetId;
this.sheetName = sheetName;
this.#sheetURL = `https://docs.google.com/spreadsheets/d/${spreadsheetId}/gviz/tq?sheet=${sheetName}`;
}
/**
* Loads and parses sheet data via HTTP GET
* Returns null on success, and an error string on failure.
*/
async loadData()
{
this.loadPromise = this.#loadData();
return this.loadPromise;
}
async #loadData()
{
this.tableJSON = null;
this.rowData = null;
this.colData = null;
this.colIndex = null;
const response = await fetch(this.#sheetURL);
if (response.ok)
{
return response.text().then((unparsedData) =>
{
//This is parsing out the valid JSON from the React method they gave us
const targetData = unparsedData.split(
GoogleSheetsReader.#RESPONSE_PREFIX
)[1].split(
GoogleSheetsReader.#RESPONSE_SUFFIX
)[0];
this.tableJSON = GoogleSheetsReader.#applyCustomLabelTypes(JSON.parse(targetData).table);
this.rowData = GoogleSheetsReader.#parseAllRows(this.tableJSON);
this.colIndex = GoogleSheetsReader.#indexColumns(this.tableJSON);
this.colData = this.tableJSON.cols;
return null;
});
}
else
{
return response.statusText || response.status;
}
}
/**
* Overrides any google-returned column data types with custom ones based on label
*/
static #applyCustomLabelTypes(tableJSON)
{
tableJSON.cols.forEach(col => {
if(this.#CUSTOM_LABEL_TYPES[col.label])
{
col.type = this.#CUSTOM_LABEL_TYPES[col.label]
};
});
return tableJSON;
}
static #parseAllRows(tableJSON)
{
const rowDataArray = [];
for(let i = 0; i < tableJSON.rows.length; i++)
{
rowDataArray.push(this.#parseRow(i, tableJSON));
}
return rowDataArray;
}
static #parseRow(rowIdx, tableJSON)
{
const rowData = {};
const cells = tableJSON.rows[rowIdx].c;
for(let i = 0; i < cells.length; i++)
{
rowData[tableJSON.cols[i].label] = this.#parseCellType(cells[i], tableJSON.cols[i].type);
}
return rowData;
}
/**
* Parses a cell based on its type. Further custom types will need their own parsing added here.
*/
static #parseCellType(cellData, cellType)
{
switch (cellType)
{
case "string":
return cellData ? cellData.v : cellData;
case "number":
return cellData ? cellData.v : cellData;
case "datetime":
case "date":
return (cellData && cellData.v) ? eval("new " + cellData.v) : null;
case "timestamp":
const cellTimestamp = new Date(cellData ? cellData.v : "");
return isNaN(cellTimestamp) ? null : cellTimestamp;
default:
return cellData;
}
}
static #indexColumns(tableJSON)
{
const colIndex = {};
for(let i = 0; i < tableJSON.cols.length; i++)
{
const colData = tableJSON.cols[i];
colIndex[colData.label] = {...colData, index: i};
}
return colIndex;
}
};
});
/**
* @file Comments control
* @author Vera Konigin vera@groundedwren.com
* https://groundedwren.neocities.org
*/
window.GW = window.GW || {};
(function Controls(ns) {
ns.CommentForm = class CommentForm extends HTMLElement {
//#region staticProperties
static instanceCount = 0;
static instanceMap = {};
//#endregion
//#region instance properties
instanceId;
isInitialized;
titleText;
discordURL;
encodedPath;
fallbackEmail;
//#region element properties
formEl;
titleEl;
bannerEl;
dispNameInpt;
emailInpt;
websiteInpt;
respToInpt;
commentInpt;
resetBtn;
submitBtn;
//#endregion
//#endregion
constructor() {
super();
this.instanceId = CommentForm.instanceCount++;
CommentForm.instanceMap[this.instanceId] = this;
}
get idKey() {
return `gw-comment-form-${this.instanceId}`;
}
connectedCallback() {
if (this.isInitialized) { return; }
this.titleText = this.getAttribute("titleText") || "Add a Comment";
this.discordURL = this.getAttribute("discordURL");
this.encodedPath = this.getAttribute("encodedPath");
this.fallbackEmail = this.getAttribute("fallbackEmail");
this.renderContent();
this.registerHandlers();
this.isInitialized = true;
}
renderContent() {
//Markup
this.innerHTML = `
<form id="${this.idKey}-form"
aria-labelledby="${this.idKey}-title"
aria-describedby="${this.idKey}-banner"
class="comment-form"
autocomplete="off"
>
<h2 id="${this.idKey}-title" class="comment-form-title">${this.titleText}</h2>
<div class="input-horizontal-wrapper">
<div class="input-vertical">
<label for="${this.idKey}-dispName">
Display name<span aria-hidden="true">*</span>
</label>
<input id="${this.idKey}-dispName" type="text" maxlength="1000" required="true">
</div>
<div class="input-vertical">
<label for="${this.idKey}-email">Email</label>
<input id="${this.idKey}-email" type="email">
</div>
<div class="input-vertical">
<label for="${this.idKey}-website">Website</label>
<input id="${this.idKey}-website" type="text" maxlength="1000">
</div>
<div class="input-vertical">
<label for="${this.idKey}-respTo">Response to</label>
<input id="${this.idKey}-respTo" type="number">
</div>
</div>
<div class="comment-box-container">
<div class="input-vertical">
<label for="${this.idKey}-comment">
Comment<span aria-hidden="true">*</span>
</label>
<textarea id="${this.idKey}-comment"
minlength="1"
maxlength="1000"
required="true"
rows="5"
></textarea>
</div>
</div>
<div id="${this.idKey}-banner" class="inline-banner" aria-live="polite">
<gw-icon iconKey="circle-info" title="info"></gw-icon>
<span>Comments are manually approved</span>
</div>
<div class="form-footer">
<input id="${this.idKey}-reset" type="reset" value="Reset">
<input id="${this.idKey}-submit" type="submit" value="Submit">
</div>
</form>
`;
//element properties
this.formEl = document.getElementById(`${this.idKey}-form`);
this.titleEl = document.getElementById(`${this.idKey}-title`);
this.bannerEl = document.getElementById(`${this.idKey}-banner`);
this.dispNameInpt = document.getElementById(`${this.idKey}-dispName`);
this.emailInpt = document.getElementById(`${this.idKey}-email`);
this.websiteInpt = document.getElementById(`${this.idKey}-website`);
this.respToInpt = document.getElementById(`${this.idKey}-respTo`);
this.commentInpt = document.getElementById(`${this.idKey}-comment`);
this.resetBtn = document.getElementById(`${this.idKey}-reset`);
this.submitBtn = document.getElementById(`${this.idKey}-submit`);
//default values
this.dispNameInpt.value = localStorage.getItem("comment-name") || "";
this.emailInpt.value = localStorage.getItem("comment-email") || "";
this.websiteInpt.value = localStorage.getItem("comment-website") || "";
}
//#region Handlers
registerHandlers() {
this.formEl.onsubmit = this.onSubmit;
}
onSubmit = (event) => {
event.preventDefault();
const contentObj = {
name: this.dispNameInpt.value,
email: this.emailInpt.value,
website: this.websiteInpt.value,
responseTo: this.respToInpt.value,
comment: (
this.commentInpt.value || ""
).replaceAll("\n", "<br>").replaceAll("(", "\\("),
timestamp: new Date().toUTCString(),
};
const contentAry = [];
for (let contentKey in contentObj) {
contentAry.push(`${contentKey}=${contentObj[contentKey]}`);
}
const request = new XMLHttpRequest();
request.open(
"POST",
this.discordURL || atob("aHR0cHM6Ly9kaXNjb3JkLmNvbS9hcGkvd2ViaG9va3Mv" + this.encodedPath),
true
);
request.setRequestHeader("Content-Type", "application/json");
request.onreadystatechange = () => {
if (request.readyState !== XMLHttpRequest.DONE) { return; }
if (Math.floor(request.status / 100) !== 2) {
console.log(request.responseText);
this.bannerEl.classList.add("warning");
this.bannerEl.innerHTML =
`
<gw-icon iconKey="triangle-exclamation" title="warning"></gw-icon>
<span>
That didn't work.
${this.fallbackEmail
? `<a class="full" href="mailto:${this.fallbackEmail}?subject=Comment on ${document.title}&body=${contentAry.join("; ")}">Click here to send as an email instead</a>.`
: ""
}
</span>
`;
}
else {
alert("Your comment has been submitted!");
}
};
request.send(JSON.stringify({
embeds: [{
fields: Object.keys(contentObj).map(key => { return { name: key, value: contentObj[key] }})
}]
}));
localStorage.setItem("comment-name", contentObj.name);
localStorage.setItem("comment-email", contentObj.email);
localStorage.setItem("comment-website", contentObj.website);
this.formEl.reset();
this.dispNameInpt.value = contentObj.name;
this.emailInpt.value = contentObj.email;
this.websiteInpt.value = contentObj.website;
};
//#endregion
};
customElements.define("gw-comment-form", ns.CommentForm);
ns.CommentList = class CommentList extends HTMLElement {
//#region staticProperties
static instanceCount = 0;
static instanceMap = {};
static Data = [];
//#endregion
//#region instance properties
instanceId;
isInitialized;
gSpreadsheetId;
gSheetId;
isNewestFirst;
gwCommentFormId;
//#region element properties
//#endregion
//#endregion
constructor() {
super();
this.instanceId = CommentList.instanceCount++;
CommentList.instanceMap[this.instanceId] = this;
CommentList.Data[this.instanceId] = {};
}
get idKey() {
return `gw-comment-list-${this.instanceId}`;
}
connectedCallback() {
if (this.isInitialized) { return; }
this.gSpreadsheetId = this.getAttribute("gSpreadsheetId");
this.gSheetId = this.getAttribute("gSheetId");
this.isNewestFirst = this.getAttribute("isNewestFirst");
this.gwCommentFormId = this.getAttribute("gwCommentFormId");
this.loadAndRender();
this.isInitialized = true;
}
async loadAndRender() {
this.innerHTML = `
<div class="inline-banner">
<gw-icon iconkey="circle-info" title="info"></gw-icon>
<span>Comments loading....</span>
</div>
`
const sheetReader = new GW.Gizmos.GoogleSheetsReader(this.gSpreadsheetId, this.gSheetId);
await sheetReader.loadData();
this.innerHTML = "";
const allComments = sheetReader.rowData;
if (this.isNewestFirst) {
allComments.reverse();
}
this.renderContent();
this.registerHandlers();
const allCommentsIndex = {};
const topLevelCommentIdxs = [];
const childCommentIdxs = [];
for (let i = 0; i < allComments.length; i++) {
const comment = allComments[i];
allCommentsIndex[comment.ID] = i;
if (!comment.ResponseTo) {
topLevelCommentIdxs.push(i);
}
else {
childCommentIdxs.push(i);
}
}
childCommentIdxs.forEach(childIdx => {
const replyId = allComments[childIdx].ResponseTo;
const respondeeComment = allComments[allCommentsIndex[replyId]];
respondeeComment.ChildIdxs = respondeeComment.ChildIdxs || [];
respondeeComment.ChildIdxs.push(childIdx);
});
let commentsToBuild = [];
topLevelCommentIdxs.forEach(
topCommentIdx => commentsToBuild.push({
parent: this.containerEl,
comment: allComments[topCommentIdx]
})
);
while (commentsToBuild.length > 0) {
let { parent, comment } = commentsToBuild.shift();
if (!comment.Timestamp) {
continue;
}
CommentList.Data[this.instanceId][comment.ID] = comment;
parent.insertAdjacentHTML("beforeend", `
<gw-comment-card id="${this.idKey}-cmt-${comment.ID}"
listInstance=${this.instanceId}
commentId=${comment.ID}
gwCommentFormId=${this.gwCommentFormId || ""}
></gw-comment-card>
`);
const commentEl = document.getElementById(`${this.idKey}-cmt-${comment.ID}`);
(comment.ChildIdxs || []).forEach(
childIdx => commentsToBuild.push({
parent: commentEl.articleEl,
comment: allComments[childIdx]
})
);
}
}
renderContent() {
//Markup
this.innerHTML = `
<div id="${this.idKey}-container" class="comments-container"">
</div>
`;
//element properties
this.containerEl = document.getElementById(`${this.idKey}-container`);
}
//#region Handlers
registerHandlers() {
}
//#endregion
};
customElements.define("gw-comment-list", ns.CommentList);
ns.CommentCard = class CommentCard extends HTMLElement {
//#region staticProperties
static instanceCount = 0;
static instanceMap = {};
//#endregion
//#region instance properties
instanceId;
isInitialized;
commentId;
gwCommentFormId;
replyToId;
numChildren;
commenterName;
datetime;
websiteURL;
commentText;
//#region element properties
articleEl;
replyBtn;
//#endregion
//#endregion
constructor() {
super();
this.instanceId = CommentCard.instanceCount++;
CommentCard.instanceMap[this.instanceId] = this;
}
get idKey() {
return `gw-comment-card-${this.instanceId}`;
}
//#region HTMLElement implementation
connectedCallback() {
if (this.isInitialized) { return; }
this.commentId = this.getAttribute("commentId");
this.gwCommentFormId = this.getAttribute("gwCommentFormId");
const commentData = ns.CommentList.Data[this.getAttribute("listInstance")][this.commentId];
this.replyToId = commentData.ResponseTo;
this.numChildren = (commentData.ChildIdxs || []).length;
this.commenterName = commentData["Display Name"];
this.datetime = commentData.Timestamp;
this.websiteURL = commentData.Website;
this.commentText = this.parseCommentText(commentData.Comment);
this.renderContent();
this.registerHandlers();
this.isInitialized = true;
}
//#endregion
renderContent() {
let headerText = this.replyToId
? `Comment #${this.commentId} replying to #${this.replyToId}`
: `Top level comment #${this.commentId}`;
headerText += ` with ${this.numChildren} direct ${this.numChildren == 1 ? "reply" : "replies"}`;
const displayTimestamp = this.datetime.toLocaleString(
undefined,
{ dateStyle: "short", timeStyle: "short" }
);
const commenterNameEl = this.websiteURL
? `<a href="${this.websiteURL}" target="_blank" class="commenter-name">${this.commenterName}</a>`
: `<span class="commenter-name">${this.commenterName}</span>`;
//Markup
this.innerHTML = `
<article id="${this.idKey}-article"
aria-labelledby="${this.idKey}-header"
class="comment-article"
>
<div id="${this.idKey}-header" class="comment-header">
<div class="comment-id" role="img" aria-label="${headerText}">
<span aria-hidden="true" class="comment-id">#${this.commentId}</span>
</div>
${commenterNameEl}
<div class="comment-header-right">
<time id="${this.idKey}-timestamp"
datetime="${this.datetime.toISOString()}"
tabindex="-1"
>${displayTimestamp}</time>
<button id="${this.idKey}-show" class="show-comment">Show #${this.commentId}</button>
</div>
</div>
<blockquote>${this.commentText}</blockquote>
<div class="comment-footer">
<button id="${this.idKey}-reply">Reply to #${this.commentId}</button>
<button id="${this.idKey}-hide">Hide #${this.commentId}</button>
</div>
</article>
`;
//element properties
this.articleEl = document.getElementById(`${this.idKey}-article`);
this.timestamp = document.getElementById(`${this.idKey}-timestamp`);
this.replyBtn = document.getElementById(`${this.idKey}-reply`);
this.hideBtn = document.getElementById(`${this.idKey}-hide`);
this.showBtn = document.getElementById(`${this.idKey}-show`);
}
//#region Handlers
registerHandlers() {
this.replyBtn.onclick = this.onReply;
this.hideBtn.onclick = this.onHide;
this.showBtn.onclick = this.onShow;
}
onReply = () => {
const gwCommentForm = document.getElementById(this.gwCommentFormId);
const respToInpt = gwCommentForm.respToInpt;
if (!respToInpt) {
alert("Comment form not found");
return;
}
respToInpt.value = this.commentId;
respToInpt.focus();
};
onHide = () => {
this.classList.add("collapsed");
this.showBtn.focus();
};
onShow = () => {
this.classList.remove("collapsed");
this.timestamp.focus();
};
//#endregion
parseCommentText(commentString) {
let commentText = "";
let linkObj = {};
for(let i = 0; i < commentString.length; i++){
let char = commentString.charAt(i);
switch (char) {
case '[':
linkObj = {tStart: i};
break;
case ']':
if(linkObj.tStart !== undefined && linkObj.tStart !== i-1) {
linkObj.tEnd = i;
}
else { linkObj = {}; }
break;
case '(':
if(linkObj.tEnd !== undefined && linkObj.tEnd === i-1) {
linkObj.lStart = i;
}
else { linkObj = {}; }
break;
case ')':
if(linkObj.lStart !== undefined && linkObj.lStart !== i-1) {
linkObj.lEnd = i;
}
else { linkObj = {}; }
break;
}
if(linkObj.lEnd !== undefined) {
const linkText = commentString.substring(linkObj.tStart + 1, linkObj.tEnd);
const linkURL = commentString.substring(linkObj.lStart + 1, linkObj.lEnd);
commentText = commentText.substring(0, commentText.length - (i - linkObj.tStart));
commentText += `<a href="${linkURL}" target="_blank">${linkText}</a>`;
linkObj = {};
}
else {
commentText += char;
}
}
return commentText;
}
};
customElements.define("gw-comment-card", ns.CommentCard);
}) (window.GW.Controls = window.GW.Controls || {});
const hero = document.querySelector(".hero");
const heroTopBarEl = document.querySelector(".hero__top-bar");
const headerImgEl = document.querySelector(".hero__img");
const todayEvent = getTodayEvent();
if (todayEvent) {
heroTopBarEl.classList.remove('hidden');
heroTopBarEl.innerHTML = todayEvent.blurb;
if (todayEvent.class) {
headerImgEl.classList.add(todayEvent.class);
}
}
function getTodayEvent() {
const date = new Date();
const month = date.getMonth() + 1;
const day = date.getDate();
const year = date.getFullYear();
const weekOfMonth = Math.ceil(day / 7);
const leilukinsHubLaunchDate = new Date("2022-09-11").getFullYear();
const siteAnniversary = year - leilukinsHubLaunchDate;
if (month === 3 && day === 1)
return {
blurb: `Today is <a href="https://www.unaids.org/en/zero-discrimination-day">Zero Discrimination Day</a>`,
class: "flag-progress-intersex",
};
else if (month === 3 && day === 8)
return {
blurb: `Today is <a href="https://www.internationalwomensday.com/">International Women's Day}</a>`,
class: "symbol-venus",
};
else if (month === 3 && day === 31)
return {
blurb: `Today is <a href="https://www.manygendersonevoice.org/tdov.html">Trans Day of Visibility</a>`,
class: "flag-trans",
};
else if (month === 4 && day === 6)
return {
blurb: `Today is <a href="https://internationalasexualityday.org/en">International Asexuality Day</a>`,
class: "flag-ace",
};
else if (month === 4 && day === 26)
return {
blurb: `Today is <a href="https://www.lesbianvisibilityweek.com">Lesbian Visibility Day</a>`,
class: "flag-lesbian",
};
else if (month === 4 && weekOfMonth === 4)
return {
blurb: `This week is <a href="https://www.lesbianvisibilityweek.com">Lesbian Visibility Week</a>`,
class: "flag-lesbian",
};
else if (month === 5 && day === 17)
return {
blurb: `Today is <a href="https://may17.org">International Day Against Homophobia, Biphobia and Transphobia</a>`,
class: "flag-progress",
};
else if (month === 5 && day === 19)
return {
blurb: `Today is <a href="https://www.believeoutloud.com/voices/article/agender-pride-day/">Agender Pride Day</a>`,
class: "flag-agender",
};
else if (month === 5 && day === 25)
return {
blurb: `Today is <a href="https://www.papyrus-uk.org/pan-visibility-day/">Pansexual and Panromantic Awareness and Visibility Day</a>`,
class: "flag-pan",
};
else if (month === 6)
return {
blurb: `Happy <a href="https://www.loc.gov/lgbt-pride-month/about/">Pride Month</a>!`,
class: "flag-progress-intersex",
};
else if (month === 7 && day === 14)
return {
blurb: `Today is <a href="https://www.manygendersonevoice.org/non-binary-peoples-day.html">Non-Binary People's Day</a>`,
class: "flag-non-binary",
};
else if (month === 7 && day === 28)
return {
blurb: `Today is Leilukin's Birthday`
};
else if (month === 7)
return{
blurb: `Happy <a href="https://diversity.ldeo.columbia.edu/heritage-months/disability-pride">Disability Pride Month</a>!`,
class: "flag-disability"
}
else if (month === 8 && day === 25)
return {
blurb: `Today is <a href="https://aromanticspectrumday.net/">Aromantic Spectrum Visibility Day</a>`,
class: "flag-aro",
};
else if (month === 9 && day === 11)
return {
blurb: `Today is the ${siteAnniversary}-year anniversary of the launch of Leilukin&#39;s Hub`
};
else if (month === 9 && day === 23)
return {
blurb: `Today is <a href="https://bivisibilityday.com/about">Bi Visibility Day</a>`,
class: "flag-bi",
};
else if (month === 10 && day === 8)
return {
blurb: `Today is <a href="https://www.lgbtiqhealth.org.au/international_lesbian_day2">International Lesbian Day</a>`,
class: "flag-lesbian",
};
else if (month === 10 && day === 11)
return {
blurb: `Today is <a href="https://www.hrc.org/resources/national-coming-out-day">National Coming Out Day</a>`,
class: "flag-rainbow",
};
else if (month === 10 && day === 17)
return {
blurb: `Today is the start of <a href="https://www.grlgbtqhealthcareconsortium.org/significantdates/genderfluid-visibility-week">Genderfluid Visibility Week</a>`,
class: "flag-genderfluid",
};
else if (month === 10 && day === 26)
return {
blurb: `Today is <a href="https://interactadvocates.org/intersex-awareness-day">Intersex Awareness Day</a>`,
class: "flag-intersex",
};
else if (month === 11 && day === 13)
return {
blurb: `Today is the start of <a href="https://glaad.org/transweek/">Transgender Awareness Week</a>`,
class: "flag-trans",
};
else
return null;
}