-
Notifications
You must be signed in to change notification settings - Fork 0
/
urlform.min.js.map
7 lines (7 loc) · 45.9 KB
/
urlform.min.js.map
1
2
3
4
5
6
7
{
"version": 3,
"sources": ["build/urlform.js"],
"sourcesContent": ["// URLFormJS is used for sticky forms and sharable URL links. See README. \n'use strict'\n\n/**\nFormParameter are the options for a form's field/parameter.\n\nExample:\n{\n \"name\": \"send_news_and_updates\",\n \"id\": \"input_send_news_and_updates',\n \"type\": \"bool\",\n \"funcTrue\": ()=> ToggleVisible(document.querySelector(\"#advancedOptions\"))\n}\n\nname: Parameter name in the URI. Is used as the default value for id.\n\nid: Id of the HTML element if it differs from the name. Example, URI parameter\n\"retrieve\" and HTML id \"Retrieve\".\n\ntype: Type of the parameter (bool/string/number). Defaults to `string`. For\n`bool`, if the parameter is present in the URL and has a function set in\n'funcTrue', the function is executed. Bool negative flags specify an explicit\nvalue and are only supported on bool types. e.g. `&-foo which denotes a value\nof `false`. Negative flags are only used when default value is `true` and form\nvalue is `false`. See README.\n\nfunc: Called if set on each call to SetForm (Populate and PopulateFromValues).\nValue is passed as the first parameter to the input function.\n e.g. ```{\"name\": \"Name\", \"func\": function(value){console.log(value)}}```\n\nfuncTrue: Execute if param is true. e.g. ```\"funcTrue\": function(value) {\nconsole.log(value)}```\nLike func, value is passed as the first parameter to the input function.\n\nqueryLocation: Option for overriding the param in the URL link to either be a\nquery parameter, or a fragment query. Defaults to empty string, which inherits\nthe 'defaultQueryLocation' from the form wide options.\n\nnonFormValue: Values that do not appear in the form, but may appear in the URL.\nURL non-form values are sticky, e.g. they must be manually removed from the URL\nif already set in the URL, otherwise ShareURL preserves all set non-form values.\n\nsaveSetting: Save and use this setting from local storage. Overwritten by URL\nflag values if present.\n\ndefaultValue: Element is populated with the specified default value on page\nloads (unless otherwise specified). Bools support defaults, e.g. a url with no\nURL params and a form parameter `foo` having a default value of `true` populates\nthe element with `true`.\n@typedef {object} FormParameter\n@property {string} name\n@property {string} [id]\n@property {ParamType} [type=string]\n@property {Function} [func]\n@property {Function} [funcTrue]\n@property {QueryLocation} [queryLocation=\"\"]\n@property {NonFormValue} [nonFormValue]\n@property {Boolean} [saveSetting=false]\n@property {Boolean} [defaultValue=false]\n */\n\n/**\nParamType is the type for a given FormParameter.\n\nA ParamType may be one of the following:\n- \"string\": String and default type.\n- \"bool\": Boolean used for checkboxes.\n- \"number\": Number converts text values to number and sanitize NaN.\n- \"\": Uses the default.\n@typedef {\"string\" | \"bool\" | \"number\" | \"\"} ParamType\n */\n\n/**\nQueryLocation is the option for what kind of query a form and/or form\nparameter is.\n\nA QueryLocation may be one of the following:\n- \"fragment\": The query is preceded by '#' and '?'.\n- \"query\": The query is preceded by '?'.\n- \"\": Empty inherits the form wide option for 'queryLocation'.\n@typedef {\"fragment\" | \"query\" | \"\"} QueryLocation\n */\n\n/**\nFormParameters is the main form object (Array) that holds the different\n`FormParameter` field objects.\n@typedef {FormParameter[]} FormParameters\n */\n\n/**\nFormOptions are the optional fields for the initialized form. The FormOptions\nobject itself is not optional, and requires the 'id' of the initialized form.\nThe 'id' should match the 'id' of the HTMLFormElement on the page.\n\nFormOptions are in this form:\n{\n\"id\":\"ExampleUserForm\",\n\"prefix\": \"input_\"\n}\n\nFields:\nprefix: Form input prefix which is prepended to name.\n\nclearBtn: Button element for clearing the form and queries/fragments in the URL.\n\nshareURL: Element ID of <a> for share link.\n\nshareURLBtn: Button element triggers generating share link.\n\nshareURLArea: Element ID of text area for share link.\n\ndefaultQueryLocation: Link sets parameter in query or fragment query. Defaults\nto fragment query (recommended).\n\ncallback: Function that's executed each time the form is processed/set, as the\nlast operation.\n\ncleanURL: If set to `true`, does not preserve any extra information from the URL\nthat is not in the initialized form. Defaults to false.\n\nRead only:\nFormParameters: Set by Init(). (Allows FormOptions to encapsulate\nFormParameters.) See docs on FormParameter.\n\nSanitized: Whether 'FormOptions' has been sanitized.\n\nInited: Whether URLFormJS module was initialized.\n\nShareURLBtnElement: Share URL button element in GUI.\n\nClearBtnElement: Clear the `shareURL` and form in GUI.\n\n\"Form mode\" parameters:\nformID: HTMLFormElement ID of <form>. Sets `formMode` to true if populated.\n\n// TODO test \"FormMode\" where FormParameters are known from Form and not set.\nForm Mode read only\nFormMode: Use `<form>` mode. FormOptions must include a form 'id' found in the\nGUI.\n\nFormElement: Form element in GUI, specified by 'id' in 'FormOptions'.\n@typedef {object} FormOptions\n@property {FormParameters} FormParameters\n@property {string} [prefix]\n@property {string} [clearBtn]\n@property {string} [shareURL] \n@property {string} [shareURLBtn] \n@property {string} [shareURLArea]\n@property {QueryLocation} [defaultQueryLocation=\"fragment\"]\n@property {Function} [callback]\n@property {Boolean} [cleanURL=false]\n\n// Read only Values (Set internally by library)\n@property {Boolean} Sanitized=false\n@property {Boolean} Inited=false\n@property {HTMLButtonElement} ShareURLBtnElement\n@property {HTMLButtonElement} ClearBtnElement\n\n// Form Mode\n@property {string} [formID]\n// Form Mode Read Only\n@property {Boolean} FormMode=false\n@property {HTMLFormElement} FormElement\n */\n\n/**\nQuery is the Query string. Everything after first ? and before first #.\n@typedef {string} QueryString\n */\n\n/**\nFragment is the Fragment string without `#`. Everything after the first #.\n@typedef {string} FragmentString\n */\n\n/**\nQuagPairs is an Object of key:value pairs for both Query Parameters and\nFragment Query Parameters. `quag` is the superset of `query` and `fragment`.\n'object' is diluted in meaning by JSDoc, and using '{}' denotes a key:val\nobject. See:\nhttps://github.com/microsoft/TypeScript/issues/50321#issuecomment-1217224937\n@typedef {object} QuagPairs\n */\n\n/**\nFragment holds the fragment parts from the URL. All parts may be nil.\nIncludes extras.\n\nTODO future: support other scheme starting delimiters and perhaps `?` for\nfragment queries.\n\n- string: The whole fragment string (everything included except starting `#`).\n- pairs: key:value object with fragment queries. Does not include extras.\n- extras:key:value that appear in fragment query but not in form.\n- before: Everything after '#' and if exists everything before the first '?'.\n- query: Everything after `before` and before the next fragment scheme\n delimiter, e.g. ':~:'. This is the \"middle part\". This is the fragment query.\n- after: Everything after `query`.\n@typedef {object} Fragment\n@property {FragmentString} string \n@property {QuagPairs} pairs\n@property {QuagPairs} extras\n@property {string} before\n@property {string} query\n@property {string} after\n */\n\n\n/**\nQuery holds the fragment parts from the URL. All parts may be nil.\nIncludes extras.\n\n- string: The string URL query component. Does not contain any fragment.\n- pairs: key:value object containing the queries. Includes extras.\n- extras: Extra query parameters given in the URL.\n@typedef {object} Query\n@property {string} string\n@property {QuagPairs} pairs\n@property {QuagPairs} extra\n */\n\n/**\nQuagParts holds the query and fragment from the existing URL. See README on\n`quag`.\n\n- pairs: All pairs. key:value object containing `query.pairs` and \n `fragment.pairs`.\n- fragment: Fragment object.\n- query: Query Object.\n@typedef {object} QuagParts\n@property {QuagPairs} pairs\n@property {Query} query\n@property {Fragment} fragment\n */\n\n/** @type {QueryLocation} */\nconst QueryLocationQuery = \"query\"\n\n/** @type {QueryLocation} */\nconst QueryLocationFragment = \"fragment\"\n\n/**\nDefaultFormOptions where all options are set to their default case.\n@type {FormOptions} \n */\nconst DefaultFormOptions = {\n\tFormParameters: [],\n\tprefix: \"\",\n\tshareURL: \"#shareURL\",\n\tshareURLBtn: \"#shareURLBtn\",\n\tshareURLArea: \"#shareURLArea\",\n\tclearBtn: \"#clearBtn\",\n\tdefaultQueryLocation: QueryLocationFragment,\n\tcallback: null,\n\tcleanURL: false,\n\tlocalStorageNamespace: \"URLFormJS_\",\n\n\t// Not externally settable module fields. \n\tSanitized: false,\n\tInited: false,\n\tShareURLBtnElement: HTMLButtonElement,\n\tClearBtnElement: HTMLButtonElement,\n\n\t// Form Mode\n\tformID: \"\",\n\tFormMode: false,\n\tFormElement: HTMLFormElement,\n}\n\n\n/**\nInitializes the globals and event listeners for the URLFormJS module.\nIf 'formOptions' is empty, defaults are used.\n@param {FormOptions} formOptions\n@returns {FormOptions} \n */\nfunction Init(formOptions) {\n\tconsole.log(\"Initializing URLFormJS: \", formOptions);\n\tlet formOpt = {}\n\tformOpt = sanitizeFormOptions(formOptions)\n\n\tformOpt.ShareURLBtnElement = document.querySelector(formOpt.shareURLBtn)\n\tif (formOpt.ShareURLBtnElement != null) {\n\t\tformOpt.ShareURLBtnElement.addEventListener('click', () => ShareURI(formOpt)) // Must be anonymous, otherwise passes pointer event object.\n\t}\n\tformOpt.ClearBtnElement = document.querySelector(formOpt.clearBtn)\n\tif (formOpt.ClearBtnElement != null) {\n\t\tformOpt.ClearBtnElement.addEventListener('click', () => {\n\t\t\tClear(formOpt)\n\t\t})\n\t}\n\t// Form Mode\n\tif (!isEmpty(formOpt.formID)) {\n\t\tformOpt.FormElement = document.getElementById(formOpt.formID)\n\t\tif (formOpt.FormElement !== null) {\n\t\t\tformOpt.FormMode = true\n\t\t}\n\t}\n\n\t// Force page reload when fragment changes. Chrome as of 03/01/2023 does not\n\t// refresh page on first enter, but the second enter and the following\n\t// corrects this errant behavior.\n\t// Related events: [locationchange, hashchange]\n\twindow.addEventListener('hashchange', function () {\n\t\twindow.location.reload()\n\t})\n\n\tformOpt.Inited = true\n\treturn formOpt\n}\n\n\n\n\n/**\nPopulate populates the GUI (form and share links) from the URI and saved\nsetting.\n@param {FormOptions} formOptions\n@returns {void}\n@throws {Error} If Init() has not been called.\n */\nfunction Populate(formOptions) {\n\t//console.log(\"Populate\")\n\t// Get local storage settings. If set, URI should overwrite. \n\tlet savedPairs = {}\n\tfor (let fp of formOptions.FormParameters) {\n\t\tif (fp.saveSetting) {\n\t\t\tsavedPairs[fp.name] = getSavedSetting(fp.name, formOptions)\n\t\t}\n\t}\n\n\tlet uriPairs = GetQuagParts(formOptions).pairs\n\tlet pairs = {\n\t\t...savedPairs,\n\t\t...uriPairs,\n\t}\n\t//console.log(\"savedPairs\", savedPairs, \"uriPairs\", uriPairs, \"Pairs\", pairs);\n\tPopulateFromValues(pairs, formOptions)\n}\n\n/**\nPopulates the GUI (form and share links) using the given key:value pairs. \n@param {QuagPairs} quagPairs\n@param {FormOptions} formOptions\n@returns {void}\n@throws {Error} Fails if Init() has not been called for the URLFormJS module.\n */\nfunction PopulateFromValues(quagPairs, formOptions) {\n\tif (!formOptions.Inited) {\n\t\tthrow new Error(\"URLFormJS: Init() must be called first to initialize the URLFormJS module.\")\n\t}\n\tSetForm(quagPairs, formOptions)\n\tShareURI(formOptions)\n}\n\n\n/**\nSetForm sets GUI for each parameter and executes funcTrue() per parameter.\nSee docs in 'FormOptions'. Form wide options are also executed (e.g.\n'callback' in 'FormOptions').\n@param {QuagPairs} kv\n@param {FormOptions} formOptions\n@returns {void}\n */\nasync function SetForm(kv, formOptions) {\n\t//console.log(\"SetForm:\", kv, formOptions);\n\ttry {\n\t\tfor (let fp of formOptions.FormParameters) {\n\t\t\t// Set as vars to avoid mutability.\n\t\t\tlet id = fp.id\n\t\t\tlet name = fp.name\n\t\t\tlet value = \"\"\n\t\t\t// If id is empty, assume name is the id on the page.\n\t\t\tif (isEmpty(id)) {\n\t\t\t\tid = formOptions.prefix + name\n\t\t\t}\n\n\t\t\t// \"undefined\" does not need to be a string as long as fp itself is\n\t\t\t// defined. `defaultValue` is `undefined` (not a string) if not set.\n\t\t\tif (fp.defaultValue !== undefined) { // TODO consider using typeof on undefined. \n\t\t\t\tvalue = fp.defaultValue\n\t\t\t}\n\t\t\tlet hasNegative = (kv[\"-\" + name] !== undefined) // Don't use `isEmpty`. // TODO test `!== undefined`\n\t\t\tif (hasNegative && fp.type == \"bool\") {\n\t\t\t\t//console.log(\"Has Negative\");\n\t\t\t\tvalue = false\n\t\t\t}\n\t\t\tif (name in kv) {\n\t\t\t\tvalue = kv[name]\n\t\t\t}\n\t\t\t//console.log(id, name, value);\n\n\t\t\t// Sanitize bool `true` to string true \n\t\t\tif (value === true) {\n\t\t\t\tvalue = \"true\"\n\t\t\t}\n\t\t\t// Flag has a key present in kv, but am empty value. Flag values for bool\n\t\t\t// may be `true` or empty. Empty as a flag is interpreted as true.\n\t\t\tif (fp.type === \"bool\" && value === \"\" && kv[name] !== undefined) {\n\t\t\t\tvalue = \"true\"\n\t\t\t}\n\t\t\t//console.log(\"Before set GUI\", fp.type, name, value)\n\n\t\t\t// Finally,set Gui and run funcs. Funcs are done last so applications\n\t\t\t// can do custom GUI setting after URLFormJS is done setting the GUI. \n\t\t\tlet e = document.getElementById(id)\n\t\t\tif (e !== null) {\n\t\t\t\tif (fp.type == \"bool\" && value == \"true\") {\n\t\t\t\t\te.checked = true\n\t\t\t\t}\n\n\t\t\t\t// Set GUI Non-bool inputs.\n\t\t\t\tif (!isEmpty(value) && fp.type !== \"bool\") {\n\t\t\t\t\te.value = value\n\t\t\t\t}\n\n\t\t\t\tif (fp.saveSetting) { // Set Action listener for savables.\n\t\t\t\t\te.addEventListener(\"input\", (e) => {\n\t\t\t\t\t\tif (fp.type == \"bool\") {\n\t\t\t\t\t\t\tsetSavedSetting(name, e.target.checked, formOptions)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsetSavedSetting(name, e.target.value, formOptions)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!isEmpty(fp.func)) { // Run func if set\n\t\t\t\tawait fp.func(value)\n\t\t\t}\n\t\t\tif (fp.type == \"bool\" && value === \"true\") { // Run `funcTrue` if set.\n\t\t\t\tif (!isEmpty(fp.funcTrue)) {\n\t\t\t\t\tawait fp.funcTrue(value)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} finally {\n\t\t//// Form wide options\n\n\t\t// Callback if any.\n\t\tif (!isEmpty(formOptions.callback)) {\n\t\t\tformOptions.callback()\n\t\t}\n\t}\n}\n\n/**\nGets the setting. \n@param {string} name\n@param {FormOptions} formOptions\n@returns {void}\n */\nfunction getSavedSetting(name, formOptions) {\n\treturn localStorage.getItem(formOptions.localStorageNamespace + formOptions.prefix + name)\n}\n\n/**\nSets the setting.\n@param {string} name\n@param {string} value\n@param {FormOptions} formOptions\n@returns {void}\n */\nfunction setSavedSetting(name, value, formOptions) {\n\t//console.log(\"URLFormJS - Saving setting:\", name, value)\n\treturn localStorage.setItem(formOptions.localStorageNamespace + formOptions.prefix + name, value)\n}\n\n/**\nSanitizes a formOptions object, and sets all of the options values to\ntheir default value if not set.\n\nModifies \"in place\" as well as returns the object.\n\nFor new options/setting FormOptions, Init() must be re-called.\n@param {FormOptions} formOptions\n@returns {FormOptions}\n@throws {Error} Fails if FormOptions or 'id' in options is empty.\n */\nfunction sanitizeFormOptions(formOptions) {\n\t// Not making a copy modifies the original, even though it's a const.\n\tlet foc = {\n\t\t...DefaultFormOptions\n\t}\n\t// If no options given, use default.\n\tif (isEmpty(formOptions)) {\n\t\treturn foc\n\t}\n\t// If FormOptions has already been sanitized, do nothing.\n\tif (!isEmpty(formOptions.Sanitized) && formOptions.Sanitized === true) {\n\t\treturn\n\t}\n\n\t//// Sanitize\n\tif (!isEmpty(formOptions.formID)) {\n\t\tfoc.formID = formOptions.formID\n\t}\n\tif (!isEmpty(formOptions.prefix)) {\n\t\tfoc.prefix = formOptions.prefix\n\t}\n\tif (!isEmpty(formOptions.clearBtn)) {\n\t\tfoc.clearBtn = formOptions.clearBtn\n\t}\n\tif (!isEmpty(formOptions.shareURLArea)) {\n\t\tfoc.shareURLArea = formOptions.shareURLArea\n\t}\n\tif (!isEmpty(formOptions.shareURL)) {\n\t\tfoc.shareURL = formOptions.shareURL\n\t}\n\tif (!isEmpty(formOptions.shareURLBtn)) {\n\t\tfoc.shareURLBtn = formOptions.shareURLBtn\n\t}\n\tif (!isEmpty(formOptions.defaultQueryLocation)) {\n\t\tfoc.defaultQueryLocation = formOptions.defaultQueryLocation\n\t}\n\tif (!isEmpty(formOptions.callback)) {\n\t\tfoc.callback = formOptions.callback\n\t}\n\tif (!isEmpty(formOptions.cleanURL)) {\n\t\tfoc.cleanURL = formOptions.cleanURL\n\t}\n\tif (!isEmpty(formOptions.localStorageNamespace)) {\n\t\tfoc.localStorageNamespace = formOptions.localStorageNamespace\n\t}\n\n\t// Options with limited valid values. \n\tif (formOptions.defaultQueryLocation !== QueryLocationQuery) {\n\t\tfoc.defaultQueryLocation = QueryLocationFragment\n\t}\n\n\t// Sanitize form parameters. (The `for` is pass by reference, not pass by copy.)\n\tfor (let fp of formOptions.FormParameters) {\n\t\t// If query location is not a recognized 'QueryLocation', use default.\n\t\tif (fp.queryLocation !== QueryLocationFragment && fp.queryLocation !== QueryLocationQuery) {\n\t\t\tfp.queryLocation = foc.defaultQueryLocation\n\t\t}\n\t\tfoc.FormParameters.push(fp)\n\t}\n\n\tfoc.Sanitized = true\n\treturn foc\n}\n\n\n/**\nSets the URL on share link and share area. \n@param {string} href\n@returns voice\n */\nfunction setShareURL(href, formOptions) {\n\t//console.log(\"setShareURL\", href)\n\t// URI Link\n\tlet shareUrl = document.querySelector(formOptions.shareURL)\n\tif (shareUrl !== null) {\n\t\tshareUrl.innerHTML = href.link(href)\n\t}\n\n\t// Text Area \n\tlet shareArea = document.querySelector(formOptions.shareURLArea)\n\tif (shareArea !== null) {\n\t\tshareArea.innerHTML = href\n\t}\n}\n\n\n/**\nShareURI \n1. Generates a share URL from the current URL and form, \n2. Populates the GUI share links, \n3. Returns URL.\n\nFragment query parameters take precedence over query parameters.\n@param {FormOptions} formOptions\n@returns {URL} Javascript URL object.\n */\nasync function ShareURI(formOptions) {\n\t//console.log(\"ShareURI\", await JSON.stringify(formOptions));\n\tlet formPairs = GetForm(formOptions) // Current form values.\n\tlet q = GetQuagParts(formOptions) // Current URL values.\n\tvar u = getURIBase()\n\t// console.log(\"formPairs:\", formPairs, \"\\nq:\", q, \"\\nURL:\", u, \"\\nformOptions.FormParameters\", formOptions.FormParameters);\n\n\t// Put the form values into query or fragment. \n\tfor (let fp of formOptions.FormParameters) {\n\t\tlet value = formPairs[fp.name]\n\t\tif (value === undefined) {\n\t\t\tvalue = \"\"\n\t\t}\n\t\t// console.log(fp, value);\n\t\tif (fp.type == \"bool\") { // Enure bools are set to \"true\", \"false, or \"\". Checked is \"true\".\n\t\t\t// \"Negative\" flag for default true (Bools with default \"true\" values).\n\t\t\tif (fp.defaultValue === true && value == \"\") {\n\t\t\t\t//console.log(\"Negative flag\")\n\t\t\t\tvalue = \"false\"\n\t\t\t}\n\t\t\t// Non-form flag in URI. Non-form URI parameters are sticky. \n\t\t\tif (fp.nonFormValue === true && fp.name in q.pairs) {\n\t\t\t\tvalue = \"true\"\n\t\t\t}\n\t\t}\n\n\t\t//console.log(fp.name, value, fp.queryLocation)\n\t\tif (fp.queryLocation === QueryLocationFragment) { // Set to Fragment\n\t\t\tu.searchParams.delete(fp.name) // In case it is currently set in query. \n\t\t\tq.fragment.pairs[fp.name] = value\n\t\t} else {\n\t\t\tq.query.pairs[fp.name] = value\n\t\t}\n\t}\n\n\tu.search = buildQueryString(q.query.pairs, q.query.extras, formOptions) // Escapes values (like encodeURIComponent)\n\tu.hash = fragmentToString(q.fragment, formOptions) // Escapes values (like encodeURIComponent)\n\t// console.log(q.query.pairs, q.fragment, u.href);\n\n\tsetShareURL(u.href, formOptions) // TODO fix this it needs to be root URL + query string + hash string\n\treturn u\n}\n\n\n/**\ngetURIBase returns the URI Base (see package Cyphrme/Path)\n@returns {URL} Javascript URL object.\n*/\nfunction getURIBase() {\n\t// `u` is the current URL. `window.location.pathname` _incorrectly_ includes\n\t// query but is replaced by `u.search = \"\"`. This is done also for hash\n\t// to follow the same form. Ideally, Javascript would provide an way to get\n\t// the URI base which does not include any quag component. (See package\n\t// `Cyphrme/URIPath`)\n\tvar u = new URL(window.location.origin + window.location.pathname)\n\tu.search = \"\"\n\tu.hash = \"\"\n\treturn u\n}\n\n\n/**\nGenerates a URL encoded fragment string from Fragment.\n\nReturns empty string when fragment is empty.\n@param {Fragment} fragment\n@param {FormOptions} formOptions\n@returns {string} Fragment string (#<before>?<middle(fromForm?extras)>[delimiter]<after>).\n */\nfunction fragmentToString(fragment, formOptions) {\n\t// URL Fragment has three parts: \n\t// 1. Before fragment query, \n\t// 2. Middle, the fragment query itself (with extras)\n\t// 3. After fragment query.\n\n\tlet fqs = \"#\" + fragment.before\n\tfqs += buildQueryString(fragment.pairs, fragment.extras, formOptions)\n\tfqs += fragment.after\n\tif (fqs == \"#\" || fqs == \"#?\") { // Return empty string if fragment is empty. \n\t\treturn \"\"\n\t}\n\treturn fqs\n}\n\n\n/**\nBuild query string (for either query or fragment query) including adding extras\nback to the string. Bools are converted to flag style and must be given with\nvalue=true or value=false, otherwise empty (`value=\"\"`) are omitted. \n@param {QuagPairs} kv\n@param {QuagPairs} extrasKV\n@param {FormOptions} formOptions\n@returns {string} Query string including \"?\" if kv length is non-zero.\n*/\nfunction buildQueryString(kv, extrasKV, formOptions) {\n\t//console.log(\"buildQueryString\", kv)\n\tlet qs = \"?\"\n\tlet firstParam = true;\n\n\t// kv\n\tif (Object.keys(kv).length !== 0) {\n\t\tfor (let key in kv) {\n\t\t\tlet value = kv[key]\n\t\t\tif (value === \"\") {\n\t\t\t\tcontinue // Omit empty parameter. \n\t\t\t}\n\t\t\tfirstParam ? firstParam = false : qs += \"&\" // Bookend separator (not on first). \n\n\t\t\tlet equal = \"=\"\n\t\t\tlet fp = formOptions.FormParameters.find(a => a.name == key)\n\t\t\tif (fp.type === \"bool\") {\n\t\t\t\t// Encode bools as flag style. (No \"=value\" for flags.) \n\t\t\t\tvalue = \"\"\n\t\t\t\tequal = \"\"\n\t\t\t\tif (kv[key] === \"false\") { // Negative flag\n\t\t\t\t\tkey = \"-\" + key\n\t\t\t\t}\n\t\t\t}\n\t\t\tqs += key + equal + value\n\t\t}\n\t}\n\n\t// Extras. \n\tif (Object.keys(extrasKV).length > 0 && !formOptions.cleanURL) {\n\t\tfor (let e in extrasKV) {\n\t\t\tfirstParam ? firstParam = false : qs += \"&\" // Bookend separator (not on first). \n\t\t\tqs += e + \"=\" + extrasKV[e]\n\t\t}\n\t}\n\n\tif (qs == \"?\") { // Return empty string if fragment is empty. \n\t\treturn \"\"\n\t}\n\treturn qs\n}\n\n\n\n/**\nHelper that returns a `k:v,k:v` object from a `k=v&k=v` string.\n@param {string} s e.g. `key=value&key=value`.\n@returns {QuagPairs} {key:value}\n */\nfunction getPairs(s) {\n\tif (isEmpty(s)) {\n\t\treturn {}\n\t}\n\n\tlet pairs = {}\n\tlet parts = s.split('&')\n\tfor (const i in parts) {\n\t\tlet kv = parts[i].split('=')\n\t\tlet key = kv[0]\n\t\tlet value = kv[1]\n\n\t\tif (key.at(0) === \"-\") { // Sanitize for negative flags.\n\t\t\tkey = removeNegativeFlag(key)\n\t\t\tvalue = \"false\"\n\t\t}\n\n\t\t// If the string begins/ends with \"&\", there is an empty element.\n\t\tif (isEmpty(key)) {\n\t\t\tcontinue\n\t\t}\n\t\t// Sanitize to string. (Don't use isEmpty as string \"true\"/\"false\" are valid.)\n\t\tif (value === undefined || value === null) {\n\t\t\tvalue = \"\"\n\t\t}\n\t\t// Browsers automatically escape values. Javascript 'unescape()' is deprecated.\n\t\t// 'decodeURI' expects the full URI.\n\t\tpairs[key] = decodeURIComponent(value)\n\t}\n\n\treturn pairs\n}\n\n\n/**\nGetQuagParts returns QuagParts generated from the current URL, not the\nform, and puts values into the correct object based on formOptions.\nIncludes extras. See docs on `QuagParts`.\n\nOn duplicate the default behavior overwrites query pairs with fragment pairs.\n@param {FormOptions} formOptions\n@returns {QuagParts}\n */\nfunction GetQuagParts(formOptions) {\n\t/**\n\tgetFragment returns (fragment,pairs,before,query,after) from the URL\n\tfragment, but not (extras). Warning: Puts all pairs, including extras, into\n\tpairs.\n\t@returns {Fragment}\n\t */\n\tfunction getFragment() {\n\t\tlet frag = {\n\t\t\tstring: getFragmentString(), // The whole fragment including `#`. \n\t\t\tpairs: {},\n\t\t\textras: {},\n\t\t\tbefore: \"\",\n\t\t\tquery: \"\",\n\t\t\tafter: \"\",\n\t\t}\n\n\t\t// Check if fragment query has 'before'.\n\t\tlet ss = frag.string.split('?')\n\t\tif (ss.length == 0) {\n\t\t\tfrag.query = ss[0]\n\t\t} else {\n\t\t\tfrag.before = ss[0]\n\t\t\tfrag.query = ss[1]\n\t\t}\n\n\t\t// Check for after. Fragment queries supports beginning delimiters for other\n\t\t// fragment schemes, like fragment directive `:~:`.\n\t\tif (!isEmpty(frag.query)) {\n\t\t\tlet s = frag.query.split(':~:')\n\t\t\tif (s.length > 1) {\n\t\t\t\tfrag.query = s[0]\n\t\t\t\tfrag.after = ':~:' + s[1]\n\t\t\t}\n\t\t}\n\t\tfrag.pairs = getPairs(frag.query)\n\n\t\t// Javascript deep copy\n\t\treturn JSON.parse(JSON.stringify(frag))\n\t}\n\n\tlet qp = {\n\t\tquery: {\n\t\t\tstring: decodeURIComponent(window.location.search.substring(1)), // substring removes \"?\"\n\t\t\tpairs: getPairs(window.location.search.substring(1)), // getPairs decodes pair values.\n\t\t\textras: {},\n\t\t},\n\t\tfragment: getFragment(),\n\t}\n\n\tqp.pairs = {\n\t\t...qp.query.pairs,\n\t\t...qp.fragment.pairs,\n\t}\n\n\t// Generate extras and remove any extras from Query and Fragment. \n\tlet formParams = []\n\tfor (let p of formOptions.FormParameters) {\n\t\tformParams.push(p.name)\n\t}\n\t//console.log(formParams);\n\n\t// Extra query pairs.\n\tfor (let key of Object.keys(qp.query.pairs)) {\n\t\tkey = removeNegativeFlag(key); // Sanitize for negative flags. \n\t\tif (!formParams.includes(key)) {\n\t\t\tqp.query.extras[key] = qp.query.pairs[key]\n\t\t\tdelete qp.query.pairs[key]\n\t\t}\n\t}\n\t// Extra frag pairs.\n\tfor (let key of Object.keys(qp.fragment.pairs)) {\n\t\tkey = removeNegativeFlag(key); // Sanitize for negative flags. \n\t\tif (!formParams.includes(key)) {\n\t\t\tqp.fragment.extras[key] = qp.fragment.pairs[key]\n\t\t\tdelete qp.fragment.pairs[key]\n\t\t}\n\t}\n\t//console.log(qp);\n\treturn qp\n}\n\n// Removes the string with a beginning \"-\" removed if present. \nfunction removeNegativeFlag(key) {\n\tif (key.at(0) === \"-\") {\n\t\treturn key.substring(1)\n\t}\n\treturn key\n}\n\n/**\nGetURLKeyValue is a helper that returns k:v from the current URL. \n\nOn duplicate the default behavior overwrites query pairs with fragment pairs.\n@param {FormOptions} [formOptions]\n@returns {QuagParts.pairs}\n */\nfunction GetURLKeyValue(formOptions) {\n\tif (isEmpty(formOptions)) {\n\t\tformOptions = GetDefaultFormOptions()\n\t}\n\tlet qp = GetQuagParts(formOptions)\n\treturn qp.pairs\n}\n\n\n/**\nSerialize serializes the initialized FormParameters that are populated in the\nGUI into a JSON string.\n@param {FormOptions} formOptions\n@returns {string}\n */\nfunction Serialize(formOptions) {\n\treturn JSON.stringify(GetForm(formOptions))\n}\n\n\n/**\nGetForm gets current form values from the GUI into {key:value,key:value}.\n\nReturnPairOnZero: Whether all pairs from 'GetForm' is always returned.\nOtherwise, on zero value, the pair is not returned in the pairs object.\n@param {FormOptions} formOptions\n@param {Boolean} [ReturnPairOnZero]\n@returns {QuagPairs} key/value\n */\nfunction GetForm(formOptions, ReturnPairOnZero) {\n\tif (!formOptions.Inited) {\n\t\tthrow new Error(\"URLFormJS: Init() must be called first to initialize the URLFormJS module.\")\n\t}\n\n\tlet pairs = {}\n\t// Normal usage, not FormMode (not in a <form>), select individual ID's.\n\tif (!formOptions.FormMode) {\n\t\tfor (let fp of formOptions.FormParameters) {\n\t\t\tlet value\n\n\t\t\tlet htmlID = fp.name\n\t\t\tif (!isEmpty(fp.id)) {\n\t\t\t\thtmlID = fp.id\n\t\t\t}\n\t\t\tlet elem = document.getElementById(formOptions.prefix + htmlID)\n\t\t\tif (elem !== null) {\n\t\t\t\tswitch (fp.type) {\n\t\t\t\t\tdefault: // String\n\t\t\t\t\t\tvalue = elem.value\n\t\t\t\t\t\tif (isEmpty(value)) { // Sanitize undefined\n\t\t\t\t\t\t\tvalue = \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"bool\":\n\t\t\t\t\t\tvalue = elem.checked\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"number\":\n\t\t\t\t\t\tvalue = Number(elem.value)\n\t\t\t\t\t\tif (isEmpty(value)) { // Sanitize NaN\n\t\t\t\t\t\t\tvalue = 0\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!isEmpty(value)) {\n\t\t\t\tpairs[fp.name] = value\n\t\t\t} else if (ReturnPairOnZero) {\n\t\t\t\tpairs[fp.name] = value\n\t\t\t}\n\t\t}\n\t\treturn pairs\n\t}\n\n\t// FormMode=true. In a <form>.\n\tlet formData = new FormData(formOptions.FormElement) // throws\n\tfor (let [name, value] of formData) {\n\t\tif (value == \"true\" || value == \"on\") {\n\t\t\tvalue = true\n\t\t}\n\t\tif (value == \"false\" || value == \"unchecked\") {\n\t\t\tvalue = false\n\t\t}\n\n\t\t// Remove prefix, if set.\n\t\tif (!isEmpty(formOptions.prefix)) {\n\t\t\tname = name.substring(formOptions.prefix.length)\n\t\t}\n\n\t\tif (!isEmpty(value)) {\n\t\t\tpairs[name] = value\n\t\t} else if (ReturnPairOnZero) {\n\t\t\tpairs[name] = value\n\t\t}\n\t}\n\treturn pairs\n}\n\n/**\nGetFormElements returns a key:value object from teh GUI form using form\nparameters, and the values are the elements that hold the form parameters'\nvalues.\n@param {FormOptions} formOptions\n@returns {QuagPairs} key/value (where value is an HTML Element)\n */\nfunction GetFormElements(formOptions) {\n\tlet kv = {}\n\tfor (let param of formOptions.FormParameters) {\n\t\tkv[param.name] = document.getElementById(formOptions.prefix + param.name)\n\t}\n\treturn kv\n}\n\n\n\n\n/**\ngetFragmentString returns URL fragment as a string, not including '#'.\nSee notes in function.\n@returns {Fragment.string}\n */\nfunction getFragmentString() {\n\tlet fParts = window.location.hash.split(\"#\") // May not work in chrome, see note below.\n\n\t// Chrome removes ':~:' (fragment directives (for text fragments)), and\n\t// anything after the text fragment. Thus, calling 'window.location.hash' with\n\t// a URL of:\n\t// https://localhost:8082/#:~:text=hello?first_name=asdf&last_name=hello\n\t// results: '#a'. And calling 'window.location.hash' with a URL of:\n\t// https://localhost:8082/#?first_name=asdf&last_name=hello:~:text=hello\n\t// results: '#?first_name=asdf&last_name=hello'.\n\t// Firefox sees and preserves the text fragment. See:\n\t// https://stackoverflow.com/a/73366996/1923095\n\t// and\n\t// https://github.com/WICG/scroll-to-text-fragment/issues/193#issuecomment-1219640246\n\t//\n\t// FireFox's way of handling the text fragment using 'window.location'is\n\t// correct and the following performs a secondary check for other browsers\n\t// (Chrome) that have changed the behavior of 'window.location'.\n\t//\n\t// Use 'performance' API for browsers other than 'Firefox', to\n\t// properly handle text fragments MDN recommends never using user agent or\n\t// browsers to determine logic, but this is the only way in Chrome to\n\t// guaranteed to be given the full URL now that Chrome may remove parts of\n\t// the URL. (WTF).\n\t//\n\t// When running files locally, calling\n\t// `performance.getEntriesByType('navigation')[0].name`\n\t// returns an empty string. Thus, running a file locally that uses\n\t// URLFormJS, and using Chrome, has no way of preserving fragment\n\t// directives in the URL, since they cannot be interpreted by the browser.\n\t// Another problem under this circumstance is that if the fragment\n\t// directive comes before the fragment query, the fragment query is not\n\t// interpreted either.\n\t// TODO Implement Chrome API for directives when supported:\n\t// https://github.com/WICG/scroll-to-text-fragment/blob/main/fragment-directive-api.md\n\n\t// See issues for not retrieving full URL (with fragment directives) when\n\t// using 'file://' protocol:\n\t// https://github.com/mozilla/standards-positions/issues/194#issuecomment-1224592766\n\t// https://github.com/WICG/scroll-to-text-fragment/issues/196#issue-1348444072\n\n\t// Can't use 'name' in performance when running locally.\n\tif (window.location.protocol !== \"file:\" && !navigator.userAgent.includes('Firefox')) {\n\t\tfParts = performance.getEntriesByType('navigation')[0].name.split(\"#\")\n\t}\n\n\tif (fParts.length == 1) { // only \"#\"\n\t\treturn \"\"\n\t}\n\t// Always decode URL, even if not URL encoded.\n\treturn decodeURIComponent(fParts[1])\n}\n\n\n\n/**\nClear clears out a form.\n@param {FormOptions} formOptions\n@returns {void}\n */\nfunction Clear(formOptions) {\n\tif (!formOptions.Inited) {\n\t\tthrow new Error(\"URLFormJS: Init() must be called first to initialize the URLFormJS module.\")\n\t}\n\n\t// FormMode clear\n\tif (formOptions.FormMode) {\n\t\t//https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements\n\t\tfor (let e of FormOptions.FormElement.elements) {\n\t\t\tif (e.type === \"checkbox\") {\n\t\t\t\te.checked = false\n\t\t\t} else {\n\t\t\t\te.value = \"\"\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\n\t// Normal Mode clear (clear each element individually)\n\tfor (let fp of formOptions.FormParameters) {\n\t\tlet name = formOptions.prefix + fp.name\n\t\tlet id = fp.id\n\t\t// If id is empty, assume name is the id on the page.\n\t\tif (isEmpty(id)) {\n\t\t\tid = name\n\t\t}\n\n\t\t// Unchecks if type=bool. Otherwise sets value of the element to \"\"\n\t\tif (fp.type == \"bool\") {\n\t\t\tlet e = document.getElementById(id)\n\t\t\tif (e != null) {\n\t\t\t\te.checked = false\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tlet e = document.getElementById(id)\n\t\tif (e != null) {\n\t\t\te.value = \"\"\n\t\t}\n\t}\n\t// Clear the share URL. \n\tvar u = new URL(window.location.origin + window.location.pathname)\n\tsetShareURL(u.href, formOptions)\n}\n\n\n/**\nGetDefaultFormOptions returns the Initialized default form options. NOTE:\nExporting DefaultFormOptions directly makes it to where the UMD format block\nneeds to be at the bottom of the file, after initialization.\n@returns {FormOptions}\n */\nfunction GetDefaultFormOptions() {\n\treturn DefaultFormOptions\n}\n\n/**\nSetURLNoReload sets the full URL, without reloading. Helper function for both\nexplicitly setting a URL without reloading, and syntax. This function also\nserves as code as documentation.\n@param {string} url Full URL\n@returns {void}\n */\nfunction SetURLNoReload(url) {\n\twindow.history.pushState({}, '', url)\n}\n\n/**\nIsEmpty returns whether or not the initialized form is empty.\n\n@param {FormOptions} formOptions\n@returns {boolean} Whether or not the form is empty.\n@throws {error} Fails if form is not of type HTMLFormElement.\n */\nfunction IsEmpty(formOptions) {\n\treturn isEmpty(GetForm(formOptions))\n}\n\n\n///////////////////////////////////\n// Helpers - Taken from Cyphr.me\n///////////////////////////////////\n\n/**\nisEmpty is a helper function to determine if thing is empty. \n\nFunctions are considered always not empty. \n\nArrays: Only if an array has no elements it is empty. isEmpty does not check\nelement contents. (For item contents, do: `isEmpty(array[0])`)\n\nObjects are empty if they have no keys. (Returns len === 0 of object keys.)\n\nNaN returns true. (NaN === NaN is always false, as NaN is never equal to\nanything. NaN is the only JavaScript value unequal to itself.)\n\nDon't use on HTMl elements. For HTML elements, use the !== equality check\n(element !== null). TODO fix this\n\nCannot use CryptoKey with this function since (len === 0) always. \n@param {any} thing Thing you wish was empty. \n@returns {boolean} Boolean. \n*/\nfunction isEmpty(thing) {\n\tif (typeof thing === 'function') {\n\t\treturn false\n\t}\n\n\tif (Array.isArray(thing)) {\n\t\tif (thing.length == 0) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\tif (thing === Object(thing)) {\n\t\tif (Object.keys(thing).length === 0) {\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tif (!isBool(thing)) {\n\t\treturn true\n\t}\n\treturn false\n}\n\n\n/**\nHelper function to determine boolean. \n\nJavascript, instead of considering everything false except a few key words,\ndecided everything is true instead of a few key words. Why? Because\nJavascript. This function inverts that assumption, so that everything can be\nconsidered false unless true. \n@param {any} bool Thing that you wish was a boolean. \n@returns {boolean} An actual boolean.\n*/\nfunction isBool(bool) {\n\tif (\n\t\tbool === false ||\n\t\tbool === \"false\" ||\n\t\tbool === undefined ||\n\t\tbool === \"undefined\" ||\n\t\tbool === \"\" ||\n\t\tbool === 0 ||\n\t\tbool === \"0\" ||\n\t\tbool === null ||\n\t\tbool === \"null\" ||\n\t\tbool === \"NaN\" ||\n\t\tNumber.isNaN(bool) ||\n\t\tbool === Object(bool) // isObject\n\t) {\n\t\treturn false\n\t}\n\treturn true\n}\n\n\n"],
"mappings": "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",
"names": ["formOptions", "formOpt", "savedPairs", "fp", "uriPairs", "pairs", "quagPairs", "kv", "id", "name", "value", "e", "foc", "href", "shareUrl", "shareArea", "formPairs", "q", "u", "fragment", "fqs", "extrasKV", "qs", "firstParam", "key", "equal", "a", "s", "parts", "i", "getFragment", "frag", "ss", "qp", "formParams", "p", "ReturnPairOnZero", "htmlID", "elem", "formData", "param", "fParts", "url", "thing", "bool"]
}