{
  "version": 3,
  "sources": ["inline_rename.js"],
  "sourcesContent": ["/*\n * static/js/inline_rename.js \u2014 renaming a UGC panel row in place (SNOW-658).\n *\n * The DOM half of includes/_ugc_panel_row.html's `renameable` state. Hugo's\n * \"Map panels \u2014 common format\" design: \"Where a row can be renamed, that\n * happens in place on the label.\" The row's pencil swaps the label for the\n * editor already sitting hidden beside it; Enter or blur commits, Escape\n * cancels, and a trimmed-empty input leaves the title unchanged.\n *\n * ONE TRIGGER, NOT TWO. A click on the label opened the editor too for a\n * day. Hugo: \"We have inline editing & the pencil - choose one.\" The\n * pencil is what stayed \u2014 see ``rowFor``'s own note for why the label\n * could not be the one kept.\n *\n * WHAT THIS REPLACES. Both renameable panels used ``window.prompt`` \u2014\n * downloads since SNOW-635, favourites for one day after SNOW-658's first\n * pass copied it. A prompt is a modal browser chrome dialogue that covers\n * the thing being renamed, cannot be styled, and reads out of place on a\n * touch device; the design puts the edit where the name is.\n *\n * WHY IT IS ITS OWN MODULE. Two panels rename \u2014 a favourite (POST to\n * favourites:rename) and a downloaded custom area (a local IndexedDB\n * write through window.pwaBasemapDownloads.rename). The INTERACTION is\n * identical and the COMMIT is not, so the interaction lives here once and\n * each module passes its own commit. The alternative \u2014 the same\n * focus/keyboard/blur state machine written twice \u2014 is exactly the\n * duplication that had the two panels' rows drifting apart to begin with.\n *\n * WHY THE EDITOR IS SERVER-RENDERED. The input is in the row's markup,\n * hidden, rather than created here: its aria-label is user-facing copy,\n * and makemessages cannot see a string built in JS (see docs/i18n.md).\n * This module only ever reveals what the template already rendered.\n *\n * NO TRAILING STATE. Every listener is bound at the start of an edit and\n * removed when it finishes, because the input is a persistent element that\n * gets edited many times \u2014 a listener added per edit and never removed\n * would fire once per previous edit on the next commit.\n */\n\n(function inlineRenameInit() {\n  'use strict';\n\n  var ROW_SELECTOR = '[data-row-renameable]';\n  var LABEL_SELECTOR = '[data-row-label]';\n  var INPUT_SELECTOR = '[data-row-rename-input]';\n  var TRIGGER_SELECTOR = '[data-row-rename]';\n\n  /**\n   * The renameable row a click belongs to, if the click should start an\n   * edit.\n   *\n   * ONE thing opens an edit: the pencil. A click anywhere else in the row \u2014\n   * the label, the meta line, the trash \u2014 is not a rename.\n   *\n   * SNOW-658, Hugo: \"We have inline editing & the pencil - choose one.\"\n   * The pencil wins. The label is a ``<span>``, so a click on it is\n   * mouse-only: there is nothing to tab to, nothing to press Enter on, and\n   * nothing for a screen reader to announce, which makes it an affordance\n   * only some users have. The pencil is a real 44\u00D744 button carrying the\n   * row's own name in its aria-label. And with the label inert, a\n   * favourites row reads exactly like a downloads or observations row at\n   * rest \u2014 which is the point of a shared row.\n   *\n   * @param {EventTarget|null} target The click's target.\n   * @returns {HTMLElement|null} The row, or null when this was not a\n   *   rename click.\n   */\n  function rowFor(target) {\n    var el = /** @type {HTMLElement|null} */ (target);\n    if (!el || !el.closest) return null;\n    var row = el.closest(ROW_SELECTOR);\n    if (!row) return null;\n    if (!el.closest(TRIGGER_SELECTOR)) return null;\n    return /** @type {HTMLElement} */ (row);\n  }\n\n  /**\n   * Put a row's label into an inline edit.\n   *\n   * Safe to call on a row already being edited (the second call just\n   * refocuses) and on a row with no editor (returns false, so a caller can\n   * fall back rather than swallow the click).\n   *\n   * @param {HTMLElement} row A `[data-row-renameable]` row.\n   * @param {function(string): void} onCommit Called with the new name \u2014\n   *   trimmed, non-empty, and different from the current one. Never called\n   *   for a cancel, an unchanged name, or an emptied field: the design's\n   *   own rule is that clearing the field leaves the title alone.\n   * @returns {boolean} Whether an edit was opened.\n   */\n  function begin(row, onCommit) {\n    var label = /** @type {HTMLElement|null} */ (row.querySelector(LABEL_SELECTOR));\n    var input = /** @type {HTMLInputElement|null} */ (row.querySelector(INPUT_SELECTOR));\n    if (!label || !input) return false;\n\n    if (!input.hidden) {\n      input.focus();\n      return true;\n    }\n\n    // The label's own text is the truth, not the input's stale `value`:\n    // the row may have been re-rendered, or a previous edit cancelled,\n    // since the input was last written to.\n    var current = label.textContent.trim();\n    input.value = current;\n    label.hidden = true;\n    input.hidden = false;\n    input.focus();\n    input.select();\n\n    /**\n     * Restore the reading state and unbind, optionally committing.\n     *\n     * The row is restored BEFORE the commit fires, not after: a commit\n     * re-reads or re-renders the list, and a row left mid-edit while that\n     * is in flight is a second source of truth about what the name is.\n     *\n     * @param {boolean} commit Whether to offer the value to the caller.\n     * @returns {void}\n     */\n    function finish(commit) {\n      input.removeEventListener('keydown', onKeyDown);\n      input.removeEventListener('blur', onBlur);\n      var next = input.value.trim();\n      input.hidden = true;\n      label.hidden = false;\n      if (!commit) return;\n      // An emptied field is not an erasure \u2014 the design's own commit()\n      // leaves the title unchanged \u2014 and an unchanged name is not an edit,\n      // so neither is worth a write.\n      if (!next || next === current) return;\n      onCommit(next);\n    }\n\n    /**\n     * @param {KeyboardEvent} event\n     * @returns {void}\n     */\n    function onKeyDown(event) {\n      if (event.key === 'Enter') {\n        event.preventDefault();\n        finish(true);\n        return;\n      }\n      if (event.key === 'Escape') {\n        event.preventDefault();\n        // Cancel first, so the blur that follows hiding a focused input\n        // finds nothing bound and cannot commit what Escape just refused.\n        finish(false);\n      }\n    }\n\n    /**\n     * @returns {void}\n     */\n    function onBlur() {\n      finish(true);\n    }\n\n    input.addEventListener('keydown', onKeyDown);\n    input.addEventListener('blur', onBlur);\n    return true;\n  }\n\n  window.pwaInlineRename = Object.freeze({\n    begin: begin,\n    rowFor: rowFor,\n  });\n})();\n"],
  "mappings": "CAuCC,UAA4B,CAC3B,aAEA,IAAIA,EAAe,wBACfC,EAAiB,mBACjBC,EAAiB,0BACjBC,EAAmB,oBAsBvB,SAASC,EAAOC,EAAQ,CACtB,IAAIC,EAAsCD,EAC1C,GAAI,CAACC,GAAM,CAACA,EAAG,QAAS,OAAO,KAC/B,IAAIC,EAAMD,EAAG,QAAQN,CAAY,EAEjC,MADI,CAACO,GACD,CAACD,EAAG,QAAQH,CAAgB,EAAU,KACPI,CACrC,CAgBA,SAASC,EAAMD,EAAKE,EAAU,CAC5B,IAAIC,EAAyCH,EAAI,cAAcN,CAAc,EACzEU,EAA8CJ,EAAI,cAAcL,CAAc,EAClF,GAAI,CAACQ,GAAS,CAACC,EAAO,MAAO,GAE7B,GAAI,CAACA,EAAM,OACT,OAAAA,EAAM,MAAM,EACL,GAMT,IAAIC,EAAUF,EAAM,YAAY,KAAK,EACrCC,EAAM,MAAQC,EACdF,EAAM,OAAS,GACfC,EAAM,OAAS,GACfA,EAAM,MAAM,EACZA,EAAM,OAAO,EAYb,SAASE,EAAOC,EAAQ,CACtBH,EAAM,oBAAoB,UAAWI,CAAS,EAC9CJ,EAAM,oBAAoB,OAAQK,CAAM,EACxC,IAAIC,EAAON,EAAM,MAAM,KAAK,EAC5BA,EAAM,OAAS,GACfD,EAAM,OAAS,GACVI,IAID,CAACG,GAAQA,IAASL,GACtBH,EAASQ,CAAI,EACf,CAMA,SAASF,EAAUG,EAAO,CACxB,GAAIA,EAAM,MAAQ,QAAS,CACzBA,EAAM,eAAe,EACrBL,EAAO,EAAI,EACX,MACF,CACIK,EAAM,MAAQ,WAChBA,EAAM,eAAe,EAGrBL,EAAO,EAAK,EAEhB,CAKA,SAASG,GAAS,CAChBH,EAAO,EAAI,CACb,CAEA,OAAAF,EAAM,iBAAiB,UAAWI,CAAS,EAC3CJ,EAAM,iBAAiB,OAAQK,CAAM,EAC9B,EACT,CAEA,OAAO,gBAAkB,OAAO,OAAO,CACrC,MAAOR,EACP,OAAQJ,CACV,CAAC,CACH,GAAG",
  "names": ["ROW_SELECTOR", "LABEL_SELECTOR", "INPUT_SELECTOR", "TRIGGER_SELECTOR", "rowFor", "target", "el", "row", "begin", "onCommit", "label", "input", "current", "finish", "commit", "onKeyDown", "onBlur", "next", "event"]
}
