{"version":3,"file":"edit_posts.js","mappings":"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","sources":["webpack://trace_taiwan/./app/javascript/packs/inline_edit.js","webpack://trace_taiwan/./app/javascript/packs/edit_posts.js"],"sourcesContent":["// Shared helpers for the on-page \"suggest an edit\" flows (trace details and river\n// details). Each caller owns its DOM swapping; this module owns the textarea\n// behaviour and the /edits/create request so the two stay in sync.\nexport const SUBMITTED_MESSAGE =\n \"Thank you for your contribution. Your update is being reviewed. It may take some \" +\n \"time before it is live. Please be patient and avoid resubmitting.\";\nexport const DUPLICATE_MESSAGE =\n \"You have already submitted an improvement for this information. Please give us time \" +\n \"to review it before creating another.\";\nexport const LOGIN_MESSAGE =\n 'Only logged in users can edit information. ' +\n 'Click to Login/Sign Up';\n\n// Grow a textarea to fit its content as the user types.\nexport function autoGrow(textarea) {\n const fit = () => {\n textarea.style.height = \"auto\";\n textarea.style.height = `${textarea.scrollHeight}px`;\n };\n textarea.addEventListener(\"input\", fit);\n fit();\n}\n\n// A status banner element; pass the literal color classes so Tailwind keeps them.\nexport function statusBanner(colorClasses, html) {\n const banner = document.createElement(\"div\");\n banner.className = `rounded-lg py-3 px-4 mt-2 text-sm font-semibold ${colorClasses}`;\n banner.innerHTML = html;\n return banner;\n}\n\n// Submit a suggested edit; resolves to 'success', 'duplicate', 'login', or 'error'.\nexport async function submitEdit(edit) {\n const params = new URLSearchParams();\n Object.entries(edit).forEach(([key, value]) => params.set(`edit[${key}]`, value ?? \"\"));\n const response = await fetch(`/edits/create?${params.toString()}`, {\n headers: { Accept: \"application/json\" }\n });\n const body = await response.json().catch(() => null);\n if (!body) return \"success\";\n if (body.message === \"login\") return \"login\";\n if (body.message === \"duplicate edit\") return \"duplicate\";\n return \"error\";\n}\n","// Trace show page: let a visitor suggest an edit to a detail field inline. Clicking\n// \"improve\" swaps the value for a textarea + Submit/Cancel; submitting sends it to\n// /edits/create for review.\nimport {\n autoGrow, statusBanner, submitEdit,\n SUBMITTED_MESSAGE, DUPLICATE_MESSAGE, LOGIN_MESSAGE\n} from \"./inline_edit\";\n\nconst EDIT_BUTTON_CLASSES =\n \"inline-flex justify-center py-1.5 mt-2 px-4 border border-transparent cursor-pointer \" +\n \"text-sm font-semibold rounded-lg text-white focus:outline-none transition duration-150 \" +\n \"ease-in-out edit-button\";\n\nconst traceDetails = document.getElementById(\"trace-details\");\n\nfunction fromHTML(html) {\n const template = document.createElement(\"template\");\n template.innerHTML = html.trim();\n return template.content.firstElementChild;\n}\n\nfunction paragraph(text) {\n return fromHTML(`
${text}
`);\n}\n\nfunction gpsLink(text) {\n return fromHTML(`\n \n \n ${text}\n `);\n}\n\nfunction writeUp(text, isGps) {\n return isGps ? gpsLink(text) : paragraph(text);\n}\n\nfunction editButton(label, colorClasses) {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.className = `${EDIT_BUTTON_CLASSES} ${colorClasses}`;\n button.textContent = label;\n return button;\n}\n\nfunction originalTextFor(content, isGps) {\n if (!isGps) return content.textContent;\n const span = content.querySelector(\"span\");\n return (span ? span.textContent : content.textContent).trim();\n}\n\nfunction startEditing(improveButton) {\n const section = improveButton.closest(\"[data-post-attribute]\");\n const content = section.querySelector(\".editable-content\");\n const isGps = content.classList.contains(\"gps-loc\");\n const originalText = originalTextFor(content, isGps);\n const restore = () => writeUp(originalText, isGps);\n\n const textarea = document.createElement(\"textarea\");\n textarea.className = \"improve post-select\";\n textarea.name = \"improvement area\";\n textarea.spellcheck = false;\n textarea.value = originalText;\n\n const submit = editButton(\"Submit Edit\", \"mr-3 bg-green-500 hover:bg-green-600\");\n const cancel = editButton(\"Cancel\", \"bg-red-500 hover:bg-red-600\");\n\n content.replaceWith(textarea);\n textarea.after(submit, cancel);\n improveButton.style.display = \"none\";\n autoGrow(textarea);\n\n cancel.addEventListener(\"click\", () => {\n textarea.replaceWith(restore());\n submit.remove();\n cancel.remove();\n improveButton.style.display = \"\";\n });\n\n submit.addEventListener(\"click\", async () => {\n const newText = textarea.value;\n const result = await submitEdit({\n before: originalText,\n after: newText,\n post_id: traceDetails.dataset.id,\n attribute_updated: section.dataset.postAttribute\n });\n\n if (result === \"success\") {\n submit.remove();\n textarea.replaceWith(writeUp(newText, isGps));\n cancel.replaceWith(statusBanner(\"bg-green-100 text-green-800\", SUBMITTED_MESSAGE));\n } else if (result === \"duplicate\") {\n submit.remove();\n textarea.replaceWith(restore());\n cancel.replaceWith(statusBanner(\"bg-yellow-100 text-yellow-800\", DUPLICATE_MESSAGE));\n } else if (result === \"login\") {\n submit.remove();\n textarea.replaceWith(restore());\n cancel.replaceWith(statusBanner(\"bg-yellow-100 text-yellow-800\", LOGIN_MESSAGE));\n }\n });\n}\n\nif (traceDetails) {\n traceDetails.querySelectorAll(\".improve-text\").forEach((button) => {\n button.addEventListener(\"click\", () => startEditing(button));\n });\n}\n"],"names":["statusBanner","colorClasses","html","banner","document","createElement","className","innerHTML","traceDetails","getElementById","fromHTML","template","trim","content","firstElementChild","writeUp","text","isGps","gpsLink","paragraph","editButton","label","button","type","textContent","querySelectorAll","forEach","addEventListener","improveButton","section","closest","querySelector","classList","contains","originalText","span","originalTextFor","restore","textarea","name","spellcheck","value","submit","cancel","replaceWith","after","style","display","fit","height","scrollHeight","autoGrow","remove","async","newText","result","edit","params","URLSearchParams","Object","entries","key","set","response","fetch","toString","headers","Accept","body","json","catch","message","submitEdit","before","post_id","dataset","id","attribute_updated","postAttribute","startEditing"],"ignoreList":[],"sourceRoot":""}