| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 |
|
| 11 | import { warning } from "../router/history.js";
|
| 12 | import { stripBasename } from "../router/utils.js";
|
| 13 | const defaultEncType = "application/x-www-form-urlencoded";
|
| 14 | function isHtmlElement(object) {
|
| 15 | return typeof HTMLElement !== "undefined" && object instanceof HTMLElement;
|
| 16 | }
|
| 17 | function isButtonElement(object) {
|
| 18 | return isHtmlElement(object) && object.tagName.toLowerCase() === "button";
|
| 19 | }
|
| 20 | function isFormElement(object) {
|
| 21 | return isHtmlElement(object) && object.tagName.toLowerCase() === "form";
|
| 22 | }
|
| 23 | function isInputElement(object) {
|
| 24 | return isHtmlElement(object) && object.tagName.toLowerCase() === "input";
|
| 25 | }
|
| 26 | function isModifiedEvent(event) {
|
| 27 | return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
|
| 28 | }
|
| 29 | function shouldProcessLinkClick(event, target) {
|
| 30 | return event.button === 0 && (!target || target === "_self") && !isModifiedEvent(event);
|
| 31 | }
|
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | |
| 41 | |
| 42 | |
| 43 | |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 51 | |
| 52 | |
| 53 | |
| 54 | |
| 55 | |
| 56 | |
| 57 |
|
| 58 | function createSearchParams(init = "") {
|
| 59 | return new URLSearchParams(typeof init === "string" || Array.isArray(init) || init instanceof URLSearchParams ? init : Object.keys(init).reduce((memo, key) => {
|
| 60 | let value = init[key];
|
| 61 | return memo.concat(Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]);
|
| 62 | }, []));
|
| 63 | }
|
| 64 | function getSearchParamsForLocation(locationSearch, defaultSearchParams) {
|
| 65 | let searchParams = createSearchParams(locationSearch);
|
| 66 | if (defaultSearchParams) defaultSearchParams.forEach((_, key) => {
|
| 67 | if (!searchParams.has(key)) defaultSearchParams.getAll(key).forEach((value) => {
|
| 68 | searchParams.append(key, value);
|
| 69 | });
|
| 70 | });
|
| 71 | return searchParams;
|
| 72 | }
|
| 73 | let _formDataSupportsSubmitter = null;
|
| 74 | function isFormDataSubmitterSupported() {
|
| 75 | if (_formDataSupportsSubmitter === null) try {
|
| 76 | new FormData(document.createElement("form"), 0);
|
| 77 | _formDataSupportsSubmitter = false;
|
| 78 | } catch (e) {
|
| 79 | _formDataSupportsSubmitter = true;
|
| 80 | }
|
| 81 | return _formDataSupportsSubmitter;
|
| 82 | }
|
| 83 | const supportedFormEncTypes = new Set([
|
| 84 | "application/x-www-form-urlencoded",
|
| 85 | "multipart/form-data",
|
| 86 | "text/plain"
|
| 87 | ]);
|
| 88 | function getFormEncType(encType) {
|
| 89 | if (encType != null && !supportedFormEncTypes.has(encType)) {
|
| 90 | warning(false, `"${encType}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${defaultEncType}"`);
|
| 91 | return null;
|
| 92 | }
|
| 93 | return encType;
|
| 94 | }
|
| 95 | function getFormSubmissionInfo(target, basename) {
|
| 96 | let method;
|
| 97 | let action;
|
| 98 | let encType;
|
| 99 | let formData;
|
| 100 | let body;
|
| 101 | if (isFormElement(target)) {
|
| 102 | let attr = target.getAttribute("action");
|
| 103 | action = attr ? stripBasename(attr, basename) : null;
|
| 104 | method = target.getAttribute("method") || "get";
|
| 105 | encType = getFormEncType(target.getAttribute("enctype")) || defaultEncType;
|
| 106 | formData = new FormData(target);
|
| 107 | } else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) {
|
| 108 | let form = target.form;
|
| 109 | if (form == null) throw new Error(`Cannot submit a <button> or <input type="submit"> without a <form>`);
|
| 110 | let attr = target.getAttribute("formaction") || form.getAttribute("action");
|
| 111 | action = attr ? stripBasename(attr, basename) : null;
|
| 112 | method = target.getAttribute("formmethod") || form.getAttribute("method") || "get";
|
| 113 | encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType;
|
| 114 | formData = new FormData(form, target);
|
| 115 | if (!isFormDataSubmitterSupported()) {
|
| 116 | let { name, type, value } = target;
|
| 117 | if (type === "image") {
|
| 118 | let prefix = name ? `${name}.` : "";
|
| 119 | formData.append(`${prefix}x`, "0");
|
| 120 | formData.append(`${prefix}y`, "0");
|
| 121 | } else if (name) formData.append(name, value);
|
| 122 | }
|
| 123 | } else if (isHtmlElement(target)) throw new Error("Cannot submit element that is not <form>, <button>, or <input type=\"submit|image\">");
|
| 124 | else {
|
| 125 | method = "get";
|
| 126 | action = null;
|
| 127 | encType = defaultEncType;
|
| 128 | body = target;
|
| 129 | }
|
| 130 | if (formData && encType === "text/plain") {
|
| 131 | body = formData;
|
| 132 | formData = void 0;
|
| 133 | }
|
| 134 | return {
|
| 135 | action,
|
| 136 | method: method.toLowerCase(),
|
| 137 | encType,
|
| 138 | formData,
|
| 139 | body
|
| 140 | };
|
| 141 | }
|
| 142 |
|
| 143 | export { createSearchParams, getFormSubmissionInfo, getSearchParamsForLocation, shouldProcessLinkClick };
|