{"version":3,"file":"edit_rivers.js","mappings":"yBAwBO,SAASA,EAAaC,EAAcC,GACzC,MAAMC,EAASC,SAASC,cAAc,OAGtC,OAFAF,EAAOG,UAAY,mDAAmDL,IACtEE,EAAOI,UAAYL,EACZC,CACT,CCrBA,MAKMK,EAAeJ,SAASK,eAAe,iBAE7C,SAASC,EAAWC,EAAOV,GACzB,MAAMW,EAASR,SAASC,cAAc,UAItC,OAHAO,EAAOC,KAAO,SACdD,EAAON,UAAY,uMAA0BL,IAC7CW,EAAOE,YAAcH,EACdC,CACT,CAGA,SAASG,EAAaC,EAAUC,GAC9B,MAAMC,EAAKF,EAASG,WAAU,GAE9B,OADAD,EAAGJ,YAAc,IAAIG,KACdC,CACT,CAwDIV,GACFA,EAAaY,iBAAiB,iBAAiBC,SAAST,IACtDA,EAAOU,iBAAiB,SAAS,IAxDrC,SAAsBC,GACpB,MAAMC,EAAQD,EAAcE,uBAC5B,IAAKD,EAAO,OACZ,MAAMR,EAAWQ,EAAML,WAAU,GAC3BO,EAAeF,EAAMV,YAAYa,OACjCC,EAAU,IAAMb,EAAaC,EAAUU,GAEvCG,EAAWzB,SAASC,cAAc,YACxCwB,EAASvB,UAAY,sBACrBuB,EAASC,KAAO,mBAChBD,EAASE,YAAa,EACtBF,EAASL,MAAQE,EAEjB,MAAMM,EAAStB,EAAW,cAAe,wCACnCuB,EAASvB,EAAW,SAAU,+BAEpCc,EAAMU,YAAYL,GAClBA,EAASM,MAAMH,EAAQC,GACvBV,EAAca,MAAMC,QAAU,ODlCzB,SAAkBR,GACvB,MAAMS,EAAM,KACVT,EAASO,MAAMG,OAAS,OACxBV,EAASO,MAAMG,OAAS,GAAGV,EAASW,gBAAgB,EAEtDX,EAASP,iBAAiB,QAASgB,GACnCA,GACF,CC4BEG,CAASZ,GAETI,EAAOX,iBAAiB,SAAS,KAC/BO,EAASK,YAAYN,KACrBI,EAAOU,SACPT,EAAOS,SACPnB,EAAca,MAAMC,QAAU,EAAE,IAGlCL,EAAOV,iBAAiB,SAASqB,UAC/B,MAAMC,EAAUf,EAASL,MACnBqB,QD5BHF,eAA0BG,GAC/B,MAAMC,EAAS,IAAIC,gBACnBC,OAAOC,QAAQJ,GAAMzB,SAAQ,EAAE8B,EAAK3B,KAAWuB,EAAOK,IAAI,QAAQD,KAAQ3B,GAAS,MACnF,MAAM6B,QAAiBC,MAAM,iBAAiBP,EAAOQ,aAAc,CACjEC,QAAS,CAAEC,OAAQ,sBAEfC,QAAaL,EAASM,OAAOC,OAAM,IAAM,OAC/C,OAAKF,EACgB,UAAjBA,EAAKG,QAA4B,QAChB,mBAAjBH,EAAKG,QAAqC,YACvC,QAHW,SAIpB,CCiByBC,CAAW,CAC9BC,OAAQrC,EACRS,MAAOS,EACPoB,QAAS,GACTC,SAAUzD,EAAa0D,QAAQC,GAC/BC,kBAAmB7C,EAAc8C,QAAQ,yBAAyBH,QAAQI,gBAG7D,YAAXzB,GACFb,EAAOU,SACPb,EAASK,YAAYnB,EAAaC,EAAU4B,IAC5CX,EAAOC,YAAYlC,EAAa,8BDnEpC,wJCoEwB,cAAX6C,GACTb,EAAOU,SACPb,EAASK,YAAYN,KACrBK,EAAOC,YAAYlC,EAAa,gCDpEpC,+HCqEwB,UAAX6C,IACTb,EAAOU,SACPb,EAASK,YAAYN,KACrBK,EAAOC,YAAYlC,EAAa,gCDrEpC,sICsEE,GAEJ,CAI2CuE,CAAa3D,IAAQ,G","sources":["webpack://trace_taiwan/./app/javascript/packs/inline_edit.js","webpack://trace_taiwan/./app/javascript/packs/edit_rivers.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","// River page: suggest an edit to a river detail inline. The value sits just before\n// the \"improve\" pencil (see rivers/_river_information.html.erb); clicking it swaps the\n// value for a textarea + Submit/Cancel and sends the suggestion to /edits/create.\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 riverDetails = document.getElementById(\"river-details\");\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\n// Rebuild the value element from a clone of the original, so its tag and classes survive.\nfunction valueElement(template, text) {\n const el = template.cloneNode(true);\n el.textContent = ` ${text} `;\n return el;\n}\n\nfunction startEditing(improveButton) {\n const value = improveButton.previousElementSibling;\n if (!value) return;\n const template = value.cloneNode(true);\n const originalText = value.textContent.trim();\n const restore = () => valueElement(template, originalText);\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 value.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: \"\",\n river_id: riverDetails.dataset.id,\n attribute_updated: improveButton.closest(\"[data-post-attribute]\").dataset.postAttribute\n });\n\n if (result === \"success\") {\n submit.remove();\n textarea.replaceWith(valueElement(template, newText));\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 (riverDetails) {\n riverDetails.querySelectorAll(\".improve-text\").forEach((button) => {\n button.addEventListener(\"click\", () => startEditing(button));\n });\n}\n"],"names":["statusBanner","colorClasses","html","banner","document","createElement","className","innerHTML","riverDetails","getElementById","editButton","label","button","type","textContent","valueElement","template","text","el","cloneNode","querySelectorAll","forEach","addEventListener","improveButton","value","previousElementSibling","originalText","trim","restore","textarea","name","spellcheck","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","river_id","dataset","id","attribute_updated","closest","postAttribute","startEditing"],"ignoreList":[],"sourceRoot":""}