{"version":3,"file":"checklist.js","names":["define","_exports","_ajax","_ajaxError","_deprecated","_getOwner","_iconLibrary","_pluginApi","_discourseI18n","_richEditorExtension","isWhitespaceNode","node","nodeType","nodeValue","match","addUlClasses","boxes","forEach","val","parent","parentElement","nodeName","firstElementChild","sibling","previousSibling","hasPrecedingContent","classList","add","nextSibling","insertAdjacentHTML","checklistSyntax","elem","postDecorator","getElementsByClassName","postModel","getModel","postWidget","withSilencedDeprecations","getOwnerWithFallback","this","lookup","useGlimmerPostStream","widget","can_edit","idx","onclick","async","box","event","currentTarget","contains","newValue","template","document","createElement","innerHTML","iconHTML","class","insertAdjacentElement","content","firstChild","e","post","ajax","id","blocks","regex","exec","raw","push","index","length","nth","found","newRaw","replace","ignored","off","every","b","save","edit_reason","i18n","attrs","isSaving","scheduleRerender","popupAjaxError","remove","querySelector","Object","defineProperty","value","default","name","initialize","withPluginApi","api","container","checklist_enabled","decorateCookedElement","registerRichEditorExtension","initializePlugin","setup","helper","registerOptions","opts","siteSettings","features","allowList","registerPlugin","md","core","ruler","processChecklist","REGEX","addCheckbox","result","state","classes","str","getClasses","checkOpenToken","Token","checkCloseToken","applyCheckboxes","pos","token","slice","i","j","l","tokens","blockTokens","nesting","type","children","processed","utils","arrayReplaceAt","extension","nodeSpec","check","checked","inline","group","draggable","selectable","toDOM","parseDOM","tag","getAttrs","dom","hasCheckedClass","className","inputRules","handler","start","end","tr","replaceWith","schema","nodes","create","parse","check_open","attrGet","check_close","noCloseToken","ignore","serializeNode","write","CHECKED_REGEX","test"],"sources":["discourse/plugins/checklist/discourse/initializers/checklist.js","discourse/plugins/checklist/lib/discourse-markdown/checklist.js","discourse/plugins/checklist/lib/rich-editor-extension.js"],"sourcesContent":["define(\"discourse/plugins/checklist/discourse/initializers/checklist\", [\"exports\", \"discourse/lib/ajax\", \"discourse/lib/ajax-error\", \"discourse/lib/deprecated\", \"discourse/lib/get-owner\", \"discourse/lib/icon-library\", \"discourse/lib/plugin-api\", \"discourse-i18n\", \"discourse/plugins/checklist/lib/rich-editor-extension\"], function (_exports, _ajax, _ajaxError, _deprecated, _getOwner, _iconLibrary, _pluginApi, _discourseI18n, _richEditorExtension) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.checklistSyntax = checklistSyntax;\n  _exports.default = void 0;\n  function initializePlugin(api) {\n    const siteSettings = api.container.lookup(\"service:site-settings\");\n    if (siteSettings.checklist_enabled) {\n      api.decorateCookedElement(checklistSyntax);\n      api.registerRichEditorExtension(_richEditorExtension.default);\n    }\n  }\n  function isWhitespaceNode(node) {\n    return node.nodeType === 3 && node.nodeValue.match(/^\\s*$/);\n  }\n  function hasPrecedingContent(node) {\n    let sibling = node.previousSibling;\n    while (sibling) {\n      if (!isWhitespaceNode(sibling)) {\n        return true;\n      }\n      sibling = sibling.previousSibling;\n    }\n    return false;\n  }\n  function addUlClasses(boxes) {\n    boxes.forEach(val => {\n      let parent = val.parentElement;\n      if (parent.nodeName === \"P\" && parent.parentElement.firstElementChild === parent) {\n        parent = parent.parentElement;\n      }\n      if (parent.nodeName === \"LI\" && parent.parentElement.nodeName === \"UL\" && !hasPrecedingContent(val)) {\n        parent.classList.add(\"has-checkbox\");\n        val.classList.add(\"list-item-checkbox\");\n        if (!val.nextSibling) {\n          val.insertAdjacentHTML(\"afterend\", \"&#8203;\"); // Ensure otherwise empty <li> does not collapse height\n        }\n      }\n    });\n  }\n  function checklistSyntax(elem, postDecorator) {\n    const boxes = [...elem.getElementsByClassName(\"chcklst-box\")];\n    addUlClasses(boxes);\n    const postModel = postDecorator?.getModel();\n\n    // TODO (glimmer-post-stream): remove this when we remove the legacy post stream code\n    const postWidget = (0, _deprecated.withSilencedDeprecations)(\"discourse.post-stream-widget-overrides\", () => (0, _getOwner.getOwnerWithFallback)(this).lookup(\"service:site\").useGlimmerPostStream ? null : postDecorator?.widget);\n    if (!postModel?.can_edit) {\n      return;\n    }\n    boxes.forEach((val, idx) => {\n      val.onclick = async event => {\n        const box = event.currentTarget;\n        const classList = box.classList;\n        if (classList.contains(\"permanent\") || classList.contains(\"readonly\")) {\n          return;\n        }\n        const newValue = classList.contains(\"checked\") ? \"[ ]\" : \"[x]\";\n        const template = document.createElement(\"template\");\n        template.innerHTML = (0, _iconLibrary.iconHTML)(\"spinner\", {\n          class: \"fa-spin list-item-checkbox\"\n        });\n        box.insertAdjacentElement(\"afterend\", template.content.firstChild);\n        box.classList.add(\"hidden\");\n        boxes.forEach(e => e.classList.add(\"readonly\"));\n        try {\n          const post = await (0, _ajax.ajax)(`/posts/${postModel.id}`);\n          const blocks = [];\n\n          // Computing offsets where checkbox are not evaluated (i.e. inside\n          // code blocks).\n          [\n          // inline code\n          /`[^`\\n]*\\n?[^`\\n]*`/gm,\n          // multi-line code\n          /^```[^]*?^```/gm,\n          // bbcode\n          /\\[code\\][^]*?\\[\\/code\\]/gm,\n          // italic/bold\n          /_(?=\\S).*?\\S_/gm,\n          // strikethrough\n          /~~(?=\\S).*?\\S~~/gm].forEach(regex => {\n            let match;\n            while ((match = regex.exec(post.raw)) != null) {\n              blocks.push([match.index, match.index + match[0].length]);\n            }\n          });\n          [\n          // italic/bold\n          /([^\\[\\n]|^)\\*\\S.+?\\S\\*(?=[^\\]\\n]|$)/gm].forEach(regex => {\n            let match;\n            while ((match = regex.exec(post.raw)) != null) {\n              // Simulate lookbehind - skip the first character\n              blocks.push([match.index + 1, match.index + match[0].length]);\n            }\n          });\n\n          // make the first run go to index = 0\n          let nth = -1;\n          let found = false;\n          const newRaw = post.raw.replace(/\\[( |x)?\\]/gi, (match, ignored, off) => {\n            if (found) {\n              return match;\n            }\n\n            // skip empty image URLs - \"![](https://example.com/image.jpg)\"\n            if (off > 0 && post.raw[off - 1] === \"!\") {\n              return match;\n            }\n            nth += blocks.every(b => b[0] >= off + match.length || off > b[1]);\n            if (nth === idx) {\n              found = true; // Do not replace any further matches\n              return newValue;\n            }\n            return match;\n          });\n          await postModel.save({\n            raw: newRaw,\n            edit_reason: (0, _discourseI18n.i18n)(\"checklist.edit_reason\")\n          });\n\n          // TODO (glimmer-post-stream): remove the following code when removing the legacy post stream code\n          if (postWidget) {\n            postWidget.attrs.isSaving = false;\n            postWidget.scheduleRerender();\n          }\n        } catch (e) {\n          (0, _ajaxError.popupAjaxError)(e);\n        } finally {\n          boxes.forEach(e => e.classList.remove(\"readonly\"));\n          box.classList.remove(\"hidden\");\n          box.parentElement.querySelector(\".fa-spin\").remove();\n        }\n      };\n    });\n  }\n  var _default = _exports.default = {\n    name: \"checklist\",\n    initialize() {\n      (0, _pluginApi.withPluginApi)(api => initializePlugin(api));\n    }\n  };\n});","define(\"discourse/plugins/checklist/lib/discourse-markdown/checklist\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.setup = setup;\n  const REGEX = /\\[( |x)?\\]/gi;\n  function getClasses(str) {\n    switch (str) {\n      case \"x\":\n        return \"checked fa fa-square-check-o fa-fw\";\n      case \"X\":\n        return \"checked permanent fa fa-square-check fa-fw\";\n      default:\n        return \"fa fa-square-o fa-fw\";\n    }\n  }\n  function addCheckbox(result, content, match, state) {\n    const classes = getClasses(match[1]);\n    const checkOpenToken = new state.Token(\"check_open\", \"span\", 1);\n    checkOpenToken.attrs = [[\"class\", `chcklst-box ${classes}`]];\n    result.push(checkOpenToken);\n    const checkCloseToken = new state.Token(\"check_close\", \"span\", -1);\n    result.push(checkCloseToken);\n  }\n  function applyCheckboxes(content, state) {\n    let match;\n    let result = null;\n    let pos = 0;\n    while (match = REGEX.exec(content)) {\n      if (match.index > pos) {\n        result = result || [];\n        const token = new state.Token(\"text\", \"\", 0);\n        token.content = content.slice(pos, match.index);\n        result.push(token);\n      }\n      pos = match.index + match[0].length;\n      result = result || [];\n      addCheckbox(result, content, match, state);\n    }\n    if (result && pos < content.length) {\n      const token = new state.Token(\"text\", \"\", 0);\n      token.content = content.slice(pos);\n      result.push(token);\n    }\n    return result;\n  }\n  function processChecklist(state) {\n    let i,\n      j,\n      l,\n      tokens,\n      token,\n      blockTokens = state.tokens,\n      nesting = 0;\n    for (j = 0, l = blockTokens.length; j < l; j++) {\n      if (blockTokens[j].type !== \"inline\") {\n        continue;\n      }\n      tokens = blockTokens[j].children;\n\n      // We scan from the end, to keep position when new tags are added.\n      // Use reversed logic in links start/end match\n      for (i = tokens.length - 1; i >= 0; i--) {\n        token = tokens[i];\n        nesting += token.nesting;\n        if (token.type === \"text\" && nesting === 0) {\n          const processed = applyCheckboxes(token.content, state);\n          if (processed) {\n            blockTokens[j].children = tokens = state.md.utils.arrayReplaceAt(tokens, i, processed);\n          }\n        }\n      }\n    }\n  }\n  function setup(helper) {\n    helper.registerOptions((opts, siteSettings) => {\n      opts.features[\"checklist\"] = !!siteSettings.checklist_enabled;\n    });\n    helper.allowList([\"span.chcklst-stroked\", \"span.chcklst-box fa fa-square-o fa-fw\", \"span.chcklst-box checked fa fa-square-check-o fa-fw\", \"span.chcklst-box checked permanent fa fa-square-check fa-fw\"]);\n    helper.registerPlugin(md => md.core.ruler.push(\"checklist\", processChecklist));\n  }\n});","define(\"discourse/plugins/checklist/lib/rich-editor-extension\", [\"exports\"], function (_exports) {\n  \"use strict\";\n\n  Object.defineProperty(_exports, \"__esModule\", {\n    value: true\n  });\n  _exports.default = void 0;\n  /** @type {RichEditorExtension} */\n  const extension = {\n    // TODO(renato): make the checkbox clickable\n    // TODO(renato): auto-continue checkbox list on ENTER\n    // TODO(renato): apply .has-checkbox style to the <li> to avoid :has\n    nodeSpec: {\n      check: {\n        attrs: {\n          checked: {\n            default: false\n          }\n        },\n        inline: true,\n        group: \"inline\",\n        draggable: true,\n        selectable: false,\n        toDOM(node) {\n          return [\"span\", {\n            class: node.attrs.checked ? \"chcklst-box checked fa fa-square-check-o fa-fw\" : \"chcklst-box fa fa-square-o fa-fw\"\n          }];\n        },\n        parseDOM: [{\n          tag: \"span.chcklst-box\",\n          getAttrs: dom => {\n            return {\n              checked: hasCheckedClass(dom.className)\n            };\n          }\n        }]\n      }\n    },\n    inputRules: [{\n      match: /(^|\\s)\\[(x? ?)]$/,\n      handler: (state, match, start, end) => state.tr.replaceWith(start + match[1].length, end, state.schema.nodes.check.create({\n        checked: match[2] === \"x\"\n      }))\n    }],\n    parse: {\n      check_open: {\n        node: \"check\",\n        getAttrs: token => ({\n          checked: hasCheckedClass(token.attrGet(\"class\"))\n        })\n      },\n      check_close: {\n        noCloseToken: true,\n        ignore: true\n      }\n    },\n    serializeNode: {\n      check: (state, node) => {\n        state.write(node.attrs.checked ? \"[x]\" : \"[ ]\");\n      }\n    }\n  };\n  const CHECKED_REGEX = /\\bchecked\\b/;\n  function hasCheckedClass(className) {\n    return CHECKED_REGEX.test(className);\n  }\n  var _default = _exports.default = extension;\n});"],"mappings":"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","ignoreList":[]}