Skip to main content

RUNTIME_JS

Constant RUNTIME_JS 

Source
pub const RUNTIME_JS: &[u8] = b"/*! Spark \xe2\x80\x94 Anvilforge\'s reactive component runtime.\n *  Loaded via @sparkScripts; binds spark:* attributes and round-trips to\n *  /_spark/update. No external dependencies.\n */\n(function () {\n  \'use strict\';\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 Boot data (from `window.__spark_boot` emitted by @sparkScripts) \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  var BOOT = (window && window.__spark_boot) || {\n    csrf: \'\',\n    endpoint: \'/_spark/update\',\n    mounts: [],\n  };\n\n  function csrfHeaders() {\n    return {\n      \'Content-Type\': \'application/json\',\n      \'X-CSRF-TOKEN\': BOOT.csrf || \'\',\n      Accept: \'application/json\',\n    };\n  }\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 Component registry \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  // Each component is identified by its root element\'s `spark:id` attribute.\n  // We don\'t keep state in JS; the snapshot lives on the DOM as `spark:snapshot`.\n  function componentRoot(el) {\n    while (el && el.nodeType === 1) {\n      if (el.hasAttribute && el.hasAttribute(\'spark:id\')) return el;\n      el = el.parentNode;\n    }\n    return null;\n  }\n\n  function snapshotOf(root) {\n    return root.getAttribute(\'spark:snapshot\') || \'\';\n  }\n\n  function setSnapshot(root, wire) {\n    root.setAttribute(\'spark:snapshot\', wire);\n  }\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 morphdom-lite \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  // Minimal DOM morphing. Preserves focus on inputs and respects spark:ignore.\n  function morph(fromNode, toNode) {\n    if (fromNode.nodeType !== toNode.nodeType) {\n      fromNode.parentNode && fromNode.parentNode.replaceChild(toNode, fromNode);\n      return toNode;\n    }\n    if (fromNode.nodeType === 3) {\n      if (fromNode.nodeValue !== toNode.nodeValue) fromNode.nodeValue = toNode.nodeValue;\n      return fromNode;\n    }\n    if (fromNode.nodeType !== 1) return fromNode;\n    if (fromNode.tagName !== toNode.tagName) {\n      fromNode.parentNode && fromNode.parentNode.replaceChild(toNode, fromNode);\n      return toNode;\n    }\n    if (fromNode.hasAttribute && fromNode.hasAttribute(\'spark:ignore\')) return fromNode;\n\n    // Attributes: diff sets.\n    var fromAttrs = fromNode.attributes;\n    for (var i = fromAttrs.length - 1; i >= 0; i--) {\n      var name = fromAttrs[i].name;\n      if (!toNode.hasAttribute(name)) fromNode.removeAttribute(name);\n    }\n    var toAttrs = toNode.attributes;\n    for (var j = 0; j < toAttrs.length; j++) {\n      var a = toAttrs[j];\n      if (fromNode.getAttribute(a.name) !== a.value) {\n        fromNode.setAttribute(a.name, a.value);\n      }\n    }\n\n    // Form value preservation: inputs with spark:model keep user-typed value\n    // unless server explicitly changed it.\n    if (\n      fromNode.tagName === \'INPUT\' ||\n      fromNode.tagName === \'TEXTAREA\' ||\n      fromNode.tagName === \'SELECT\'\n    ) {\n      if (fromNode.hasAttribute(\'spark:model\')) {\n        var newVal = toNode.getAttribute(\'value\');\n        if (newVal !== null && fromNode.value !== newVal) {\n          fromNode.value = newVal;\n        }\n      }\n    }\n\n    // Children: pairwise morph + tail adjust.\n    var fc = fromNode.firstChild;\n    var tc = toNode.firstChild;\n    while (fc || tc) {\n      if (!tc) {\n        var nextFc = fc.nextSibling;\n        fromNode.removeChild(fc);\n        fc = nextFc;\n        continue;\n      }\n      if (!fc) {\n        var nextTc = tc.nextSibling;\n        fromNode.appendChild(tc);\n        tc = nextTc;\n        continue;\n      }\n      var nextFromSibling = fc.nextSibling;\n      var nextToSibling = tc.nextSibling;\n      morph(fc, tc);\n      fc = nextFromSibling;\n      tc = nextToSibling;\n    }\n    return fromNode;\n  }\n\n  function parseHtml(html) {\n    var wrapper = document.createElement(\'div\');\n    wrapper.innerHTML = html.trim();\n    return wrapper.firstChild;\n  }\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 Request batching \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  function sendUpdate(componentRoot, payload) {\n    return fetch(BOOT.endpoint || \'/_spark/update\', {\n      method: \'POST\',\n      headers: csrfHeaders(),\n      body: JSON.stringify({\n        _token: BOOT.csrf || \'\',\n        components: [\n          Object.assign(\n            { snapshot: snapshotOf(componentRoot), updates: [], calls: [] },\n            payload\n          ),\n        ],\n      }),\n    })\n      .then(function (resp) {\n        if (resp.status === 419) {\n          // Snapshot expired \xe2\x80\x94 reload.\n          window.location.reload();\n          throw new Error(\'snapshot expired\');\n        }\n        if (!resp.ok) {\n          return resp.text().then(function (t) {\n            throw new Error(\'spark: \' + resp.status + \' \' + t);\n          });\n        }\n        return resp.json();\n      })\n      .then(function (body) {\n        if (!body || !body.components || !body.components.length) return;\n        var result = body.components[0];\n        applyResult(componentRoot, result);\n      });\n  }\n\n  function applyResult(currentRoot, result) {\n    // Set the new snapshot first so the boot reflection sees it.\n    setSnapshot(currentRoot, result.snapshot);\n\n    // Apply islands (partial morph) if present; else morph the whole subtree.\n    if (result.effects && result.effects.islands && result.effects.islands.length) {\n      result.effects.islands.forEach(function (island) {\n        var target = currentRoot.querySelector(\n          \'[spark\\\\:island=\"\' + island.name + \'\"]\'\n        );\n        if (!target) return;\n        var fragment = parseHtml(island.html);\n        if (fragment) morph(target, fragment);\n      });\n    } else if (result.html) {\n      var newRoot = parseHtml(result.html);\n      if (newRoot) morph(currentRoot, newRoot);\n    }\n\n    // Side effects.\n    if (result.effects) {\n      (result.effects.dispatched || []).forEach(function (d) {\n        window.dispatchEvent(new CustomEvent(d.event, { detail: d.payload }));\n      });\n      (result.effects.emitted || []).forEach(function (e) {\n        window.dispatchEvent(\n          new CustomEvent(\'spark:emit:\' + e.event, { detail: e.payload })\n        );\n      });\n      if (result.effects.redirect) {\n        window.location.href = result.effects.redirect;\n      }\n    }\n  }\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 Event binding \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  // We attach a small set of capturing handlers at document level. Each handler\n  // walks up to the nearest spark:* attribute and dispatches accordingly.\n\n  function parseAction(value) {\n    // Accepts `methodName` or `methodName(arg1, arg2)`.\n    var m = /^([A-Za-z_][A-Za-z0-9_]*)(\\((.*)\\))?$/.exec((value || \'\').trim());\n    if (!m) return null;\n    var method = m[1];\n    var argsList = (m[3] || \'\').trim();\n    var params = [];\n    if (argsList.length) {\n      // Naive split on top-level commas. Wrapped strings respected.\n      params = splitCommaArgs(argsList).map(function (a) {\n        return parseLiteral(a.trim());\n      });\n    }\n    return { method: method, params: params };\n  }\n\n  function splitCommaArgs(s) {\n    var out = [];\n    var depth = 0;\n    var inString = null;\n    var start = 0;\n    for (var i = 0; i < s.length; i++) {\n      var c = s.charAt(i);\n      if (inString) {\n        if (c === inString && s.charAt(i - 1) !== \'\\\\\') inString = null;\n        continue;\n      }\n      if (c === \'\"\' || c === \"\'\") { inString = c; continue; }\n      if (c === \'(\' || c === \'[\' || c === \'{\') depth++;\n      else if (c === \')\' || c === \']\' || c === \'}\') depth--;\n      else if (c === \',\' && depth === 0) {\n        out.push(s.substring(start, i));\n        start = i + 1;\n      }\n    }\n    if (start < s.length) out.push(s.substring(start));\n    return out;\n  }\n\n  function parseLiteral(s) {\n    if (s === \'true\') return true;\n    if (s === \'false\') return false;\n    if (s === \'null\') return null;\n    if (/^-?\\d+$/.test(s)) return parseInt(s, 10);\n    if (/^-?\\d+\\.\\d+$/.test(s)) return parseFloat(s);\n    if ((s.startsWith(\'\"\') && s.endsWith(\'\"\')) || (s.startsWith(\"\'\") && s.endsWith(\"\'\"))) {\n      return s.substring(1, s.length - 1);\n    }\n    return s; // fall through as raw string\n  }\n\n  function dispatchAction(root, parsed, opts) {\n    if (!root || !parsed) return;\n    var calls = [{ method: parsed.method, params: parsed.params, island: opts && opts.island }];\n    return sendUpdate(root, { calls: calls });\n  }\n\n  function dispatchUpdate(root, name, value) {\n    if (!root) return;\n    var updates = [{ name: name, value: value }];\n    return sendUpdate(root, { updates: updates });\n  }\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 spark:click \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  document.addEventListener(\'click\', function (event) {\n    var el = event.target;\n    while (el && el !== document) {\n      if (el.hasAttribute && el.hasAttribute(\'spark:click\')) {\n        var action = parseAction(el.getAttribute(\'spark:click\'));\n        if (!action) return;\n        var root = componentRoot(el);\n        if (!root) return;\n        toggleLoading(root, true);\n        dispatchAction(root, action).finally(function () { toggleLoading(root, false); });\n        return;\n      }\n      el = el.parentNode;\n    }\n  });\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 spark:submit \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  document.addEventListener(\'submit\', function (event) {\n    var form = event.target;\n    if (!form || !form.hasAttribute || !form.hasAttribute(\'spark:submit\')) return;\n    event.preventDefault();\n    var action = parseAction(form.getAttribute(\'spark:submit\'));\n    if (!action) return;\n    var root = componentRoot(form);\n    if (!root) return;\n    var data = new FormData(form);\n    var updates = [];\n    data.forEach(function (val, key) { updates.push({ name: key, value: val }); });\n    var calls = [{ method: action.method, params: action.params }];\n    toggleLoading(root, true);\n    sendUpdate(root, { updates: updates, calls: calls }).finally(function () {\n      toggleLoading(root, false);\n    });\n  });\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 spark:keydown.<key> \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  document.addEventListener(\'keydown\', function (event) {\n    var el = event.target;\n    while (el && el !== document) {\n      if (el.attributes) {\n        for (var i = 0; i < el.attributes.length; i++) {\n          var attr = el.attributes[i];\n          var m = /^spark:keydown\\.(.+)$/.exec(attr.name);\n          if (m && m[1].toLowerCase() === event.key.toLowerCase()) {\n            var action = parseAction(attr.value);\n            if (!action) return;\n            var root = componentRoot(el);\n            if (!root) return;\n            dispatchAction(root, action);\n            return;\n          }\n        }\n      }\n      el = el.parentNode;\n    }\n  });\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 spark:model[.modifiers] \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  var pendingModel = new WeakMap();\n  function findModelAttr(el) {\n    if (!el.attributes) return null;\n    for (var i = 0; i < el.attributes.length; i++) {\n      var a = el.attributes[i];\n      if (a.name === \'spark:model\' || a.name.indexOf(\'spark:model.\') === 0) {\n        return { attr: a.name, value: a.value };\n      }\n    }\n    return null;\n  }\n\n  function handleModelChange(el, event) {\n    var info = findModelAttr(el);\n    if (!info) return;\n    var modifiers = info.attr.split(\'.\').slice(1);\n    var live = modifiers.indexOf(\'live\') !== -1;\n    var lazy = modifiers.indexOf(\'lazy\') !== -1;\n    var debounceModifier = modifiers.find(function (m) { return /^debounce$/.test(m); });\n    var hasDebounceMs = false;\n    var debounceMs = 300;\n    for (var i = 0; i < modifiers.length; i++) {\n      var ms = /^(\\d+)ms$/.exec(modifiers[i]);\n      if (ms) { debounceMs = parseInt(ms[1], 10); hasDebounceMs = true; }\n    }\n    var name = info.value;\n    var value = (el.type === \'checkbox\') ? !!el.checked : el.value;\n    var root = componentRoot(el);\n    if (!root) return;\n    if (lazy && event.type !== \'change\' && event.type !== \'blur\') return;\n    if (!live && !lazy && event.type !== \'input\' && event.type !== \'change\') return;\n\n    var dispatch = function () {\n      dispatchUpdate(root, name, value);\n      pendingModel.delete(el);\n    };\n\n    if (live || hasDebounceMs || debounceModifier) {\n      var existing = pendingModel.get(el);\n      if (existing) clearTimeout(existing);\n      pendingModel.set(el, setTimeout(dispatch, debounceMs));\n    } else {\n      dispatch();\n    }\n  }\n\n  document.addEventListener(\'input\', function (event) {\n    handleModelChange(event.target, event);\n  });\n  document.addEventListener(\'change\', function (event) {\n    handleModelChange(event.target, event);\n  });\n  document.addEventListener(\'blur\', function (event) {\n    handleModelChange(event.target, event);\n  }, true);\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 spark:loading toggles \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  function toggleLoading(root, isLoading) {\n    if (!root) return;\n    var elems = root.querySelectorAll(\'[spark\\\\:loading], [spark\\\\:loading\\\\.remove], [spark\\\\:loading\\\\.attr]\');\n    elems.forEach(function (el) {\n      // Delay support: spark:loading.delay.200ms\n      var hasDelay = false;\n      var delayMs = 200;\n      for (var i = 0; i < el.attributes.length; i++) {\n        var name = el.attributes[i].name;\n        if (name.indexOf(\'spark:loading.delay.\') === 0) {\n          hasDelay = true;\n          var m = /(\\d+)ms/.exec(name);\n          if (m) delayMs = parseInt(m[1], 10);\n        }\n      }\n      var remove = el.hasAttribute(\'spark:loading.remove\');\n      var attrToggle = el.getAttribute(\'spark:loading.attr\');\n\n      var apply = function () {\n        if (attrToggle) {\n          if (isLoading) el.setAttribute(attrToggle, \'\');\n          else el.removeAttribute(attrToggle);\n          return;\n        }\n        if (remove) {\n          el.style.display = isLoading ? \'none\' : \'\';\n          return;\n        }\n        el.style.display = isLoading ? \'\' : \'none\';\n      };\n\n      if (hasDelay && isLoading) {\n        el.__sparkLoadingTimer = setTimeout(apply, delayMs);\n      } else {\n        if (el.__sparkLoadingTimer) {\n          clearTimeout(el.__sparkLoadingTimer);\n          el.__sparkLoadingTimer = null;\n        }\n        apply();\n      }\n    });\n  }\n\n  // Default hide for any spark:loading element on first paint.\n  function initLoadingDefaults() {\n    document.querySelectorAll(\'[spark\\\\:loading]\').forEach(function (el) {\n      if (!el.hasAttribute(\'spark:loading.remove\') && !el.hasAttribute(\'spark:loading.attr\')) {\n        el.style.display = \'none\';\n      }\n    });\n  }\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 spark:poll[.<ms>] \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  function initPolling() {\n    document.querySelectorAll(\'[spark\\\\:poll]\').forEach(function (el) {\n      var attr = null;\n      for (var i = 0; i < el.attributes.length; i++) {\n        if (el.attributes[i].name.indexOf(\'spark:poll\') === 0) {\n          attr = el.attributes[i];\n          break;\n        }\n      }\n      if (!attr) return;\n      var ms = 2000;\n      var m = /spark:poll\\.(\\d+)ms/.exec(attr.name);\n      if (m) ms = parseInt(m[1], 10);\n      var action = parseAction(attr.value || \'refresh\');\n      if (!action) return;\n      var root = componentRoot(el);\n      if (!root) return;\n      setInterval(function () {\n        if (document.hidden) return;\n        dispatchAction(root, action);\n      }, ms);\n    });\n  }\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 Echo (WebSocket) subscription for #[spark::on] listeners \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  function initEchoSubscriptions() {\n    if (!BOOT.mounts || !BOOT.mounts.length) return;\n    // We try to use Laravel Echo if loaded; otherwise we fall back to raw\n    // WebSocket against Bellows\' Pusher-protocol endpoint.\n    var hasEcho = window.Echo && typeof window.Echo.channel === \'function\';\n    BOOT.mounts.forEach(function (mount) {\n      (mount.listeners || []).forEach(function (eventName) {\n        if (hasEcho) {\n          var channel = inferChannel(eventName);\n          window.Echo.channel(channel).listen(\'.\' + eventName, function (payload) {\n            triggerBroadcast(mount.id, eventName, payload);\n          });\n        }\n      });\n    });\n  }\n  function inferChannel(eventName) {\n    var dot = eventName.indexOf(\'.\');\n    return dot > 0 ? eventName.substring(0, dot) : eventName;\n  }\n  function triggerBroadcast(componentId, eventName, payload) {\n    var root = document.querySelector(\'[spark\\\\:id=\"\' + componentId + \'\"]\');\n    if (!root) return;\n    var calls = [{ method: \'__on_broadcast\', params: [eventName, payload || null] }];\n    sendUpdate(root, { calls: calls });\n  }\n\n  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 Public API \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n  var Spark = {\n    start: function () {\n      initLoadingDefaults();\n      initPolling();\n      initEchoSubscriptions();\n    },\n    boot: BOOT,\n    dispatch: function (event, payload) {\n      window.dispatchEvent(new CustomEvent(event, { detail: payload }));\n    },\n    on: function (event, fn) {\n      window.addEventListener(\'spark:emit:\' + event, function (e) {\n        fn(e.detail);\n      });\n    },\n    request: function (componentId, payload) {\n      var root = document.querySelector(\'[spark\\\\:id=\"\' + componentId + \'\"]\');\n      if (root) sendUpdate(root, payload);\n    },\n  };\n  window.Spark = Spark;\n\n  if (document.readyState === \'loading\') {\n    document.addEventListener(\'DOMContentLoaded\', function () { Spark.start(); });\n  } else {\n    Spark.start();\n  }\n})();\n";