plutonium 0.62.2 → 0.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/skills/plutonium/SKILL.md +44 -0
- data/.claude/skills/plutonium-app/SKILL.md +3 -3
- data/.claude/skills/plutonium-async-interactions/SKILL.md +191 -0
- data/.claude/skills/plutonium-auth/SKILL.md +36 -0
- data/.claude/skills/plutonium-behavior/SKILL.md +121 -24
- data/.claude/skills/plutonium-kanban/SKILL.md +17 -3
- data/.claude/skills/plutonium-resource/SKILL.md +259 -12
- data/.claude/skills/plutonium-tenancy/SKILL.md +32 -3
- data/.claude/skills/plutonium-ui/SKILL.md +115 -14
- data/.claude/skills/plutonium-wizard/SKILL.md +73 -4
- data/CHANGELOG.md +67 -0
- data/CLAUDE.md +87 -0
- data/Rakefile +34 -0
- data/SECURITY.md +1 -1
- data/app/assets/plutonium.css +1 -1
- data/app/assets/plutonium.js +685 -102
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +53 -53
- data/app/assets/plutonium.min.js.map +4 -4
- data/app/views/rodauth/_login_form.html.erb +13 -0
- data/db/migrate/async_interactions/20260817000001_create_plutonium_async_runs.rb +170 -0
- data/docs/.vitepress/config.ts +81 -3
- data/docs/.vitepress/theme/blog.data.ts +44 -0
- data/docs/.vitepress/theme/components/BlogIndex.vue +87 -0
- data/docs/.vitepress/theme/components/BlogMeta.vue +47 -0
- data/docs/.vitepress/theme/components/HomeFeatureTour.vue +293 -0
- data/docs/.vitepress/theme/components/HomeHero.vue +3 -3
- data/docs/.vitepress/theme/components/HomeInTheBox.vue +8 -0
- data/docs/.vitepress/theme/components/HomeStopWriting.vue +1 -0
- data/docs/.vitepress/theme/components/HomeWhyPlutonium.vue +84 -0
- data/docs/.vitepress/theme/index.ts +8 -4
- data/docs/blog/association-inputs-post-signed-ids.md +70 -0
- data/docs/blog/fix-the-model-not-the-policy.md +122 -0
- data/docs/blog/fractional-ordering-runs-out-of-room.md +67 -0
- data/docs/blog/half-finished-forms-are-pii.md +76 -0
- data/docs/blog/index.md +13 -0
- data/docs/blog/interactions-are-presentation-objects.md +152 -0
- data/docs/blog/introducing-plutonium.md +253 -0
- data/docs/blog/jobs-are-not-permission-snapshots.md +100 -0
- data/docs/blog/plutonium-and-ai-agents.md +48 -0
- data/docs/blog/realtime-is-one-line-and-four-dependencies.md +70 -0
- data/docs/blog/two-forms-one-dom-id.md +69 -0
- data/docs/blog/whats-new-async-kanban-wizards.md +130 -0
- data/docs/getting-started/tutorial/04-authorization.md +12 -3
- data/docs/getting-started/tutorial/06-nested-resources.md +3 -1
- data/docs/getting-started/tutorial/07-author-portal.md +2 -2
- data/docs/guides/authentication.md +73 -0
- data/docs/guides/authorization.md +2 -0
- data/docs/guides/creating-packages.md +5 -3
- data/docs/guides/custom-actions.md +74 -12
- data/docs/guides/customizing-ui.md +9 -2
- data/docs/guides/index.md +1 -0
- data/docs/guides/kanban.md +7 -5
- data/docs/guides/nested-resources.md +11 -1
- data/docs/guides/performance.md +104 -0
- data/docs/guides/user-invites.md +1 -1
- data/docs/guides/wizards.md +9 -1
- data/docs/index.md +3 -3
- data/docs/public/images/home/tour-actions.png +0 -0
- data/docs/public/images/home/tour-async.png +0 -0
- data/docs/public/images/home/tour-kanban.png +0 -0
- data/docs/public/images/home/tour-tenancy.png +0 -0
- data/docs/public/images/home/tour-wizard.png +0 -0
- data/docs/public/images/reference/async-progress-page.png +0 -0
- data/docs/public/images/reference/async-running-banner.png +0 -0
- data/docs/public/templates/experimental.rb +34 -0
- data/docs/public/templates/pluton8.rb +14 -0
- data/docs/reference/app/portals.md +15 -3
- data/docs/reference/auth/accounts.md +19 -0
- data/docs/reference/behavior/async-interactions.md +295 -0
- data/docs/reference/behavior/controllers.md +17 -4
- data/docs/reference/behavior/index.md +7 -1
- data/docs/reference/behavior/interactions.md +152 -22
- data/docs/reference/configuration.md +5 -0
- data/docs/reference/index.md +1 -0
- data/docs/reference/kanban/dsl.md +7 -4
- data/docs/reference/kanban/index.md +1 -1
- data/docs/reference/kanban/positioning.md +26 -4
- data/docs/reference/positioning.md +568 -0
- data/docs/reference/resource/actions.md +97 -4
- data/docs/reference/resource/definition.md +181 -9
- data/docs/reference/tenancy/invites.md +1 -1
- data/docs/reference/tenancy/nested-resources.md +60 -2
- data/docs/reference/ui/assets.md +4 -0
- data/docs/reference/ui/components.md +57 -4
- data/docs/reference/ui/displays.md +20 -10
- data/docs/reference/ui/index.md +1 -1
- data/docs/reference/wizard/dsl.md +33 -0
- data/docs/reference/wizard/storage-config.md +1 -0
- data/docs/superpowers/plans/2026-07-16-homepage-depth-upgrade.md +624 -0
- data/docs/superpowers/plans/2026-07-16-homepage-depth-upgrade.md.tasks.json +32 -0
- data/docs/superpowers/plans/2026-07-31-positioned-drag-and-drop.md +1787 -0
- data/docs/superpowers/plans/2026-07-31-positioned-drag-and-drop.md.tasks.json +91 -0
- data/docs/superpowers/plans/2026-08-17-async-interactions.md +1414 -0
- data/docs/superpowers/plans/2026-08-17-async-interactions.md.tasks.json +66 -0
- data/docs/superpowers/specs/2026-07-16-homepage-depth-upgrade-design.md +111 -0
- data/docs/superpowers/specs/2026-07-17-action-html-attributes-design.md +124 -0
- data/docs/superpowers/specs/2026-07-31-positioned-drag-and-drop-design.md +506 -0
- data/docs/superpowers/specs/2026-08-17-async-interactions-design.md +185 -0
- data/gemfiles/postgres.gemfile.lock +85 -85
- data/gemfiles/rails_7.gemfile.lock +322 -140
- data/gemfiles/rails_8.0.gemfile.lock +125 -115
- data/gemfiles/rails_8.1.gemfile.lock +126 -116
- data/lib/generators/pu/async_interactions/install_generator.rb +111 -0
- data/lib/generators/pu/async_interactions/templates/app/controllers/async_runs_controller.rb.tt +15 -0
- data/lib/generators/pu/core/typespec/typespec_generator.rb +7 -4
- data/lib/generators/pu/invites/install_generator.rb +3 -3
- data/lib/generators/pu/invites/templates/packages/invites/app/views/layouts/invites/invitation.html.erb.tt +2 -2
- data/lib/generators/pu/lib/plutonium_generators/concerns/mounts_engines.rb +47 -2
- data/lib/generators/pu/lib/plutonium_generators/concerns/resource_registration.rb +41 -0
- data/lib/generators/pu/lite/litestream/litestream_generator.rb +1 -1
- data/lib/generators/pu/lite/solid_queue/solid_queue_generator.rb +1 -1
- data/lib/generators/pu/res/conn/conn_generator.rb +19 -39
- data/lib/generators/pu/res/conn/templates/app/controllers/resource_controller.rb.tt +4 -0
- data/lib/generators/pu/rodauth/templates/app/rodauth/account_rodauth_plugin.rb.tt +15 -6
- data/lib/generators/pu/rodauth/templates/app/rodauth/rodauth_plugin.rb.tt +7 -0
- data/lib/generators/pu/saas/welcome/templates/app/views/layouts/welcome.html.erb.tt +2 -2
- data/lib/generators/pu/wizards/install_generator.rb +78 -0
- data/lib/plutonium/action/base.rb +71 -9
- data/lib/plutonium/action/interactive.rb +9 -0
- data/lib/plutonium/attachments.rb +254 -0
- data/lib/plutonium/configuration.rb +82 -1
- data/lib/plutonium/core/controller.rb +50 -7
- data/lib/plutonium/core/controllers/authorizable.rb +16 -0
- data/lib/plutonium/core/controllers/entity_scoping.rb +12 -2
- data/lib/plutonium/definition/base.rb +51 -0
- data/lib/plutonium/definition/display_layout.rb +112 -0
- data/lib/plutonium/definition/index_views.rb +8 -7
- data/lib/plutonium/definition/input_aliases.rb +38 -0
- data/lib/plutonium/definition/page_widths.rb +65 -0
- data/lib/plutonium/definition/positioning.rb +126 -0
- data/lib/plutonium/definition/sorting.rb +17 -2
- data/lib/plutonium/helpers/turbo_helper.rb +7 -0
- data/lib/plutonium/interaction/README.md +61 -24
- data/lib/plutonium/interaction/async/configuration.rb +38 -0
- data/lib/plutonium/interaction/async/context.rb +419 -0
- data/lib/plutonium/interaction/async/executor.rb +422 -0
- data/lib/plutonium/interaction/async/job.rb +80 -0
- data/lib/plutonium/interaction/async/reap_job.rb +81 -0
- data/lib/plutonium/interaction/async/run.rb +394 -0
- data/lib/plutonium/interaction/async/run_definition.rb +155 -0
- data/lib/plutonium/interaction/async/run_policy.rb +86 -0
- data/lib/plutonium/interaction/base.rb +34 -7
- data/lib/plutonium/interaction/concerns/dispatchable.rb +518 -0
- data/lib/plutonium/interaction/concerns/scoping.rb +70 -9
- data/lib/plutonium/interaction/response/redirect.rb +11 -3
- data/lib/plutonium/kanban/board.rb +14 -0
- data/lib/plutonium/kanban/column.rb +4 -2
- data/lib/plutonium/kanban/dsl.rb +4 -1
- data/lib/plutonium/kanban/grouping.rb +9 -22
- data/lib/plutonium/kanban/positioning.rb +5 -65
- data/lib/plutonium/positioning/config.rb +94 -0
- data/lib/plutonium/positioning/model.rb +128 -0
- data/lib/plutonium/positioning.rb +25 -86
- data/lib/plutonium/railtie.rb +1 -0
- data/lib/plutonium/resource/controller.rb +118 -38
- data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +32 -2
- data/lib/plutonium/resource/controllers/crud_actions.rb +30 -2
- data/lib/plutonium/resource/controllers/eager_loading.rb +87 -0
- data/lib/plutonium/resource/controllers/export_csv.rb +10 -1
- data/lib/plutonium/resource/controllers/kanban_actions.rb +53 -14
- data/lib/plutonium/resource/controllers/position_actions.rb +390 -0
- data/lib/plutonium/resource/controllers/presentable.rb +19 -13
- data/lib/plutonium/resource/controllers/queryable.rb +5 -1
- data/lib/plutonium/resource/controllers/wizard_actions.rb +21 -0
- data/lib/plutonium/resource/policy.rb +33 -0
- data/lib/plutonium/resource/query_object.rb +36 -0
- data/lib/plutonium/routing/mapper_extensions.rb +100 -8
- data/lib/plutonium/routing/route_set_extensions.rb +15 -1
- data/lib/plutonium/routing/wizard_registration.rb +4 -0
- data/lib/plutonium/testing/resource_policy.rb +6 -2
- data/lib/plutonium/ui/action_button.rb +12 -7
- data/lib/plutonium/ui/actions_dropdown.rb +1 -1
- data/lib/plutonium/ui/block.rb +21 -1
- data/lib/plutonium/ui/breadcrumbs.rb +187 -55
- data/lib/plutonium/ui/component/methods.rb +5 -0
- data/lib/plutonium/ui/component/positionable.rb +112 -0
- data/lib/plutonium/ui/component/resolves_tags.rb +57 -0
- data/lib/plutonium/ui/component/section.rb +185 -0
- data/lib/plutonium/ui/display/base.rb +13 -1
- data/lib/plutonium/ui/display/components/formatted_value.rb +26 -0
- data/lib/plutonium/ui/display/components/section.rb +18 -0
- data/lib/plutonium/ui/display/resource.rb +141 -22
- data/lib/plutonium/ui/display/theme.rb +20 -1
- data/lib/plutonium/ui/export_button.rb +1 -1
- data/lib/plutonium/ui/form/base.rb +8 -7
- data/lib/plutonium/ui/form/components/intl_tel_input.rb +1 -1
- data/lib/plutonium/ui/form/components/section.rb +7 -62
- data/lib/plutonium/ui/form/components/uppy.rb +12 -1
- data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +16 -3
- data/lib/plutonium/ui/form/concerns/renders_structured_inputs.rb +5 -1
- data/lib/plutonium/ui/form/query.rb +2 -4
- data/lib/plutonium/ui/form/resource.rb +92 -15
- data/lib/plutonium/ui/form/theme.rb +17 -0
- data/lib/plutonium/ui/form/wizard.rb +25 -1
- data/lib/plutonium/ui/grid/card.rb +79 -11
- data/lib/plutonium/ui/grid/resource.rb +47 -5
- data/lib/plutonium/ui/interaction/async/run_progress.rb +227 -0
- data/lib/plutonium/ui/interaction/async/running_banner.rb +65 -0
- data/lib/plutonium/ui/kanban/card.rb +2 -1
- data/lib/plutonium/ui/kanban/column.rb +12 -6
- data/lib/plutonium/ui/kanban/resource.rb +6 -7
- data/lib/plutonium/ui/layout/base.rb +10 -3
- data/lib/plutonium/ui/nav_grid_menu.rb +1 -0
- data/lib/plutonium/ui/page/base.rb +19 -0
- data/lib/plutonium/ui/page/edit.rb +4 -1
- data/lib/plutonium/ui/page/index.rb +69 -18
- data/lib/plutonium/ui/page/interactive_action.rb +5 -1
- data/lib/plutonium/ui/page/new.rb +4 -1
- data/lib/plutonium/ui/page/show.rb +27 -10
- data/lib/plutonium/ui/page/wizard.rb +10 -1
- data/lib/plutonium/ui/page/wizard_chooser.rb +36 -11
- data/lib/plutonium/ui/page_width.rb +58 -0
- data/lib/plutonium/ui/table/base.rb +34 -1
- data/lib/plutonium/ui/table/components/attachment.rb +1 -1
- data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +32 -8
- data/lib/plutonium/ui/table/components/drag_handle.rb +120 -0
- data/lib/plutonium/ui/table/components/filter_form.rb +1 -4
- data/lib/plutonium/ui/table/components/filter_pills.rb +1 -1
- data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +1 -1
- data/lib/plutonium/ui/table/resource.rb +50 -5
- data/lib/plutonium/ui/table/theme.rb +59 -2
- data/lib/plutonium/ui/wizard/review.rb +4 -2
- data/lib/plutonium/ui/wizard/summary_display.rb +42 -14
- data/lib/plutonium/version.rb +1 -1
- data/lib/plutonium/wizard/attachments.rb +32 -197
- data/lib/plutonium/wizard/base.rb +6 -1
- data/lib/plutonium/wizard/configuration.rb +12 -0
- data/lib/plutonium/wizard/controller.rb +14 -0
- data/lib/plutonium/wizard/driving.rb +99 -15
- data/lib/plutonium/wizard/dsl.rb +23 -0
- data/lib/plutonium/wizard/resume.rb +127 -49
- data/lib/plutonium/wizard/runner.rb +46 -2
- data/lib/plutonium/wizard/step_adapter.rb +1 -1
- data/lib/plutonium/wizard/sweep_job.rb +16 -0
- data/lib/plutonium.rb +21 -0
- data/lib/rodauth/features/session_isolation.rb +92 -0
- data/lib/rodauth/plugins.rb +1 -0
- data/package.json +2 -1
- data/plutonium.gemspec +29 -11
- data/src/css/components.css +89 -1
- data/src/css/slim_select.css +20 -0
- data/src/js/controllers/breadcrumbs_controller.js +112 -0
- data/src/js/controllers/bulk_actions_controller.js +10 -2
- data/src/js/controllers/kanban_controller.js +30 -21
- data/src/js/controllers/positioned_controller.js +452 -0
- data/src/js/controllers/register_controllers.js +6 -0
- data/src/js/controllers/resource_drop_down_controller.js +5 -0
- data/src/js/controllers/run_progress_controller.js +73 -0
- data/src/js/drag/sortable.js +186 -0
- data/yarn.lock +108 -63
- metadata +103 -16
- data/docs/.vitepress/theme/components/HomeAudienceSplit.vue +0 -53
- data/docs/.vitepress/theme/components/HomePillars.vue +0 -42
data/app/assets/plutonium.js
CHANGED
|
@@ -13180,6 +13180,7 @@
|
|
|
13180
13180
|
this.menu.classList.remove("hidden");
|
|
13181
13181
|
this.menu.classList.add("block");
|
|
13182
13182
|
this.menu.removeAttribute("aria-hidden");
|
|
13183
|
+
this.triggerTarget.setAttribute("aria-expanded", "true");
|
|
13183
13184
|
this.popperInstance.setOptions((options2) => ({
|
|
13184
13185
|
...options2,
|
|
13185
13186
|
modifiers: [
|
|
@@ -13195,6 +13196,7 @@
|
|
|
13195
13196
|
this.menu.classList.remove("block");
|
|
13196
13197
|
this.menu.classList.add("hidden");
|
|
13197
13198
|
this.menu.setAttribute("aria-hidden", "true");
|
|
13199
|
+
this.triggerTarget.setAttribute("aria-expanded", "false");
|
|
13198
13200
|
this.popperInstance.setOptions((options2) => ({
|
|
13199
13201
|
...options2,
|
|
13200
13202
|
modifiers: [
|
|
@@ -13660,7 +13662,7 @@
|
|
|
13660
13662
|
var mathMlDisallowed = freeze(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]);
|
|
13661
13663
|
var text = freeze(["#text"]);
|
|
13662
13664
|
var html = freeze(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "command", "commandfor", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "exportparts", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inert", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "nonce", "noshade", "novalidate", "nowrap", "open", "optimum", "part", "pattern", "placeholder", "playsinline", "popover", "popovertarget", "popovertargetaction", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "slot", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "wrap", "xmlns"]);
|
|
13663
|
-
var svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]);
|
|
13665
|
+
var svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dominant-baseline", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "pointer-events", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-orientation", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "vector-effect", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]);
|
|
13664
13666
|
var mathMl = freeze(["accent", "accentunder", "align", "bevelled", "close", "columnalign", "columnlines", "columnspacing", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lquote", "lspace", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]);
|
|
13665
13667
|
var xml = freeze(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]);
|
|
13666
13668
|
var MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
|
|
@@ -13700,6 +13702,15 @@
|
|
|
13700
13702
|
notation: 12
|
|
13701
13703
|
// Deprecated
|
|
13702
13704
|
};
|
|
13705
|
+
var LITERAL_TEXT_ELEMENT_NAMES = ["style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext", "noscript"];
|
|
13706
|
+
var LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, LITERAL_TEXT_ELEMENT_NAMES));
|
|
13707
|
+
var LITERAL_TEXT_CLOSE = (function() {
|
|
13708
|
+
const map = {};
|
|
13709
|
+
arrayForEach(LITERAL_TEXT_ELEMENT_NAMES, (name) => {
|
|
13710
|
+
map[name] = seal(new RegExp("</" + name + "(?=[\\t\\n\\f\\r />])", "i"));
|
|
13711
|
+
});
|
|
13712
|
+
return freeze(map);
|
|
13713
|
+
})();
|
|
13703
13714
|
var getGlobal = function getGlobal2() {
|
|
13704
13715
|
return typeof window === "undefined" ? null : window;
|
|
13705
13716
|
};
|
|
@@ -13743,10 +13754,14 @@
|
|
|
13743
13754
|
var _resolveSetOption = function _resolveSetOption2(cfg, key, fallback, options2) {
|
|
13744
13755
|
return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options2.base ? clone(options2.base) : {}, cfg[key], options2.transform) : fallback;
|
|
13745
13756
|
};
|
|
13757
|
+
var _resolveObjectOption = function _resolveObjectOption2(cfg, key, makeFallback) {
|
|
13758
|
+
const value = objectHasOwnProperty(cfg, key) ? cfg[key] : void 0;
|
|
13759
|
+
return value && typeof value === "object" ? clone(value) : makeFallback();
|
|
13760
|
+
};
|
|
13746
13761
|
function createDOMPurify() {
|
|
13747
13762
|
let window2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal();
|
|
13748
13763
|
const DOMPurify = (root) => createDOMPurify(root);
|
|
13749
|
-
DOMPurify.version = "3.4.
|
|
13764
|
+
DOMPurify.version = "3.4.14";
|
|
13750
13765
|
DOMPurify.removed = [];
|
|
13751
13766
|
if (!window2 || !window2.document || window2.document.nodeType !== NODE_TYPE.document || !window2.Element) {
|
|
13752
13767
|
DOMPurify.isSupported = false;
|
|
@@ -13770,6 +13785,13 @@
|
|
|
13770
13785
|
const getAttributes = lookupGetter(ElementPrototype, "attributes");
|
|
13771
13786
|
const getNodeType = Node2 && Node2.prototype ? lookupGetter(Node2.prototype, "nodeType") : null;
|
|
13772
13787
|
const getNodeName2 = Node2 && Node2.prototype ? lookupGetter(Node2.prototype, "nodeName") : null;
|
|
13788
|
+
const getOwnerDocument = Node2 && Node2.prototype ? lookupGetter(Node2.prototype, "ownerDocument") : null;
|
|
13789
|
+
const _readNodeType = function _readNodeType2(node) {
|
|
13790
|
+
return getNodeType ? getNodeType(node) : node.nodeType;
|
|
13791
|
+
};
|
|
13792
|
+
const _readNodeName = function _readNodeName2(node) {
|
|
13793
|
+
return getNodeName2 ? getNodeName2(node) : node.nodeName;
|
|
13794
|
+
};
|
|
13773
13795
|
if (typeof HTMLTemplateElement2 === "function") {
|
|
13774
13796
|
const template = document2.createElement("template");
|
|
13775
13797
|
if (template.content && template.content.ownerDocument) {
|
|
@@ -13996,9 +14018,19 @@
|
|
|
13996
14018
|
IN_PLACE = cfg.IN_PLACE || false;
|
|
13997
14019
|
IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI;
|
|
13998
14020
|
NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE;
|
|
13999
|
-
MATHML_TEXT_INTEGRATION_POINTS =
|
|
14000
|
-
|
|
14001
|
-
|
|
14021
|
+
MATHML_TEXT_INTEGRATION_POINTS = _resolveObjectOption(
|
|
14022
|
+
cfg,
|
|
14023
|
+
"MATHML_TEXT_INTEGRATION_POINTS",
|
|
14024
|
+
() => addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS)
|
|
14025
|
+
// Default built-in map
|
|
14026
|
+
);
|
|
14027
|
+
HTML_INTEGRATION_POINTS = _resolveObjectOption(
|
|
14028
|
+
cfg,
|
|
14029
|
+
"HTML_INTEGRATION_POINTS",
|
|
14030
|
+
() => addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS)
|
|
14031
|
+
// Default built-in map
|
|
14032
|
+
);
|
|
14033
|
+
const customElementHandling = _resolveObjectOption(cfg, "CUSTOM_ELEMENT_HANDLING", () => create(null));
|
|
14002
14034
|
CUSTOM_ELEMENT_HANDLING = create(null);
|
|
14003
14035
|
if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) {
|
|
14004
14036
|
CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck;
|
|
@@ -14061,15 +14093,6 @@
|
|
|
14061
14093
|
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
14062
14094
|
}
|
|
14063
14095
|
}
|
|
14064
|
-
if (objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) {
|
|
14065
|
-
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
14066
|
-
}
|
|
14067
|
-
if (objectHasOwnProperty(cfg, "FORBID_CONTENTS") && arrayIsArray(cfg.FORBID_CONTENTS)) {
|
|
14068
|
-
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
14069
|
-
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
14070
|
-
}
|
|
14071
|
-
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
14072
|
-
}
|
|
14073
14096
|
if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
|
|
14074
14097
|
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
14075
14098
|
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
@@ -14186,7 +14209,18 @@
|
|
|
14186
14209
|
}
|
|
14187
14210
|
}
|
|
14188
14211
|
};
|
|
14212
|
+
const _stripAttributeNode = function _stripAttributeNode2(element, attribute, name) {
|
|
14213
|
+
try {
|
|
14214
|
+
element.removeAttributeNode(attribute);
|
|
14215
|
+
} catch (_4) {
|
|
14216
|
+
try {
|
|
14217
|
+
element.removeAttribute(name);
|
|
14218
|
+
} catch (_5) {
|
|
14219
|
+
}
|
|
14220
|
+
}
|
|
14221
|
+
};
|
|
14189
14222
|
const _neutralizeRoot = function _neutralizeRoot2(root) {
|
|
14223
|
+
_neutralizeSubtree(root);
|
|
14190
14224
|
const childNodes = getChildNodes(root);
|
|
14191
14225
|
if (childNodes) {
|
|
14192
14226
|
const snapshot = [];
|
|
@@ -14206,27 +14240,35 @@
|
|
|
14206
14240
|
const attribute = attributes[i4];
|
|
14207
14241
|
const name = attribute && attribute.name;
|
|
14208
14242
|
if (typeof name === "string") {
|
|
14209
|
-
|
|
14210
|
-
root.removeAttribute(name);
|
|
14211
|
-
} catch (_4) {
|
|
14212
|
-
}
|
|
14243
|
+
_stripAttributeNode(root, attribute, name);
|
|
14213
14244
|
}
|
|
14214
14245
|
}
|
|
14215
14246
|
}
|
|
14216
14247
|
};
|
|
14217
|
-
const _removeAttribute = function _removeAttribute2(name, element) {
|
|
14248
|
+
const _removeAttribute = function _removeAttribute2(name, element, attr) {
|
|
14249
|
+
if (!attr) {
|
|
14250
|
+
try {
|
|
14251
|
+
attr = element.getAttributeNode(name);
|
|
14252
|
+
} catch (_4) {
|
|
14253
|
+
attr = null;
|
|
14254
|
+
}
|
|
14255
|
+
}
|
|
14256
|
+
arrayPush(DOMPurify.removed, {
|
|
14257
|
+
attribute: attr || null,
|
|
14258
|
+
from: element
|
|
14259
|
+
});
|
|
14218
14260
|
try {
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14261
|
+
if (attr) {
|
|
14262
|
+
element.removeAttributeNode(attr);
|
|
14263
|
+
} else {
|
|
14264
|
+
element.removeAttribute(name);
|
|
14265
|
+
}
|
|
14223
14266
|
} catch (_4) {
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
}
|
|
14267
|
+
try {
|
|
14268
|
+
element.removeAttribute(name);
|
|
14269
|
+
} catch (_5) {
|
|
14270
|
+
}
|
|
14228
14271
|
}
|
|
14229
|
-
element.removeAttribute(name);
|
|
14230
14272
|
if (name === "is") {
|
|
14231
14273
|
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
|
14232
14274
|
try {
|
|
@@ -14252,17 +14294,14 @@
|
|
|
14252
14294
|
if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) {
|
|
14253
14295
|
continue;
|
|
14254
14296
|
}
|
|
14255
|
-
|
|
14256
|
-
element.removeAttribute(name);
|
|
14257
|
-
} catch (_4) {
|
|
14258
|
-
}
|
|
14297
|
+
_stripAttributeNode(element, attribute, name);
|
|
14259
14298
|
}
|
|
14260
14299
|
};
|
|
14261
14300
|
const _neutralizeSubtree = function _neutralizeSubtree2(root) {
|
|
14262
14301
|
const stack = [root];
|
|
14263
14302
|
while (stack.length > 0) {
|
|
14264
14303
|
const node = stack.pop();
|
|
14265
|
-
const nodeType =
|
|
14304
|
+
const nodeType = _readNodeType(node);
|
|
14266
14305
|
if (nodeType === NODE_TYPE.element) {
|
|
14267
14306
|
_stripDisallowedAttributes(node);
|
|
14268
14307
|
}
|
|
@@ -14274,6 +14313,51 @@
|
|
|
14274
14313
|
}
|
|
14275
14314
|
}
|
|
14276
14315
|
};
|
|
14316
|
+
const _isPatchLinkageAttribute = function _isPatchLinkageAttribute2(lcName, lcTag) {
|
|
14317
|
+
if (!SAFE_FOR_XML) {
|
|
14318
|
+
return false;
|
|
14319
|
+
}
|
|
14320
|
+
if (lcName === "patchsrc") {
|
|
14321
|
+
return true;
|
|
14322
|
+
}
|
|
14323
|
+
return lcName === "for" && lcTag !== "label" && lcTag !== "output";
|
|
14324
|
+
};
|
|
14325
|
+
const _neutralizePatchLinkage = function _neutralizePatchLinkage2(root) {
|
|
14326
|
+
if (!SAFE_FOR_XML) {
|
|
14327
|
+
return;
|
|
14328
|
+
}
|
|
14329
|
+
const stack = [root];
|
|
14330
|
+
while (stack.length > 0) {
|
|
14331
|
+
const node = stack.pop();
|
|
14332
|
+
const nodeType = _readNodeType(node);
|
|
14333
|
+
if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
|
|
14334
|
+
try {
|
|
14335
|
+
remove(node);
|
|
14336
|
+
} catch (_4) {
|
|
14337
|
+
}
|
|
14338
|
+
continue;
|
|
14339
|
+
}
|
|
14340
|
+
if (nodeType === NODE_TYPE.element) {
|
|
14341
|
+
const element = node;
|
|
14342
|
+
const lcTag = transformCaseFunc(_readNodeName(node));
|
|
14343
|
+
try {
|
|
14344
|
+
if (element.hasAttribute && element.hasAttribute("patchsrc")) {
|
|
14345
|
+
element.removeAttribute("patchsrc");
|
|
14346
|
+
}
|
|
14347
|
+
if (element.hasAttribute && element.hasAttribute("for") && _isPatchLinkageAttribute("for", lcTag)) {
|
|
14348
|
+
element.removeAttribute("for");
|
|
14349
|
+
}
|
|
14350
|
+
} catch (_4) {
|
|
14351
|
+
}
|
|
14352
|
+
}
|
|
14353
|
+
const childNodes = getChildNodes(node);
|
|
14354
|
+
if (childNodes) {
|
|
14355
|
+
for (let i4 = childNodes.length - 1; i4 >= 0; --i4) {
|
|
14356
|
+
stack.push(childNodes[i4]);
|
|
14357
|
+
}
|
|
14358
|
+
}
|
|
14359
|
+
}
|
|
14360
|
+
};
|
|
14277
14361
|
const _initDocument = function _initDocument2(dirty) {
|
|
14278
14362
|
let doc = null;
|
|
14279
14363
|
let leadingWhitespace = null;
|
|
@@ -14310,8 +14394,9 @@
|
|
|
14310
14394
|
return WHOLE_DOCUMENT ? doc.documentElement : body;
|
|
14311
14395
|
};
|
|
14312
14396
|
const _createNodeIterator = function _createNodeIterator2(root) {
|
|
14397
|
+
const doc = getOwnerDocument ? getOwnerDocument(root) : root.ownerDocument;
|
|
14313
14398
|
return createNodeIterator.call(
|
|
14314
|
-
|
|
14399
|
+
doc || root,
|
|
14315
14400
|
root,
|
|
14316
14401
|
// eslint-disable-next-line no-bitwise
|
|
14317
14402
|
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION,
|
|
@@ -14327,8 +14412,9 @@
|
|
|
14327
14412
|
const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
|
|
14328
14413
|
var _node$querySelectorAl;
|
|
14329
14414
|
node.normalize();
|
|
14415
|
+
const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument;
|
|
14330
14416
|
const walker = createNodeIterator.call(
|
|
14331
|
-
|
|
14417
|
+
doc || node,
|
|
14332
14418
|
node,
|
|
14333
14419
|
// eslint-disable-next-line no-bitwise
|
|
14334
14420
|
NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION,
|
|
@@ -14413,7 +14499,7 @@
|
|
|
14413
14499
|
if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) {
|
|
14414
14500
|
return true;
|
|
14415
14501
|
}
|
|
14416
|
-
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "
|
|
14502
|
+
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && LITERAL_TEXT_ELEMENTS[tagName] && (_isNode(currentNode.firstElementChild) || typeof currentNode.textContent === "string" && regExpTest(LITERAL_TEXT_CLOSE[tagName], currentNode.textContent))) {
|
|
14417
14503
|
return true;
|
|
14418
14504
|
}
|
|
14419
14505
|
if (currentNode.nodeType === NODE_TYPE.processingInstruction) {
|
|
@@ -14424,14 +14510,21 @@
|
|
|
14424
14510
|
}
|
|
14425
14511
|
return false;
|
|
14426
14512
|
};
|
|
14427
|
-
const
|
|
14428
|
-
if (
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
14513
|
+
const _matchesNameCheck = function _matchesNameCheck2(check, name) {
|
|
14514
|
+
if (check instanceof RegExp) {
|
|
14515
|
+
return regExpTest(check, name);
|
|
14516
|
+
}
|
|
14517
|
+
if (check instanceof Function) {
|
|
14518
|
+
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
|
14519
|
+
args[_key - 2] = arguments[_key];
|
|
14434
14520
|
}
|
|
14521
|
+
return Boolean(check(name, ...args));
|
|
14522
|
+
}
|
|
14523
|
+
return false;
|
|
14524
|
+
};
|
|
14525
|
+
const _sanitizeDisallowedNode = function _sanitizeDisallowedNode2(currentNode, tagName, root) {
|
|
14526
|
+
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
14527
|
+
return false;
|
|
14435
14528
|
}
|
|
14436
14529
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
14437
14530
|
const parentNode = getParentNode2(currentNode);
|
|
@@ -14439,7 +14532,7 @@
|
|
|
14439
14532
|
if (childNodes && parentNode) {
|
|
14440
14533
|
const childCount = childNodes.length;
|
|
14441
14534
|
for (let i4 = childCount - 1; i4 >= 0; --i4) {
|
|
14442
|
-
const hoisted =
|
|
14535
|
+
const hoisted = currentNode === root ? cloneNode(childNodes[i4], true) : childNodes[i4];
|
|
14443
14536
|
parentNode.insertBefore(hoisted, getNextSibling(currentNode));
|
|
14444
14537
|
}
|
|
14445
14538
|
}
|
|
@@ -14447,25 +14540,51 @@
|
|
|
14447
14540
|
_forceRemove(currentNode);
|
|
14448
14541
|
return true;
|
|
14449
14542
|
};
|
|
14450
|
-
const
|
|
14543
|
+
const _forkSharedAllowlist = function _forkSharedAllowlist2(hookList, set, defaultSet, setConfigSet) {
|
|
14544
|
+
if (hookList.length === 0) {
|
|
14545
|
+
return set;
|
|
14546
|
+
}
|
|
14547
|
+
return set === defaultSet || set === setConfigSet ? clone(set) : set;
|
|
14548
|
+
};
|
|
14549
|
+
const _handleHookDetachedNode = function _handleHookDetachedNode2(currentNode, root) {
|
|
14550
|
+
if (currentNode === root || getParentNode2(currentNode) !== null) {
|
|
14551
|
+
return false;
|
|
14552
|
+
}
|
|
14553
|
+
if (IN_PLACE) {
|
|
14554
|
+
_neutralizeSubtree(currentNode);
|
|
14555
|
+
}
|
|
14556
|
+
return true;
|
|
14557
|
+
};
|
|
14558
|
+
const _sanitizeElements = function _sanitizeElements2(currentNode, root) {
|
|
14451
14559
|
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
|
|
14560
|
+
if (_handleHookDetachedNode(currentNode, root)) {
|
|
14561
|
+
return true;
|
|
14562
|
+
}
|
|
14452
14563
|
if (_isClobbered(currentNode)) {
|
|
14453
14564
|
_forceRemove(currentNode);
|
|
14454
14565
|
return true;
|
|
14455
14566
|
}
|
|
14456
|
-
const tagName = transformCaseFunc(
|
|
14567
|
+
const tagName = transformCaseFunc(_readNodeName(currentNode));
|
|
14568
|
+
ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
|
|
14457
14569
|
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
|
14458
14570
|
tagName,
|
|
14459
14571
|
allowedTags: ALLOWED_TAGS
|
|
14460
14572
|
});
|
|
14573
|
+
if (_handleHookDetachedNode(currentNode, root)) {
|
|
14574
|
+
return true;
|
|
14575
|
+
}
|
|
14461
14576
|
if (_isUnsafeNode(currentNode, tagName)) {
|
|
14462
14577
|
_forceRemove(currentNode);
|
|
14463
14578
|
return true;
|
|
14464
14579
|
}
|
|
14465
14580
|
if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
|
|
14466
|
-
|
|
14581
|
+
const removed = _sanitizeDisallowedNode(currentNode, tagName, root);
|
|
14582
|
+
if (removed === false) {
|
|
14583
|
+
_executeHooks(hooks.afterSanitizeElements, currentNode, null);
|
|
14584
|
+
}
|
|
14585
|
+
return removed;
|
|
14467
14586
|
}
|
|
14468
|
-
const nt =
|
|
14587
|
+
const nt = _readNodeType(currentNode);
|
|
14469
14588
|
if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
|
|
14470
14589
|
_forceRemove(currentNode);
|
|
14471
14590
|
return true;
|
|
@@ -14490,32 +14609,43 @@
|
|
|
14490
14609
|
if (FORBID_ATTR[lcName]) {
|
|
14491
14610
|
return false;
|
|
14492
14611
|
}
|
|
14612
|
+
if (_isPatchLinkageAttribute(lcName, lcTag)) {
|
|
14613
|
+
return false;
|
|
14614
|
+
}
|
|
14493
14615
|
if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document2 || value in formElement)) {
|
|
14494
14616
|
return false;
|
|
14495
14617
|
}
|
|
14496
14618
|
const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
|
|
14497
|
-
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName))
|
|
14498
|
-
|
|
14499
|
-
|
|
14500
|
-
|
|
14501
|
-
|
|
14502
|
-
|
|
14503
|
-
|
|
14504
|
-
|
|
14505
|
-
//
|
|
14506
|
-
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
|
|
14513
|
-
|
|
14514
|
-
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
|
|
14518
|
-
|
|
14619
|
+
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) {
|
|
14620
|
+
return true;
|
|
14621
|
+
}
|
|
14622
|
+
if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) {
|
|
14623
|
+
return true;
|
|
14624
|
+
}
|
|
14625
|
+
if (!nameIsPermitted) {
|
|
14626
|
+
return (
|
|
14627
|
+
// Condition a) covers a basically valid custom element tag name whose
|
|
14628
|
+
// tag passes the configured tagNameCheck and whose attribute name
|
|
14629
|
+
// passes the configured attributeNameCheck ...
|
|
14630
|
+
_isBasicCustomElement(lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName, lcTag) || // Condition b) covers an `is` attribute whose value passes the
|
|
14631
|
+
// configured tagNameCheck while customized built-in elements are
|
|
14632
|
+
// allowed.
|
|
14633
|
+
lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value)
|
|
14634
|
+
);
|
|
14635
|
+
}
|
|
14636
|
+
if (URI_SAFE_ATTRIBUTES[lcName]) {
|
|
14637
|
+
return true;
|
|
14638
|
+
}
|
|
14639
|
+
if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) {
|
|
14640
|
+
return true;
|
|
14641
|
+
}
|
|
14642
|
+
if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]) {
|
|
14643
|
+
return true;
|
|
14644
|
+
}
|
|
14645
|
+
if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) {
|
|
14646
|
+
return true;
|
|
14647
|
+
}
|
|
14648
|
+
return !value;
|
|
14519
14649
|
};
|
|
14520
14650
|
const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ["annotation-xml", "color-profile", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "missing-glyph"]);
|
|
14521
14651
|
const _isBasicCustomElement = function _isBasicCustomElement2(tagName) {
|
|
@@ -14556,6 +14686,7 @@
|
|
|
14556
14686
|
if (!attributes || _isClobbered(currentNode)) {
|
|
14557
14687
|
return;
|
|
14558
14688
|
}
|
|
14689
|
+
ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR);
|
|
14559
14690
|
const hookEvent = {
|
|
14560
14691
|
attrName: "",
|
|
14561
14692
|
attrValue: "",
|
|
@@ -14578,33 +14709,33 @@
|
|
|
14578
14709
|
_executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
|
|
14579
14710
|
value = hookEvent.attrValue;
|
|
14580
14711
|
if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
|
|
14581
|
-
_removeAttribute(name, currentNode);
|
|
14712
|
+
_removeAttribute(name, currentNode, attr);
|
|
14582
14713
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
14583
14714
|
}
|
|
14584
14715
|
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
|
|
14585
|
-
_removeAttribute(name, currentNode);
|
|
14716
|
+
_removeAttribute(name, currentNode, attr);
|
|
14586
14717
|
continue;
|
|
14587
14718
|
}
|
|
14588
14719
|
if (lcName === "attributename" && stringMatch(value, "href")) {
|
|
14589
|
-
_removeAttribute(name, currentNode);
|
|
14720
|
+
_removeAttribute(name, currentNode, attr);
|
|
14590
14721
|
continue;
|
|
14591
14722
|
}
|
|
14592
14723
|
if (hookEvent.forceKeepAttr) {
|
|
14593
14724
|
continue;
|
|
14594
14725
|
}
|
|
14595
14726
|
if (!hookEvent.keepAttr) {
|
|
14596
|
-
_removeAttribute(name, currentNode);
|
|
14727
|
+
_removeAttribute(name, currentNode, attr);
|
|
14597
14728
|
continue;
|
|
14598
14729
|
}
|
|
14599
14730
|
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
|
|
14600
|
-
_removeAttribute(name, currentNode);
|
|
14731
|
+
_removeAttribute(name, currentNode, attr);
|
|
14601
14732
|
continue;
|
|
14602
14733
|
}
|
|
14603
14734
|
if (SAFE_FOR_TEMPLATES) {
|
|
14604
14735
|
value = _stripTemplateExpressions(value);
|
|
14605
14736
|
}
|
|
14606
14737
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
14607
|
-
_removeAttribute(name, currentNode);
|
|
14738
|
+
_removeAttribute(name, currentNode, attr);
|
|
14608
14739
|
continue;
|
|
14609
14740
|
}
|
|
14610
14741
|
value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
|
|
@@ -14620,13 +14751,12 @@
|
|
|
14620
14751
|
_executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
|
|
14621
14752
|
while (shadowNode = shadowIterator.nextNode()) {
|
|
14622
14753
|
_executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
|
|
14623
|
-
_sanitizeElements(shadowNode);
|
|
14754
|
+
_sanitizeElements(shadowNode, fragment);
|
|
14624
14755
|
_sanitizeAttributes(shadowNode);
|
|
14625
14756
|
if (_isDocumentFragment(shadowNode.content)) {
|
|
14626
14757
|
_sanitizeShadowDOM2(shadowNode.content);
|
|
14627
14758
|
}
|
|
14628
|
-
|
|
14629
|
-
if (shadowNodeType === NODE_TYPE.element) {
|
|
14759
|
+
if (_readNodeType(shadowNode) === NODE_TYPE.element) {
|
|
14630
14760
|
const innerSr = getShadowRoot(shadowNode);
|
|
14631
14761
|
if (_isDocumentFragment(innerSr)) {
|
|
14632
14762
|
_sanitizeAttachedShadowRoots(innerSr);
|
|
@@ -14648,7 +14778,7 @@
|
|
|
14648
14778
|
continue;
|
|
14649
14779
|
}
|
|
14650
14780
|
const node = item.node;
|
|
14651
|
-
const nodeType =
|
|
14781
|
+
const nodeType = _readNodeType(node);
|
|
14652
14782
|
const isElement2 = nodeType === NODE_TYPE.element;
|
|
14653
14783
|
const childNodes = getChildNodes(node);
|
|
14654
14784
|
if (childNodes) {
|
|
@@ -14719,14 +14849,17 @@
|
|
|
14719
14849
|
DOMPurify.removed = [];
|
|
14720
14850
|
const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty);
|
|
14721
14851
|
if (inPlace) {
|
|
14722
|
-
|
|
14852
|
+
_neutralizePatchLinkage(dirty);
|
|
14853
|
+
const nn2 = _readNodeName(dirty);
|
|
14723
14854
|
if (typeof nn2 === "string") {
|
|
14724
14855
|
const tagName = transformCaseFunc(nn2);
|
|
14725
14856
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
14857
|
+
_neutralizeRoot(dirty);
|
|
14726
14858
|
throw typeErrorCreate("root node is forbidden and cannot be sanitized in-place");
|
|
14727
14859
|
}
|
|
14728
14860
|
}
|
|
14729
14861
|
if (_isClobbered(dirty)) {
|
|
14862
|
+
_neutralizeRoot(dirty);
|
|
14730
14863
|
throw typeErrorCreate("root node is clobbered and cannot be sanitized in-place");
|
|
14731
14864
|
}
|
|
14732
14865
|
try {
|
|
@@ -14759,10 +14892,11 @@
|
|
|
14759
14892
|
if (body && FORCE_BODY) {
|
|
14760
14893
|
_forceRemove(body.firstChild);
|
|
14761
14894
|
}
|
|
14762
|
-
const
|
|
14895
|
+
const walkRoot = inPlace ? dirty : body;
|
|
14763
14896
|
try {
|
|
14897
|
+
const nodeIterator = _createNodeIterator(walkRoot);
|
|
14764
14898
|
while (currentNode = nodeIterator.nextNode()) {
|
|
14765
|
-
_sanitizeElements(currentNode);
|
|
14899
|
+
_sanitizeElements(currentNode, walkRoot);
|
|
14766
14900
|
_sanitizeAttributes(currentNode);
|
|
14767
14901
|
if (_isDocumentFragment(currentNode.content)) {
|
|
14768
14902
|
_sanitizeShadowDOM2(currentNode.content);
|
|
@@ -14771,6 +14905,11 @@
|
|
|
14771
14905
|
} catch (error2) {
|
|
14772
14906
|
if (inPlace) {
|
|
14773
14907
|
_neutralizeRoot(dirty);
|
|
14908
|
+
arrayForEach(DOMPurify.removed, (entry) => {
|
|
14909
|
+
if (entry.element) {
|
|
14910
|
+
_neutralizeSubtree(entry.element);
|
|
14911
|
+
}
|
|
14912
|
+
});
|
|
14774
14913
|
}
|
|
14775
14914
|
throw error2;
|
|
14776
14915
|
}
|
|
@@ -18614,7 +18753,7 @@ ${text2}</tr>
|
|
|
18614
18753
|
var nanoid = (size = 21) => {
|
|
18615
18754
|
let id2 = "";
|
|
18616
18755
|
let i4 = size | 0;
|
|
18617
|
-
while (i4--) {
|
|
18756
|
+
while (i4-- > 0) {
|
|
18618
18757
|
id2 += urlAlphabet[Math.random() * 64 | 0];
|
|
18619
18758
|
}
|
|
18620
18759
|
return id2;
|
|
@@ -28216,7 +28355,9 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
28216
28355
|
const baseUrl = button.dataset.bulkActionUrl;
|
|
28217
28356
|
const actionName = button.dataset.bulkActionName;
|
|
28218
28357
|
if (baseUrl) {
|
|
28219
|
-
|
|
28358
|
+
const [path, query] = baseUrl.split("?");
|
|
28359
|
+
const merged = [query, idsParam].filter(Boolean).join("&");
|
|
28360
|
+
button.href = merged ? `${path}?${merged}` : path;
|
|
28220
28361
|
}
|
|
28221
28362
|
button.style.display = allowedActions.has(actionName) ? "" : "none";
|
|
28222
28363
|
});
|
|
@@ -28913,6 +29054,97 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
28913
29054
|
};
|
|
28914
29055
|
};
|
|
28915
29056
|
|
|
29057
|
+
// src/js/drag/sortable.js
|
|
29058
|
+
function computeDropIndex(clientY, items) {
|
|
29059
|
+
for (let i4 = 0; i4 < items.length; i4++) {
|
|
29060
|
+
const rect = items[i4].getBoundingClientRect();
|
|
29061
|
+
if (clientY < rect.top + rect.height / 2) return i4;
|
|
29062
|
+
}
|
|
29063
|
+
return items.length;
|
|
29064
|
+
}
|
|
29065
|
+
function computeDropIndexHorizontal(clientX, items) {
|
|
29066
|
+
for (let i4 = 0; i4 < items.length; i4++) {
|
|
29067
|
+
const rect = items[i4].getBoundingClientRect();
|
|
29068
|
+
if (clientX < rect.left + rect.width / 2) return i4;
|
|
29069
|
+
}
|
|
29070
|
+
return items.length;
|
|
29071
|
+
}
|
|
29072
|
+
function beginDrag(event, element, { draggingClass, payload, dragImage = null }) {
|
|
29073
|
+
event.dataTransfer.effectAllowed = "move";
|
|
29074
|
+
event.dataTransfer.setData("text/plain", payload);
|
|
29075
|
+
if (dragImage) {
|
|
29076
|
+
const rect = dragImage.getBoundingClientRect();
|
|
29077
|
+
event.dataTransfer.setDragImage(dragImage, event.clientX - rect.left, event.clientY - rect.top);
|
|
29078
|
+
}
|
|
29079
|
+
requestAnimationFrame(() => element.classList.add(draggingClass));
|
|
29080
|
+
}
|
|
29081
|
+
function endDrag(element, { draggingClass }) {
|
|
29082
|
+
element.classList.remove(draggingClass);
|
|
29083
|
+
hideInsertionMarker();
|
|
29084
|
+
}
|
|
29085
|
+
var MARKER_ID = "pu-drag-insertion-marker";
|
|
29086
|
+
function insertionMarker() {
|
|
29087
|
+
let marker = document.getElementById(MARKER_ID);
|
|
29088
|
+
if (!marker) {
|
|
29089
|
+
marker = document.createElement("div");
|
|
29090
|
+
marker.id = MARKER_ID;
|
|
29091
|
+
marker.className = "pu-drag-marker";
|
|
29092
|
+
marker.setAttribute("aria-hidden", "true");
|
|
29093
|
+
document.body.appendChild(marker);
|
|
29094
|
+
}
|
|
29095
|
+
return marker;
|
|
29096
|
+
}
|
|
29097
|
+
function showInsertionMarker(items, index, { axis = "vertical", container = null, gap = null } = {}) {
|
|
29098
|
+
const marker = insertionMarker();
|
|
29099
|
+
if (gap) {
|
|
29100
|
+
marker.style.setProperty("--pu-drag-marker-gap", gap);
|
|
29101
|
+
} else {
|
|
29102
|
+
marker.style.removeProperty("--pu-drag-marker-gap");
|
|
29103
|
+
}
|
|
29104
|
+
const vertical = axis !== "horizontal";
|
|
29105
|
+
const near = (rect) => vertical ? rect.top : rect.left;
|
|
29106
|
+
const far = (rect) => vertical ? rect.bottom : rect.right;
|
|
29107
|
+
let span;
|
|
29108
|
+
let offset2;
|
|
29109
|
+
let edge;
|
|
29110
|
+
if (items.length === 0) {
|
|
29111
|
+
if (!container) return hideInsertionMarker();
|
|
29112
|
+
span = container.getBoundingClientRect();
|
|
29113
|
+
offset2 = near(span);
|
|
29114
|
+
edge = "leading";
|
|
29115
|
+
} else if (index <= 0) {
|
|
29116
|
+
span = items[0].getBoundingClientRect();
|
|
29117
|
+
offset2 = near(span);
|
|
29118
|
+
edge = "leading";
|
|
29119
|
+
} else if (index >= items.length) {
|
|
29120
|
+
span = items[items.length - 1].getBoundingClientRect();
|
|
29121
|
+
offset2 = far(span);
|
|
29122
|
+
edge = "trailing";
|
|
29123
|
+
} else {
|
|
29124
|
+
span = items[index].getBoundingClientRect();
|
|
29125
|
+
offset2 = (far(items[index - 1].getBoundingClientRect()) + near(span)) / 2;
|
|
29126
|
+
edge = "between";
|
|
29127
|
+
}
|
|
29128
|
+
if (vertical) {
|
|
29129
|
+
marker.style.left = `${span.left}px`;
|
|
29130
|
+
marker.style.top = `${offset2}px`;
|
|
29131
|
+
marker.style.width = `${span.width}px`;
|
|
29132
|
+
marker.style.height = "";
|
|
29133
|
+
} else {
|
|
29134
|
+
marker.style.left = `${offset2}px`;
|
|
29135
|
+
marker.style.top = `${span.top}px`;
|
|
29136
|
+
marker.style.height = `${span.height}px`;
|
|
29137
|
+
marker.style.width = "";
|
|
29138
|
+
}
|
|
29139
|
+
marker.dataset.axis = axis;
|
|
29140
|
+
marker.dataset.edge = edge;
|
|
29141
|
+
marker.style.display = "block";
|
|
29142
|
+
}
|
|
29143
|
+
function hideInsertionMarker() {
|
|
29144
|
+
const marker = document.getElementById(MARKER_ID);
|
|
29145
|
+
if (marker) marker.style.display = "none";
|
|
29146
|
+
}
|
|
29147
|
+
|
|
28916
29148
|
// src/js/controllers/kanban_controller.js
|
|
28917
29149
|
var kanban_controller_default = class extends Controller {
|
|
28918
29150
|
static values = { moveUrlTemplate: String, collapseCookie: String, collapsePath: String };
|
|
@@ -29166,9 +29398,10 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
29166
29398
|
const card = event.target.closest("[data-kanban-record-id]");
|
|
29167
29399
|
if (!card) return;
|
|
29168
29400
|
this.draggedCard = card;
|
|
29169
|
-
event
|
|
29170
|
-
|
|
29171
|
-
|
|
29401
|
+
beginDrag(event, card, {
|
|
29402
|
+
draggingClass: "pu-kanban-dragging",
|
|
29403
|
+
payload: card.dataset.kanbanRecordId
|
|
29404
|
+
});
|
|
29172
29405
|
this.#applyDropHints(card.dataset.kanbanColumnKey);
|
|
29173
29406
|
}
|
|
29174
29407
|
#onDragOver(event) {
|
|
@@ -29179,15 +29412,25 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
29179
29412
|
event.preventDefault();
|
|
29180
29413
|
event.dataTransfer.dropEffect = "move";
|
|
29181
29414
|
this.#highlightColumn(column);
|
|
29415
|
+
const existingCards = [...column.querySelectorAll("[data-kanban-record-id]")].filter((c4) => c4 !== this.draggedCard);
|
|
29416
|
+
showInsertionMarker(existingCards, computeDropIndex(event.clientY, existingCards), {
|
|
29417
|
+
axis: "vertical",
|
|
29418
|
+
container: column,
|
|
29419
|
+
// Cards sit further apart than table rows, so the table's clearance reads
|
|
29420
|
+
// as cramped against a card's edge here.
|
|
29421
|
+
gap: "10px"
|
|
29422
|
+
});
|
|
29182
29423
|
}
|
|
29183
29424
|
#onDragLeave(event) {
|
|
29184
29425
|
if (!this.element.contains(event.relatedTarget)) {
|
|
29185
29426
|
this.#clearHighlights();
|
|
29427
|
+
hideInsertionMarker();
|
|
29186
29428
|
}
|
|
29187
29429
|
}
|
|
29188
29430
|
async #onDrop(event) {
|
|
29189
29431
|
event.preventDefault();
|
|
29190
29432
|
this.#clearHighlights();
|
|
29433
|
+
hideInsertionMarker();
|
|
29191
29434
|
if (!this.draggedCard) return;
|
|
29192
29435
|
const wrapper = event.target.closest("[data-kanban-col]");
|
|
29193
29436
|
if (wrapper?.classList.contains("pu-kanban-no-drop")) return;
|
|
@@ -29197,7 +29440,7 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
29197
29440
|
const fromColumn = this.draggedCard.dataset.kanbanColumnKey;
|
|
29198
29441
|
const toColumn = column.dataset.kanbanColumnKeyValue;
|
|
29199
29442
|
const existingCards = [...column.querySelectorAll("[data-kanban-record-id]")].filter((c4) => c4 !== this.draggedCard);
|
|
29200
|
-
const toIndex =
|
|
29443
|
+
const toIndex = computeDropIndex(event.clientY, existingCards);
|
|
29201
29444
|
const destWrapper = column.closest("[data-kanban-col]");
|
|
29202
29445
|
if (destWrapper?.dataset.kanbanDropInteraction === "true" && fromColumn !== toColumn) {
|
|
29203
29446
|
if (destWrapper.dataset.kanbanDropImmediate === "true") {
|
|
@@ -29276,7 +29519,7 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
29276
29519
|
this.#clearHighlights();
|
|
29277
29520
|
this.#clearDropHints();
|
|
29278
29521
|
if (this.draggedCard) {
|
|
29279
|
-
this.draggedCard
|
|
29522
|
+
endDrag(this.draggedCard, { draggingClass: "pu-kanban-dragging" });
|
|
29280
29523
|
this.draggedCard = null;
|
|
29281
29524
|
}
|
|
29282
29525
|
}
|
|
@@ -29336,17 +29579,6 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
29336
29579
|
document.cookie = `${name}=${value}; path=${path}; max-age=${60 * 60 * 24 * 180}; SameSite=Lax`;
|
|
29337
29580
|
}
|
|
29338
29581
|
// ─── helpers ─────────────────────────────────────────────────────────────────
|
|
29339
|
-
// Returns the 0-based insertion index within the destination column by
|
|
29340
|
-
// comparing the cursor y-position against each card's vertical midpoint.
|
|
29341
|
-
// The card is inserted before the first card whose midpoint is below the
|
|
29342
|
-
// cursor, or appended after all cards if the cursor is below every midpoint.
|
|
29343
|
-
#computeDropIndex(clientY, cards) {
|
|
29344
|
-
for (let i4 = 0; i4 < cards.length; i4++) {
|
|
29345
|
-
const rect = cards[i4].getBoundingClientRect();
|
|
29346
|
-
if (clientY < rect.top + rect.height / 2) return i4;
|
|
29347
|
-
}
|
|
29348
|
-
return cards.length;
|
|
29349
|
-
}
|
|
29350
29582
|
#highlightColumn(column) {
|
|
29351
29583
|
this.columnTargets.forEach((c4) => {
|
|
29352
29584
|
c4.classList.toggle("pu-kanban-drop-target", c4 === column);
|
|
@@ -29357,6 +29589,254 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
29357
29589
|
}
|
|
29358
29590
|
};
|
|
29359
29591
|
|
|
29592
|
+
// src/js/controllers/positioned_controller.js
|
|
29593
|
+
var DRAGGING_CLASS = "opacity-30";
|
|
29594
|
+
var positioned_controller_default = class extends Controller {
|
|
29595
|
+
static values = { urlTemplate: String, axis: { type: String, default: "vertical" } };
|
|
29596
|
+
connect() {
|
|
29597
|
+
this.draggedRow = null;
|
|
29598
|
+
this.onDragStart = this.#onDragStart.bind(this);
|
|
29599
|
+
this.onDragOver = this.#onDragOver.bind(this);
|
|
29600
|
+
this.onDragLeave = this.#onDragLeave.bind(this);
|
|
29601
|
+
this.onDrop = this.#onDrop.bind(this);
|
|
29602
|
+
this.onDragEnd = this.#onDragEnd.bind(this);
|
|
29603
|
+
this.onKeyDown = this.#onKeyDown.bind(this);
|
|
29604
|
+
this.element.addEventListener("dragstart", this.onDragStart);
|
|
29605
|
+
this.element.addEventListener("dragover", this.onDragOver);
|
|
29606
|
+
this.element.addEventListener("dragleave", this.onDragLeave);
|
|
29607
|
+
this.element.addEventListener("drop", this.onDrop);
|
|
29608
|
+
this.element.addEventListener("dragend", this.onDragEnd);
|
|
29609
|
+
this.element.addEventListener("keydown", this.onKeyDown);
|
|
29610
|
+
}
|
|
29611
|
+
disconnect() {
|
|
29612
|
+
this.element.removeEventListener("dragstart", this.onDragStart);
|
|
29613
|
+
this.element.removeEventListener("dragover", this.onDragOver);
|
|
29614
|
+
this.element.removeEventListener("dragleave", this.onDragLeave);
|
|
29615
|
+
this.element.removeEventListener("drop", this.onDrop);
|
|
29616
|
+
this.element.removeEventListener("dragend", this.onDragEnd);
|
|
29617
|
+
this.element.removeEventListener("keydown", this.onKeyDown);
|
|
29618
|
+
hideInsertionMarker();
|
|
29619
|
+
}
|
|
29620
|
+
// ─── drag lifecycle ─────────────────────────────────────────────────────────
|
|
29621
|
+
#onDragStart(event) {
|
|
29622
|
+
const grip = event.target.closest("[data-positioned-grip]");
|
|
29623
|
+
if (!grip) return;
|
|
29624
|
+
const row = this.#rowFor(grip);
|
|
29625
|
+
if (!row) return;
|
|
29626
|
+
this.draggedRow = row;
|
|
29627
|
+
beginDrag(event, row, {
|
|
29628
|
+
draggingClass: DRAGGING_CLASS,
|
|
29629
|
+
payload: row.dataset.positionedRowId,
|
|
29630
|
+
// The grip carries draggable="true", so without this the browser ghosts
|
|
29631
|
+
// the grip alone and the row looks like it never left.
|
|
29632
|
+
dragImage: row
|
|
29633
|
+
});
|
|
29634
|
+
}
|
|
29635
|
+
#onDragOver(event) {
|
|
29636
|
+
if (!this.draggedRow) return;
|
|
29637
|
+
if (!this.#sameGroupAs(event.target)) {
|
|
29638
|
+
hideInsertionMarker();
|
|
29639
|
+
return;
|
|
29640
|
+
}
|
|
29641
|
+
event.preventDefault();
|
|
29642
|
+
event.dataTransfer.dropEffect = "move";
|
|
29643
|
+
const others = this.#rows().filter((r4) => r4 !== this.draggedRow);
|
|
29644
|
+
showInsertionMarker(others, this.#dropIndex(event, others), {
|
|
29645
|
+
axis: this.axisValue === "horizontal" ? "horizontal" : "vertical",
|
|
29646
|
+
container: this.element
|
|
29647
|
+
});
|
|
29648
|
+
}
|
|
29649
|
+
#onDragLeave(event) {
|
|
29650
|
+
if (event.relatedTarget && this.element.contains(event.relatedTarget)) return;
|
|
29651
|
+
hideInsertionMarker();
|
|
29652
|
+
}
|
|
29653
|
+
#onDrop(event) {
|
|
29654
|
+
event.preventDefault();
|
|
29655
|
+
hideInsertionMarker();
|
|
29656
|
+
if (!this.draggedRow) return;
|
|
29657
|
+
const row = this.draggedRow;
|
|
29658
|
+
const others = this.#rows().filter((r4) => r4 !== row);
|
|
29659
|
+
this.#applyMove(row, others, this.#dropIndex(event, others));
|
|
29660
|
+
}
|
|
29661
|
+
// Where a drop at the cursor lands, in `items`' own order.
|
|
29662
|
+
//
|
|
29663
|
+
// A table stacks: one row per line, so the vertical midpoint test is the
|
|
29664
|
+
// whole story. A grid WRAPS: cards flow left-to-right and then onto a new
|
|
29665
|
+
// line, and reading that layout off clientY alone would collapse every card
|
|
29666
|
+
// on a line into a single slot — the drop would land at the start of the row
|
|
29667
|
+
// no matter which gap the user aimed at.
|
|
29668
|
+
//
|
|
29669
|
+
// But clientX alone is no better, because every visual row starts at the same
|
|
29670
|
+
// left edge: x=250 is "after the third card" in row 1 and row 4 alike. So
|
|
29671
|
+
// narrow to the row the cursor is over FIRST, then let the horizontal
|
|
29672
|
+
// midpoint test choose the gap inside it.
|
|
29673
|
+
#dropIndex(event, items) {
|
|
29674
|
+
if (this.axisValue !== "horizontal") return computeDropIndex(event.clientY, items);
|
|
29675
|
+
if (items.length === 0) return 0;
|
|
29676
|
+
const rows = this.#visualRows(items);
|
|
29677
|
+
if (event.clientY < rows[0].top) return 0;
|
|
29678
|
+
const row = rows.find((r4) => event.clientY <= r4.bottom);
|
|
29679
|
+
if (!row) return items.length;
|
|
29680
|
+
return row.start + computeDropIndexHorizontal(event.clientX, items.slice(row.start, row.end));
|
|
29681
|
+
}
|
|
29682
|
+
// Groups `items` into the lines the browser actually laid them out on, as
|
|
29683
|
+
// {top, bottom, start, end} spans over `items`.
|
|
29684
|
+
//
|
|
29685
|
+
// Recovered from geometry rather than from a column count on purpose: the
|
|
29686
|
+
// grid is responsive (1/2/3/4 columns by breakpoint) and a definition may pin
|
|
29687
|
+
// its own, so the only thing that reliably knows how the cards wrapped is
|
|
29688
|
+
// where they ended up. A new line starts wherever an item's top edge leaves
|
|
29689
|
+
// the current one's — with a pixel of slack, since equal-height cards in a
|
|
29690
|
+
// row can still differ by a sub-pixel.
|
|
29691
|
+
#visualRows(items) {
|
|
29692
|
+
const rows = [];
|
|
29693
|
+
items.forEach((item, i4) => {
|
|
29694
|
+
const rect = item.getBoundingClientRect();
|
|
29695
|
+
const row = rows[rows.length - 1];
|
|
29696
|
+
if (row && Math.abs(rect.top - row.top) <= 1) {
|
|
29697
|
+
row.end = i4 + 1;
|
|
29698
|
+
row.bottom = Math.max(row.bottom, rect.bottom);
|
|
29699
|
+
} else {
|
|
29700
|
+
rows.push({ top: rect.top, bottom: rect.bottom, start: i4, end: i4 + 1 });
|
|
29701
|
+
}
|
|
29702
|
+
});
|
|
29703
|
+
return rows;
|
|
29704
|
+
}
|
|
29705
|
+
#onDragEnd(_event) {
|
|
29706
|
+
if (!this.draggedRow) return;
|
|
29707
|
+
endDrag(this.draggedRow, { draggingClass: DRAGGING_CLASS });
|
|
29708
|
+
this.draggedRow = null;
|
|
29709
|
+
}
|
|
29710
|
+
// ─── keyboard ───────────────────────────────────────────────────────────────
|
|
29711
|
+
#onKeyDown(event) {
|
|
29712
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
29713
|
+
const grip = event.target.closest("[data-positioned-grip]");
|
|
29714
|
+
if (!grip) return;
|
|
29715
|
+
const row = this.#rowFor(grip);
|
|
29716
|
+
if (!row) return;
|
|
29717
|
+
event.preventDefault();
|
|
29718
|
+
const rows = this.#rows();
|
|
29719
|
+
const from = rows.indexOf(row);
|
|
29720
|
+
const to = event.key === "ArrowUp" ? from - 1 : from + 1;
|
|
29721
|
+
if (to < 0 || to >= rows.length) return;
|
|
29722
|
+
const others = rows.filter((r4) => r4 !== row);
|
|
29723
|
+
this.#applyMove(row, others, to);
|
|
29724
|
+
grip.focus();
|
|
29725
|
+
}
|
|
29726
|
+
// ─── the move itself ────────────────────────────────────────────────────────
|
|
29727
|
+
// Moves `row` to `index` among `others` (which must already exclude `row`),
|
|
29728
|
+
// optimistically, then tells the server. Shared by drop and keyboard so the
|
|
29729
|
+
// two can never compute neighbours differently.
|
|
29730
|
+
#applyMove(row, others, index) {
|
|
29731
|
+
const before = others[index] ?? null;
|
|
29732
|
+
const after = others[index - 1] ?? null;
|
|
29733
|
+
if (row.nextElementSibling === before && row.previousElementSibling === after) return;
|
|
29734
|
+
const restoreAnchor = row.nextSibling;
|
|
29735
|
+
row.parentElement.insertBefore(row, before);
|
|
29736
|
+
this.#submit(row, restoreAnchor, {
|
|
29737
|
+
// The ids of the row's VISIBLE neighbours. A blank one means "nothing on
|
|
29738
|
+
// that side of my page" — the server treats that as a claim about the
|
|
29739
|
+
// viewport, not about the positioning group, and looks the real boundary
|
|
29740
|
+
// neighbour up itself (see PositionActions#resolve_position_boundaries).
|
|
29741
|
+
prevId: after?.dataset.positionedRowId ?? "",
|
|
29742
|
+
nextId: before?.dataset.positionedRowId ?? "",
|
|
29743
|
+
toIndex: index
|
|
29744
|
+
});
|
|
29745
|
+
}
|
|
29746
|
+
// `row` is the already-moved element and `restoreAnchor` the sibling it sat
|
|
29747
|
+
// in front of beforehand, so every path that does not end in the server's own
|
|
29748
|
+
// truth can undo the optimistic move rather than leave it standing.
|
|
29749
|
+
async #submit(row, restoreAnchor, { prevId, nextId, toIndex }) {
|
|
29750
|
+
const recordId = row.dataset.positionedRowId;
|
|
29751
|
+
const url = this.urlTemplateValue.replace("__ID__", recordId) + window.location.search;
|
|
29752
|
+
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content ?? "";
|
|
29753
|
+
try {
|
|
29754
|
+
const response = await fetch(url, {
|
|
29755
|
+
method: "POST",
|
|
29756
|
+
headers: {
|
|
29757
|
+
"Accept": "text/vnd.turbo-stream.html",
|
|
29758
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
29759
|
+
"X-CSRF-Token": csrfToken
|
|
29760
|
+
},
|
|
29761
|
+
body: new URLSearchParams({
|
|
29762
|
+
prev_id: prevId,
|
|
29763
|
+
next_id: nextId,
|
|
29764
|
+
to_index: toIndex
|
|
29765
|
+
}),
|
|
29766
|
+
credentials: "same-origin"
|
|
29767
|
+
});
|
|
29768
|
+
if (response.status === 204) return;
|
|
29769
|
+
const contentType = response.headers.get("Content-Type") || "";
|
|
29770
|
+
if (contentType.includes("text/vnd.turbo-stream.html") && window.Turbo) {
|
|
29771
|
+
const focusedRowId = this.#focusedRowId();
|
|
29772
|
+
window.Turbo.renderStreamMessage(await response.text());
|
|
29773
|
+
if (focusedRowId) this.#restoreFocus(focusedRowId);
|
|
29774
|
+
} else if (!response.ok) {
|
|
29775
|
+
console.error(`[positioned] reposition rejected (${response.status}); reverting the move`);
|
|
29776
|
+
this.#revertMove(row, restoreAnchor);
|
|
29777
|
+
} else {
|
|
29778
|
+
console.warn("[positioned] reposition returned a non-stream response (session expired?); reverting the move");
|
|
29779
|
+
this.#revertMove(row, restoreAnchor);
|
|
29780
|
+
}
|
|
29781
|
+
} catch (error2) {
|
|
29782
|
+
console.error("[positioned] reposition request failed:", error2);
|
|
29783
|
+
this.#revertMove(row, restoreAnchor);
|
|
29784
|
+
}
|
|
29785
|
+
}
|
|
29786
|
+
// Undoes the optimistic move. Only meaningful while the row is still the node
|
|
29787
|
+
// we moved: once a turbo-stream has replaced the collection the server's truth
|
|
29788
|
+
// owns the DOM, and this instance's nodes are detached.
|
|
29789
|
+
//
|
|
29790
|
+
// A missing/relocated anchor falls back to appending, which is also what a
|
|
29791
|
+
// null anchor legitimately means — the row was last before the move.
|
|
29792
|
+
#revertMove(row, anchor) {
|
|
29793
|
+
const parent = row.parentElement;
|
|
29794
|
+
if (!parent || !row.isConnected) return;
|
|
29795
|
+
const refocus = row.contains(document.activeElement);
|
|
29796
|
+
parent.insertBefore(row, anchor?.parentNode === parent ? anchor : null);
|
|
29797
|
+
if (refocus) row.querySelector("[data-positioned-grip]")?.focus();
|
|
29798
|
+
}
|
|
29799
|
+
// ─── helpers ────────────────────────────────────────────────────────────────
|
|
29800
|
+
#rows() {
|
|
29801
|
+
return [...this.element.querySelectorAll("[data-positioned-row-id]")];
|
|
29802
|
+
}
|
|
29803
|
+
#rowFor(element) {
|
|
29804
|
+
return element.closest("[data-positioned-row-id]");
|
|
29805
|
+
}
|
|
29806
|
+
// Whether the row under the cursor shares the dragged row's positioning
|
|
29807
|
+
// group. An UNSCOPED resource emits no group attribute at all, so both sides
|
|
29808
|
+
// read undefined and every row matches — the guard costs nothing there.
|
|
29809
|
+
//
|
|
29810
|
+
// Pointing at no row (the gutter below the last one, the wrapper's padding)
|
|
29811
|
+
// counts as a match: the drop resolves against the collection's own ends,
|
|
29812
|
+
// which are in the dragged row's group by construction.
|
|
29813
|
+
#sameGroupAs(target) {
|
|
29814
|
+
const row = this.#rowFor(target);
|
|
29815
|
+
if (!row) return true;
|
|
29816
|
+
return row.dataset.positionedGroup === this.draggedRow.dataset.positionedGroup;
|
|
29817
|
+
}
|
|
29818
|
+
#focusedRowId() {
|
|
29819
|
+
const grip = document.activeElement?.closest?.("[data-positioned-grip]");
|
|
29820
|
+
return grip ? this.#rowFor(grip)?.dataset.positionedRowId : null;
|
|
29821
|
+
}
|
|
29822
|
+
// Deferred a frame: renderStreamMessage resolves its render asynchronously,
|
|
29823
|
+
// so the replacement rows are not in the document yet when it returns.
|
|
29824
|
+
//
|
|
29825
|
+
// Queried off `document`, NOT `this.element`. The stream replaces the contents
|
|
29826
|
+
// of the collection wrapper (Page::Index.collection_dom_id), and this
|
|
29827
|
+
// controller's element — the div around the <table>, or the grid div — is one
|
|
29828
|
+
// of the nodes it discards. By the time this callback runs `this.element` is
|
|
29829
|
+
// detached, so scoping the lookup to it finds nothing and focus is silently
|
|
29830
|
+
// lost on exactly the path this method exists to cover: a keyboard move that
|
|
29831
|
+
// triggered a rebalance. A fresh controller is already connected to the
|
|
29832
|
+
// replacement; `document` is the only handle that spans both.
|
|
29833
|
+
#restoreFocus(rowId) {
|
|
29834
|
+
requestAnimationFrame(() => {
|
|
29835
|
+
document.querySelector(`[data-positioned-row-id="${CSS.escape(rowId)}"] [data-positioned-grip]`)?.focus();
|
|
29836
|
+
});
|
|
29837
|
+
}
|
|
29838
|
+
};
|
|
29839
|
+
|
|
29360
29840
|
// src/js/controllers/currency_input_controller.js
|
|
29361
29841
|
var currency_input_controller_default = class extends Controller {
|
|
29362
29842
|
static targets = ["prefix", "field"];
|
|
@@ -29375,6 +29855,106 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
29375
29855
|
}
|
|
29376
29856
|
};
|
|
29377
29857
|
|
|
29858
|
+
// src/js/controllers/breadcrumbs_controller.js
|
|
29859
|
+
var breadcrumbs_controller_default = class extends Controller {
|
|
29860
|
+
static targets = ["list", "item", "last", "overflow", "menuItem"];
|
|
29861
|
+
connect() {
|
|
29862
|
+
this.menuItems = this.menuItemTargets;
|
|
29863
|
+
this.observer = new ResizeObserver(() => this.reflow());
|
|
29864
|
+
this.observer.observe(this.element);
|
|
29865
|
+
this.reflow();
|
|
29866
|
+
document.fonts?.ready.then(() => this.reflow());
|
|
29867
|
+
}
|
|
29868
|
+
disconnect() {
|
|
29869
|
+
this.observer.disconnect();
|
|
29870
|
+
}
|
|
29871
|
+
reflow() {
|
|
29872
|
+
if (!this.element.isConnected || !this.hasListTarget) return;
|
|
29873
|
+
this.itemTargets.forEach((el) => this.#show(el));
|
|
29874
|
+
if (this.hasOverflowTarget) this.#hide(this.overflowTarget);
|
|
29875
|
+
if (this.hasLastTarget) this.lastTarget.classList.add("shrink-0");
|
|
29876
|
+
if (this.#overflows()) {
|
|
29877
|
+
if (this.hasOverflowTarget) {
|
|
29878
|
+
this.#show(this.overflowTarget);
|
|
29879
|
+
for (const item of this.itemTargets) {
|
|
29880
|
+
if (!this.#overflows()) break;
|
|
29881
|
+
this.#hide(item);
|
|
29882
|
+
}
|
|
29883
|
+
}
|
|
29884
|
+
if (this.#overflows() && this.hasLastTarget) {
|
|
29885
|
+
this.lastTarget.classList.remove("shrink-0");
|
|
29886
|
+
}
|
|
29887
|
+
}
|
|
29888
|
+
this.#syncMenu();
|
|
29889
|
+
}
|
|
29890
|
+
// Measured on the nav rather than the <ol>, because the nav is the element
|
|
29891
|
+
// that actually clips (`overflow-hidden`). A non-scrolling box reports
|
|
29892
|
+
// overflow inconsistently once direction is rtl; the clipping box doesn't.
|
|
29893
|
+
#overflows() {
|
|
29894
|
+
return this.element.scrollWidth > this.element.clientWidth;
|
|
29895
|
+
}
|
|
29896
|
+
#show(el) {
|
|
29897
|
+
el.classList.remove("hidden");
|
|
29898
|
+
el.classList.add("flex");
|
|
29899
|
+
}
|
|
29900
|
+
#hide(el) {
|
|
29901
|
+
el.classList.remove("flex");
|
|
29902
|
+
el.classList.add("hidden");
|
|
29903
|
+
}
|
|
29904
|
+
// A menu row is shown exactly when its inline twin has been folded away.
|
|
29905
|
+
#syncMenu() {
|
|
29906
|
+
if (!this.hasOverflowTarget) return;
|
|
29907
|
+
const folded = this.itemTargets.map((el) => el.classList.contains("hidden"));
|
|
29908
|
+
this.menuItems.forEach((row, i4) => {
|
|
29909
|
+
row.classList.toggle("hidden", !folded[i4]);
|
|
29910
|
+
});
|
|
29911
|
+
if (!folded.some(Boolean)) this.#closeOverflowMenu();
|
|
29912
|
+
}
|
|
29913
|
+
// The trail grew back far enough that the control is gone. Its menu may
|
|
29914
|
+
// still be open — and teleported to <body>, so hiding the control does not
|
|
29915
|
+
// hide the menu. Popper would go on positioning it against a display:none
|
|
29916
|
+
// trigger, whose rect is all zeros, parking the menu in the viewport corner.
|
|
29917
|
+
#closeOverflowMenu() {
|
|
29918
|
+
const host = this.overflowTarget.querySelector('[data-controller~="resource-drop-down"]');
|
|
29919
|
+
const dropdown = this.application.getControllerForElementAndIdentifier(host, "resource-drop-down");
|
|
29920
|
+
if (dropdown?.visible) dropdown.hide();
|
|
29921
|
+
}
|
|
29922
|
+
};
|
|
29923
|
+
|
|
29924
|
+
// src/js/controllers/run_progress_controller.js
|
|
29925
|
+
var run_progress_controller_default = class extends Controller {
|
|
29926
|
+
static values = {
|
|
29927
|
+
url: String,
|
|
29928
|
+
interval: { type: Number, default: 2e3 },
|
|
29929
|
+
// Set by the server on the LAST poll only — see AsyncRunProgress#poll_attributes.
|
|
29930
|
+
finished: Boolean
|
|
29931
|
+
};
|
|
29932
|
+
connect() {
|
|
29933
|
+
if (this.finishedValue) return this.reloadPage();
|
|
29934
|
+
this.schedule();
|
|
29935
|
+
}
|
|
29936
|
+
disconnect() {
|
|
29937
|
+
if (this.timer) clearTimeout(this.timer);
|
|
29938
|
+
this.timer = null;
|
|
29939
|
+
}
|
|
29940
|
+
schedule() {
|
|
29941
|
+
this.timer = setTimeout(() => this.refresh(), this.intervalValue);
|
|
29942
|
+
}
|
|
29943
|
+
reloadPage() {
|
|
29944
|
+
window.Turbo?.visit(window.location.href, { action: "replace" });
|
|
29945
|
+
}
|
|
29946
|
+
refresh() {
|
|
29947
|
+
const frame = this.element.closest("turbo-frame");
|
|
29948
|
+
if (!frame) return;
|
|
29949
|
+
this.schedule();
|
|
29950
|
+
if (frame.src) {
|
|
29951
|
+
frame.reload();
|
|
29952
|
+
} else {
|
|
29953
|
+
frame.src = this.urlValue;
|
|
29954
|
+
}
|
|
29955
|
+
}
|
|
29956
|
+
};
|
|
29957
|
+
|
|
29378
29958
|
// src/js/controllers/register_controllers.js
|
|
29379
29959
|
function register_controllers_default(application2) {
|
|
29380
29960
|
application2.register("password-visibility", password_visibility_controller_default);
|
|
@@ -29415,7 +29995,10 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
29415
29995
|
application2.register("dirty-form-guard", dirty_form_guard_controller_default);
|
|
29416
29996
|
application2.register("wizard", wizard_controller_default);
|
|
29417
29997
|
application2.register("kanban", kanban_controller_default);
|
|
29998
|
+
application2.register("positioned", positioned_controller_default);
|
|
29418
29999
|
application2.register("currency-input", currency_input_controller_default);
|
|
30000
|
+
application2.register("breadcrumbs", breadcrumbs_controller_default);
|
|
30001
|
+
application2.register("run-progress", run_progress_controller_default);
|
|
29419
30002
|
}
|
|
29420
30003
|
|
|
29421
30004
|
// src/js/turbo/turbo_actions.js
|
|
@@ -29573,7 +30156,7 @@ cropperjs/dist/cropper.js:
|
|
|
29573
30156
|
*)
|
|
29574
30157
|
|
|
29575
30158
|
dompurify/dist/purify.es.mjs:
|
|
29576
|
-
(*! @license DOMPurify 3.4.
|
|
30159
|
+
(*! @license DOMPurify 3.4.14 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.14/LICENSE *)
|
|
29577
30160
|
|
|
29578
30161
|
@uppy/utils/lib/Translator.js:
|
|
29579
30162
|
(**
|