{
  "version": 3,
  "sources": ["row_removed.js"],
  "sourcesContent": ["/*\n * static/js/row_removed.js \u2014 SNOW-752: notice a row leaving a UGC list.\n *\n * Every list of a user's own data \u2014 favourites, routes, field observations,\n * on the map panels and again on their account pages \u2014 removes a row the\n * same way: the row carries a plain HTMX form, the delete endpoint answers\n * an empty 200, and `hx-target`/`hx-swap=\"outerHTML\"` on the row's own id\n * turns that into a removal with no JS involved.\n *\n * What the surfaces then need is identical too, and until this module they\n * each wrote it out: know that a row has gone, so the list can be re-read\n * (its empty state is a server-side clause, and the swap that emptied one\n * <li> cannot produce one) and the map told (a deleted pin, line or flag\n * has to leave the layer as well as the list).\n *\n * WHY THIS IS AWKWARD ENOUGH TO SHARE. The obvious version \u2014 one\n * `htmx:afterRequest` listener asking whether the request came from inside\n * the list \u2014 does not work. An `outerHTML` swap DETACHES the element that\n * made the request before that event fires, so `elt.closest(...)` runs\n * against an orphan and answers null. So it is two steps: mark on\n * `htmx:beforeRequest`, while the tree is still attached, and act on\n * `htmx:afterRequest`, the last event in htmx's lifecycle.\n *\n * And the mark cannot be a variable. Both listeners are document-level, so\n * every HTMX request on the page runs through them \u2014 the map homepage\n * carries four of these panels at once, plus report.js's own form-load\n * `htmx.ajax()` \u2014 and a shared variable is rewritten by whichever request\n * fires last, with no way to correlate an afterRequest back to the\n * beforeRequest that set it. htmx carries the same `xhr` object on both\n * events, so the mark rides the request it describes.\n *\n * That reasoning was written out three times (favourites.js, routes.js, and\n * report.js, each with a comment saying it was lifted from the last) before\n * SNOW-752 needed it three times more on the account pages. It is one of the\n * shared row modules now, beside static/js/row_focus.js,\n * static/js/inline_rename.js and static/js/row_rename_commit.js.\n *\n * A SECOND ACTION USES THE SAME MACHINERY (SNOW-764). Claiming a shared\n * route is a plain HTMX form on the row, posting to the claim endpoint and\n * swapping the response over the row's own id \u2014 the same shape as Remove,\n * with the same detached-element problem and the same thing needed\n * afterwards (re-read the list, tell the map). So `watch` takes an optional\n * third argument naming the hook, defaulting to the delete form's. What it\n * recognises is \"a row-scoped action landed inside this list\"; removal was\n * simply the only such action until there were two.\n *\n * WHAT IT DELIBERATELY DOES NOT DO. It never re-reads a list, never\n * dispatches an event and never touches the map. Which list to re-read,\n * from which URL, and which overlay to announce are the caller's business\n * and differ on all six surfaces; recognising the removal is the part that\n * does not.\n *\n * Usage \u2014 the selector names the LIST this caller owns:\n *\n *     window.pwaRowRemoved.watch('[data-routes-rows]', function () {\n *       loadRows();\n *       document.dispatchEvent(new CustomEvent('snowdesk:routes-changed'));\n *     });\n *\n * TWO CONDITIONS, NOT ONE. A request counts only when it comes from a\n * `[data-row-remove]` element (the delete form itself \u2014 the hook the three\n * `_*_row_actions.html` partials put there) AND that element is inside the\n * caller's list.\n *\n * The list alone is not enough, because a row is not only a delete. On\n * /account/favourites/ the row's disclosure chevron hx-gets the pin's\n * detail card from inside the very same list, so a watcher keyed on the\n * list would re-read it every time a user expanded a card \u2014 closing the\n * card they had just opened. The form alone is not enough either: the map\n * homepage carries three of these lists at once, and a pin deleted in the\n * favourites panel must not make the routes panel refetch.\n *\n * The listeners are registered once per watch() and are never removed:\n * these lists are re-rendered wholesale on every read, so a listener bound\n * to a specific container would have to be rebound on each swap. Delegation\n * from the document is what makes a caller's single call at boot enough.\n *\n * A re-read made with `htmx.ajax(verb, url, {target})` cannot loop: that\n * call's source element defaults to `document.body`, which is no delete\n * form, so it is never marked.\n */\n\n(function rowRemovedInit() {\n  'use strict';\n\n  // The delete form's own hook, rendered by favourites/, routes/ and\n  // observations/'s `_*_row_actions.html`. One name across all three,\n  // because \"this request removes a row\" is one fact however the row is\n  // spelled \u2014 the same reasoning behind `data-row-rename` and\n  // `data-row-focus` on the shared row.\n  const REMOVE_SELECTOR = '[data-row-remove]';\n\n  // One mark name per watch(), so two lists on the same page cannot read\n  // each other's. A counter rather than the selector itself: a selector is\n  // not a valid property name, and two callers watching the same selector\n  // for different reasons is a legitimate thing to do.\n  let watchCount = 0;\n\n  /**\n   * Call `handler` after a successful HTMX request made from inside a list.\n   *\n   * @param {string} listSelector CSS selector for the list container whose\n   *   removals this caller wants \u2014 the scoping half of the test.\n   * @param {Function} handler Called with no arguments, once per successful\n   *   action. Never called for a failed one: a delete that did not land\n   *   left the row where it was, and re-reading would say otherwise.\n   * @param {string} [actionSelector] The row-scoped hook whose requests\n   *   count, defaulting to the delete form's `[data-row-remove]`. SNOW-764\n   *   passes `[data-row-claimed]` for the shared-route Save, which is the\n   *   same shape of request needing the same thing afterwards.\n   * @returns {void}\n   */\n  function watch(listSelector, handler, actionSelector) {\n    if (typeof listSelector !== 'string' || typeof handler !== 'function') return;\n    const action =\n      typeof actionSelector === 'string' && actionSelector\n        ? actionSelector\n        : REMOVE_SELECTOR;\n\n    watchCount += 1;\n    const mark = 'snowdeskRowRemoved' + watchCount;\n\n    document.addEventListener('htmx:beforeRequest', function (event) {\n      const detail = event.detail || {};\n      if (!detail.xhr) return;\n      const elt = detail.elt;\n      if (!elt || !elt.closest) return;\n      detail.xhr[mark] = !!(elt.closest(action) && elt.closest(listSelector));\n    });\n\n    document.addEventListener('htmx:afterRequest', function (event) {\n      const detail = event.detail || {};\n      if (!detail.xhr || !detail.xhr[mark]) return;\n      if (!detail.successful) return;\n      handler();\n    });\n  }\n\n  // Frozen, like every other window.pwa* bridge in static/js \u2014 the export is\n  // a contract, not a namespace for callers to extend.\n  window.pwaRowRemoved = Object.freeze({ watch: watch });\n}());\n"],
  "mappings": "CAkFC,UAA0B,CACzB,aAOA,MAAMA,EAAkB,oBAMxB,IAAIC,EAAa,EAgBjB,SAASC,EAAMC,EAAcC,EAASC,EAAgB,CACpD,GAAI,OAAOF,GAAiB,UAAY,OAAOC,GAAY,WAAY,OACvE,MAAME,EACJ,OAAOD,GAAmB,UAAYA,EAClCA,EACAL,EAENC,GAAc,EACd,MAAMM,EAAO,qBAAuBN,EAEpC,SAAS,iBAAiB,qBAAsB,SAAUO,EAAO,CAC/D,MAAMC,EAASD,EAAM,QAAU,CAAC,EAChC,GAAI,CAACC,EAAO,IAAK,OACjB,MAAMC,EAAMD,EAAO,IACf,CAACC,GAAO,CAACA,EAAI,UACjBD,EAAO,IAAIF,CAAI,EAAI,CAAC,EAAEG,EAAI,QAAQJ,CAAM,GAAKI,EAAI,QAAQP,CAAY,GACvE,CAAC,EAED,SAAS,iBAAiB,oBAAqB,SAAUK,EAAO,CAC9D,MAAMC,EAASD,EAAM,QAAU,CAAC,EAC5B,CAACC,EAAO,KAAO,CAACA,EAAO,IAAIF,CAAI,GAC9BE,EAAO,YACZL,EAAQ,CACV,CAAC,CACH,CAIA,OAAO,cAAgB,OAAO,OAAO,CAAE,MAAOF,CAAM,CAAC,CACvD,GAAE",
  "names": ["REMOVE_SELECTOR", "watchCount", "watch", "listSelector", "handler", "actionSelector", "action", "mark", "event", "detail", "elt"]
}
