domma-cms 0.43.1 → 0.45.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.
- package/CLAUDE.md +53 -53
- package/README.md +27 -27
- package/admin/css/admin.css +1 -1
- package/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/index.html +2 -2
- package/admin/js/app.js +1 -1
- package/admin/js/lib/card-builder.js +2 -2
- package/admin/js/lib/crud-tutorial.js +1 -1
- package/admin/js/lib/effect-defs.js +1 -1
- package/admin/js/lib/effects-builder.js +1 -1
- package/admin/js/lib/image-editor.js +1 -1
- package/admin/js/lib/markdown-toolbar.js +2 -2
- package/admin/js/lib/project-context.js +1 -1
- package/admin/js/lib/project-quick-create.js +1 -1
- package/admin/js/lib/scribe-composer.js +1 -1
- package/admin/js/lib/server-restart.js +1 -1
- package/admin/js/lib/shortcode-context-menu.js +2 -2
- package/admin/js/lib/simple-editor.js +1 -1
- package/admin/js/lib/themes.js +1 -1
- package/admin/js/lib/timeline-builder.js +1 -1
- package/admin/js/templates/action-editor.html +8 -8
- package/admin/js/templates/api-endpoint-editor.html +7 -7
- package/admin/js/templates/api-endpoints.html +1 -1
- package/admin/js/templates/api-reference.html +1 -1
- package/admin/js/templates/block-editor.html +6 -6
- package/admin/js/templates/collection-editor.html +1 -1
- package/admin/js/templates/component-editor.html +2 -2
- package/admin/js/templates/dashboard/cache.html +3 -3
- package/admin/js/templates/dashboard/journeys.html +3 -3
- package/admin/js/templates/dashboard/kpi-strip.html +3 -3
- package/admin/js/templates/dashboard/top-pages.html +1 -1
- package/admin/js/templates/dashboard/traffic-chart.html +1 -1
- package/admin/js/templates/docs/api-actions.html +1 -1
- package/admin/js/templates/docs/api-collections.html +4 -4
- package/admin/js/templates/docs/api-pages.html +2 -2
- package/admin/js/templates/docs/api-plugins.html +1 -1
- package/admin/js/templates/docs/api-settings.html +2 -2
- package/admin/js/templates/docs/api-users.html +1 -1
- package/admin/js/templates/docs/components-howto.html +4 -4
- package/admin/js/templates/docs/components-reference.html +21 -21
- package/admin/js/templates/docs/components-rules.html +14 -14
- package/admin/js/templates/docs/components-walkthrough.html +13 -13
- package/admin/js/templates/docs/tutorial-crud.html +49 -49
- package/admin/js/templates/docs/tutorial-forms.html +4 -4
- package/admin/js/templates/docs/tutorial-plugin.html +10 -10
- package/admin/js/templates/docs/usage-actions.html +6 -6
- package/admin/js/templates/docs/usage-cta-shortcode.html +9 -9
- package/admin/js/templates/docs/usage-dconfig.html +4 -4
- package/admin/js/templates/docs/usage-navigation.html +1 -1
- package/admin/js/templates/docs/usage-pages.html +1 -1
- package/admin/js/templates/docs/usage-shortcodes.html +24 -24
- package/admin/js/templates/docs/usage-users-roles.html +3 -3
- package/admin/js/templates/docs/usage-views.html +4 -4
- package/admin/js/templates/documentation.html +1 -1
- package/admin/js/templates/effects.html +25 -25
- package/admin/js/templates/form-editor.html +5 -5
- package/admin/js/templates/login.html +5 -5
- package/admin/js/templates/menu-editor.html +10 -10
- package/admin/js/templates/navigation.html +11 -11
- package/admin/js/templates/notifications.html +1 -1
- package/admin/js/templates/page-editor.html +4 -4
- package/admin/js/templates/pro-docs.html +14 -14
- package/admin/js/templates/role-editor.html +1 -1
- package/admin/js/templates/settings.html +10 -10
- package/admin/js/templates/tutorials.html +3 -3
- package/admin/js/templates/view-editor.html +15 -15
- package/admin/js/views/action-editor.js +1 -1
- package/admin/js/views/actions-list.js +1 -1
- package/admin/js/views/api-endpoint-editor.js +2 -2
- package/admin/js/views/api-endpoints.js +2 -2
- package/admin/js/views/api-tokens.js +3 -3
- package/admin/js/views/blocks.js +2 -2
- package/admin/js/views/collection-editor.js +1 -1
- package/admin/js/views/collection-entries.js +1 -1
- package/admin/js/views/collections.js +1 -1
- package/admin/js/views/component-editor.js +1 -1
- package/admin/js/views/components.js +4 -4
- package/admin/js/views/dashboard/widgets/cache.js +1 -1
- package/admin/js/views/dashboard/widgets/journeys.js +1 -1
- package/admin/js/views/dashboard/widgets/kpi-strip.js +1 -1
- package/admin/js/views/form-editor.js +7 -7
- package/admin/js/views/form-submissions.js +1 -1
- package/admin/js/views/forms.js +1 -1
- package/admin/js/views/layouts.js +1 -1
- package/admin/js/views/login.js +2 -2
- package/admin/js/views/menu-editor.js +3 -3
- package/admin/js/views/menu-locations.js +1 -1
- package/admin/js/views/menus.js +3 -3
- package/admin/js/views/navigation.js +8 -8
- package/admin/js/views/page-editor.js +40 -40
- package/admin/js/views/pages.js +3 -3
- package/admin/js/views/plugin-code.js +2 -2
- package/admin/js/views/plugins.js +1 -1
- package/admin/js/views/project-settings.js +1 -1
- package/admin/js/views/projects.js +1 -1
- package/admin/js/views/roles.js +1 -1
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/users.js +3 -3
- package/admin/js/views/view-editor.js +1 -1
- package/admin/js/views/view-preview.js +1 -1
- package/admin/js/views/views-list.js +1 -1
- package/bin/cli.js +8 -8
- package/bin/lib/config-merge.js +5 -5
- package/bin/update.js +16 -16
- package/config/site.json +86 -86
- package/package.json +2 -2
- package/plugins/_template/admin/views/index.js +1 -1
- package/plugins/_template/config.js +1 -1
- package/plugins/_template/plugin.js +1 -1
- package/plugins/analytics/admin/templates/analytics.html +3 -3
- package/plugins/analytics/admin/views/analytics.js +1 -1
- package/plugins/analytics/config.js +1 -1
- package/plugins/analytics/plugin.js +4 -4
- package/plugins/analytics/plugin.json +1 -1
- package/plugins/analytics/public/inject-body.html +2 -2
- package/plugins/analytics/public/inject-head.html +1 -1
- package/plugins/blog/admin/templates/blog.html +4 -4
- package/plugins/blog/admin/views/blog.js +3 -3
- package/plugins/blog/admin/views/categories.js +2 -2
- package/plugins/blog/admin/views/comments.js +4 -4
- package/plugins/blog/admin/views/post-editor.js +1 -1
- package/plugins/blog/plugin.js +2 -2
- package/plugins/blog/plugin.json +4 -4
- package/plugins/contacts/admin/views/contacts.js +8 -8
- package/plugins/contacts/plugin.js +4 -4
- package/plugins/contacts/plugin.json +1 -1
- package/plugins/invoice/admin/templates/editor.html +6 -6
- package/plugins/invoice/admin/templates/index.html +4 -4
- package/plugins/invoice/admin/views/editor.js +3 -3
- package/plugins/invoice/admin/views/index.js +4 -4
- package/plugins/invoice/admin/views/issuers.js +1 -1
- package/plugins/invoice/admin/views/party-view.js +3 -3
- package/plugins/invoice/admin/views/receivers.js +1 -1
- package/plugins/invoice/config.js +1 -1
- package/plugins/invoice/plugin.js +1 -1
- package/plugins/invoice/plugin.json +4 -4
- package/plugins/notes/admin/views/notes.js +4 -4
- package/plugins/notes/plugin.js +1 -1
- package/plugins/notes/plugin.json +1 -1
- package/plugins/site-search/admin/templates/site-search.html +3 -3
- package/plugins/site-search/admin/views/site-search.js +1 -1
- package/plugins/site-search/config.js +1 -1
- package/plugins/site-search/plugin.js +4 -4
- package/plugins/site-search/plugin.json +1 -1
- package/plugins/surveys/admin/templates/results.html +1 -1
- package/plugins/surveys/admin/templates/survey-editor.html +4 -4
- package/plugins/surveys/admin/views/audience.js +6 -6
- package/plugins/surveys/admin/views/results.js +3 -3
- package/plugins/surveys/admin/views/survey-editor.js +1 -1
- package/plugins/surveys/admin/views/surveys.js +2 -2
- package/plugins/surveys/plugin.js +1 -1
- package/plugins/surveys/plugin.json +4 -4
- package/plugins/theme-switcher/admin/views/theme-switcher.js +1 -1
- package/plugins/theme-switcher/plugin.json +3 -3
- package/plugins/theme-switcher/public/inject-body.html +28 -28
- package/plugins/theme-switcher/public/inject-head.html +1 -1
- package/plugins/todo/plugin.js +1 -1
- package/public/css/forms.css +1 -1
- package/public/js/collection-browser.js +1 -1
- package/public/js/collection-context.js +1 -1
- package/public/js/form-logic-engine.js +1 -1
- package/public/js/forms.js +2 -1
- package/public/js/site.js +1 -1
- package/scripts/build.js +100 -6
- package/scripts/create-plugin.js +2 -2
- package/scripts/fresh.js +2 -2
- package/scripts/gen-instance-secret.js +1 -1
- package/scripts/pro.js +12 -12
- package/scripts/reset.js +2 -2
- package/scripts/setup.js +15 -15
- package/scripts/users.js +5 -5
- package/scripts/verify-assets.mjs +6 -6
- package/server/config.js +1 -1
- package/server/middleware/auth.js +11 -11
- package/server/middleware/managerAuth.js +3 -3
- package/server/routes/api/actions.js +4 -4
- package/server/routes/api/api-endpoints.js +7 -7
- package/server/routes/api/api-tokens.js +5 -5
- package/server/routes/api/auth.js +10 -10
- package/server/routes/api/blocks.js +3 -3
- package/server/routes/api/collections.js +18 -18
- package/server/routes/api/dashboard.js +5 -5
- package/server/routes/api/effects.js +2 -2
- package/server/routes/api/endpoints-public.js +5 -5
- package/server/routes/api/forms.js +47 -47
- package/server/routes/api/menu-locations.js +3 -3
- package/server/routes/api/menus.js +7 -7
- package/server/routes/api/notifications.js +2 -2
- package/server/routes/api/pages.js +14 -2
- package/server/routes/api/plugin-marketplace.js +3 -3
- package/server/routes/api/plugins.js +6 -6
- package/server/routes/api/projects.js +9 -9
- package/server/routes/api/scaffold.js +7 -7
- package/server/routes/api/settings.js +6 -6
- package/server/routes/api/sidebar.js +1 -1
- package/server/routes/api/users.js +5 -5
- package/server/routes/api/versions.js +1 -1
- package/server/routes/api/views.js +1 -1
- package/server/routes/docs-public.js +3 -3
- package/server/routes/public.js +14 -14
- package/server/server.js +34 -16
- package/server/services/actions.js +19 -19
- package/server/services/adapters/FileAdapter.js +2 -2
- package/server/services/adapters/MongoAdapter.js +5 -5
- package/server/services/apiEndpoints.js +15 -15
- package/server/services/apiTokens.js +7 -7
- package/server/services/blocks.js +13 -13
- package/server/services/cache/drivers/MemoryDriver.js +3 -3
- package/server/services/cache/drivers/NoneDriver.js +1 -1
- package/server/services/cache/index.js +5 -5
- package/server/services/collections.js +14 -14
- package/server/services/components.js +9 -9
- package/server/services/connectionManager.js +4 -4
- package/server/services/content.js +25 -2
- package/server/services/docs.js +14 -14
- package/server/services/email.js +1 -1
- package/server/services/filterEngine.js +6 -6
- package/server/services/forms.js +18 -10
- package/server/services/health.js +1 -1
- package/server/services/hooks.js +7 -7
- package/server/services/images.js +4 -4
- package/server/services/managerClient.js +1 -1
- package/server/services/markdown.js +79 -79
- package/server/services/menuRender.js +5 -5
- package/server/services/menus-migration.js +3 -3
- package/server/services/menus.js +31 -31
- package/server/services/permissionRegistry.js +1 -1
- package/server/services/pluginFiles.js +5 -5
- package/server/services/pluginInstaller.js +17 -17
- package/server/services/pluginScaffold.js +1 -1
- package/server/services/plugins.js +17 -17
- package/server/services/presetCollections.js +2 -2
- package/server/services/projects.js +35 -26
- package/server/services/recipes/contact-list.json +1 -1
- package/server/services/recipes/onboarding.json +8 -8
- package/server/services/references.js +8 -8
- package/server/services/renderer.js +9 -9
- package/server/services/roles.js +9 -9
- package/server/services/rowAccess.js +10 -10
- package/server/services/scaffolder.js +30 -30
- package/server/services/sidebar-migration.js +10 -10
- package/server/services/sitemap.js +1 -1
- package/server/services/userProfiles.js +4 -4
- package/server/services/userRoles.js +7 -7
- package/server/services/users.js +5 -5
- package/server/services/versions.js +3 -3
- package/server/services/viewPipeline.js +6 -6
- package/server/services/views.js +11 -11
- package/server/templates/page.html +5 -5
- package/config/navigation.json.bak +0 -31
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
],
|
|
33
33
|
"views": {
|
|
34
34
|
"pluginThemeSwitcher": {
|
|
35
|
-
"entry": "theme-switcher/admin/views/theme-switcher.js?v=
|
|
35
|
+
"entry": "theme-switcher/admin/views/theme-switcher.js?v=c906bed1",
|
|
36
36
|
"exportName": "themeSwitcherView"
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"options": [
|
|
47
47
|
{
|
|
48
48
|
"value": "right-center",
|
|
49
|
-
"label": "Right
|
|
49
|
+
"label": "Right - Centre"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
"value": "left-center",
|
|
53
|
-
"label": "Left
|
|
53
|
+
"label": "Left - Centre"
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
56
|
"value": "bottom-right",
|
|
@@ -1,30 +1,6 @@
|
|
|
1
1
|
<div class="dm-theme-switcher" id="dm-theme-switcher" role="navigation" aria-label="Theme switcher">
|
|
2
2
|
<button class="dm-ts-trigger" data-tooltip="Switch theme" aria-haspopup="true" aria-expanded="false"></button>
|
|
3
3
|
<div class="dm-ts-options" role="menu">
|
|
4
|
-
<button class="dm-ts-dot dm-ts-dot-ocean-dark" data-theme="ocean-dark" data-tooltip="Ocean Dark"
|
|
5
|
-
aria-label="Ocean Dark"></button>
|
|
6
|
-
<button class="dm-ts-dot dm-ts-dot-ocean-light" data-theme="ocean-light" data-tooltip="Ocean Light"
|
|
7
|
-
aria-label="Ocean Light"></button>
|
|
8
|
-
<button class="dm-ts-dot dm-ts-dot-forest-dark" data-theme="forest-dark" data-tooltip="Forest Dark"
|
|
9
|
-
aria-label="Forest Dark"></button>
|
|
10
|
-
<button class="dm-ts-dot dm-ts-dot-forest-light" data-theme="forest-light" data-tooltip="Forest Light"
|
|
11
|
-
aria-label="Forest Light"></button>
|
|
12
|
-
<button class="dm-ts-dot dm-ts-dot-sunset-dark" data-theme="sunset-dark" data-tooltip="Sunset Dark"
|
|
13
|
-
aria-label="Sunset Dark"></button>
|
|
14
|
-
<button class="dm-ts-dot dm-ts-dot-sunset-light" data-theme="sunset-light" data-tooltip="Sunset Light"
|
|
15
|
-
aria-label="Sunset Light"></button>
|
|
16
|
-
<button class="dm-ts-dot dm-ts-dot-royal-dark" data-theme="royal-dark" data-tooltip="Royal Dark"
|
|
17
|
-
aria-label="Royal Dark"></button>
|
|
18
|
-
<button class="dm-ts-dot dm-ts-dot-royal-light" data-theme="royal-light" data-tooltip="Royal Light"
|
|
19
|
-
aria-label="Royal Light"></button>
|
|
20
|
-
<button class="dm-ts-dot dm-ts-dot-lemon-dark" data-theme="lemon-dark" data-tooltip="Lemon Dark"
|
|
21
|
-
aria-label="Lemon Dark"></button>
|
|
22
|
-
<button class="dm-ts-dot dm-ts-dot-lemon-light" data-theme="lemon-light" data-tooltip="Lemon Light"
|
|
23
|
-
aria-label="Lemon Light"></button>
|
|
24
|
-
<button class="dm-ts-dot dm-ts-dot-silver-dark" data-theme="silver-dark" data-tooltip="Silver Dark"
|
|
25
|
-
aria-label="Silver Dark"></button>
|
|
26
|
-
<button class="dm-ts-dot dm-ts-dot-silver-light" data-theme="silver-light" data-tooltip="Silver Light"
|
|
27
|
-
aria-label="Silver Light"></button>
|
|
28
4
|
<button class="dm-ts-dot dm-ts-dot-charcoal-dark" data-theme="charcoal-dark" data-tooltip="Charcoal Dark"
|
|
29
5
|
aria-label="Charcoal Dark"></button>
|
|
30
6
|
<button class="dm-ts-dot dm-ts-dot-charcoal-light" data-theme="charcoal-light" data-tooltip="Charcoal Light"
|
|
@@ -33,22 +9,46 @@
|
|
|
33
9
|
aria-label="Christmas Dark"></button>
|
|
34
10
|
<button class="dm-ts-dot dm-ts-dot-christmas-light" data-theme="christmas-light" data-tooltip="Christmas Light"
|
|
35
11
|
aria-label="Christmas Light"></button>
|
|
36
|
-
<button class="dm-ts-dot dm-ts-dot-unicorn-dark" data-theme="unicorn-dark" data-tooltip="Unicorn Dark"
|
|
37
|
-
aria-label="Unicorn Dark"></button>
|
|
38
|
-
<button class="dm-ts-dot dm-ts-dot-unicorn-light" data-theme="unicorn-light" data-tooltip="Unicorn Light"
|
|
39
|
-
aria-label="Unicorn Light"></button>
|
|
40
12
|
<button class="dm-ts-dot dm-ts-dot-dreamy-dark" data-theme="dreamy-dark" data-tooltip="Dreamy Dark"
|
|
41
13
|
aria-label="Dreamy Dark"></button>
|
|
42
14
|
<button class="dm-ts-dot dm-ts-dot-dreamy-light" data-theme="dreamy-light" data-tooltip="Dreamy Light"
|
|
43
15
|
aria-label="Dreamy Light"></button>
|
|
16
|
+
<button class="dm-ts-dot dm-ts-dot-forest-dark" data-theme="forest-dark" data-tooltip="Forest Dark"
|
|
17
|
+
aria-label="Forest Dark"></button>
|
|
18
|
+
<button class="dm-ts-dot dm-ts-dot-forest-light" data-theme="forest-light" data-tooltip="Forest Light"
|
|
19
|
+
aria-label="Forest Light"></button>
|
|
44
20
|
<button class="dm-ts-dot dm-ts-dot-grayve-dark" data-theme="grayve-dark" data-tooltip="Grayve Dark"
|
|
45
21
|
aria-label="Grayve Dark"></button>
|
|
46
22
|
<button class="dm-ts-dot dm-ts-dot-grayve-light" data-theme="grayve-light" data-tooltip="Grayve Light"
|
|
47
23
|
aria-label="Grayve Light"></button>
|
|
24
|
+
<button class="dm-ts-dot dm-ts-dot-lemon-dark" data-theme="lemon-dark" data-tooltip="Lemon Dark"
|
|
25
|
+
aria-label="Lemon Dark"></button>
|
|
26
|
+
<button class="dm-ts-dot dm-ts-dot-lemon-light" data-theme="lemon-light" data-tooltip="Lemon Light"
|
|
27
|
+
aria-label="Lemon Light"></button>
|
|
48
28
|
<button class="dm-ts-dot dm-ts-dot-mint-dark" data-theme="mint-dark" data-tooltip="Mint Dark"
|
|
49
29
|
aria-label="Mint Dark"></button>
|
|
50
30
|
<button class="dm-ts-dot dm-ts-dot-mint-light" data-theme="mint-light" data-tooltip="Mint Light"
|
|
51
31
|
aria-label="Mint Light"></button>
|
|
32
|
+
<button class="dm-ts-dot dm-ts-dot-ocean-dark" data-theme="ocean-dark" data-tooltip="Ocean Dark"
|
|
33
|
+
aria-label="Ocean Dark"></button>
|
|
34
|
+
<button class="dm-ts-dot dm-ts-dot-ocean-light" data-theme="ocean-light" data-tooltip="Ocean Light"
|
|
35
|
+
aria-label="Ocean Light"></button>
|
|
36
|
+
<button class="dm-ts-dot dm-ts-dot-royal-dark" data-theme="royal-dark" data-tooltip="Royal Dark"
|
|
37
|
+
aria-label="Royal Dark"></button>
|
|
38
|
+
<button class="dm-ts-dot dm-ts-dot-royal-light" data-theme="royal-light" data-tooltip="Royal Light"
|
|
39
|
+
aria-label="Royal Light"></button>
|
|
40
|
+
<button class="dm-ts-dot dm-ts-dot-silver-dark" data-theme="silver-dark" data-tooltip="Silver Dark"
|
|
41
|
+
aria-label="Silver Dark"></button>
|
|
42
|
+
<button class="dm-ts-dot dm-ts-dot-silver-light" data-theme="silver-light" data-tooltip="Silver Light"
|
|
43
|
+
aria-label="Silver Light"></button>
|
|
44
|
+
<button class="dm-ts-dot dm-ts-dot-sunset-dark" data-theme="sunset-dark" data-tooltip="Sunset Dark"
|
|
45
|
+
aria-label="Sunset Dark"></button>
|
|
46
|
+
<button class="dm-ts-dot dm-ts-dot-sunset-light" data-theme="sunset-light" data-tooltip="Sunset Light"
|
|
47
|
+
aria-label="Sunset Light"></button>
|
|
48
|
+
<button class="dm-ts-dot dm-ts-dot-unicorn-dark" data-theme="unicorn-dark" data-tooltip="Unicorn Dark"
|
|
49
|
+
aria-label="Unicorn Dark"></button>
|
|
50
|
+
<button class="dm-ts-dot dm-ts-dot-unicorn-light" data-theme="unicorn-light" data-tooltip="Unicorn Light"
|
|
51
|
+
aria-label="Unicorn Light"></button>
|
|
52
52
|
<button class="dm-ts-dot dm-ts-dot-wedding-dark" data-theme="wedding-dark" data-tooltip="Wedding Dark"
|
|
53
53
|
aria-label="Wedding Dark"></button>
|
|
54
54
|
<button class="dm-ts-dot dm-ts-dot-wedding-light" data-theme="wedding-light" data-tooltip="Wedding Light"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<style>
|
|
2
2
|
/* ============================================================
|
|
3
|
-
Theme Switcher
|
|
3
|
+
Theme Switcher - Floating Disc
|
|
4
4
|
Position is applied inline by inject-body.html script.
|
|
5
5
|
============================================================ */
|
|
6
6
|
.dm-theme-switcher {
|
package/plugins/todo/plugin.js
CHANGED
|
@@ -78,7 +78,7 @@ export default async function todoPlugin(fastify, options) {
|
|
|
78
78
|
return reply.send(toTodo(updated));
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
/** DELETE /api/plugins/todo/completed
|
|
81
|
+
/** DELETE /api/plugins/todo/completed - must be registered before /:id */
|
|
82
82
|
fastify.delete('/completed', {preHandler: [authenticate]}, async (request, reply) => {
|
|
83
83
|
const uid = userId(request);
|
|
84
84
|
const all = await loadAll(uid);
|
package/public/css/forms.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.fb-form-wrapper{max-width:600px;margin:2rem auto}.fb-form-honeypot{position:absolute;left:-9999px;top:-9999px;width:0;height:0;overflow:hidden;opacity:0;z-index:-1}.fb-form-success{padding:1rem 1.25rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-success) 12%,transparent);border:1px solid color-mix(in srgb,var(--dm-success) 30%,transparent);color:var(--dm-success);font-size:.95rem;margin-top:.5rem}.fb-form-error{padding:.75rem 1rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-danger) 10%,transparent);border:1px solid color-mix(in srgb,var(--dm-danger) 25%,transparent);color:var(--dm-danger);font-size:.875rem;margin-top:.75rem}.fb-form-loading{opacity:.6;pointer-events:none}.wizard-progress{height:4px;background:var(--dm-border);border-radius:2px;margin-bottom:1rem}.wizard-progress-bar{height:100%;background:var(--dm-primary);border-radius:2px;transition:width .3s ease}.wizard-step-title{font-size:1.1rem;font-weight:600;margin-bottom:.25rem}.wizard-step-description{font-size:.875rem;color:var(--dm-text-muted);margin-bottom:1rem}.wizard-nav{display:flex;justify-content:space-between;gap:.5rem;margin-top:1rem}.fb-field-hidden{display:none!important}.fb-validation-error{color:var(--dm-danger);font-size:.8rem;margin-top:.25rem}.fb-form-wrapper .domma-form-field{margin-bottom:2rem}.fb-form-wrapper .form-group:not(.form-buttons){margin-bottom:2rem}.fb-spacer{height:2rem}.fb-field-required .picker-label:after,.fb-field-required>.form-label:after{content:" *";color:var(--dm-danger)}.fb-field-required .picker-label .picker-required{display:none}
|
|
1
|
+
.fb-form-wrapper{max-width:600px;margin:2rem auto}.fb-form-honeypot{position:absolute;left:-9999px;top:-9999px;width:0;height:0;overflow:hidden;opacity:0;z-index:-1}.fb-form-success{padding:1rem 1.25rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-success) 12%,transparent);border:1px solid color-mix(in srgb,var(--dm-success) 30%,transparent);color:var(--dm-success);font-size:.95rem;margin-top:.5rem}.fb-form-error{padding:.75rem 1rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-danger) 10%,transparent);border:1px solid color-mix(in srgb,var(--dm-danger) 25%,transparent);color:var(--dm-danger);font-size:.875rem;margin-top:.75rem}.fb-form-loading{opacity:.6;pointer-events:none}.wizard-progress{height:4px;background:var(--dm-border);border-radius:2px;margin-bottom:1rem}.wizard-progress-bar{height:100%;background:var(--dm-primary);border-radius:2px;transition:width .3s ease}.wizard-step-title{font-size:1.1rem;font-weight:600;margin-bottom:.25rem}.wizard-step-description{font-size:.875rem;color:var(--dm-text-muted);margin-bottom:1rem}.wizard-nav{display:flex;justify-content:space-between;gap:.5rem;margin-top:1rem}.fb-field-hidden{display:none!important}.fb-validation-error{color:var(--dm-danger);font-size:.8rem;margin-top:.25rem}.fb-form-wrapper .domma-form-field{margin-bottom:2rem}.fb-form-wrapper .form-group:not(.form-buttons){margin-bottom:2rem}.fb-spacer{height:2rem}.fb-field-required .picker-label:after,.fb-field-required>.form-label:after{content:" *";color:var(--dm-danger)}.fb-field-required .picker-label .picker-required{display:none}.fb-field-invalid>.form-label,.fb-field-invalid .picker-label{color:var(--dm-danger)}.fb-field-invalid .form-input,.fb-field-invalid .form-select,.fb-field-invalid textarea,.fb-field-invalid .picker-options{border-color:var(--dm-danger)}@media(max-width:700px){.fb-form-wrapper form.grid,[data-form-inline] form.grid,.fb-form-wrapper .wizard form.grid,[data-form-inline] .wizard form.grid{grid-template-columns:1fr!important}.fb-form-wrapper form.grid>[class*=col-span-],[data-form-inline] form.grid>[class*=col-span-]{grid-column:span 1 / span 1!important}}.wizard-nav{gap:1rem;flex-wrap:wrap}.wizard-nav .btn{min-width:7.5rem}@media(max-width:480px){.wizard-nav{flex-direction:column-reverse}.wizard-nav .btn{width:100%}}.fb-form-wrapper .form-buttons,[data-form-inline] .form-buttons{display:flex;gap:1rem;flex-wrap:wrap;margin-top:1.25rem}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const __browsers=[];(function(){const t=document.querySelectorAll(".dm-collection-browser");t.length&&(t.forEach((e,i)=>{try{__browsers.push(new CollectionBrowser(e,i))}catch(n){console.error("[collection-browser] hydration failed:",n)}}),installGlobalKeyboardNav())})();function installGlobalKeyboardNav(){__browsers.length&&document.addEventListener("keydown",l=>{const t=l.target&&(l.target.tagName==="INPUT"||l.target.tagName==="TEXTAREA"||l.target.isContentEditable);if(l.key==="/"&&!t){const i=__browsers[0]?.el.querySelector(".dm-cb-search-input");i&&(l.preventDefault(),i.focus(),i.select());return}if((l.key==="ArrowLeft"||l.key==="ArrowRight")&&!t){const e=__browsers.find(s=>s.el.contains(l.target))||__browsers[0];if(!e)return;const i=Math.max(1,Math.ceil(e.currentTotal/e.config.pageSize)),n=l.key==="ArrowRight"?Math.min(i,e.state.page+1):Math.max(1,e.state.page-1);n!==e.state.page&&(l.preventDefault(),e.setState({page:n}))}})}function decodePayload(l){if(!l)return null;try{const t=atob(l),e=decodeURIComponent(escape(t));return JSON.parse(e)}catch{try{return JSON.parse(atob(l))}catch{return null}}}function clear(l){l&&typeof l.replaceChildren=="function"&&l.replaceChildren()}function distinctValues(l,t){const e=new Set;for(const i of l||[]){const n=i?.data?.[t];n!=null&&(Array.isArray(n)?n.forEach(s=>s!=null&&e.add(String(s))):e.add(String(n)))}return[...e].sort()}class CollectionBrowser{constructor(t,e){this.el=t,this.config=decodePayload(t.dataset.cbConfig)||{},this.schema=decodePayload(t.dataset.cbSchema)||{fields:[]};const i=decodePayload(t.dataset.cbData)||{entries:[],total:0,page:1,pageSize:12},n=(this.config.id||`${this.config.slug}-${e}`).replace(/[^a-z0-9]/gi,"_");let s=n,r=1;for(;__browsers.some(a=>a.idScope===s);)r+=1,s=`${n}_${r}`;this.idScope=s,this.urlPrefix=`cb_${s}_`,this._fragReqId=0,this.entries=i.entries||[],this.total=i.total||0,this.state={search:"",filter:{},sort:this.config.initial?.sort||"createdAt",order:this.config.initial?.order||"desc",page:1},this.readUrlState(),this.buildSkeleton(),this.refresh()}buildSkeleton(){clear(this.el);const t=elt("div","dm-cb-header");this.config.filterable?.length&&t.appendChild(this.buildDrawerToggle()),this.config.searchable&&t.appendChild(this.buildSearchInput()),this.config.sortable&&t.appendChild(this.buildSortControl()),this.config.savedSearches!==!1&&t.appendChild(this.buildSavedSearches()),this.config.exportable&&t.appendChild(this.buildExportButton());const e=elt("div","dm-cb-layout");this.filterRail=elt("aside","dm-cb-filter-rail"),this.bodyEl=elt("div","dm-cb-body"),e.appendChild(this.filterRail),e.appendChild(this.bodyEl),this.config.filterable?.length?this.renderFilterRail():this.filterRail.style.display="none",this.pagerEl=elt("div","dm-cb-pagination"),t.childElementCount&&this.el.appendChild(t),this.el.appendChild(e),this.el.appendChild(this.pagerEl),this.el.classList.add("dm-cb-hydrated")}buildSavedSearches(){const t=elt("div","dm-cb-saved"),e=elt("button","dm-cb-saved-toggle btn btn-outline");e.type="button",e.textContent="Saved \u25BE",t.appendChild(e);const i=elt("div","dm-cb-saved-menu");i.hidden=!0,t.appendChild(i);const n=()=>{clear(i);const s=this.loadSavedSearches();if(!s.length){const o=elt("p","dm-cb-saved-empty");o.textContent="No saved views yet.",i.appendChild(o)}for(const o of s){const c=elt("div","dm-cb-saved-item"),d=elt("button","dm-cb-saved-apply");d.type="button",d.textContent=o.name,d.addEventListener("click",()=>{this.state.search=o.search||"",this.state.filter={...o.filter||{}},this.state.sort=o.sort||this.config.initial?.sort||"createdAt",this.state.order=o.order||this.config.initial?.order||"desc",this.state.page=1,this.renderFilterRail();const p=this.el.querySelector(".dm-cb-search-input");p&&(p.value=this.state.search),i.hidden=!0,this.refresh()});const h=elt("button","dm-cb-saved-del");h.type="button",h.textContent="\xD7",h.title="Delete saved view",h.addEventListener("click",p=>{p.stopPropagation(),this.deleteSavedSearch(o.name),n()}),c.appendChild(d),c.appendChild(h),i.appendChild(c)}const r=elt("div","dm-cb-saved-actions"),a=elt("button","dm-cb-saved-create btn btn-primary");a.type="button",a.textContent="Save current view",a.addEventListener("click",async()=>{const o=await this.promptName();o&&(this.addSavedSearch({name:o,search:this.state.search,filter:this.state.filter,sort:this.state.sort,order:this.state.order}),n())}),r.appendChild(a),i.appendChild(r)};return e.addEventListener("click",()=>{i.hidden=!i.hidden,i.hidden||n()}),document.addEventListener("click",s=>{t.contains(s.target)||(i.hidden=!0)}),t}async promptName(){const t=typeof window<"u"&&typeof window.prompt=="function"?window.prompt("Name this saved view:"):null;return t&&t.trim()||null}loadSavedSearches(){try{const t=`cb_saved_${this.idScope}`,e=typeof S<"u"&&S.get?S.get(t):null;return Array.isArray(e)?e:[]}catch{return[]}}addSavedSearch(t){const e=this.loadSavedSearches().filter(i=>i.name!==t.name);e.push(t);try{typeof S<"u"&&S.set&&S.set(`cb_saved_${this.idScope}`,e)}catch{}}deleteSavedSearch(t){const e=this.loadSavedSearches().filter(i=>i.name!==t);try{typeof S<"u"&&S.set&&S.set(`cb_saved_${this.idScope}`,e)}catch{}}buildExportButton(){const t=elt("button","dm-cb-export btn btn-outline");return t.type="button",t.textContent="Export CSV",t.addEventListener("click",()=>this.exportCsv()),t}exportCsv(){if(this.config.mode==="client"){let n=this.entries;if(this.state.search){const o=this.state.search.toLowerCase();n=n.filter(c=>Object.values(c.data||{}).some(d=>String(d).toLowerCase().includes(o)))}const s={...this.state.filter,...this.config.baked||{}};n=applyFilterInMemory(n,s);const r=this.visibleFields(n),a=toCsv(n,r);downloadCsv(`${this.config.slug}-export.csv`,a);return}const t=new URLSearchParams;t.set("format","csv"),this.state.search&&t.set("search",this.state.search);const e={...this.state.filter,...this.config.baked||{}};for(const[n,s]of Object.entries(e))t.set(`filter[${n}]`,s);const i=`/api/collections/${encodeURIComponent(this.config.slug)}/export?${t.toString()}`;window.open(i,"_blank")}buildDrawerToggle(){const t=elt("button","dm-cb-drawer-toggle btn btn-outline");t.type="button",t.setAttribute("aria-label","Toggle filters");const e=elt("span","dm-cb-drawer-label");e.textContent="Filters";const i=elt("span","dm-cb-drawer-count");return t.appendChild(e),t.appendChild(document.createTextNode(" ")),t.appendChild(i),t.addEventListener("click",()=>{this.el.classList.toggle("dm-cb-drawer-open")}),t}buildSearchInput(){const t=elt("div","dm-cb-search"),e=elt("input","dm-cb-search-input");return e.type="search",e.placeholder="Search\u2026",e.value=this.state.search,e.addEventListener("input",debounce(()=>{this.setState({search:e.value,page:1})},200)),t.appendChild(e),t}buildSortControl(){const t=elt("div","dm-cb-sort"),e=elt("label","dm-cb-sort-label");e.textContent="Sort:",t.appendChild(e);const i=elt("select","dm-cb-sort-select"),n=this.sortableFieldList();for(const r of n){const a=elt("option");a.value=r.name,a.textContent=r.label,r.name===this.state.sort&&(a.selected=!0),i.appendChild(a)}i.addEventListener("change",()=>this.setState({sort:i.value,page:1})),t.appendChild(i);const s=elt("button","dm-cb-sort-dir");return s.type="button",s.textContent=this.state.order==="asc"?"\u2191":"\u2193",s.title=this.state.order==="asc"?"Ascending":"Descending",s.addEventListener("click",()=>{this.setState({order:this.state.order==="asc"?"desc":"asc",page:1}),s.textContent=this.state.order==="asc"?"\u2191":"\u2193"}),t.appendChild(s),t}sortableFieldList(){const t=this.config.sortableFields?.length?new Set(this.config.sortableFields):null,e=[{name:"createdAt",label:"Most recent"}];for(const i of this.schema.fields||[])t&&!t.has(i.name)||e.push({name:i.name,label:i.label||i.name});return e}renderFilterRail(){clear(this.filterRail);const t=elt("h4","dm-cb-filter-heading");t.textContent="Filters",this.filterRail.appendChild(t);for(const i of this.config.filterable){const n=(this.schema.fields||[]).find(r=>r.name===i);if(!n)continue;const s=this.buildFilterControl(n);s&&this.filterRail.appendChild(s)}const e=elt("button","dm-cb-filter-reset");e.type="button",e.textContent="Clear filters",e.addEventListener("click",()=>this.setState({filter:{},search:"",page:1})),this.filterRail.appendChild(e)}buildFilterControl(t){const e=elt("div","dm-cb-filter"),i=elt("label","dm-cb-filter-label");switch(i.textContent=t.label||t.name,e.appendChild(i),t.type){case"reference":e.appendChild(this.buildReferenceFilter(t));break;case"select":case"chooser":e.appendChild(this.buildSelectControl(t,!1));break;case"multiselect":case"tags":case"tag":e.appendChild(this.buildSelectControl(t,!0));break;case"number":e.appendChild(this.buildRangeControl(t,"number"));break;case"date":case"datetime":e.appendChild(this.buildRangeControl(t,"date"));break;case"boolean":case"checkbox":e.appendChild(this.buildBooleanControl(t));break;default:e.appendChild(this.buildTextControl(t));break}return e}buildReferenceFilter(t){const e=new Map;for(const r of this.entries){const a=r._refs?.[t.name];if(!a)continue;const o=Array.isArray(a)?a:[a];for(const c of o)!c||c.missing||e.has(c.id)||e.set(c.id,c.display)}const i=`${t.name}_eq`,n=elt("select","dm-cb-select"),s=elt("option");s.value="",s.textContent=this.config.mode==="server"?"Any (loaded)":"Any",n.appendChild(s);for(const[r,a]of e){const o=elt("option");o.value=r,o.textContent=a,String(this.state.filter[i]??"")===String(r)&&(o.selected=!0),n.appendChild(o)}return n.addEventListener("change",()=>this.updateFilter(i,n.value)),n}buildTextControl(t){const e=`${t.name}_contains`,i=elt("input","dm-cb-text");return i.type="text",i.placeholder="Contains\u2026",i.value=this.state.filter[e]||"",i.addEventListener("input",debounce(()=>{this.updateFilter(e,i.value.trim())},200)),i}buildSelectControl(t,e){const i=Array.isArray(t.options)&&t.options.length?t.options.map(o=>typeof o=="object"?o:{value:o,label:o}):distinctValues(this.entries,t.name).map(o=>({value:o,label:o})),n=this.config.mode==="client"?this.facetCounts(t.name,e?"_in":"_eq",i.map(o=>o.value)):null;if(e){const o=`${t.name}_in`,c=elt("div","dm-cb-chips"),d=new Set((this.state.filter[o]||"").split(",").filter(Boolean));for(const h of i){const p=elt("button","dm-cb-chip");p.type="button",d.has(String(h.value))&&p.classList.add("dm-cb-chip-active");const u=elt("span","dm-cb-chip-label");if(u.textContent=h.label??h.value,p.appendChild(u),n){const g=elt("span","dm-cb-chip-count");g.textContent=n[String(h.value)]??0,p.appendChild(g)}p.addEventListener("click",()=>{d.has(String(h.value))?d.delete(String(h.value)):d.add(String(h.value)),this.updateFilter(o,d.size?[...d].join(","):"")}),c.appendChild(p)}return c}const s=`${t.name}_eq`,r=elt("select","dm-cb-select"),a=elt("option");a.value="",a.textContent="Any",r.appendChild(a);for(const o of i){const c=elt("option");c.value=o.value;const d=n?` (${n[String(o.value)]??0})`:"";c.textContent=(o.label??o.value)+d,String(this.state.filter[s]??"")===String(o.value)&&(c.selected=!0),r.appendChild(c)}return r.addEventListener("change",()=>this.updateFilter(s,r.value)),r}facetCounts(t,e,i){const n={};for(const[o,c]of Object.entries(this.state.filter||{})){const{field:d}=parseFilterKey(o);d!==t&&(n[o]=c)}let s=this.entries;if(this.state.search){const o=this.state.search.toLowerCase();s=s.filter(c=>Object.values(c.data||{}).some(d=>String(d).toLowerCase().includes(o)))}const r={...n,...this.config.baked||{}};s=applyFilterInMemory(s,r);const a={};for(const o of i){const c={...r,[`${t}${e}`]:String(o)};a[String(o)]=applyFilterInMemory(s,c).length}return a}buildRangeControl(t,e){const i=`${t.name}_gte`,n=`${t.name}_lte`,s=elt("div","dm-cb-range"),r=elt("div","dm-cb-range-inputs"),a=elt("input","dm-cb-range-min"),o=elt("input","dm-cb-range-max");a.type=e,o.type=e,a.placeholder="Min",o.placeholder="Max",a.value=this.state.filter[i]||"",o.value=this.state.filter[n]||"",r.appendChild(a),r.appendChild(document.createTextNode(" \u2013 ")),r.appendChild(o),s.appendChild(r);let c=null;if(e==="number"&&this.config.mode==="client"&&this.entries.length){const h=this.entries.map(p=>Number(p.data?.[t.name])).filter(p=>Number.isFinite(p));if(h.length){const p=Math.min(...h),u=Math.max(...h);u>p&&(c=this.buildDualSlider(p,u,a,o,i,n),s.appendChild(c))}}const d=debounce(()=>{this.updateFilter(i,a.value,!0),this.updateFilter(n,o.value),c&&syncSliderToInputs(c,a.value,o.value)},250);return a.addEventListener("input",d),o.addEventListener("input",d),s}buildDualSlider(t,e,i,n,s,r){const a=elt("div","dm-cb-slider");a.dataset.lo=String(t),a.dataset.hi=String(e);const o=elt("div","dm-cb-slider-track"),c=elt("div","dm-cb-slider-fill");o.appendChild(c),a.appendChild(o);const d=elt("input","dm-cb-slider-handle dm-cb-slider-handle-min"),h=elt("input","dm-cb-slider-handle dm-cb-slider-handle-max");for(const[f,m]of[[d,t],[h,e]])f.type="range",f.min=String(t),f.max=String(e),f.step="any",f.value=String(m);d.value=String(i.value||t),h.value=String(n.value||e),a.appendChild(d),a.appendChild(h);const p=()=>{const f=Math.min(Number(d.value),Number(h.value)),m=Math.max(Number(d.value),Number(h.value)),b=e-t||1;c.style.left=`${(f-t)/b*100}%`,c.style.right=`${100-(m-t)/b*100}%`};p();const u=()=>{Number(d.value)>Number(h.value)&&(d.value=h.value),p(),i.value=d.value,n.value=h.value};d.addEventListener("input",u),h.addEventListener("input",u);const g=()=>{this.updateFilter(s,Number(d.value)>t?d.value:"",!0),this.updateFilter(r,Number(h.value)<e?h.value:"")};return d.addEventListener("change",g),h.addEventListener("change",g),a}buildBooleanControl(t){const e=`${t.name}_eq`,i=elt("select","dm-cb-select");for(const[n,s]of[["","Any"],["true","Yes"],["false","No"]]){const r=elt("option");r.value=n,r.textContent=s,String(this.state.filter[e]??"")===n&&(r.selected=!0),i.appendChild(r)}return i.addEventListener("change",()=>this.updateFilter(e,i.value)),i}updateFilter(t,e,i=!1){const n={...this.state.filter};e===""||e==null?delete n[t]:n[t]=e,this.state.filter=n,this.state.page=1,i||this.refresh()}setState(t){Object.assign(this.state,t),this.refresh()}async refresh(){this.config.syncUrl&&this.writeUrlState(),this.config.mode==="server"&&await this.fetchPage(),this.renderBody(),this.renderPagination(),this.updateFacetCounts(),this.updateDrawerBadge()}updateFacetCounts(){if(this.config.mode==="client"&&this.filterRail)for(const t of this.config.filterable||[]){const e=(this.schema.fields||[]).find(a=>a.name===t);if(!e)continue;const i=e.type==="multiselect"||e.type==="tags"||e.type==="tag"?"_in":"_eq",n=Array.isArray(e.options)&&e.options.length?e.options.map(a=>typeof a=="object"?a:{value:a,label:a}):distinctValues(this.entries,t).map(a=>({value:a,label:a})),s=this.facetCounts(t,i,n.map(a=>a.value)),r=this.filterRail.querySelectorAll(".dm-cb-filter");for(const a of r){const o=a.querySelector(".dm-cb-filter-label");if(!o||o.textContent!==(e.label||e.name))continue;a.querySelectorAll(".dm-cb-chip").forEach((h,p)=>{const u=h.querySelector(".dm-cb-chip-count");u&&n[p]&&(u.textContent=s[String(n[p].value)]??0)});const d=a.querySelector("select.dm-cb-select");d&&Array.from(d.options).forEach(h=>{if(!h.value)return;const p=n.find(u=>String(u.value)===h.value)?.label??h.value;h.textContent=`${p} (${s[h.value]??0})`})}}}updateDrawerBadge(){const t=this.el.querySelector(".dm-cb-drawer-toggle");if(!t)return;const e=(this.state.search?1:0)+Object.keys(this.state.filter||{}).length,i=t.querySelector(".dm-cb-drawer-count");i&&(i.textContent=e>0?`(${e})`:"")}async fetchPage(){const t={...this.state.filter,...this.config.baked||{}},e=new URLSearchParams;e.set("page",this.state.page),e.set("limit",this.config.pageSize),e.set("sort",this.state.sort),e.set("order",this.state.order),this.state.search&&e.set("search",this.state.search);for(const[n,s]of Object.entries(t))e.set(`filter[${n}]`,s);this._fetchAbort&&this._fetchAbort.abort(),this._fetchAbort=new AbortController;const i=this.config.sourceKind==="view"?`/api/views/${encodeURIComponent(this.config.slug)}/public?${e.toString()}`:`/api/collections/${encodeURIComponent(this.config.slug)}/public?${e.toString()}`;try{const n=await fetch(i,{headers:this.authHeaders(),signal:this._fetchAbort.signal});if(!n.ok){this.entries=[],this.total=0;return}const s=await n.json(),r=s.entries||s.results||[];this.entries=r.map(a=>a.data?a:{id:a.id||"",data:a.data||a}),this.total=s.total||r.length}catch(n){if(n.name==="AbortError")return;this.entries=[],this.total=0}}authHeaders(){try{const t=typeof S<"u"&&S.get?S.get("auth_token"):null;return t?{Authorization:`Bearer ${t}`}:{}}catch{return{}}}pipeline(){if(this.config.mode==="server")return{visible:this.entries,total:this.total};let t=this.entries,e=null;if(this.state.search){const c=this.state.search.toLowerCase();e=new Map,t=t.filter(d=>{let h=0;for(const[p,u]of Object.entries(d.data||{})){if(u==null)continue;const g=String(u).toLowerCase();let f=0,m=0;for(;(f=g.indexOf(c,f))!==-1;)m++,f+=c.length;m>0&&(h+=m*(p===this.config.titleField?3:1))}return h>0&&e.set(d.id||d,h),h>0})}if(Object.keys(this.state.filter).length||Object.keys(this.config.baked||{}).length){const c={...this.state.filter,...this.config.baked||{}};t=applyFilterInMemory(t,c)}const i=this.config.initial?.sort||"createdAt",n=this.config.initial?.order||"desc",s=this.state.sort===i&&this.state.order===n;this.state.search&&e&&s?(t=[...t].sort((c,d)=>{const h=e.get(c.id||c)||0;return(e.get(d.id||d)||0)-h}),this._activeSortMode="relevance"):(t=sortEntries(t,this.state.sort,this.state.order),this._activeSortMode=null);const r=t.length,a=(this.state.page-1)*this.config.pageSize;return{visible:t.slice(a,a+this.config.pageSize),total:r}}renderBody(){const{visible:t,total:e}=this.pipeline();if(this.currentTotal=e,clear(this.bodyEl),!t.length){this.bodyEl.appendChild(this.buildEmptyState());return}const i=this.visibleFields(t);this.bodyEl.appendChild(this.renderForDisplay(t,i)),typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(this.bodyEl),this.config.cta&&typeof wireCTAButtons=="function"&&wireCTAButtons(this.bodyEl)}buildEmptyState(){const t=elt("div","dm-collection-display dm-collection-empty"),e=!!this.state.search||Object.keys(this.state.filter||{}).length>0,i=elt("p");if(e){i.textContent="No results for these filters.",t.appendChild(i);const n=elt("button","btn btn-outline dm-cb-empty-clear");n.type="button",n.textContent="Clear filters",n.addEventListener("click",()=>{this.setState({filter:{},search:"",page:1}),this.renderFilterRail();const s=this.el.querySelector(".dm-cb-search-input");s&&(s.value="")}),t.appendChild(n)}else i.textContent=this.config.emptyMsg,t.appendChild(i);return t}visibleFields(t){let e=this.schema.fields||[];return this.config.fields?.length&&(e=this.config.fields.map(i=>e.find(n=>n.name===i)||{name:i,label:i})),!e.length&&t.length&&(e=Object.keys(t[0].data||{}).map(i=>({name:i,label:i}))),e}renderCards(t,e){const i=elt("div",`dm-collection-cards grid grid-cols-${this.config.columns}`);for(const n of t){const s=elt("div","card dm-collection-card"),r=e.find(c=>c.name===this.config.titleField),a=r?fieldDisplay(n,r):this.config.titleField?formatValue(n.data?.[this.config.titleField]):"";if(a){const c=elt("div","card-header");c.textContent=a,s.appendChild(c)}const o=elt("div","card-body");for(const c of e){if(this.config.titleField===c.name||!fieldDisplay(n,c))continue;const h=elt("div","dm-collection-card-field"),p=elt("strong");p.textContent=(c.label||c.name)+": ",h.appendChild(p),h.appendChild(fieldDisplayNode(n,c)),o.appendChild(h)}this.config.cta&&o.appendChild(this.buildCtaButton(n)),this.config.transitions&&o.appendChild(this.buildTransitionsGroup(n)),s.appendChild(o),i.appendChild(s)}return i}renderList(t,e){const i=elt("ul","dm-collection-list");for(const n of t){const s=elt("li","dm-collection-list-item"),r=e.find(c=>c.name===this.config.titleField),a=r?fieldDisplay(n,r):this.config.titleField?formatValue(n.data?.[this.config.titleField]):"";if(a){const c=elt("div","dm-collection-list-title");c.textContent=a,s.appendChild(c)}const o=e.filter(c=>c.name!==this.config.titleField).map(c=>{const d=fieldDisplay(n,c);return d?`${c.label||c.name}: ${d}`:""}).filter(Boolean).join(" \xB7 ");if(o){const c=elt("div","dm-collection-list-meta");c.textContent=o,s.appendChild(c)}this.config.cta&&s.appendChild(this.buildCtaButton(n)),this.config.transitions&&s.appendChild(this.buildTransitionsGroup(n)),i.appendChild(s)}return i}renderTable(t,e){const i=elt("table","dm-collection-table"),n=elt("thead"),s=elt("tr");for(const a of e){const o=elt("th");o.textContent=a.label||a.name,s.appendChild(o)}this.config.cta&&s.appendChild(elt("th")),this.config.transitions&&s.appendChild(elt("th")),n.appendChild(s),i.appendChild(n);const r=elt("tbody");for(const a of t){const o=elt("tr");for(const c of e){const d=elt("td");d.appendChild(fieldDisplayNode(a,c)),o.appendChild(d)}if(this.config.cta){const c=elt("td");c.appendChild(this.buildCtaButton(a)),o.appendChild(c)}if(this.config.transitions){const c=elt("td");c.appendChild(this.buildTransitionsGroup(a)),o.appendChild(c)}r.appendChild(o)}return i.appendChild(r),i}renderAccordion(t){const e=elt("div","accordion dm-collection-accordion");for(const i of t){const n=elt("div","accordion-item"),s=this.config.titleField&&i.data?.[this.config.titleField]||"Untitled",r=this.config.bodyField&&i.data?.[this.config.bodyField]||"",a=elt("button","accordion-header");a.type="button",a.textContent=String(s);const o=elt("div","accordion-panel");o.textContent=String(r),a.addEventListener("click",()=>n.classList.toggle("open")),n.appendChild(a),n.appendChild(o),e.appendChild(n)}return e}buildCtaButton(t){const e=this.config.cta,i=elt("button",`btn btn-${e.style||"primary"} dm-cta-trigger`);if(i.dataset.action=e.action,i.dataset.entry=t.id||"",e.confirm&&(i.dataset.confirm=e.confirm),e.icon){const n=elt("span");n.dataset.icon=e.icon,i.appendChild(n),i.appendChild(document.createTextNode(" "))}return i.appendChild(document.createTextNode(e.label||"Run")),i}buildTransitionsGroup(t){const e=elt("div","dm-cb-transitions");return e.dataset.entry=t.id||"",e.textContent="Loading actions\u2026",Promise.resolve().then(()=>this.loadTransitions(t,e)),e}async loadTransitions(t,e){try{const i=new URLSearchParams({collection:this.config.slug,entryId:t.id||""}),n=await fetch(`/api/actions/transitions?${i.toString()}`,{headers:this.authHeaders()});if(clear(e),!n.ok)return;const{transitions:s}=await n.json();if(!Array.isArray(s)||!s.length)return;for(const r of s){const a=elt("button",`btn btn-${r.trigger?.style||"outline"} dm-cb-transition-btn dm-cta-trigger`);if(a.dataset.action=r.slug,a.dataset.entry=t.id||"",r.trigger?.confirmMessage&&(a.dataset.confirm=r.trigger.confirmMessage),r.trigger?.icon){const o=elt("span");o.dataset.icon=r.trigger.icon,a.appendChild(o),a.appendChild(document.createTextNode(" "))}a.appendChild(document.createTextNode(r.trigger?.label||r.title)),e.appendChild(a)}typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(e),typeof wireCTAButtons=="function"&&wireCTAButtons(e)}catch{clear(e)}}renderPagination(){if(this.config.pagination==="scroll"){this.renderInfiniteSentinel();return}const t=Math.max(1,Math.ceil(this.currentTotal/this.config.pageSize));if(clear(this.pagerEl),t<=1)return;const e=elt("button","dm-cb-page-prev btn btn-outline");e.type="button",e.textContent="\u2039 Prev",e.disabled=this.state.page<=1,e.addEventListener("click",()=>this.setState({page:Math.max(1,this.state.page-1)}));const i=elt("button","dm-cb-page-next btn btn-outline");i.type="button",i.textContent="Next \u203A",i.disabled=this.state.page>=t,i.addEventListener("click",()=>this.setState({page:Math.min(t,this.state.page+1)}));const n=elt("span","dm-cb-page-info");n.textContent=`Page ${this.state.page} of ${t} (${this.currentTotal} entr${this.currentTotal===1?"y":"ies"})`,this.pagerEl.appendChild(e),this.pagerEl.appendChild(n),this.pagerEl.appendChild(i)}renderInfiniteSentinel(){clear(this.pagerEl);const t=Math.max(1,Math.ceil(this.currentTotal/this.config.pageSize));if(this.state.page>=t){const i=elt("p","dm-cb-scroll-end");i.textContent=`All ${this.currentTotal} entries loaded.`,this.pagerEl.appendChild(i);return}const e=elt("div","dm-cb-scroll-sentinel");e.setAttribute("aria-hidden","true"),e.textContent="Loading more\u2026",this.pagerEl.appendChild(e),this._scrollObserver&&this._scrollObserver.disconnect(),this._scrollObserver=new IntersectionObserver(async i=>{i[0].isIntersecting&&(this._scrollObserver.disconnect(),await this.loadMore())},{rootMargin:"200px 0px"}),this._scrollObserver.observe(e)}async loadMore(){const t=this.state.page+1,e=this.currentTotal,i=this.entries,n=this.state.page;this.state.page=t,this.config.syncUrl&&this.writeUrlState();let s;if(this.config.mode==="server")await this.fetchPage(),s=this.entries;else{const{visible:c}=this.pipeline();s=c}if(!s.length){this.state.page=n,this.entries=i,this.currentTotal=e,this.renderPagination();return}const r=this.visibleFields(s),a=this.renderForDisplay(s,r),o=this.bodyEl.firstElementChild;if(o&&o.tagName===a.tagName)for(;a.firstChild;)o.appendChild(a.firstChild);else this.bodyEl.appendChild(a);typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(this.bodyEl),this.config.cta&&typeof wireCTAButtons=="function"&&wireCTAButtons(this.bodyEl),this.renderPagination()}renderForDisplay(t,e){const i=this.config.display;return i==="list"?this.renderList(t,e):i==="table"?this.renderTable(t,e):i==="accordion"?this.renderAccordion(t):i==="timeline"?this.renderTimeline(t):i==="block"?this.renderBlockPlaceholder(t):this.renderCards(t,e)}renderTimeline(t){const e=["vertical","centred","horizontal"].includes(this.config.layout)?this.config.layout:"vertical",i=["minimal","corporate","modern"].includes(this.config.theme)?this.config.theme:"minimal",n=elt("div",`dm-collection-timeline timeline timeline-${e} timeline-${i}`);for(const s of t){const r=elt("div","timeline-event"),a=this.config.dateField&&s.data?.[this.config.dateField]||"",o=this.config.titleField&&s.data?.[this.config.titleField]||"",c=this.config.bodyField&&s.data?.[this.config.bodyField]||"",d=this.config.statusField&&s.data?.[this.config.statusField]||"",h=this.config.iconField&&s.data?.[this.config.iconField]||"";if(h){const p=elt("span","timeline-icon");p.dataset.icon=String(h),r.appendChild(p)}if(a){const p=elt("div","timeline-date");p.textContent=String(a),r.appendChild(p)}if(o){const p=elt("h4","timeline-title");p.textContent=String(o),r.appendChild(p)}if(d){const p=elt("span",`badge badge-${d}`);p.textContent=String(d),r.appendChild(p)}if(c){const p=elt("div","timeline-body");p.textContent=String(c),r.appendChild(p)}n.appendChild(r)}return n}renderBlockPlaceholder(t){const e=elt("div","dm-collection-display dm-cb-block-loading");return e.textContent="Rendering\u2026",this.fetchBlockFragment(t,e),e}async fetchBlockFragment(t,e){const i=++this._fragReqId,n=t.map(a=>a.id).filter(Boolean),s={slug:this.config.slug,display:"block",block:this.config.block,"title-field":this.config.titleField,"body-field":this.config.bodyField,fields:this.config.fields?this.config.fields.join(","):"",empty:this.config.emptyMsg,limit:String(n.length||1)},r={...this.state.filter,...this.config.baked||{}};for(const[a,o]of Object.entries(r))o!==""&&o!=null&&(s[`where_${a}`]=String(o));s.sort=this.state.sort,s.order=this.state.order,s.limit=String(this.config.pageSize);try{const a=btoa(unescape(encodeURIComponent(JSON.stringify(s)))),o=await fetch("/api/collections/render-fragment",{method:"POST",headers:{"Content-Type":"application/json",...this.authHeaders()},body:JSON.stringify({attrs:a,page:this.state.page})});if(i!==this._fragReqId)return;if(!o.ok){e.textContent=this.config.emptyMsg;return}const{html:c}=await o.json(),d=document.createElement("template");d.innerHTML=c||"",e.replaceWith(d.content)}catch{e.textContent="Unable to load block view."}}readUrlState(){if(!this.config.syncUrl)return;const t=new URLSearchParams(window.location.search),e=this.urlPrefix,i=r=>t.get(e+r);i("search")&&(this.state.search=i("search")),i("sort")&&(this.state.sort=i("sort")),i("order")&&(this.state.order=i("order")),i("page")&&(this.state.page=parseInt(i("page"),10)||1);const n={},s=`${e}filter[`;for(const[r,a]of t.entries())if(r.startsWith(s)&&r.endsWith("]")){const o=r.slice(s.length,-1);o&&(n[o]=a)}Object.keys(n).length&&(this.state.filter=n)}writeUrlState(){const t=new URL(window.location.href),e=this.urlPrefix,i=[];for(const s of t.searchParams.keys())s.startsWith(e)&&i.push(s);i.forEach(s=>t.searchParams.delete(s));const n=(s,r)=>{r!==""&&r!=null&&t.searchParams.set(e+s,r)};n("search",this.state.search),this.state.sort!==(this.config.initial?.sort||"createdAt")&&n("sort",this.state.sort),this.state.order!==(this.config.initial?.order||"desc")&&n("order",this.state.order),this.state.page!==1&&n("page",this.state.page);for(const[s,r]of Object.entries(this.state.filter))r!==""&&r!=null&&t.searchParams.set(`${e}filter[${s}]`,r);try{window.history.replaceState({},"",t.toString())}catch{}}}const OPERATORS=["_eq","_ne","_gte","_lte","_gt","_lt","_in","_nin","_contains","_starts","_ends","_exists"];function parseFilterKey(l){for(const t of OPERATORS)if(l.endsWith(t))return{field:l.slice(0,-t.length),op:t};return{field:l,op:"_eq"}}function resolveField(l,t){if(t==="createdBy")return l.meta?.createdBy;if(t==="id")return l.id;const e=t.split(".");let i=l.data;for(const n of e){if(i==null)return;i=i[n]}return i}function maybeNumber(l){if(typeof l=="number"||typeof l!="string")return l;const t=Number(l);return Number.isFinite(t)&&String(t)===l.trim()?t:l}function applyOp(l,t,e){switch(l){case"_eq":{const i=maybeNumber(t),n=maybeNumber(e);return Array.isArray(t)?t.map(maybeNumber).includes(n):i===n||String(i)===String(n)}case"_ne":{const i=maybeNumber(t),n=maybeNumber(e);return Array.isArray(t)?!t.map(maybeNumber).includes(n):!(i===n||String(i)===String(n))}case"_gt":return maybeNumber(t)>maybeNumber(e);case"_gte":return maybeNumber(t)>=maybeNumber(e);case"_lt":return maybeNumber(t)<maybeNumber(e);case"_lte":return maybeNumber(t)<=maybeNumber(e);case"_in":{const i=String(e).split(",").map(n=>maybeNumber(n.trim()));return Array.isArray(t)?t.map(maybeNumber).some(n=>i.includes(n)):i.includes(maybeNumber(t))}case"_nin":{const i=String(e).split(",").map(n=>maybeNumber(n.trim()));return Array.isArray(t)?!t.map(maybeNumber).some(n=>i.includes(n)):!i.includes(maybeNumber(t))}case"_contains":return String(t??"").toLowerCase().includes(String(e).toLowerCase());case"_starts":return String(t??"").toLowerCase().startsWith(String(e).toLowerCase());case"_ends":return String(t??"").toLowerCase().endsWith(String(e).toLowerCase());case"_exists":{const i=t!=null&&t!=="";return e==="true"||e==="1"||e===!0?i:!i}default:return!1}}function applyFilterInMemory(l,t){return!t||!Object.keys(t).length?l:l.filter(e=>{for(const[i,n]of Object.entries(t)){if(n==null||n==="")continue;const{field:s,op:r}=parseFilterKey(i),a=resolveField(e,s);if(!applyOp(r,a,n))return!1}return!0})}function sortEntries(l,t,e){const i=e==="asc"?1:-1;return[...l].sort((n,s)=>{const r=t==="createdAt"?n.meta?.createdAt||"":n.data?.[t]??"",a=t==="createdAt"?s.meta?.createdAt||"":s.data?.[t]??"";return r<a?-i:r>a?i:0})}function elt(l,t){const e=document.createElement(l);return t&&(e.className=t),e}function isFileRef(l){return l&&typeof l=="object"&&typeof l.url=="string"&&typeof l.name=="string"}function formatValue(l){return l==null?"":isFileRef(l)?l.name:Array.isArray(l)?l.join(", "):typeof l=="boolean"?l?"Yes":"No":String(l)}function fieldDisplay(l,t){if(t?.type==="reference"){const e=l?._refs?.[t.name];if(e!=null)return Array.isArray(e)?e.map(i=>i.missing?`${i.id} (missing)`:i.display).join(", "):e.missing?`${e.id} (missing)`:e.display}return formatValue(l?.data?.[t?.name])}function fieldDisplayNode(l,t){if(t?.type==="reference"){const i=l?._refs?.[t.name];if(i!=null){const n=document.createDocumentFragment();return(Array.isArray(i)?i:[i]).forEach((r,a)=>{if(a>0&&n.appendChild(document.createTextNode(", ")),r.missing)n.appendChild(document.createTextNode(`${r.id} (missing)`));else if(r.link){const o=document.createElement("a");o.href=r.link,o.textContent=r.display,n.appendChild(o)}else n.appendChild(document.createTextNode(r.display))}),n}}const e=l?.data?.[t?.name];if(isFileRef(e)){const i=document.createElement("a");if(i.href=e.url,String(e.mime||"").startsWith("image/")){i.target="_blank",i.rel="noopener";const n=document.createElement("img");n.src=e.url,n.alt=e.name,n.loading="lazy",n.className="dm-file-thumb",i.appendChild(n)}else i.download="",i.textContent=e.name;return i}return document.createTextNode(formatValue(e))}function debounce(l,t){let e;return(...i)=>{clearTimeout(e),e=setTimeout(()=>l(...i),t)}}function toCsv(l,t){const e=s=>{if(s==null)return"";let r=Array.isArray(s)?s.join(", "):String(s);return/[",\n\r]/.test(r)&&(r='"'+r.replace(/"/g,'""')+'"'),r},i=t.map(s=>e(s.label||s.name)).join(","),n=l.map(s=>t.map(r=>e(s.data?.[r.name])).join(",")).join(`
|
|
1
|
+
const __browsers=[];(function(){const t=document.querySelectorAll(".dm-collection-browser");t.length&&(t.forEach((e,i)=>{try{__browsers.push(new CollectionBrowser(e,i))}catch(n){console.error("[collection-browser] hydration failed:",n)}}),installGlobalKeyboardNav())})();function installGlobalKeyboardNav(){__browsers.length&&document.addEventListener("keydown",l=>{const t=l.target&&(l.target.tagName==="INPUT"||l.target.tagName==="TEXTAREA"||l.target.isContentEditable);if(l.key==="/"&&!t){const i=__browsers[0]?.el.querySelector(".dm-cb-search-input");i&&(l.preventDefault(),i.focus(),i.select());return}if((l.key==="ArrowLeft"||l.key==="ArrowRight")&&!t){const e=__browsers.find(s=>s.el.contains(l.target))||__browsers[0];if(!e)return;const i=Math.max(1,Math.ceil(e.currentTotal/e.config.pageSize)),n=l.key==="ArrowRight"?Math.min(i,e.state.page+1):Math.max(1,e.state.page-1);n!==e.state.page&&(l.preventDefault(),e.setState({page:n}))}})}function decodePayload(l){if(!l)return null;try{const t=atob(l),e=decodeURIComponent(escape(t));return JSON.parse(e)}catch{try{return JSON.parse(atob(l))}catch{return null}}}function clear(l){l&&typeof l.replaceChildren=="function"&&l.replaceChildren()}function distinctValues(l,t){const e=new Set;for(const i of l||[]){const n=i?.data?.[t];n!=null&&(Array.isArray(n)?n.forEach(s=>s!=null&&e.add(String(s))):e.add(String(n)))}return[...e].sort()}class CollectionBrowser{constructor(t,e){this.el=t,this.config=decodePayload(t.dataset.cbConfig)||{},this.schema=decodePayload(t.dataset.cbSchema)||{fields:[]};const i=decodePayload(t.dataset.cbData)||{entries:[],total:0,page:1,pageSize:12},n=(this.config.id||`${this.config.slug}-${e}`).replace(/[^a-z0-9]/gi,"_");let s=n,r=1;for(;__browsers.some(a=>a.idScope===s);)r+=1,s=`${n}_${r}`;this.idScope=s,this.urlPrefix=`cb_${s}_`,this._fragReqId=0,this.entries=i.entries||[],this.total=i.total||0,this.state={search:"",filter:{},sort:this.config.initial?.sort||"createdAt",order:this.config.initial?.order||"desc",page:1},this.readUrlState(),this.buildSkeleton(),this.refresh()}buildSkeleton(){clear(this.el);const t=elt("div","dm-cb-header");this.config.filterable?.length&&t.appendChild(this.buildDrawerToggle()),this.config.searchable&&t.appendChild(this.buildSearchInput()),this.config.sortable&&t.appendChild(this.buildSortControl()),this.config.savedSearches!==!1&&t.appendChild(this.buildSavedSearches()),this.config.exportable&&t.appendChild(this.buildExportButton());const e=elt("div","dm-cb-layout");this.filterRail=elt("aside","dm-cb-filter-rail"),this.bodyEl=elt("div","dm-cb-body"),e.appendChild(this.filterRail),e.appendChild(this.bodyEl),this.config.filterable?.length?this.renderFilterRail():this.filterRail.style.display="none",this.pagerEl=elt("div","dm-cb-pagination"),t.childElementCount&&this.el.appendChild(t),this.el.appendChild(e),this.el.appendChild(this.pagerEl),this.el.classList.add("dm-cb-hydrated")}buildSavedSearches(){const t=elt("div","dm-cb-saved"),e=elt("button","dm-cb-saved-toggle btn btn-outline");e.type="button",e.textContent="Saved \u25BE",t.appendChild(e);const i=elt("div","dm-cb-saved-menu");i.hidden=!0,t.appendChild(i);const n=()=>{clear(i);const s=this.loadSavedSearches();if(!s.length){const o=elt("p","dm-cb-saved-empty");o.textContent="No saved views yet.",i.appendChild(o)}for(const o of s){const c=elt("div","dm-cb-saved-item"),d=elt("button","dm-cb-saved-apply");d.type="button",d.textContent=o.name,d.addEventListener("click",()=>{this.state.search=o.search||"",this.state.filter={...o.filter||{}},this.state.sort=o.sort||this.config.initial?.sort||"createdAt",this.state.order=o.order||this.config.initial?.order||"desc",this.state.page=1,this.renderFilterRail();const p=this.el.querySelector(".dm-cb-search-input");p&&(p.value=this.state.search),i.hidden=!0,this.refresh()});const h=elt("button","dm-cb-saved-del");h.type="button",h.textContent="\xD7",h.title="Delete saved view",h.addEventListener("click",p=>{p.stopPropagation(),this.deleteSavedSearch(o.name),n()}),c.appendChild(d),c.appendChild(h),i.appendChild(c)}const r=elt("div","dm-cb-saved-actions"),a=elt("button","dm-cb-saved-create btn btn-primary");a.type="button",a.textContent="Save current view",a.addEventListener("click",async()=>{const o=await this.promptName();o&&(this.addSavedSearch({name:o,search:this.state.search,filter:this.state.filter,sort:this.state.sort,order:this.state.order}),n())}),r.appendChild(a),i.appendChild(r)};return e.addEventListener("click",()=>{i.hidden=!i.hidden,i.hidden||n()}),document.addEventListener("click",s=>{t.contains(s.target)||(i.hidden=!0)}),t}async promptName(){const t=typeof window<"u"&&typeof window.prompt=="function"?window.prompt("Name this saved view:"):null;return t&&t.trim()||null}loadSavedSearches(){try{const t=`cb_saved_${this.idScope}`,e=typeof S<"u"&&S.get?S.get(t):null;return Array.isArray(e)?e:[]}catch{return[]}}addSavedSearch(t){const e=this.loadSavedSearches().filter(i=>i.name!==t.name);e.push(t);try{typeof S<"u"&&S.set&&S.set(`cb_saved_${this.idScope}`,e)}catch{}}deleteSavedSearch(t){const e=this.loadSavedSearches().filter(i=>i.name!==t);try{typeof S<"u"&&S.set&&S.set(`cb_saved_${this.idScope}`,e)}catch{}}buildExportButton(){const t=elt("button","dm-cb-export btn btn-outline");return t.type="button",t.textContent="Export CSV",t.addEventListener("click",()=>this.exportCsv()),t}exportCsv(){if(this.config.mode==="client"){let n=this.entries;if(this.state.search){const o=this.state.search.toLowerCase();n=n.filter(c=>Object.values(c.data||{}).some(d=>String(d).toLowerCase().includes(o)))}const s={...this.state.filter,...this.config.baked||{}};n=applyFilterInMemory(n,s);const r=this.visibleFields(n),a=toCsv(n,r);downloadCsv(`${this.config.slug}-export.csv`,a);return}const t=new URLSearchParams;t.set("format","csv"),this.state.search&&t.set("search",this.state.search);const e={...this.state.filter,...this.config.baked||{}};for(const[n,s]of Object.entries(e))t.set(`filter[${n}]`,s);const i=`/api/collections/${encodeURIComponent(this.config.slug)}/export?${t.toString()}`;window.open(i,"_blank")}buildDrawerToggle(){const t=elt("button","dm-cb-drawer-toggle btn btn-outline");t.type="button",t.setAttribute("aria-label","Toggle filters");const e=elt("span","dm-cb-drawer-label");e.textContent="Filters";const i=elt("span","dm-cb-drawer-count");return t.appendChild(e),t.appendChild(document.createTextNode(" ")),t.appendChild(i),t.addEventListener("click",()=>{this.el.classList.toggle("dm-cb-drawer-open")}),t}buildSearchInput(){const t=elt("div","dm-cb-search"),e=elt("input","dm-cb-search-input");return e.type="search",e.placeholder="Search\u2026",e.value=this.state.search,e.addEventListener("input",debounce(()=>{this.setState({search:e.value,page:1})},200)),t.appendChild(e),t}buildSortControl(){const t=elt("div","dm-cb-sort"),e=elt("label","dm-cb-sort-label");e.textContent="Sort:",t.appendChild(e);const i=elt("select","dm-cb-sort-select"),n=this.sortableFieldList();for(const r of n){const a=elt("option");a.value=r.name,a.textContent=r.label,r.name===this.state.sort&&(a.selected=!0),i.appendChild(a)}i.addEventListener("change",()=>this.setState({sort:i.value,page:1})),t.appendChild(i);const s=elt("button","dm-cb-sort-dir");return s.type="button",s.textContent=this.state.order==="asc"?"\u2191":"\u2193",s.title=this.state.order==="asc"?"Ascending":"Descending",s.addEventListener("click",()=>{this.setState({order:this.state.order==="asc"?"desc":"asc",page:1}),s.textContent=this.state.order==="asc"?"\u2191":"\u2193"}),t.appendChild(s),t}sortableFieldList(){const t=this.config.sortableFields?.length?new Set(this.config.sortableFields):null,e=[{name:"createdAt",label:"Most recent"}];for(const i of this.schema.fields||[])t&&!t.has(i.name)||e.push({name:i.name,label:i.label||i.name});return e}renderFilterRail(){clear(this.filterRail);const t=elt("h4","dm-cb-filter-heading");t.textContent="Filters",this.filterRail.appendChild(t);for(const i of this.config.filterable){const n=(this.schema.fields||[]).find(r=>r.name===i);if(!n)continue;const s=this.buildFilterControl(n);s&&this.filterRail.appendChild(s)}const e=elt("button","dm-cb-filter-reset");e.type="button",e.textContent="Clear filters",e.addEventListener("click",()=>this.setState({filter:{},search:"",page:1})),this.filterRail.appendChild(e)}buildFilterControl(t){const e=elt("div","dm-cb-filter"),i=elt("label","dm-cb-filter-label");switch(i.textContent=t.label||t.name,e.appendChild(i),t.type){case"reference":e.appendChild(this.buildReferenceFilter(t));break;case"select":case"chooser":e.appendChild(this.buildSelectControl(t,!1));break;case"multiselect":case"tags":case"tag":e.appendChild(this.buildSelectControl(t,!0));break;case"number":e.appendChild(this.buildRangeControl(t,"number"));break;case"date":case"datetime":e.appendChild(this.buildRangeControl(t,"date"));break;case"boolean":case"checkbox":e.appendChild(this.buildBooleanControl(t));break;default:e.appendChild(this.buildTextControl(t));break}return e}buildReferenceFilter(t){const e=new Map;for(const r of this.entries){const a=r._refs?.[t.name];if(!a)continue;const o=Array.isArray(a)?a:[a];for(const c of o)!c||c.missing||e.has(c.id)||e.set(c.id,c.display)}const i=`${t.name}_eq`,n=elt("select","dm-cb-select"),s=elt("option");s.value="",s.textContent=this.config.mode==="server"?"Any (loaded)":"Any",n.appendChild(s);for(const[r,a]of e){const o=elt("option");o.value=r,o.textContent=a,String(this.state.filter[i]??"")===String(r)&&(o.selected=!0),n.appendChild(o)}return n.addEventListener("change",()=>this.updateFilter(i,n.value)),n}buildTextControl(t){const e=`${t.name}_contains`,i=elt("input","dm-cb-text");return i.type="text",i.placeholder="Contains\u2026",i.value=this.state.filter[e]||"",i.addEventListener("input",debounce(()=>{this.updateFilter(e,i.value.trim())},200)),i}buildSelectControl(t,e){const i=Array.isArray(t.options)&&t.options.length?t.options.map(o=>typeof o=="object"?o:{value:o,label:o}):distinctValues(this.entries,t.name).map(o=>({value:o,label:o})),n=this.config.mode==="client"?this.facetCounts(t.name,e?"_in":"_eq",i.map(o=>o.value)):null;if(e){const o=`${t.name}_in`,c=elt("div","dm-cb-chips"),d=new Set((this.state.filter[o]||"").split(",").filter(Boolean));for(const h of i){const p=elt("button","dm-cb-chip");p.type="button",d.has(String(h.value))&&p.classList.add("dm-cb-chip-active");const u=elt("span","dm-cb-chip-label");if(u.textContent=h.label??h.value,p.appendChild(u),n){const g=elt("span","dm-cb-chip-count");g.textContent=n[String(h.value)]??0,p.appendChild(g)}p.addEventListener("click",()=>{d.has(String(h.value))?d.delete(String(h.value)):d.add(String(h.value)),this.updateFilter(o,d.size?[...d].join(","):"")}),c.appendChild(p)}return c}const s=`${t.name}_eq`,r=elt("select","dm-cb-select"),a=elt("option");a.value="",a.textContent="Any",r.appendChild(a);for(const o of i){const c=elt("option");c.value=o.value;const d=n?` (${n[String(o.value)]??0})`:"";c.textContent=(o.label??o.value)+d,String(this.state.filter[s]??"")===String(o.value)&&(c.selected=!0),r.appendChild(c)}return r.addEventListener("change",()=>this.updateFilter(s,r.value)),r}facetCounts(t,e,i){const n={};for(const[o,c]of Object.entries(this.state.filter||{})){const{field:d}=parseFilterKey(o);d!==t&&(n[o]=c)}let s=this.entries;if(this.state.search){const o=this.state.search.toLowerCase();s=s.filter(c=>Object.values(c.data||{}).some(d=>String(d).toLowerCase().includes(o)))}const r={...n,...this.config.baked||{}};s=applyFilterInMemory(s,r);const a={};for(const o of i){const c={...r,[`${t}${e}`]:String(o)};a[String(o)]=applyFilterInMemory(s,c).length}return a}buildRangeControl(t,e){const i=`${t.name}_gte`,n=`${t.name}_lte`,s=elt("div","dm-cb-range"),r=elt("div","dm-cb-range-inputs"),a=elt("input","dm-cb-range-min"),o=elt("input","dm-cb-range-max");a.type=e,o.type=e,a.placeholder="Min",o.placeholder="Max",a.value=this.state.filter[i]||"",o.value=this.state.filter[n]||"",r.appendChild(a),r.appendChild(document.createTextNode(" - ")),r.appendChild(o),s.appendChild(r);let c=null;if(e==="number"&&this.config.mode==="client"&&this.entries.length){const h=this.entries.map(p=>Number(p.data?.[t.name])).filter(p=>Number.isFinite(p));if(h.length){const p=Math.min(...h),u=Math.max(...h);u>p&&(c=this.buildDualSlider(p,u,a,o,i,n),s.appendChild(c))}}const d=debounce(()=>{this.updateFilter(i,a.value,!0),this.updateFilter(n,o.value),c&&syncSliderToInputs(c,a.value,o.value)},250);return a.addEventListener("input",d),o.addEventListener("input",d),s}buildDualSlider(t,e,i,n,s,r){const a=elt("div","dm-cb-slider");a.dataset.lo=String(t),a.dataset.hi=String(e);const o=elt("div","dm-cb-slider-track"),c=elt("div","dm-cb-slider-fill");o.appendChild(c),a.appendChild(o);const d=elt("input","dm-cb-slider-handle dm-cb-slider-handle-min"),h=elt("input","dm-cb-slider-handle dm-cb-slider-handle-max");for(const[f,m]of[[d,t],[h,e]])f.type="range",f.min=String(t),f.max=String(e),f.step="any",f.value=String(m);d.value=String(i.value||t),h.value=String(n.value||e),a.appendChild(d),a.appendChild(h);const p=()=>{const f=Math.min(Number(d.value),Number(h.value)),m=Math.max(Number(d.value),Number(h.value)),b=e-t||1;c.style.left=`${(f-t)/b*100}%`,c.style.right=`${100-(m-t)/b*100}%`};p();const u=()=>{Number(d.value)>Number(h.value)&&(d.value=h.value),p(),i.value=d.value,n.value=h.value};d.addEventListener("input",u),h.addEventListener("input",u);const g=()=>{this.updateFilter(s,Number(d.value)>t?d.value:"",!0),this.updateFilter(r,Number(h.value)<e?h.value:"")};return d.addEventListener("change",g),h.addEventListener("change",g),a}buildBooleanControl(t){const e=`${t.name}_eq`,i=elt("select","dm-cb-select");for(const[n,s]of[["","Any"],["true","Yes"],["false","No"]]){const r=elt("option");r.value=n,r.textContent=s,String(this.state.filter[e]??"")===n&&(r.selected=!0),i.appendChild(r)}return i.addEventListener("change",()=>this.updateFilter(e,i.value)),i}updateFilter(t,e,i=!1){const n={...this.state.filter};e===""||e==null?delete n[t]:n[t]=e,this.state.filter=n,this.state.page=1,i||this.refresh()}setState(t){Object.assign(this.state,t),this.refresh()}async refresh(){this.config.syncUrl&&this.writeUrlState(),this.config.mode==="server"&&await this.fetchPage(),this.renderBody(),this.renderPagination(),this.updateFacetCounts(),this.updateDrawerBadge()}updateFacetCounts(){if(this.config.mode==="client"&&this.filterRail)for(const t of this.config.filterable||[]){const e=(this.schema.fields||[]).find(a=>a.name===t);if(!e)continue;const i=e.type==="multiselect"||e.type==="tags"||e.type==="tag"?"_in":"_eq",n=Array.isArray(e.options)&&e.options.length?e.options.map(a=>typeof a=="object"?a:{value:a,label:a}):distinctValues(this.entries,t).map(a=>({value:a,label:a})),s=this.facetCounts(t,i,n.map(a=>a.value)),r=this.filterRail.querySelectorAll(".dm-cb-filter");for(const a of r){const o=a.querySelector(".dm-cb-filter-label");if(!o||o.textContent!==(e.label||e.name))continue;a.querySelectorAll(".dm-cb-chip").forEach((h,p)=>{const u=h.querySelector(".dm-cb-chip-count");u&&n[p]&&(u.textContent=s[String(n[p].value)]??0)});const d=a.querySelector("select.dm-cb-select");d&&Array.from(d.options).forEach(h=>{if(!h.value)return;const p=n.find(u=>String(u.value)===h.value)?.label??h.value;h.textContent=`${p} (${s[h.value]??0})`})}}}updateDrawerBadge(){const t=this.el.querySelector(".dm-cb-drawer-toggle");if(!t)return;const e=(this.state.search?1:0)+Object.keys(this.state.filter||{}).length,i=t.querySelector(".dm-cb-drawer-count");i&&(i.textContent=e>0?`(${e})`:"")}async fetchPage(){const t={...this.state.filter,...this.config.baked||{}},e=new URLSearchParams;e.set("page",this.state.page),e.set("limit",this.config.pageSize),e.set("sort",this.state.sort),e.set("order",this.state.order),this.state.search&&e.set("search",this.state.search);for(const[n,s]of Object.entries(t))e.set(`filter[${n}]`,s);this._fetchAbort&&this._fetchAbort.abort(),this._fetchAbort=new AbortController;const i=this.config.sourceKind==="view"?`/api/views/${encodeURIComponent(this.config.slug)}/public?${e.toString()}`:`/api/collections/${encodeURIComponent(this.config.slug)}/public?${e.toString()}`;try{const n=await fetch(i,{headers:this.authHeaders(),signal:this._fetchAbort.signal});if(!n.ok){this.entries=[],this.total=0;return}const s=await n.json(),r=s.entries||s.results||[];this.entries=r.map(a=>a.data?a:{id:a.id||"",data:a.data||a}),this.total=s.total||r.length}catch(n){if(n.name==="AbortError")return;this.entries=[],this.total=0}}authHeaders(){try{const t=typeof S<"u"&&S.get?S.get("auth_token"):null;return t?{Authorization:`Bearer ${t}`}:{}}catch{return{}}}pipeline(){if(this.config.mode==="server")return{visible:this.entries,total:this.total};let t=this.entries,e=null;if(this.state.search){const c=this.state.search.toLowerCase();e=new Map,t=t.filter(d=>{let h=0;for(const[p,u]of Object.entries(d.data||{})){if(u==null)continue;const g=String(u).toLowerCase();let f=0,m=0;for(;(f=g.indexOf(c,f))!==-1;)m++,f+=c.length;m>0&&(h+=m*(p===this.config.titleField?3:1))}return h>0&&e.set(d.id||d,h),h>0})}if(Object.keys(this.state.filter).length||Object.keys(this.config.baked||{}).length){const c={...this.state.filter,...this.config.baked||{}};t=applyFilterInMemory(t,c)}const i=this.config.initial?.sort||"createdAt",n=this.config.initial?.order||"desc",s=this.state.sort===i&&this.state.order===n;this.state.search&&e&&s?(t=[...t].sort((c,d)=>{const h=e.get(c.id||c)||0;return(e.get(d.id||d)||0)-h}),this._activeSortMode="relevance"):(t=sortEntries(t,this.state.sort,this.state.order),this._activeSortMode=null);const r=t.length,a=(this.state.page-1)*this.config.pageSize;return{visible:t.slice(a,a+this.config.pageSize),total:r}}renderBody(){const{visible:t,total:e}=this.pipeline();if(this.currentTotal=e,clear(this.bodyEl),!t.length){this.bodyEl.appendChild(this.buildEmptyState());return}const i=this.visibleFields(t);this.bodyEl.appendChild(this.renderForDisplay(t,i)),typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(this.bodyEl),this.config.cta&&typeof wireCTAButtons=="function"&&wireCTAButtons(this.bodyEl)}buildEmptyState(){const t=elt("div","dm-collection-display dm-collection-empty"),e=!!this.state.search||Object.keys(this.state.filter||{}).length>0,i=elt("p");if(e){i.textContent="No results for these filters.",t.appendChild(i);const n=elt("button","btn btn-outline dm-cb-empty-clear");n.type="button",n.textContent="Clear filters",n.addEventListener("click",()=>{this.setState({filter:{},search:"",page:1}),this.renderFilterRail();const s=this.el.querySelector(".dm-cb-search-input");s&&(s.value="")}),t.appendChild(n)}else i.textContent=this.config.emptyMsg,t.appendChild(i);return t}visibleFields(t){let e=this.schema.fields||[];return this.config.fields?.length&&(e=this.config.fields.map(i=>e.find(n=>n.name===i)||{name:i,label:i})),!e.length&&t.length&&(e=Object.keys(t[0].data||{}).map(i=>({name:i,label:i}))),e}renderCards(t,e){const i=elt("div",`dm-collection-cards grid grid-cols-${this.config.columns}`);for(const n of t){const s=elt("div","card dm-collection-card"),r=e.find(c=>c.name===this.config.titleField),a=r?fieldDisplay(n,r):this.config.titleField?formatValue(n.data?.[this.config.titleField]):"";if(a){const c=elt("div","card-header");c.textContent=a,s.appendChild(c)}const o=elt("div","card-body");for(const c of e){if(this.config.titleField===c.name||!fieldDisplay(n,c))continue;const h=elt("div","dm-collection-card-field"),p=elt("strong");p.textContent=(c.label||c.name)+": ",h.appendChild(p),h.appendChild(fieldDisplayNode(n,c)),o.appendChild(h)}this.config.cta&&o.appendChild(this.buildCtaButton(n)),this.config.transitions&&o.appendChild(this.buildTransitionsGroup(n)),s.appendChild(o),i.appendChild(s)}return i}renderList(t,e){const i=elt("ul","dm-collection-list");for(const n of t){const s=elt("li","dm-collection-list-item"),r=e.find(c=>c.name===this.config.titleField),a=r?fieldDisplay(n,r):this.config.titleField?formatValue(n.data?.[this.config.titleField]):"";if(a){const c=elt("div","dm-collection-list-title");c.textContent=a,s.appendChild(c)}const o=e.filter(c=>c.name!==this.config.titleField).map(c=>{const d=fieldDisplay(n,c);return d?`${c.label||c.name}: ${d}`:""}).filter(Boolean).join(" \xB7 ");if(o){const c=elt("div","dm-collection-list-meta");c.textContent=o,s.appendChild(c)}this.config.cta&&s.appendChild(this.buildCtaButton(n)),this.config.transitions&&s.appendChild(this.buildTransitionsGroup(n)),i.appendChild(s)}return i}renderTable(t,e){const i=elt("table","dm-collection-table"),n=elt("thead"),s=elt("tr");for(const a of e){const o=elt("th");o.textContent=a.label||a.name,s.appendChild(o)}this.config.cta&&s.appendChild(elt("th")),this.config.transitions&&s.appendChild(elt("th")),n.appendChild(s),i.appendChild(n);const r=elt("tbody");for(const a of t){const o=elt("tr");for(const c of e){const d=elt("td");d.appendChild(fieldDisplayNode(a,c)),o.appendChild(d)}if(this.config.cta){const c=elt("td");c.appendChild(this.buildCtaButton(a)),o.appendChild(c)}if(this.config.transitions){const c=elt("td");c.appendChild(this.buildTransitionsGroup(a)),o.appendChild(c)}r.appendChild(o)}return i.appendChild(r),i}renderAccordion(t){const e=elt("div","accordion dm-collection-accordion");for(const i of t){const n=elt("div","accordion-item"),s=this.config.titleField&&i.data?.[this.config.titleField]||"Untitled",r=this.config.bodyField&&i.data?.[this.config.bodyField]||"",a=elt("button","accordion-header");a.type="button",a.textContent=String(s);const o=elt("div","accordion-panel");o.textContent=String(r),a.addEventListener("click",()=>n.classList.toggle("open")),n.appendChild(a),n.appendChild(o),e.appendChild(n)}return e}buildCtaButton(t){const e=this.config.cta,i=elt("button",`btn btn-${e.style||"primary"} dm-cta-trigger`);if(i.dataset.action=e.action,i.dataset.entry=t.id||"",e.confirm&&(i.dataset.confirm=e.confirm),e.icon){const n=elt("span");n.dataset.icon=e.icon,i.appendChild(n),i.appendChild(document.createTextNode(" "))}return i.appendChild(document.createTextNode(e.label||"Run")),i}buildTransitionsGroup(t){const e=elt("div","dm-cb-transitions");return e.dataset.entry=t.id||"",e.textContent="Loading actions\u2026",Promise.resolve().then(()=>this.loadTransitions(t,e)),e}async loadTransitions(t,e){try{const i=new URLSearchParams({collection:this.config.slug,entryId:t.id||""}),n=await fetch(`/api/actions/transitions?${i.toString()}`,{headers:this.authHeaders()});if(clear(e),!n.ok)return;const{transitions:s}=await n.json();if(!Array.isArray(s)||!s.length)return;for(const r of s){const a=elt("button",`btn btn-${r.trigger?.style||"outline"} dm-cb-transition-btn dm-cta-trigger`);if(a.dataset.action=r.slug,a.dataset.entry=t.id||"",r.trigger?.confirmMessage&&(a.dataset.confirm=r.trigger.confirmMessage),r.trigger?.icon){const o=elt("span");o.dataset.icon=r.trigger.icon,a.appendChild(o),a.appendChild(document.createTextNode(" "))}a.appendChild(document.createTextNode(r.trigger?.label||r.title)),e.appendChild(a)}typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(e),typeof wireCTAButtons=="function"&&wireCTAButtons(e)}catch{clear(e)}}renderPagination(){if(this.config.pagination==="scroll"){this.renderInfiniteSentinel();return}const t=Math.max(1,Math.ceil(this.currentTotal/this.config.pageSize));if(clear(this.pagerEl),t<=1)return;const e=elt("button","dm-cb-page-prev btn btn-outline");e.type="button",e.textContent="\u2039 Prev",e.disabled=this.state.page<=1,e.addEventListener("click",()=>this.setState({page:Math.max(1,this.state.page-1)}));const i=elt("button","dm-cb-page-next btn btn-outline");i.type="button",i.textContent="Next \u203A",i.disabled=this.state.page>=t,i.addEventListener("click",()=>this.setState({page:Math.min(t,this.state.page+1)}));const n=elt("span","dm-cb-page-info");n.textContent=`Page ${this.state.page} of ${t} (${this.currentTotal} entr${this.currentTotal===1?"y":"ies"})`,this.pagerEl.appendChild(e),this.pagerEl.appendChild(n),this.pagerEl.appendChild(i)}renderInfiniteSentinel(){clear(this.pagerEl);const t=Math.max(1,Math.ceil(this.currentTotal/this.config.pageSize));if(this.state.page>=t){const i=elt("p","dm-cb-scroll-end");i.textContent=`All ${this.currentTotal} entries loaded.`,this.pagerEl.appendChild(i);return}const e=elt("div","dm-cb-scroll-sentinel");e.setAttribute("aria-hidden","true"),e.textContent="Loading more\u2026",this.pagerEl.appendChild(e),this._scrollObserver&&this._scrollObserver.disconnect(),this._scrollObserver=new IntersectionObserver(async i=>{i[0].isIntersecting&&(this._scrollObserver.disconnect(),await this.loadMore())},{rootMargin:"200px 0px"}),this._scrollObserver.observe(e)}async loadMore(){const t=this.state.page+1,e=this.currentTotal,i=this.entries,n=this.state.page;this.state.page=t,this.config.syncUrl&&this.writeUrlState();let s;if(this.config.mode==="server")await this.fetchPage(),s=this.entries;else{const{visible:c}=this.pipeline();s=c}if(!s.length){this.state.page=n,this.entries=i,this.currentTotal=e,this.renderPagination();return}const r=this.visibleFields(s),a=this.renderForDisplay(s,r),o=this.bodyEl.firstElementChild;if(o&&o.tagName===a.tagName)for(;a.firstChild;)o.appendChild(a.firstChild);else this.bodyEl.appendChild(a);typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(this.bodyEl),this.config.cta&&typeof wireCTAButtons=="function"&&wireCTAButtons(this.bodyEl),this.renderPagination()}renderForDisplay(t,e){const i=this.config.display;return i==="list"?this.renderList(t,e):i==="table"?this.renderTable(t,e):i==="accordion"?this.renderAccordion(t):i==="timeline"?this.renderTimeline(t):i==="block"?this.renderBlockPlaceholder(t):this.renderCards(t,e)}renderTimeline(t){const e=["vertical","centred","horizontal"].includes(this.config.layout)?this.config.layout:"vertical",i=["minimal","corporate","modern"].includes(this.config.theme)?this.config.theme:"minimal",n=elt("div",`dm-collection-timeline timeline timeline-${e} timeline-${i}`);for(const s of t){const r=elt("div","timeline-event"),a=this.config.dateField&&s.data?.[this.config.dateField]||"",o=this.config.titleField&&s.data?.[this.config.titleField]||"",c=this.config.bodyField&&s.data?.[this.config.bodyField]||"",d=this.config.statusField&&s.data?.[this.config.statusField]||"",h=this.config.iconField&&s.data?.[this.config.iconField]||"";if(h){const p=elt("span","timeline-icon");p.dataset.icon=String(h),r.appendChild(p)}if(a){const p=elt("div","timeline-date");p.textContent=String(a),r.appendChild(p)}if(o){const p=elt("h4","timeline-title");p.textContent=String(o),r.appendChild(p)}if(d){const p=elt("span",`badge badge-${d}`);p.textContent=String(d),r.appendChild(p)}if(c){const p=elt("div","timeline-body");p.textContent=String(c),r.appendChild(p)}n.appendChild(r)}return n}renderBlockPlaceholder(t){const e=elt("div","dm-collection-display dm-cb-block-loading");return e.textContent="Rendering\u2026",this.fetchBlockFragment(t,e),e}async fetchBlockFragment(t,e){const i=++this._fragReqId,n=t.map(a=>a.id).filter(Boolean),s={slug:this.config.slug,display:"block",block:this.config.block,"title-field":this.config.titleField,"body-field":this.config.bodyField,fields:this.config.fields?this.config.fields.join(","):"",empty:this.config.emptyMsg,limit:String(n.length||1)},r={...this.state.filter,...this.config.baked||{}};for(const[a,o]of Object.entries(r))o!==""&&o!=null&&(s[`where_${a}`]=String(o));s.sort=this.state.sort,s.order=this.state.order,s.limit=String(this.config.pageSize);try{const a=btoa(unescape(encodeURIComponent(JSON.stringify(s)))),o=await fetch("/api/collections/render-fragment",{method:"POST",headers:{"Content-Type":"application/json",...this.authHeaders()},body:JSON.stringify({attrs:a,page:this.state.page})});if(i!==this._fragReqId)return;if(!o.ok){e.textContent=this.config.emptyMsg;return}const{html:c}=await o.json(),d=document.createElement("template");d.innerHTML=c||"",e.replaceWith(d.content)}catch{e.textContent="Unable to load block view."}}readUrlState(){if(!this.config.syncUrl)return;const t=new URLSearchParams(window.location.search),e=this.urlPrefix,i=r=>t.get(e+r);i("search")&&(this.state.search=i("search")),i("sort")&&(this.state.sort=i("sort")),i("order")&&(this.state.order=i("order")),i("page")&&(this.state.page=parseInt(i("page"),10)||1);const n={},s=`${e}filter[`;for(const[r,a]of t.entries())if(r.startsWith(s)&&r.endsWith("]")){const o=r.slice(s.length,-1);o&&(n[o]=a)}Object.keys(n).length&&(this.state.filter=n)}writeUrlState(){const t=new URL(window.location.href),e=this.urlPrefix,i=[];for(const s of t.searchParams.keys())s.startsWith(e)&&i.push(s);i.forEach(s=>t.searchParams.delete(s));const n=(s,r)=>{r!==""&&r!=null&&t.searchParams.set(e+s,r)};n("search",this.state.search),this.state.sort!==(this.config.initial?.sort||"createdAt")&&n("sort",this.state.sort),this.state.order!==(this.config.initial?.order||"desc")&&n("order",this.state.order),this.state.page!==1&&n("page",this.state.page);for(const[s,r]of Object.entries(this.state.filter))r!==""&&r!=null&&t.searchParams.set(`${e}filter[${s}]`,r);try{window.history.replaceState({},"",t.toString())}catch{}}}const OPERATORS=["_eq","_ne","_gte","_lte","_gt","_lt","_in","_nin","_contains","_starts","_ends","_exists"];function parseFilterKey(l){for(const t of OPERATORS)if(l.endsWith(t))return{field:l.slice(0,-t.length),op:t};return{field:l,op:"_eq"}}function resolveField(l,t){if(t==="createdBy")return l.meta?.createdBy;if(t==="id")return l.id;const e=t.split(".");let i=l.data;for(const n of e){if(i==null)return;i=i[n]}return i}function maybeNumber(l){if(typeof l=="number"||typeof l!="string")return l;const t=Number(l);return Number.isFinite(t)&&String(t)===l.trim()?t:l}function applyOp(l,t,e){switch(l){case"_eq":{const i=maybeNumber(t),n=maybeNumber(e);return Array.isArray(t)?t.map(maybeNumber).includes(n):i===n||String(i)===String(n)}case"_ne":{const i=maybeNumber(t),n=maybeNumber(e);return Array.isArray(t)?!t.map(maybeNumber).includes(n):!(i===n||String(i)===String(n))}case"_gt":return maybeNumber(t)>maybeNumber(e);case"_gte":return maybeNumber(t)>=maybeNumber(e);case"_lt":return maybeNumber(t)<maybeNumber(e);case"_lte":return maybeNumber(t)<=maybeNumber(e);case"_in":{const i=String(e).split(",").map(n=>maybeNumber(n.trim()));return Array.isArray(t)?t.map(maybeNumber).some(n=>i.includes(n)):i.includes(maybeNumber(t))}case"_nin":{const i=String(e).split(",").map(n=>maybeNumber(n.trim()));return Array.isArray(t)?!t.map(maybeNumber).some(n=>i.includes(n)):!i.includes(maybeNumber(t))}case"_contains":return String(t??"").toLowerCase().includes(String(e).toLowerCase());case"_starts":return String(t??"").toLowerCase().startsWith(String(e).toLowerCase());case"_ends":return String(t??"").toLowerCase().endsWith(String(e).toLowerCase());case"_exists":{const i=t!=null&&t!=="";return e==="true"||e==="1"||e===!0?i:!i}default:return!1}}function applyFilterInMemory(l,t){return!t||!Object.keys(t).length?l:l.filter(e=>{for(const[i,n]of Object.entries(t)){if(n==null||n==="")continue;const{field:s,op:r}=parseFilterKey(i),a=resolveField(e,s);if(!applyOp(r,a,n))return!1}return!0})}function sortEntries(l,t,e){const i=e==="asc"?1:-1;return[...l].sort((n,s)=>{const r=t==="createdAt"?n.meta?.createdAt||"":n.data?.[t]??"",a=t==="createdAt"?s.meta?.createdAt||"":s.data?.[t]??"";return r<a?-i:r>a?i:0})}function elt(l,t){const e=document.createElement(l);return t&&(e.className=t),e}function isFileRef(l){return l&&typeof l=="object"&&typeof l.url=="string"&&typeof l.name=="string"}function formatValue(l){return l==null?"":isFileRef(l)?l.name:Array.isArray(l)?l.join(", "):typeof l=="boolean"?l?"Yes":"No":String(l)}function fieldDisplay(l,t){if(t?.type==="reference"){const e=l?._refs?.[t.name];if(e!=null)return Array.isArray(e)?e.map(i=>i.missing?`${i.id} (missing)`:i.display).join(", "):e.missing?`${e.id} (missing)`:e.display}return formatValue(l?.data?.[t?.name])}function fieldDisplayNode(l,t){if(t?.type==="reference"){const i=l?._refs?.[t.name];if(i!=null){const n=document.createDocumentFragment();return(Array.isArray(i)?i:[i]).forEach((r,a)=>{if(a>0&&n.appendChild(document.createTextNode(", ")),r.missing)n.appendChild(document.createTextNode(`${r.id} (missing)`));else if(r.link){const o=document.createElement("a");o.href=r.link,o.textContent=r.display,n.appendChild(o)}else n.appendChild(document.createTextNode(r.display))}),n}}const e=l?.data?.[t?.name];if(isFileRef(e)){const i=document.createElement("a");if(i.href=e.url,String(e.mime||"").startsWith("image/")){i.target="_blank",i.rel="noopener";const n=document.createElement("img");n.src=e.url,n.alt=e.name,n.loading="lazy",n.className="dm-file-thumb",i.appendChild(n)}else i.download="",i.textContent=e.name;return i}return document.createTextNode(formatValue(e))}function debounce(l,t){let e;return(...i)=>{clearTimeout(e),e=setTimeout(()=>l(...i),t)}}function toCsv(l,t){const e=s=>{if(s==null)return"";let r=Array.isArray(s)?s.join(", "):String(s);return/[",\n\r]/.test(r)&&(r='"'+r.replace(/"/g,'""')+'"'),r},i=t.map(s=>e(s.label||s.name)).join(","),n=l.map(s=>t.map(r=>e(s.data?.[r.name])).join(",")).join(`
|
|
2
2
|
`);return i+`
|
|
3
3
|
`+n+`
|
|
4
4
|
`}function downloadCsv(l,t){const e=new Blob([t],{type:"text/csv;charset=utf-8"}),i=URL.createObjectURL(e),n=document.createElement("a");n.href=i,n.download=l,document.body.appendChild(n),n.click(),n.remove(),setTimeout(()=>URL.revokeObjectURL(i),1e3)}function syncSliderToInputs(l,t,e){if(!l)return;const i=l.querySelector(".dm-cb-slider-handle-min"),n=l.querySelector(".dm-cb-slider-handle-max"),s=l.querySelector(".dm-cb-slider-fill");if(!i||!n||!s)return;const r=Number(l.dataset.lo),a=Number(l.dataset.hi),o=Number(t),c=Number(e);Number.isFinite(o)&&(i.value=String(Math.max(r,Math.min(a,o)))),Number.isFinite(c)&&(n.value=String(Math.max(r,Math.min(a,c))));const d=Math.min(Number(i.value),Number(n.value)),h=Math.max(Number(i.value),Number(n.value)),p=a-r||1;s.style.left=`${(d-r)/p*100}%`,s.style.right=`${100-(h-r)/p*100}%`}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{compareValues as mt,sortEntries as D}from"/public/js/collection-sort.mjs";import{serialise as T}from"/public/js/collection-export.mjs";import{parseQuery as ut}from"/public/js/collection-query.mjs";(function(){"use strict";const q='url("data:image/svg+xml,'+encodeURIComponent("<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M5 2v15.5l4.2-4 2.4 5.4 2.8-1.2-2.4-5.3 5.5-.1z' fill='#fff' stroke='#000' stroke-width='1.2' stroke-linejoin='round'/><path d='M13.5 15h9.5l-3.6 4.2v4l-2.3-1.8v-2.2z' fill='#5b8cff' stroke='#fff' stroke-width='1' stroke-linejoin='round'/></svg>")+'") 5 3, context-menu',P=document.createElement("style");P.textContent=["[data-ctx], [data-collection-table] { cursor: "+q+"; }","[data-ctx] a, [data-ctx] button, [data-collection-table] a, [data-collection-table] button,","[data-ctx] input, [data-collection-table] input { cursor: pointer; }",'[data-ctx] input[type="text"], [data-collection-table] input[type="text"] { cursor: text; }',".dm-ctx-hidden { display: none !important; }",".dm-ctx-menu { position: fixed; z-index: 10000; min-width: 200px; max-width: 300px; max-height: 60vh; overflow-y: auto;background: var(--dm-surface, #1c1c30); border: 1px solid var(--dm-border, #2a2a40); border-radius: 6px;box-shadow: var(--dm-shadow-lg, 0 8px 24px rgba(0,0,0,.4)); padding: .3rem; font-size: .83rem;color: var(--dm-text, #e5e5e5); }",".dm-ctx-menu button.dm-ctx-row { display: flex; align-items: center; gap: .5rem; width: 100%; text-align: left;background: none; border: none; color: inherit; font: inherit; padding: .35rem .6rem; border-radius: 4px; cursor: pointer; }",".dm-ctx-menu button.dm-ctx-row:hover { background: var(--dm-surface-2, rgba(255,255,255,.06)); }",".dm-ctx-heading { padding: .3rem .6rem; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;color: var(--dm-text-muted, #9a9aac); }",".dm-ctx-input { width: 100%; font-size: .8rem; padding: .3rem .5rem; border-radius: 4px;border: 1px solid var(--dm-border, #2a2a40); background: var(--dm-surface-2, rgba(255,255,255,.04)); color: inherit; cursor: text; }",".dm-ctx-chips { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin: 0 0 .6rem; }",".dm-ctx-chip { display: inline-flex; align-items: center; gap: .35rem; font-size: .76rem; padding: .2rem .6rem;border-radius: 999px; background: var(--dm-surface-2, rgba(255,255,255,.08)); border: 1px solid var(--dm-border, #2a2a40); }",".dm-ctx-chip button { background: none; border: none; cursor: pointer; color: inherit; font-size: .9rem; line-height: 1; padding: 0; }",".dm-ctx-empty-note { padding: .75rem; font-size: .85rem; color: var(--dm-text-muted, #9a9aac); }",".dm-ctx-panel-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem;border-bottom: 1px solid var(--dm-border, #2a2a40); margin-bottom: .25rem; }",".dm-ctx-menu button.dm-ctx-back { width: auto; padding: .3rem .5rem; color: var(--dm-text-muted, #9a9aac); }",".dm-ctx-group-heading { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em;color: var(--dm-text-muted, #9a9aac); padding: .5rem 0 .25rem; grid-column: 1 / -1; }"].join(`
|
|
2
|
-
`),document.head.appendChild(P);function v(t){if(t._dmTable)return{fields:t._dmTable.columns.filter(e=>e.key!=="_cta").map(e=>({name:e.key,label:e.title||e.key})),entries:t._dmTable.rows.map((e,o)=>({id:String(o),data:e}))};if(t._dmCtxModel)return t._dmCtxModel;try{t._dmCtxModel=JSON.parse(atob(t.dataset.ctx))}catch{t._dmCtxModel=null}return t._dmCtxModel}function $(t,e){if(e.field==="*"){const n=String(e.value).toLowerCase();return Object.values(t.data||{}).some(d=>String(d??"").toLowerCase().includes(n))}const o=String(t.data?.[e.field]??"");switch(e.op){case"eq":return o===String(e.value);case"ne":return o!==String(e.value);case"contains":return o.toLowerCase().includes(String(e.value).toLowerCase());case"gt":case"lt":{const n=mt(o,e.value);return e.op==="gt"?n>0:n<0}default:return!0}}function p(t){const e=t._dmCtxFilters||[],o=v(t);if(!o)return;const n=t._dmCtxSort||null,d=D(o.entries.filter(i=>e.every(s=>$(i,s))),n),l=new Set(d.map(i=>i.id));if(t._dmTable)t._dmTable.render(d.map(i=>i.data));else if(t._dmCtx&&t._dmCtx.instance&&t._dmCtx.instance.setItems)t._dmCtx.instance.setItems(t._dmCtx.items.filter(i=>l.has(String(i._entryId))));else if(t._dmCtxSlides)J(t,l);else{const i=Array.from(t.querySelectorAll("[data-entry-id]"));i.forEach(h=>h.classList.toggle("dm-ctx-hidden",!l.has(h.dataset.entryId)));const s=new Map(i.map(h=>[h.dataset.entryId,h])),u=i.length?i[0].parentNode:null;n&&u&&d.forEach(h=>{const x=s.get(h.id);x&&x.parentNode===u&&u.appendChild(x)}),t.querySelectorAll(".dm-ctx-group-heading").forEach(h=>h.remove());const c=t._dmCtxGroup;if(c&&u){let h=null;d.forEach(x=>{const b=String(x.data?.[c]??"")||"\u2014";if(b===h)return;h=b;const a=document.createElement("div");a.className="dm-ctx-group-heading",a.textContent=b;const r=s.get(x.id);r&&u.insertBefore(a,r)})}}Q(t,e),w(t,d.length,e.length),O()}const R="dmf";function A(){return Array.from(document.querySelectorAll("[data-ctx], [data-collection-table]"))}function F(t){return btoa(unescape(encodeURIComponent(JSON.stringify(t)))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function H(t){const e=t.replace(/-/g,"+").replace(/_/g,"/");return JSON.parse(decodeURIComponent(escape(atob(e))))}function O(){const t={};A().forEach((n,d)=>{const l={};n._dmCtxFilters&&n._dmCtxFilters.length&&(l.f=n._dmCtxFilters),n._dmCtxSort&&(l.s=n._dmCtxSort),n._dmCtxGroup&&(l.g=n._dmCtxGroup),Object.keys(l).length&&(t[d]=l)});const e=(location.hash||"").replace(/^#/,"").split("&").filter(n=>n&&!n.startsWith(R+"="));Object.keys(t).length&&e.push(R+"="+F(t));const o=location.pathname+location.search+(e.length?"#"+e.join("&"):"");try{history.replaceState(null,"",o)}catch{}}function V(){const t=(location.hash||"").match(/(?:^#|&)dmf=([A-Za-z0-9_-]+)/);if(!t)return null;try{return H(t[1])}catch{return null}}function N(t=0){const e=V();if(!e)return;const o=A();let n=!1;for(const[d,l]of Object.entries(e)){const i=o[Number(d)];if(!i||!l)continue;if(i.hasAttribute("data-collection-table")?!i._dmTable:i.classList.contains("dm-progression")?!i._dmCtx:i.classList.contains("carousel")?!i._dmCtxSlides:!1){n=!0;continue}const u=Array.isArray(l)?{f:l}:l||{};i._dmCtxFilters=(u.f||[]).filter(c=>c&&c.field&&c.op!=null&&"value"in c),i._dmCtxSort=u.s||null,i._dmCtxGroup=u.g||null,p(i)}n&&t<20&&setTimeout(()=>N(t+1),100)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>setTimeout(N,0)):setTimeout(N,0);function J(t,e){if(t._dmCarousel&&typeof t._dmCarousel.destroy=="function")try{t._dmCarousel.destroy()}catch{}const o=document.createElement("div");o.className="carousel-track",t._dmCtxSlides.forEach(n=>{e.has(n.dataset.entryId)&&o.appendChild(n.cloneNode(!0))}),t.replaceChildren(o),o.children.length&&typeof Domma<"u"&&Domma.elements?.carousel&&(t._dmCarousel=Domma.elements.carousel(t,t._dmCarouselOpts||{}))}function W(t,e,o){const n=URL.createObjectURL(new Blob([t],{type:o})),d=document.createElement("a");d.href=n,d.download=e,document.body.appendChild(d),d.click(),d.remove(),setTimeout(()=>URL.revokeObjectURL(n),0)}function _(t,e){const o=document.createElement("textarea");o.value=t,o.style.cssText="position:fixed;opacity:0;",document.body.appendChild(o),o.select();const n=document.execCommand("copy");o.remove(),typeof E<"u"&&E.toast&&E.toast(n?e:"Copy failed",{type:n?"success":"error"})}function Y(){return new Date().toISOString().slice(0,10)}let k=null;function X(){if(!k){const t=typeof S<"u"&&S.get?S.get("auth_token"):null;k=t?fetch("/api/auth/me",{headers:{Authorization:`Bearer ${t}`}}).then(e=>e.ok?e.json():null).catch(()=>null):Promise.resolve(null)}return k}async function Z(t){if(!t||!t.allowed)return!1;if(t.access==="public")return!0;const e=await X();return e?[e.role,...e.additionalRoles||[]].filter(Boolean).some(n=>(t.roles||[]).includes(n)):!1}const K={eq:"=",ne:"\u2260",contains:"contains",gt:">",lt:"<"};function Q(t,e){let o=t._dmCtxBar;if(!e.length){o&&(o.remove(),t._dmCtxBar=null);return}o||(o=document.createElement("div"),o.className="dm-ctx-chips",t.parentNode.insertBefore(o,t),t._dmCtxBar=o),o.replaceChildren(),e.forEach((d,l)=>{const i=document.createElement("span");i.className="dm-ctx-chip";const s=String(d.value),u=s.length>24?s.slice(0,24)+"\u2026":s;i.appendChild(document.createTextNode(d.field==="*"?`search \u201C${u}\u201D`:`${d.label||d.field} ${K[d.op]||d.op} \u201C${u}\u201D`));const c=document.createElement("button");c.type="button",c.textContent="\xD7",c.title="Remove filter",c.addEventListener("click",()=>{t._dmCtxFilters.splice(l,1),p(t)}),i.appendChild(c),o.appendChild(i)});const n=document.createElement("button");n.type="button",n.className="dm-ctx-chip",n.style.cursor="pointer",n.textContent="Clear all",n.addEventListener("click",()=>{t._dmCtxFilters=[],p(t)}),o.appendChild(n)}function w(t,e,o){if(t._dmCtxEmptyNote&&(t._dmCtxEmptyNote.remove(),t._dmCtxEmptyNote=null),e||!o)return;const n=document.createElement("div");n.className="dm-ctx-empty-note",n.textContent="No entries match the current filters.",t.appendChild(n),t._dmCtxEmptyNote=n}let C=null;function f(){C&&(C.remove(),C=null,document.removeEventListener("mousedown",j,!0),document.removeEventListener("keydown",G,!0),window.removeEventListener("scroll",M,!0))}const j=t=>{C&&!C.contains(t.target)&&f()},G=t=>{t.key==="Escape"&&f()},M=t=>{C&&!C.contains(t.target)&&f()};function m(t,e){const o=document.createElement("button");return o.type="button",o.className="dm-ctx-row",o.textContent=t,o.addEventListener("click",e),o}function y(t){const e=document.createElement("div");return e.className="dm-ctx-heading",e.textContent=t,e}function I(){const t=document.createElement("div");return t.style.cssText="border-top:1px solid var(--dm-border,#2a2a40);margin:.25rem 0;",t}const g=(t,e=24)=>{const o=String(t);return o.length>e?o.slice(0,e)+"\u2026":o};function B(t){const e=t.getBoundingClientRect();t.style.left=Math.min(t._dmX,window.innerWidth-e.width-8)+"px",t.style.top=Math.min(t._dmY,window.innerHeight-e.height-8)+"px"}function U(t,e,o){if(t._dmPanelToken=(t._dmPanelToken||0)+1,t.replaceChildren(),o){const n=document.createElement("div");n.className="dm-ctx-panel-head";const d=document.createElement("button");d.type="button",d.className="dm-ctx-row dm-ctx-back",d.textContent="\u2039 Back",d.addEventListener("click",()=>t._dmPop()),n.appendChild(d),n.appendChild(y(o)),t.appendChild(n)}e(t),B(t)}function tt(t){const e=[];return t._dmPush=(o,n)=>{e.push({build:o,title:n}),U(t,o,n)},t._dmPop=()=>{e.pop();const o=e[e.length-1];o&&U(t,o.build,o.title)},t}function et(t){return!t._dmTable&&!t._dmCtx?.instance?.setItems&&!t._dmCtxSlides}function nt(t,e){const o=t.entries.map(d=>d.data?.[e]).find(d=>d!==""&&d!=null),n=String(o??"");return n!==""&&!Number.isNaN(parseFloat(n))?["low \u2192 high","high \u2192 low"]:Number.isNaN(Date.parse(n))?["A \u2192 Z","Z \u2192 A"]:["oldest \u2192 newest","newest \u2192 oldest"]}function ot(t,e,o){o.fields.forEach(n=>{const[d,l]=nt(o,n.name);t.appendChild(m(`${n.label||n.name} ${d}`,()=>{e._dmCtxSort={field:n.name,label:n.label||n.name,dir:"asc"},p(e),f()})),t.appendChild(m(`${n.label||n.name} ${l}`,()=>{e._dmCtxSort={field:n.name,label:n.label||n.name,dir:"desc"},p(e),f()}))}),e._dmCtxSort&&t.appendChild(m("Clear sort",()=>{e._dmCtxSort=null,p(e),f()}))}function dt(t,e,o){o.fields.forEach(n=>{t.appendChild(m(n.label||n.name,()=>{e._dmCtxGroup=n.name,(!e._dmCtxSort||e._dmCtxSort.field!==n.name)&&(e._dmCtxSort={field:n.name,label:n.label||n.name,dir:"asc"}),p(e),f()}))}),e._dmCtxGroup&&t.appendChild(m("Clear grouping",()=>{e._dmCtxGroup=null,p(e),f()}))}function z(t,e){const o=t._dmCtxFilters||[];return D(e.entries.filter(n=>o.every(d=>$(n,d))),t._dmCtxSort||null).map(n=>n.data)}function it(t,e,o,n){const d=o.slug||e._dmTable?.slug||"collection";n.formats.forEach(l=>{t.appendChild(m(l.toUpperCase(),()=>{const i=T(z(e,o),o.fields,l);W(i,`${d}-${Y()}.${l}`,l==="csv"?"text/csv;charset=utf-8":"application/json"),f()}))})}function at(t,e,o,n,d){n&&d&&t.appendChild(m("This value",()=>{_(String(n.data?.[d.name]??""),"Value copied"),f()})),n&&t.appendChild(m("This row (JSON)",()=>{_(T([n.data],o.fields,"json"),"Row copied"),f()})),t.appendChild(m("Visible entries as a table",()=>{_(T(z(e,o),o.fields,"markdown"),"Table copied"),f()}))}function lt(t,e,o,n,d){const l=(a,r,L,ct)=>{(e._dmCtxFilters=e._dmCtxFilters||[]).push({field:a,label:r,op:L,value:ct}),p(e),f()};if(n&&o){const a=o.data?.[n.name]??"";t.appendChild(y(n.label||n.name)),t.appendChild(m(`Filter: = \u201C${g(a)}\u201D`,()=>l(n.name,n.label,"eq",a))),t.appendChild(m(`Filter: \u2260 \u201C${g(a)}\u201D`,()=>l(n.name,n.label,"ne",a)));const r=String(a);(r!==""&&!Number.isNaN(parseFloat(r))||!Number.isNaN(Date.parse(r)))&&(t.appendChild(m(`Filter: > \u201C${g(a)}\u201D`,()=>l(n.name,n.label,"gt",a))),t.appendChild(m(`Filter: < \u201C${g(a)}\u201D`,()=>l(n.name,n.label,"lt",a))))}else if(o){t.appendChild(y("Filter by"));for(const a of d.fields){const r=o.data?.[a.name];r==null||String(r)===""||t.appendChild(m(`${a.label||a.name}: \u201C${g(r,20)}\u201D`,()=>l(a.name,a.label,"eq",r)))}}const i=document.createElement("div");i.style.padding=".35rem .6rem";const s=document.createElement("input");s.type="text",s.className="dm-ctx-input",s.placeholder="Search\u2026 or name: value",s.addEventListener("mousedown",a=>a.stopPropagation()),s.addEventListener("keydown",a=>{if(a.key!=="Enter"||!s.value.trim())return;const r=ut(s.value,d.fields);r?l(r.field,r.label,r.op,r.value):l("*","search","contains",s.value.trim())}),i.appendChild(s),t.appendChild(i),t.appendChild(I()),t.appendChild(y("This display")),t.appendChild(m("Sort\u2026",()=>t._dmPush(a=>ot(a,e,d),"Sort"))),et(e)&&t.appendChild(m("Group by\u2026",()=>t._dmPush(a=>dt(a,e,d),"Group by"))),t.appendChild(m("Copy\u2026",()=>t._dmPush(a=>at(a,e,d,o,n),"Copy")));const u=m("Print",()=>{e.setAttribute("data-dm-print",""),document.body.classList.add("dm-ctx-printing"),f();const a=()=>{e.removeAttribute("data-dm-print"),document.body.classList.remove("dm-ctx-printing"),window.removeEventListener("afterprint",a)};window.addEventListener("afterprint",a),window.print()});t.appendChild(u),t.appendChild(m("Copy link to this view",()=>{O(),_(location.href,"Link copied"),f()}));const c=d.export||e._dmTable?.exportCfg,h=t._dmPanelToken;Z(c).then(a=>{!a||C!==t||t._dmPanelToken!==h||(t.insertBefore(m("Export\u2026",()=>t._dmPush(r=>it(r,e,d,c),"Export")),u),B(t))});const x=(e._dmCtxFilters||[]).length;if(x||e._dmCtxSort||e._dmCtxGroup){const a=[];x&&a.push(`${x} filter${x===1?"":"s"}`),e._dmCtxSort&&a.push("sort"),e._dmCtxGroup&&a.push("grouping"),t.appendChild(I()),t.appendChild(m(`Clear all (${a.join(", ")})`,()=>{e._dmCtxFilters=[],e._dmCtxSort=null,e._dmCtxGroup=null,p(e),f()}))}}function st(t,e,o,n,d){f();const l=v(o);if(!l)return;const i=tt(document.createElement("div"));i.className="dm-ctx-menu",i._dmX=t,i._dmY=e,C=i,document.body.appendChild(i),i._dmPush(s=>lt(s,o,n,d,l),null),document.addEventListener("mousedown",j,!0),document.addEventListener("keydown",G,!0),window.addEventListener("scroll",M,!0),setTimeout(()=>{const s=i.querySelector(".dm-ctx-input");s&&s.focus()},0)}function rt(t,e,o){if(t._dmTable){const s=e.closest("tbody tr");if(!s)return{entry:null,field:null};const u=e.closest("td"),c=s.querySelectorAll("td"),h=Array.from(c).map(a=>a.textContent.trim()),x=o.entries.find(a=>o.fields.every((r,L)=>String(a.data?.[r.name]??"").trim()===(h[L]??"").trim()))||null,b=u&&o.fields[u.cellIndex]||null;return{entry:x,field:b}}const n=e.closest("[data-entry-id]");if(!n)return{entry:null,field:null};const d=o.entries.find(s=>s.id===n.dataset.entryId)||null;if(!d)return{entry:null,field:null};const l=(e.textContent||"").trim().slice(0,80);let i=null;if(l){const s=o.fields.filter(u=>{const c=String(d.data?.[u.name]??"");return c&&(c.includes(l)||l.includes(c))});s.length===1&&(i=s[0])}return{entry:d,field:i}}document.addEventListener("contextmenu",t=>{const e=t.target.closest("[data-ctx], [data-collection-table]");if(!e)return;const o=v(e);if(!o||!o.fields?.length)return;t.preventDefault();const{entry:n,field:d}=rt(e,t.target,o);st(t.clientX,t.clientY,e,n,d)})})();
|
|
2
|
+
`),document.head.appendChild(P);function v(t){if(t._dmTable)return{fields:t._dmTable.columns.filter(e=>e.key!=="_cta").map(e=>({name:e.key,label:e.title||e.key})),entries:t._dmTable.rows.map((e,o)=>({id:String(o),data:e}))};if(t._dmCtxModel)return t._dmCtxModel;try{t._dmCtxModel=JSON.parse(atob(t.dataset.ctx))}catch{t._dmCtxModel=null}return t._dmCtxModel}function $(t,e){if(e.field==="*"){const n=String(e.value).toLowerCase();return Object.values(t.data||{}).some(d=>String(d??"").toLowerCase().includes(n))}const o=String(t.data?.[e.field]??"");switch(e.op){case"eq":return o===String(e.value);case"ne":return o!==String(e.value);case"contains":return o.toLowerCase().includes(String(e.value).toLowerCase());case"gt":case"lt":{const n=mt(o,e.value);return e.op==="gt"?n>0:n<0}default:return!0}}function p(t){const e=t._dmCtxFilters||[],o=v(t);if(!o)return;const n=t._dmCtxSort||null,d=D(o.entries.filter(i=>e.every(s=>$(i,s))),n),l=new Set(d.map(i=>i.id));if(t._dmTable)t._dmTable.render(d.map(i=>i.data));else if(t._dmCtx&&t._dmCtx.instance&&t._dmCtx.instance.setItems)t._dmCtx.instance.setItems(t._dmCtx.items.filter(i=>l.has(String(i._entryId))));else if(t._dmCtxSlides)J(t,l);else{const i=Array.from(t.querySelectorAll("[data-entry-id]"));i.forEach(h=>h.classList.toggle("dm-ctx-hidden",!l.has(h.dataset.entryId)));const s=new Map(i.map(h=>[h.dataset.entryId,h])),u=i.length?i[0].parentNode:null;n&&u&&d.forEach(h=>{const x=s.get(h.id);x&&x.parentNode===u&&u.appendChild(x)}),t.querySelectorAll(".dm-ctx-group-heading").forEach(h=>h.remove());const c=t._dmCtxGroup;if(c&&u){let h=null;d.forEach(x=>{const b=String(x.data?.[c]??"")||"-";if(b===h)return;h=b;const a=document.createElement("div");a.className="dm-ctx-group-heading",a.textContent=b;const r=s.get(x.id);r&&u.insertBefore(a,r)})}}Q(t,e),w(t,d.length,e.length),O()}const R="dmf";function A(){return Array.from(document.querySelectorAll("[data-ctx], [data-collection-table]"))}function F(t){return btoa(unescape(encodeURIComponent(JSON.stringify(t)))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function H(t){const e=t.replace(/-/g,"+").replace(/_/g,"/");return JSON.parse(decodeURIComponent(escape(atob(e))))}function O(){const t={};A().forEach((n,d)=>{const l={};n._dmCtxFilters&&n._dmCtxFilters.length&&(l.f=n._dmCtxFilters),n._dmCtxSort&&(l.s=n._dmCtxSort),n._dmCtxGroup&&(l.g=n._dmCtxGroup),Object.keys(l).length&&(t[d]=l)});const e=(location.hash||"").replace(/^#/,"").split("&").filter(n=>n&&!n.startsWith(R+"="));Object.keys(t).length&&e.push(R+"="+F(t));const o=location.pathname+location.search+(e.length?"#"+e.join("&"):"");try{history.replaceState(null,"",o)}catch{}}function V(){const t=(location.hash||"").match(/(?:^#|&)dmf=([A-Za-z0-9_-]+)/);if(!t)return null;try{return H(t[1])}catch{return null}}function N(t=0){const e=V();if(!e)return;const o=A();let n=!1;for(const[d,l]of Object.entries(e)){const i=o[Number(d)];if(!i||!l)continue;if(i.hasAttribute("data-collection-table")?!i._dmTable:i.classList.contains("dm-progression")?!i._dmCtx:i.classList.contains("carousel")?!i._dmCtxSlides:!1){n=!0;continue}const u=Array.isArray(l)?{f:l}:l||{};i._dmCtxFilters=(u.f||[]).filter(c=>c&&c.field&&c.op!=null&&"value"in c),i._dmCtxSort=u.s||null,i._dmCtxGroup=u.g||null,p(i)}n&&t<20&&setTimeout(()=>N(t+1),100)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>setTimeout(N,0)):setTimeout(N,0);function J(t,e){if(t._dmCarousel&&typeof t._dmCarousel.destroy=="function")try{t._dmCarousel.destroy()}catch{}const o=document.createElement("div");o.className="carousel-track",t._dmCtxSlides.forEach(n=>{e.has(n.dataset.entryId)&&o.appendChild(n.cloneNode(!0))}),t.replaceChildren(o),o.children.length&&typeof Domma<"u"&&Domma.elements?.carousel&&(t._dmCarousel=Domma.elements.carousel(t,t._dmCarouselOpts||{}))}function W(t,e,o){const n=URL.createObjectURL(new Blob([t],{type:o})),d=document.createElement("a");d.href=n,d.download=e,document.body.appendChild(d),d.click(),d.remove(),setTimeout(()=>URL.revokeObjectURL(n),0)}function _(t,e){const o=document.createElement("textarea");o.value=t,o.style.cssText="position:fixed;opacity:0;",document.body.appendChild(o),o.select();const n=document.execCommand("copy");o.remove(),typeof E<"u"&&E.toast&&E.toast(n?e:"Copy failed",{type:n?"success":"error"})}function Y(){return new Date().toISOString().slice(0,10)}let k=null;function X(){if(!k){const t=typeof S<"u"&&S.get?S.get("auth_token"):null;k=t?fetch("/api/auth/me",{headers:{Authorization:`Bearer ${t}`}}).then(e=>e.ok?e.json():null).catch(()=>null):Promise.resolve(null)}return k}async function Z(t){if(!t||!t.allowed)return!1;if(t.access==="public")return!0;const e=await X();return e?[e.role,...e.additionalRoles||[]].filter(Boolean).some(n=>(t.roles||[]).includes(n)):!1}const K={eq:"=",ne:"\u2260",contains:"contains",gt:">",lt:"<"};function Q(t,e){let o=t._dmCtxBar;if(!e.length){o&&(o.remove(),t._dmCtxBar=null);return}o||(o=document.createElement("div"),o.className="dm-ctx-chips",t.parentNode.insertBefore(o,t),t._dmCtxBar=o),o.replaceChildren(),e.forEach((d,l)=>{const i=document.createElement("span");i.className="dm-ctx-chip";const s=String(d.value),u=s.length>24?s.slice(0,24)+"\u2026":s;i.appendChild(document.createTextNode(d.field==="*"?`search \u201C${u}\u201D`:`${d.label||d.field} ${K[d.op]||d.op} \u201C${u}\u201D`));const c=document.createElement("button");c.type="button",c.textContent="\xD7",c.title="Remove filter",c.addEventListener("click",()=>{t._dmCtxFilters.splice(l,1),p(t)}),i.appendChild(c),o.appendChild(i)});const n=document.createElement("button");n.type="button",n.className="dm-ctx-chip",n.style.cursor="pointer",n.textContent="Clear all",n.addEventListener("click",()=>{t._dmCtxFilters=[],p(t)}),o.appendChild(n)}function w(t,e,o){if(t._dmCtxEmptyNote&&(t._dmCtxEmptyNote.remove(),t._dmCtxEmptyNote=null),e||!o)return;const n=document.createElement("div");n.className="dm-ctx-empty-note",n.textContent="No entries match the current filters.",t.appendChild(n),t._dmCtxEmptyNote=n}let C=null;function f(){C&&(C.remove(),C=null,document.removeEventListener("mousedown",j,!0),document.removeEventListener("keydown",G,!0),window.removeEventListener("scroll",M,!0))}const j=t=>{C&&!C.contains(t.target)&&f()},G=t=>{t.key==="Escape"&&f()},M=t=>{C&&!C.contains(t.target)&&f()};function m(t,e){const o=document.createElement("button");return o.type="button",o.className="dm-ctx-row",o.textContent=t,o.addEventListener("click",e),o}function y(t){const e=document.createElement("div");return e.className="dm-ctx-heading",e.textContent=t,e}function I(){const t=document.createElement("div");return t.style.cssText="border-top:1px solid var(--dm-border,#2a2a40);margin:.25rem 0;",t}const g=(t,e=24)=>{const o=String(t);return o.length>e?o.slice(0,e)+"\u2026":o};function B(t){const e=t.getBoundingClientRect();t.style.left=Math.min(t._dmX,window.innerWidth-e.width-8)+"px",t.style.top=Math.min(t._dmY,window.innerHeight-e.height-8)+"px"}function U(t,e,o){if(t._dmPanelToken=(t._dmPanelToken||0)+1,t.replaceChildren(),o){const n=document.createElement("div");n.className="dm-ctx-panel-head";const d=document.createElement("button");d.type="button",d.className="dm-ctx-row dm-ctx-back",d.textContent="\u2039 Back",d.addEventListener("click",()=>t._dmPop()),n.appendChild(d),n.appendChild(y(o)),t.appendChild(n)}e(t),B(t)}function tt(t){const e=[];return t._dmPush=(o,n)=>{e.push({build:o,title:n}),U(t,o,n)},t._dmPop=()=>{e.pop();const o=e[e.length-1];o&&U(t,o.build,o.title)},t}function et(t){return!t._dmTable&&!t._dmCtx?.instance?.setItems&&!t._dmCtxSlides}function nt(t,e){const o=t.entries.map(d=>d.data?.[e]).find(d=>d!==""&&d!=null),n=String(o??"");return n!==""&&!Number.isNaN(parseFloat(n))?["low \u2192 high","high \u2192 low"]:Number.isNaN(Date.parse(n))?["A \u2192 Z","Z \u2192 A"]:["oldest \u2192 newest","newest \u2192 oldest"]}function ot(t,e,o){o.fields.forEach(n=>{const[d,l]=nt(o,n.name);t.appendChild(m(`${n.label||n.name} ${d}`,()=>{e._dmCtxSort={field:n.name,label:n.label||n.name,dir:"asc"},p(e),f()})),t.appendChild(m(`${n.label||n.name} ${l}`,()=>{e._dmCtxSort={field:n.name,label:n.label||n.name,dir:"desc"},p(e),f()}))}),e._dmCtxSort&&t.appendChild(m("Clear sort",()=>{e._dmCtxSort=null,p(e),f()}))}function dt(t,e,o){o.fields.forEach(n=>{t.appendChild(m(n.label||n.name,()=>{e._dmCtxGroup=n.name,(!e._dmCtxSort||e._dmCtxSort.field!==n.name)&&(e._dmCtxSort={field:n.name,label:n.label||n.name,dir:"asc"}),p(e),f()}))}),e._dmCtxGroup&&t.appendChild(m("Clear grouping",()=>{e._dmCtxGroup=null,p(e),f()}))}function z(t,e){const o=t._dmCtxFilters||[];return D(e.entries.filter(n=>o.every(d=>$(n,d))),t._dmCtxSort||null).map(n=>n.data)}function it(t,e,o,n){const d=o.slug||e._dmTable?.slug||"collection";n.formats.forEach(l=>{t.appendChild(m(l.toUpperCase(),()=>{const i=T(z(e,o),o.fields,l);W(i,`${d}-${Y()}.${l}`,l==="csv"?"text/csv;charset=utf-8":"application/json"),f()}))})}function at(t,e,o,n,d){n&&d&&t.appendChild(m("This value",()=>{_(String(n.data?.[d.name]??""),"Value copied"),f()})),n&&t.appendChild(m("This row (JSON)",()=>{_(T([n.data],o.fields,"json"),"Row copied"),f()})),t.appendChild(m("Visible entries as a table",()=>{_(T(z(e,o),o.fields,"markdown"),"Table copied"),f()}))}function lt(t,e,o,n,d){const l=(a,r,L,ct)=>{(e._dmCtxFilters=e._dmCtxFilters||[]).push({field:a,label:r,op:L,value:ct}),p(e),f()};if(n&&o){const a=o.data?.[n.name]??"";t.appendChild(y(n.label||n.name)),t.appendChild(m(`Filter: = \u201C${g(a)}\u201D`,()=>l(n.name,n.label,"eq",a))),t.appendChild(m(`Filter: \u2260 \u201C${g(a)}\u201D`,()=>l(n.name,n.label,"ne",a)));const r=String(a);(r!==""&&!Number.isNaN(parseFloat(r))||!Number.isNaN(Date.parse(r)))&&(t.appendChild(m(`Filter: > \u201C${g(a)}\u201D`,()=>l(n.name,n.label,"gt",a))),t.appendChild(m(`Filter: < \u201C${g(a)}\u201D`,()=>l(n.name,n.label,"lt",a))))}else if(o){t.appendChild(y("Filter by"));for(const a of d.fields){const r=o.data?.[a.name];r==null||String(r)===""||t.appendChild(m(`${a.label||a.name}: \u201C${g(r,20)}\u201D`,()=>l(a.name,a.label,"eq",r)))}}const i=document.createElement("div");i.style.padding=".35rem .6rem";const s=document.createElement("input");s.type="text",s.className="dm-ctx-input",s.placeholder="Search\u2026 or name: value",s.addEventListener("mousedown",a=>a.stopPropagation()),s.addEventListener("keydown",a=>{if(a.key!=="Enter"||!s.value.trim())return;const r=ut(s.value,d.fields);r?l(r.field,r.label,r.op,r.value):l("*","search","contains",s.value.trim())}),i.appendChild(s),t.appendChild(i),t.appendChild(I()),t.appendChild(y("This display")),t.appendChild(m("Sort\u2026",()=>t._dmPush(a=>ot(a,e,d),"Sort"))),et(e)&&t.appendChild(m("Group by\u2026",()=>t._dmPush(a=>dt(a,e,d),"Group by"))),t.appendChild(m("Copy\u2026",()=>t._dmPush(a=>at(a,e,d,o,n),"Copy")));const u=m("Print",()=>{e.setAttribute("data-dm-print",""),document.body.classList.add("dm-ctx-printing"),f();const a=()=>{e.removeAttribute("data-dm-print"),document.body.classList.remove("dm-ctx-printing"),window.removeEventListener("afterprint",a)};window.addEventListener("afterprint",a),window.print()});t.appendChild(u),t.appendChild(m("Copy link to this view",()=>{O(),_(location.href,"Link copied"),f()}));const c=d.export||e._dmTable?.exportCfg,h=t._dmPanelToken;Z(c).then(a=>{!a||C!==t||t._dmPanelToken!==h||(t.insertBefore(m("Export\u2026",()=>t._dmPush(r=>it(r,e,d,c),"Export")),u),B(t))});const x=(e._dmCtxFilters||[]).length;if(x||e._dmCtxSort||e._dmCtxGroup){const a=[];x&&a.push(`${x} filter${x===1?"":"s"}`),e._dmCtxSort&&a.push("sort"),e._dmCtxGroup&&a.push("grouping"),t.appendChild(I()),t.appendChild(m(`Clear all (${a.join(", ")})`,()=>{e._dmCtxFilters=[],e._dmCtxSort=null,e._dmCtxGroup=null,p(e),f()}))}}function st(t,e,o,n,d){f();const l=v(o);if(!l)return;const i=tt(document.createElement("div"));i.className="dm-ctx-menu",i._dmX=t,i._dmY=e,C=i,document.body.appendChild(i),i._dmPush(s=>lt(s,o,n,d,l),null),document.addEventListener("mousedown",j,!0),document.addEventListener("keydown",G,!0),window.addEventListener("scroll",M,!0),setTimeout(()=>{const s=i.querySelector(".dm-ctx-input");s&&s.focus()},0)}function rt(t,e,o){if(t._dmTable){const s=e.closest("tbody tr");if(!s)return{entry:null,field:null};const u=e.closest("td"),c=s.querySelectorAll("td"),h=Array.from(c).map(a=>a.textContent.trim()),x=o.entries.find(a=>o.fields.every((r,L)=>String(a.data?.[r.name]??"").trim()===(h[L]??"").trim()))||null,b=u&&o.fields[u.cellIndex]||null;return{entry:x,field:b}}const n=e.closest("[data-entry-id]");if(!n)return{entry:null,field:null};const d=o.entries.find(s=>s.id===n.dataset.entryId)||null;if(!d)return{entry:null,field:null};const l=(e.textContent||"").trim().slice(0,80);let i=null;if(l){const s=o.fields.filter(u=>{const c=String(d.data?.[u.name]??"");return c&&(c.includes(l)||l.includes(c))});s.length===1&&(i=s[0])}return{entry:d,field:i}}document.addEventListener("contextmenu",t=>{const e=t.target.closest("[data-ctx], [data-collection-table]");if(!e)return;const o=v(e);if(!o||!o.fields?.length)return;t.preventDefault();const{entry:n,field:d}=rt(e,t.target,o);st(t.clientX,t.clientY,e,n,d)})})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(c,l){typeof module<"u"&&module.exports?module.exports=l():c.FormLogicEngine=l()})(typeof globalThis<"u"?globalThis:this,function(){"use strict";function c(e){return e===""||e===null||e===void 0?"":String(e)}function l(e){const r=parseFloat(e);return isNaN(r)?null:r}function f(e){return e==null?!0:typeof e=="string"?e.trim()==="":Array.isArray(e)?e.length===0:!1}const x={not_equals:"equals",not_contains:"contains",not_in:"in"};function m(e,r){const s=c(r),t=c(e.value);switch(e.operator){case"equals":return s===t;case"not_equals":return s!==t;case"contains":return s.toLowerCase().includes(t.toLowerCase());case"not_contains":return!s.toLowerCase().includes(t.toLowerCase());case"starts_with":return s.toLowerCase().startsWith(t.toLowerCase());case"ends_with":return s.toLowerCase().endsWith(t.toLowerCase());case"greater_than":{const n=l(r),i=l(e.value);return n!==null&&i!==null&&n>i}case"less_than":{const n=l(r),i=l(e.value);return n!==null&&i!==null&&n<i}case"is_empty":return f(r);case"is_not_empty":return!f(r);case"in":return(Array.isArray(e.value)?e.value.map(c):String(e.value).split(",").map(i=>i.trim())).includes(s);case"not_in":return!(Array.isArray(e.value)?e.value.map(c):String(e.value).split(",").map(i=>i.trim())).includes(s);case"matches_regex":try{const n=e.flags||"";return new RegExp(e.value,n).test(s)}catch(n){return typeof console<"u"&&console.warn&&console.warn('[FormLogicEngine] Invalid regex in condition for field "'+e.field+'": '+e.value,n&&n.message),!1}default:return!0}}function y(e,r){if(!e||!e.field||!e.operator)return!0;const s=r[e.field];if(!Array.isArray(s))return m(e,s);if(e.operator==="is_empty")return f(s);if(e.operator==="is_not_empty")return!f(s);const t=x[e.operator];if(t){const n=Object.assign({},e,{operator:t});return!s.some(i=>m(n,i))}return s.some(n=>m(e,n))}function p(e,r){return e?Array.isArray(e.all)?e.all.every(s=>s.all||s.any?p(s,r):y(s,r)):Array.isArray(e.any)?e.any.some(s=>s.all||s.any?p(s,r):y(s,r)):e.field&&e.operator?y(e,r):!0:!0}function g(e,r){const s=e.logic;if(!s||!s.visibility)return"visible";const t=s.visibility,n=t.conditions||[];for(const i of n)if(i.when&&p(i.when,r))return i.then==="hidden"?"hidden":"visible";return t.default==="hidden"?"hidden":"visible"}function v(e,r){const s=e.logic;if(!s||!s.requirement)return e.required||!1;const t=s.requirement,n=t.conditions||[];for(const i of n)if(i.when&&p(i.when,r))return i.then===!0;return t.default===!0}function b(e,r,s){const t=e.logic;if(!t||!Array.isArray(t.validation))return[];const n=[];for(const i of t.validation)switch(i.type){case"regex":{if(!f(r))try{new RegExp(i.pattern||"",i.flags||"").test(c(r))||n.push({message:i.message||"Invalid format."})}catch{}break}case"match":{const a=s[i.field];!f(r)&&c(r)!==c(a)&&n.push({message:i.message||"Fields do not match."});break}}return n}function w(e,r){const s=e.logic;if(!s||!s.cascade||!s.cascade.sourceField)return null;const t=s.cascade,n=t.mapping||{},i=r[t.sourceField];if(Array.isArray(i)){const u=new Set,d=[];return i.forEach(function(M){const E=c(M);Object.prototype.hasOwnProperty.call(n,E)&&(n[E]||[]).forEach(function(_){const q=c(_&&_.value);u.has(q)||(u.add(q),d.push(_))})}),d.length?d:t.defaultOptions||null}const a=c(i);return Object.prototype.hasOwnProperty.call(n,a)?n[a]||[]:t.defaultOptions||null}const F={fade:250,slide:300,scale:200};function A(e,r){const s=Number(r);return!isFinite(s)||s<0||s>5e3?F[e]||250:Math.round(s)}function L(e,r,s){const t=A(r,s);if(r==="fade")e.style.transition="opacity "+t+"ms ease",e.style.opacity="1",requestAnimationFrame(function(){e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.opacity=""},t+10)});else if(r==="slide"){const n=Math.round(t*.67);e.style.overflow="hidden",e.style.maxHeight=e.scrollHeight+"px",e.style.transition="max-height "+t+"ms ease, opacity "+n+"ms ease",requestAnimationFrame(function(){e.style.maxHeight="0",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},t+20)})}else r==="scale"&&(e.style.transition="opacity "+t+"ms ease, transform "+t+"ms ease",e.style.transform="scale(1)",e.style.opacity="1",requestAnimationFrame(function(){e.style.transform="scale(0.95)",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.transform="",e.style.opacity=""},t+20)}))}function C(e,r,s){const t=A(r,s);if(e.classList.remove("fb-field-hidden"),r==="fade")e.style.opacity="0",e.style.transition="opacity "+t+"ms ease",requestAnimationFrame(function(){e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.opacity=""},t+10)});else if(r==="slide"){const n=Math.round(t*.67);e.style.overflow="hidden",e.style.maxHeight="0",e.style.opacity="0",e.style.transition="max-height "+t+"ms ease, opacity "+n+"ms ease",requestAnimationFrame(function(){e.style.maxHeight=e.scrollHeight+"px",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},t+20)})}else r==="scale"&&(e.style.transform="scale(0.95)",e.style.opacity="0",e.style.transition="opacity "+t+"ms ease, transform "+t+"ms ease",requestAnimationFrame(function(){e.style.transform="scale(1)",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.transform="",e.style.opacity=""},t+20)}))}function o(e,r){this._form=e,this._wrapper=r,this._fields=(e.fields||[]).filter(s=>s.type!=="page-break"),this._listeners=[],this._depMap=new Map,this._initialEval=!1}function h(e,r,s){const t=s||"",n=r||"";return t+'[name="'+e+'"]'+n+", "+t+'[name="'+e+'[]"]'+n}function S(e){return String(e||"").replace(/\[\]$/,"")}return o.prototype._fieldInputs=function(e){return this._wrapper.querySelectorAll(h(e))},o.prototype._fieldInput=function(e){return this._wrapper.querySelector(h(e))},o.prototype._buildDepMap=function(){this._depMap.clear();const e=this;e._fields.forEach(function(r){const s=r.logic;if(!s)return;function t(n){if(!n)return;(n.all||n.any||[]).forEach(function(a){a.field?(e._depMap.has(a.field)||e._depMap.set(a.field,new Set),e._depMap.get(a.field).add(r.name)):t(a)})}if(s.visibility&&(s.visibility.conditions||[]).forEach(function(n){t(n.when)}),s.requirement&&(s.requirement.conditions||[]).forEach(function(n){t(n.when)}),s.cascade&&s.cascade.sourceField){const n=s.cascade.sourceField;e._depMap.has(n)||e._depMap.set(n,new Set),e._depMap.get(n).add(r.name)}})},o.prototype._getValues=function(){const e={};return this._fields.forEach(function(r){const s=this._fieldInputs(r.name);if(!s.length)return;const t=s[0];if(t.type==="radio"){const n=this._wrapper.querySelector(h(r.name,":checked"));e[r.name]=n?n.value:""}else if(t.type==="checkbox")if(s.length>1||/\[\]$/.test(t.name||"")){const n=[];s.forEach(function(i){i.checked&&n.push(i.value)}),e[r.name]=n}else e[r.name]=t.checked?t.value||"true":"";else e[r.name]=t.value},this),e},o.prototype._applyVisibility=function(e,r){const t=g(e,r)==="hidden",n=this._findFieldWrapper(e.name);if(!n)return;n.setAttribute("aria-hidden",String(t));const i=this._initialEval?"none":e.logic?.visibility?.transition||"none";if(i==="none"){n.classList.toggle("fb-field-hidden",t);return}const a=e.logic?.visibility?.duration;n.style.transition="",t?L(n,i,a):C(n,i,a)},o.prototype._applyRequirement=function(e,r){const s=v(e,r),t=this._fieldInput(e.name);if(t){if(/\[\]$/.test(t.name||"")||t.closest&&t.closest(".domma-chooser")){const n=this._findFieldWrapper(e.name);t.removeAttribute("required"),n&&(n.setAttribute("aria-required",String(s)),n.classList.toggle("fb-field-required",s));return}s?t.setAttribute("required",""):t.removeAttribute("required")}},o.prototype._applyCascade=function(e,r){const s=w(e,r);if(s===null)return;const t=this._wrapper.querySelector(h(e.name,"","select"));if(!t)return;const n=t.value;t.textContent="",s.forEach(function(i){const a=document.createElement("option");a.value=i.value,a.textContent=i.label||i.value,i.value===n&&(a.selected=!0),t.appendChild(a)})},o.prototype._applyValidation=function(e,r){const s=this._fieldInput(e.name);if(!s)return;const t=b(e,r[e.name],r);let n=s.parentNode.querySelector(".fb-validation-error");t.length?(n||(n=document.createElement("div"),n.className="fb-validation-error",s.parentNode.appendChild(n)),n.textContent=t[0].message):n&&n.remove()},o.prototype._findFieldWrapper=function(e){const r=this._fieldInput(e);if(!r)return null;const s=r.closest("form")||this._wrapper;let t=r;for(;t.parentNode&&t.parentNode!==s;)t=t.parentNode;return t},o.prototype.evaluate=function(e){const r=this._getValues(),s=this;let t;if(e&&this._depMap.has(e)){const n=this._depMap.get(e);t=this._fields.filter(function(i){return n.has(i.name)})}else t=this._fields;t.forEach(function(n){n.logic&&(s._applyVisibility(n,r),s._applyRequirement(n,r),s._applyCascade(n,r))})},o.prototype.init=function(){this._buildDepMap();const e=this;this._wrapper.querySelectorAll("input, select, textarea").forEach(function(t){const n=S(t.getAttribute("name"));if(!n)return;const i=function(){e.evaluate(n)};t.addEventListener("input",i),t.addEventListener("change",i),e._listeners.push({el:t,event:"input",fn:i}),e._listeners.push({el:t,event:"change",fn:i});const a=e._fields.find(function(u){return u.name===n});if(a&&a.logic&&Array.isArray(a.logic.validation)&&a.logic.validation.length){const u=function(){const d=e._getValues();e._applyValidation(a,d)};t.addEventListener("blur",u),e._listeners.push({el:t,event:"blur",fn:u})}}),this._wrapper.querySelectorAll("[data-chooser-field]").forEach(function(t){const n=t.getAttribute("data-chooser-field");if(!n)return;const i=function(){setTimeout(function(){e.evaluate(n)},0)};t.addEventListener("click",i),e._listeners.push({el:t,event:"click",fn:i})}),this._initialEval=!0,this.evaluate(),this._initialEval=!1},o.prototype.destroy=function(){this._listeners.forEach(function(e){e.el.removeEventListener(e.event,e.fn)}),this._listeners=[]},{evaluateCondition:y,evaluateConditionGroup:p,evaluateFieldVisibility:g,evaluateFieldRequirement:v,validateField:b,getCascadeOptions:w,FormLogicRuntime:o}});
|
|
1
|
+
(function(u,f){typeof module<"u"&&module.exports?module.exports=f():u.FormLogicEngine=f()})(typeof globalThis<"u"?globalThis:this,function(){"use strict";function u(e){return e===""||e===null||e===void 0?"":String(e)}function f(e){const r=parseFloat(e);return isNaN(r)?null:r}function p(e){return e==null?!0:typeof e=="string"?e.trim()==="":Array.isArray(e)?e.length===0:!1}const F={not_equals:"equals",not_contains:"contains",not_in:"in"};function m(e,r){const n=u(r),t=u(e.value);switch(e.operator){case"equals":return n===t;case"not_equals":return n!==t;case"contains":return n.toLowerCase().includes(t.toLowerCase());case"not_contains":return!n.toLowerCase().includes(t.toLowerCase());case"starts_with":return n.toLowerCase().startsWith(t.toLowerCase());case"ends_with":return n.toLowerCase().endsWith(t.toLowerCase());case"greater_than":{const s=f(r),i=f(e.value);return s!==null&&i!==null&&s>i}case"less_than":{const s=f(r),i=f(e.value);return s!==null&&i!==null&&s<i}case"is_empty":return p(r);case"is_not_empty":return!p(r);case"in":return(Array.isArray(e.value)?e.value.map(u):String(e.value).split(",").map(i=>i.trim())).includes(n);case"not_in":return!(Array.isArray(e.value)?e.value.map(u):String(e.value).split(",").map(i=>i.trim())).includes(n);case"matches_regex":try{const s=e.flags||"";return new RegExp(e.value,s).test(n)}catch(s){return typeof console<"u"&&console.warn&&console.warn('[FormLogicEngine] Invalid regex in condition for field "'+e.field+'": '+e.value,s&&s.message),!1}default:return!0}}function y(e,r){if(!e||!e.field||!e.operator)return!0;const n=r[e.field];if(!Array.isArray(n))return m(e,n);if(e.operator==="is_empty")return p(n);if(e.operator==="is_not_empty")return!p(n);const t=F[e.operator];if(t){const s=Object.assign({},e,{operator:t});return!n.some(i=>m(s,i))}return n.some(s=>m(e,s))}function h(e,r){return e?Array.isArray(e.all)?e.all.every(n=>n.all||n.any?h(n,r):y(n,r)):Array.isArray(e.any)?e.any.some(n=>n.all||n.any?h(n,r):y(n,r)):e.field&&e.operator?y(e,r):!0:!0}function g(e,r){const n=e.logic;if(!n||!n.visibility)return"visible";const t=n.visibility,s=t.conditions||[];for(const i of s)if(i.when&&h(i.when,r))return i.then==="hidden"?"hidden":"visible";return t.default==="hidden"?"hidden":"visible"}function _(e,r){const n=e.logic;if(!n||!n.requirement)return e.required||!1;const t=n.requirement,s=t.conditions||[];for(const i of s)if(i.when&&h(i.when,r))return i.then===!0;return t.default===!0}function v(e,r,n){const t=e.logic;if(!t||!Array.isArray(t.validation))return[];const s=[];for(const i of t.validation)switch(i.type){case"regex":{if(!p(r))try{new RegExp(i.pattern||"",i.flags||"").test(u(r))||s.push({message:i.message||"Invalid format."})}catch{}break}case"match":{const a=n[i.field];!p(r)&&u(r)!==u(a)&&s.push({message:i.message||"Fields do not match."});break}}return s}function w(e,r){const n=e.logic;if(!n||!n.cascade||!n.cascade.sourceField)return null;const t=n.cascade,s=t.mapping||{},i=r[t.sourceField];if(Array.isArray(i)){const c=new Set,l=[];return i.forEach(function(T){const q=u(T);Object.prototype.hasOwnProperty.call(s,q)&&(s[q]||[]).forEach(function(b){const x=u(b&&b.value);c.has(x)||(c.add(x),l.push(b))})}),l.length?l:t.defaultOptions||null}const a=u(i);return Object.prototype.hasOwnProperty.call(s,a)?s[a]||[]:t.defaultOptions||null}const L={fade:250,slide:300,scale:200};function A(e,r){const n=Number(r);return!isFinite(n)||n<0||n>5e3?L[e]||250:Math.round(n)}function S(e,r,n){const t=A(r,n);if(r==="fade")e.style.transition="opacity "+t+"ms ease",e.style.opacity="1",requestAnimationFrame(function(){e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.opacity=""},t+10)});else if(r==="slide"){const s=Math.round(t*.67);e.style.overflow="hidden",e.style.maxHeight=e.scrollHeight+"px",e.style.transition="max-height "+t+"ms ease, opacity "+s+"ms ease",requestAnimationFrame(function(){e.style.maxHeight="0",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},t+20)})}else r==="scale"&&(e.style.transition="opacity "+t+"ms ease, transform "+t+"ms ease",e.style.transform="scale(1)",e.style.opacity="1",requestAnimationFrame(function(){e.style.transform="scale(0.95)",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.transform="",e.style.opacity=""},t+20)}))}function C(e,r,n){const t=A(r,n);if(e.classList.remove("fb-field-hidden"),r==="fade")e.style.opacity="0",e.style.transition="opacity "+t+"ms ease",requestAnimationFrame(function(){e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.opacity=""},t+10)});else if(r==="slide"){const s=Math.round(t*.67);e.style.overflow="hidden",e.style.maxHeight="0",e.style.opacity="0",e.style.transition="max-height "+t+"ms ease, opacity "+s+"ms ease",requestAnimationFrame(function(){e.style.maxHeight=e.scrollHeight+"px",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},t+20)})}else r==="scale"&&(e.style.transform="scale(0.95)",e.style.opacity="0",e.style.transition="opacity "+t+"ms ease, transform "+t+"ms ease",requestAnimationFrame(function(){e.style.transform="scale(1)",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.transform="",e.style.opacity=""},t+20)}))}function o(e,r){this._form=e,this._wrapper=r,this._fields=(e.fields||[]).filter(n=>n.type!=="page-break"),this._listeners=[],this._depMap=new Map,this._initialEval=!1}function d(e,r,n){const t=n||"",s=r||"";return t+'[name="'+e+'"]'+s+", "+t+'[name="'+e+'[]"]'+s}function k(e){return String(e||"").replace(/\[\]$/,"")}o.prototype._fieldInputs=function(e){return this._wrapper.querySelectorAll(d(e))},o.prototype._fieldInput=function(e){return this._wrapper.querySelector(d(e))},o.prototype._buildDepMap=function(){this._depMap.clear();const e=this;e._fields.forEach(function(r){const n=r.logic;if(!n)return;function t(s){if(!s)return;(s.all||s.any||[]).forEach(function(a){a.field?(e._depMap.has(a.field)||e._depMap.set(a.field,new Set),e._depMap.get(a.field).add(r.name)):t(a)})}if(n.visibility&&(n.visibility.conditions||[]).forEach(function(s){t(s.when)}),n.requirement&&(n.requirement.conditions||[]).forEach(function(s){t(s.when)}),n.cascade&&n.cascade.sourceField){const s=n.cascade.sourceField;e._depMap.has(s)||e._depMap.set(s,new Set),e._depMap.get(s).add(r.name)}})};function E(e,r){const n={};return(r||[]).forEach(function(t){if(!t||!t.name)return;const s=e.querySelectorAll(d(t.name));if(!s.length)return;const i=s[0];if(i.type==="radio"){const a=e.querySelector(d(t.name,":checked"));n[t.name]=a?a.value:""}else if(i.type==="checkbox")if(s.length>1||/\[\]$/.test(i.name||"")){const a=[];s.forEach(function(c){c.checked&&a.push(c.value)}),n[t.name]=a}else n[t.name]=i.checked?i.value||"true":"";else n[t.name]=i.value}),n}function M(e,r){const n=E(e,r),t=[],s=[];return(r||[]).forEach(function(i){if(!i||!i.name||g(i,n)==="hidden")return;const a=n[i.name],c=Array.isArray(a)?a.length===0:!String(a??"").trim();if(_(i,n)&&c){t.push({name:i.name,label:i.label||i.name});return}if(c)return;const l=v(i,a,n);l.length&&s.push(l[0].message)}),{valid:t.length===0&&s.length===0,missing:t,errors:s,values:n}}return o.prototype._getValues=function(){const e={};return this._fields.forEach(function(r){const n=this._fieldInputs(r.name);if(!n.length)return;const t=n[0];if(t.type==="radio"){const s=this._wrapper.querySelector(d(r.name,":checked"));e[r.name]=s?s.value:""}else if(t.type==="checkbox")if(n.length>1||/\[\]$/.test(t.name||"")){const s=[];n.forEach(function(i){i.checked&&s.push(i.value)}),e[r.name]=s}else e[r.name]=t.checked?t.value||"true":"";else e[r.name]=t.value},this),e},o.prototype._applyVisibility=function(e,r){const t=g(e,r)==="hidden",s=this._findFieldWrapper(e.name);if(!s)return;s.setAttribute("aria-hidden",String(t));const i=this._initialEval?"none":e.logic?.visibility?.transition||"none";if(i==="none"){s.classList.toggle("fb-field-hidden",t);return}const a=e.logic?.visibility?.duration;s.style.transition="",t?S(s,i,a):C(s,i,a)},o.prototype._applyRequirement=function(e,r){const n=_(e,r),t=this._fieldInput(e.name);if(!t)return;if(/\[\]$/.test(t.name||"")||t.closest&&t.closest(".domma-chooser")){const i=this._findFieldWrapper(e.name);t.removeAttribute("required"),i&&(i.setAttribute("aria-required",String(n)),i.classList.toggle("fb-field-required",n));return}n?t.setAttribute("required",""):t.removeAttribute("required");const s=this._findFieldWrapper(e.name);s&&(s.setAttribute("aria-required",String(n)),s.classList.toggle("fb-field-required",n))},o.prototype._applyCascade=function(e,r){const n=w(e,r);if(n===null)return;const t=this._wrapper.querySelector(d(e.name,"","select"));if(!t)return;const s=t.value;t.textContent="",n.forEach(function(i){const a=document.createElement("option");a.value=i.value,a.textContent=i.label||i.value,i.value===s&&(a.selected=!0),t.appendChild(a)})},o.prototype._applyValidation=function(e,r){const n=this._fieldInput(e.name);if(!n)return;const t=v(e,r[e.name],r);let s=n.parentNode.querySelector(".fb-validation-error");t.length?(s||(s=document.createElement("div"),s.className="fb-validation-error",n.parentNode.appendChild(s)),s.textContent=t[0].message):s&&s.remove()},o.prototype._findFieldWrapper=function(e){const r=this._fieldInput(e);if(!r)return null;const n=r.closest("form")||this._wrapper;let t=r;for(;t.parentNode&&t.parentNode!==n;)t=t.parentNode;return t},o.prototype.evaluate=function(e){const r=this._getValues(),n=this;let t;if(e&&this._depMap.has(e)){const s=this._depMap.get(e);t=this._fields.filter(function(i){return s.has(i.name)})}else t=this._fields;t.forEach(function(s){s.logic&&(n._applyVisibility(s,r),n._applyRequirement(s,r),n._applyCascade(s,r))})},o.prototype.init=function(){this._buildDepMap();const e=this;this._wrapper.querySelectorAll("input, select, textarea").forEach(function(t){const s=k(t.getAttribute("name"));if(!s)return;const i=function(){e.evaluate(s)};t.addEventListener("input",i),t.addEventListener("change",i),e._listeners.push({el:t,event:"input",fn:i}),e._listeners.push({el:t,event:"change",fn:i});const a=e._fields.find(function(c){return c.name===s});if(a&&a.logic&&Array.isArray(a.logic.validation)&&a.logic.validation.length){const c=function(){const l=e._getValues();e._applyValidation(a,l)};t.addEventListener("blur",c),e._listeners.push({el:t,event:"blur",fn:c})}}),this._wrapper.querySelectorAll("[data-chooser-field]").forEach(function(t){const s=t.getAttribute("data-chooser-field");if(!s)return;const i=function(){setTimeout(function(){e.evaluate(s)},0)};t.addEventListener("click",i),e._listeners.push({el:t,event:"click",fn:i})}),this._initialEval=!0,this.evaluate(),this._initialEval=!1},o.prototype.destroy=function(){this._listeners.forEach(function(e){e.el.removeEventListener(e.event,e.fn)}),this._listeners=[]},{evaluateCondition:y,evaluateConditionGroup:h,evaluateFieldVisibility:g,evaluateFieldRequirement:_,validateField:v,collectValues:E,validateFields:M,getCascadeOptions:w,FormLogicRuntime:o}});
|
package/public/js/forms.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
const x=document.querySelectorAll("[data-form]");x.length&&x.forEach(D);function y(a,o,t){const e=a.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const i=document.createElement("div");i.className=t==="success"?"fb-form-success":"fb-form-error",i.textContent=o,a.appendChild(i)}function E(a,o){if(a._formLogicRuntime=o,!a.parentNode||typeof MutationObserver>"u")return;const t=new MutationObserver(function(e){for(const i of e)for(const r of i.removedNodes)if(r===a||r.nodeType===1&&r.contains&&r.contains(a)){o.destroy(),t.disconnect();return}});t.observe(a.parentNode,{childList:!0,subtree:!1})}function w(a,o){const t={};return a.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const i=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),r=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":i?"chooser":e.type,l={...e.formConfig||{}};l.span==="full"&&o&&(l.span=o);const n={type:r,label:e.label||e.name,required:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...l}};e.minLength!==void 0&&(n.minLength=e.minLength),e.maxLength!==void 0&&(n.maxLength=e.maxLength),e.min!==void 0&&(n.min=e.min),e.max!==void 0&&(n.max=e.max),i&&(e.variant&&(n.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(n.multiple=!0),e.density&&(n.density=e.density),e.columns&&(n.columns=e.columns),e.accent&&(n.accent=e.accent),e.accentStyle&&(n.accentStyle=e.accentStyle),e.glow&&(n.glow=!0),e.glowColour&&(n.glowColour=e.glowColour),e.shadow&&(n.shadow=e.shadow),e.shadowColour&&(n.shadowColour=e.shadowColour)),t[e.name]=n}),t}function j(a){const o={};return a.forEach(function(t){if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(o[t.name]=typeof e=="object"?e.value:e)}}),o}function C(a,o){(o||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=a.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}function N(a,o){const t=[];let e=[],i=o||"Step 1",r="";return a.forEach(function(l){l.type==="page-break"?(t.push({title:i,description:r,fieldGroup:e}),e=[],i=l.label||"Step "+(t.length+1),r=l.description||""):l.type!=="spacer"&&e.push(l)}),t.push({title:i,description:r,fieldGroup:e}),t}const k="padding:.45rem .7rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.85em;flex-shrink:0;line-height:1.2;";function L(a){const o=document.createElement("div");o.style.cssText="position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:20px;";const t=document.createElement("div");t.style.cssText="background:var(--dm-surface-overlay,var(--dm-surface));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:10px;width:100%;max-width:560px;max-height:75vh;display:flex;flex-direction:column;gap:.6rem;padding:1rem;box-shadow:var(--dm-shadow-lg,0 12px 40px rgba(0,0,0,.35));";const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;justify-content:space-between;gap:.5rem;";const i=document.createElement("strong");i.textContent=a;const r=document.createElement("button");r.type="button",r.textContent="\xD7",r.setAttribute("aria-label","Close"),r.style.cssText=k+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(i),e.appendChild(r),t.appendChild(e);const l=document.createElement("div");l.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(l),o.appendChild(t);const n=u=>{u.key==="Escape"&&s()};function s(){document.removeEventListener("keydown",n),o.remove()}return r.addEventListener("click",s),o.addEventListener("click",u=>{u.target===o&&s()}),document.addEventListener("keydown",n),document.body.appendChild(o),{body:l,close:s}}function A(a){const{body:o,close:t}=L("Choose an icon"),e=document.createElement("input");e.type="text",e.placeholder="Search icons\u2026",e.className="form-input",e.style.cssText="padding:.45rem .6rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:var(--dm-input-bg,transparent);color:var(--dm-text);",o.appendChild(e);const i=document.createElement("div");i.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:4px;overflow-y:auto;min-height:0;",o.appendChild(i);const r=window.I&&typeof I.list=="function"?I.list():[],l=r.map(n=>{const s=document.createElement("button");s.type="button",s.title=n,s.dataset.iconName=n,s.style.cssText="display:flex;align-items:center;justify-content:center;padding:.55rem 0;border:1px solid transparent;border-radius:6px;background:transparent;color:inherit;cursor:pointer;";const u=document.createElement("span");return u.setAttribute("data-icon",n),u.setAttribute("data-icon-size","18"),s.appendChild(u),s.addEventListener("mouseenter",()=>{s.style.borderColor="var(--dm-border)"}),s.addEventListener("mouseleave",()=>{s.style.borderColor="transparent"}),s.addEventListener("click",()=>{t(),a(n)}),i.appendChild(s),s});if(!r.length){const n=document.createElement("p");n.textContent="Icon engine unavailable \u2014 type an icon name into the field instead.",i.appendChild(n)}window.I?.scan?.(i),e.addEventListener("input",()=>{const n=e.value.trim().toLowerCase();l.forEach(s=>{s.style.display=!n||s.dataset.iconName.includes(n)?"":"none"})}),e.focus()}async function R(){const a=typeof S<"u"&&S.get?S.get("auth_token"):null;if(!a)return{error:"auth"};const o=i=>fetch("/api/media",{headers:{Authorization:"Bearer "+i}});let t;try{if(t=await o(a),t.status===401&&S.get("auth_refresh_token")){const i=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:S.get("auth_refresh_token")})});if(i.ok){const{token:r}=await i.json();S.set("auth_token",r),t=await o(r)}}}catch{return{error:"load"}}if(!t.ok)return{error:t.status===401||t.status===403?"auth":"load"};const e=await t.json().catch(()=>[]);return{files:(Array.isArray(e)?e:[]).filter(i=>/\.(png|jpe?g|gif|webp|svg|avif)$/i.test(i.name||i.url||""))}}function _(a){const{body:o,close:t}=L("Choose an image"),e=document.createElement("p");e.textContent="Loading media library\u2026",e.style.cssText="margin:0;font-size:.85em;color:var(--dm-text-muted);",o.appendChild(e),R().then(({files:i,error:r})=>{if(r){e.textContent=r==="auth"?"Sign in with media access to browse the library \u2014 or paste an image URL into the field.":"Could not load the media library \u2014 paste an image URL into the field instead.";return}if(!i.length){e.textContent="No images in the media library yet.";return}e.remove();const l=document.createElement("div");l.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",i.forEach(n=>{const s=document.createElement("button");s.type="button",s.title=n.name||n.url,s.style.cssText="display:flex;flex-direction:column;gap:.25rem;padding:.35rem;border:1px solid var(--dm-border);border-radius:8px;background:transparent;color:inherit;cursor:pointer;min-width:0;";const u=document.createElement("img");u.src=n.url,u.alt=n.name||"",u.loading="lazy",u.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const d=document.createElement("span");d.textContent=n.name||n.url,d.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",s.appendChild(u),s.appendChild(d),s.addEventListener("click",()=>{t(),a(n.url)}),l.appendChild(s)}),o.appendChild(l)})}function T(a,o){a.value=o,a.dispatchEvent(new Event("input",{bubbles:!0})),a.dispatchEvent(new Event("change",{bubbles:!0}))}function q(a){const o=document.createElement("div");return o.style.cssText="display:flex;align-items:center;gap:.5rem;",a.parentNode.insertBefore(o,a),o.appendChild(a),a.style.flex="1",a.style.minWidth="0",o}function F(a){const o=document.createElement("button");return o.type="button",o.textContent=a,o.style.cssText=k,o}function B(a){if(!window.I||typeof I.list!="function")return;const o=q(a),t=document.createElement("span");t.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);";const e=()=>{t.textContent="";const r=a.value.trim();if(!r)return;const l=document.createElement("span");l.setAttribute("data-icon",r),l.setAttribute("data-icon-size","16"),t.appendChild(l),window.I?.scan?.(t)};a.addEventListener("input",e),e();const i=F("Browse");i.addEventListener("click",()=>A(r=>{T(a,r),e()})),o.appendChild(t),o.appendChild(i)}function z(a){const o=q(a),t=document.createElement("img");t.alt="",t.style.cssText="width:2rem;height:2rem;flex-shrink:0;object-fit:cover;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);display:none;";const e=()=>{const r=a.value.trim();t.style.display=r?"":"none",r&&(t.src=r)};a.addEventListener("input",e),e();const i=F("Browse");i.addEventListener("click",()=>_(r=>{T(a,r),e()})),o.appendChild(t),o.appendChild(i)}export function enhancePickerFields(a,o){const t=typeof a=="string"?document.querySelector(a):a;t&&(o||[]).forEach(function(e){if(!e.name||e.type!=="icon"&&e.type!=="image")return;const i=t.querySelector('[name="'+e.name+'"]');!i||i.dataset.pickerEnhanced||(i.dataset.pickerEnhanced="1",e.type==="icon"?B(i):z(i))})}function g(a){const o=document.createElement("div");o.className="fb-form-honeypot",o.setAttribute("aria-hidden","true");const t=document.createElement("input");t.name="website",t.type="text",t.tabIndex=-1,t.autocomplete="url",t.placeholder="https://",o.appendChild(t);const e=document.createElement("input");e.name="_t",e.type="hidden",e.value=Date.now(),o.appendChild(e),a.appendChild(o)}function O(a,o){const t=a.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let i=0;o.forEach(function(r){if(r.type==="spacer"){const l=document.createElement("div");l.className="fb-spacer";const n=e[i];if(n)t.insertBefore(l,n);else{const s=t.querySelector('[type="submit"]');s?t.insertBefore(l,s):t.appendChild(l)}}else r.type!=="page-break"&&i++})}function b(a,o,t,e,i){const r=i||e,l=r.querySelector('[name="website"]')?.value||"",n=r.querySelector('[name="_t"]')?.value||"",s=r?Array.from(r.querySelectorAll('input[type="file"]')):[],u=s.some(m=>m.files&&m.files.length>0);let d,c;if(u){const m=new FormData;for(const[h,p]of Object.entries(o||{}))p!=null&&(s.some(f=>f.name===h)||m.append(h,typeof p=="object"?JSON.stringify(p):String(p)));for(const h of s)for(const p of h.files)m.append(h.name,p,p.name);m.append("_hp",l),m.append("_t",n),d=m,c={}}else{const m=Object.assign({},o,{_hp:l,_t:n});d=JSON.stringify(m),c={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+a,{method:"POST",headers:c,body:d}).then(m=>m.json().then(h=>({ok:m.ok,body:h}))).then(m=>{m.ok&&m.body.ok?(e.textContent="",y(e,m.body.message||t.successMessage||"Thank you.","success")):y(e,m.body.error||"Something went wrong.","error")}).catch(()=>{y(e,"Unable to submit. Please check your connection.","error")})}function P(a,o,t,e,i){const r=document.createElement("form");r.noValidate=!0,o.forEach(function(n){const s=document.createElement("div");s.className="form-group",s.style.marginBottom="1.25rem";const u=document.createElement("label");if(u.className="form-label",u.textContent=n.label||n.name,n.required){const c=document.createElement("span");c.textContent=" *",c.style.color="var(--dm-danger)",u.appendChild(c)}let d;n.type==="textarea"?(d=document.createElement("textarea"),d.rows=n.formConfig?.rows||4,d.className="form-input"):n.type==="select"?(d=document.createElement("select"),d.className="form-input",(n.options||[]).forEach(function(c){const m=document.createElement("option");m.value=typeof c=="string"?c:c.value??"",m.textContent=typeof c=="string"?c:c.label||m.value,d.appendChild(m)})):(d=document.createElement("input"),d.type=n.type==="icon"||n.type==="image"?"text":n.type||"text",d.className="form-input",n.placeholder&&(d.placeholder=n.placeholder),n.type==="file"&&(n.file?.accept&&(d.accept=n.file.accept),n.multiple&&(d.multiple=!0))),d.name=n.name,d.required=n.required||!1,s.appendChild(u),s.appendChild(d),r.appendChild(s)}),t.honeypot&&g(r);const l=document.createElement("button");l.type="submit",l.className="btn btn-primary",l.textContent=t.submitText||"Submit",r.appendChild(l),r.addEventListener("submit",function(n){n.preventDefault();const s={};if(o.forEach(function(u){const d=r.querySelector('[name="'+u.name+'"]');d&&(s[u.name]=d.value)}),window.FormLogicEngine&&i){const u=window.FormLogicEngine,d=[],c=[];if(o.forEach(function(m){if(u.evaluateFieldVisibility(m,s)==="hidden"){delete s[m.name];return}const p=u.evaluateFieldRequirement(m,s),f=s[m.name];p&&(!f||!String(f).trim())&&d.push(m.label||m.name);const v=u.validateField(m,f||"",s);v.length&&c.push(v[0].message)}),d.length||c.length){const m=[];d.length&&m.push("Required: "+d.join(", ")),c.length&&m.push(c.join("; ")),y(a,m.join(". "),"error");return}}a.classList.add("fb-form-loading"),l.disabled=!0,b(e,s,t,a,r).finally(function(){a.classList.remove("fb-form-loading"),l.disabled=!1})}),a.appendChild(r),enhancePickerFields(a,o),window.FormLogicEngine&&i&&o.some(n=>n.logic)&&new window.FormLogicEngine.FormLogicRuntime(i,a).init()}function D(a){const o=a.getAttribute("data-form");o&&fetch("/api/forms/"+o+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+o);return t.json()}).then(t=>{const e=t.fields||[],i=t.settings||{},r=document.createElement("div");r.className="fb-form-wrapper",a.appendChild(r);const l=e.some(n=>n.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const n=i.columns||1;if(l&&Domma.forms.wizard){const u=N(e,t.title).map(function(c){return{title:c.title,description:c.description,fields:w(c.fieldGroup,n)}}),d=Domma.forms.wizard(r,{schema:{steps:u},onSubmit:function(c){return b(o,c,i,r,null)}});Promise.resolve(d).then(function(){if(C(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&e.some(c=>c.logic)){const c=new window.FormLogicEngine.FormLogicRuntime(t,r);c.init(),E(r,c)}if(i.honeypot){const c=r.querySelector("form");c&&g(c)}})}else if(Domma.forms.render){const s=w(e,n),u=j(e),d=Domma.forms.render(r,s,u,{submitText:i.submitText||"Submit",layout:i.layout||"stacked",columns:n,onSubmit:function(c){return b(o,c,i,r,null)}});Promise.resolve(d).then(function(){if(C(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&e.some(c=>c.logic)){const c=new window.FormLogicEngine.FormLogicRuntime(t,r);c.init(),E(r,c)}if(e.some(c=>c.type==="spacer")&&O(r,e),i.honeypot){const c=r.querySelector("form");c&&g(c)}})}}else P(r,e.filter(n=>n.type!=="page-break"&&n.type!=="spacer"),i,o,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:var(--dm-danger);font-style:italic;",a.appendChild(e),console.warn("[forms]",t.message)})}
|
|
1
|
+
const C=document.querySelectorAll("[data-form]");C.length&&C.forEach(U);function A(n,o){const t=n.querySelector('[name="'+o+'"], [name="'+o+'[]"]')||n.querySelector('[data-chooser-field="'+o+'"]');if(!t)return null;const e=t.closest("form")||n;let a=t;for(;a.parentNode&&a.parentNode!==e;)a=a.parentNode;return a}export function markInvalidFields(n,o){n.querySelectorAll(".fb-field-invalid").forEach(e=>e.classList.remove("fb-field-invalid"));let t=null;(o||[]).forEach(function(e){const a=A(n,e.name);a&&(a.classList.add("fb-field-invalid"),t||(t=a))}),t&&t.scrollIntoView&&t.scrollIntoView({behavior:"smooth",block:"center"})}export function showValidationPopup(n){const o=(n.missing||[]).map(e=>"<strong>"+k(e.label)+"</strong> is required.").concat((n.errors||[]).map(k)),t=o.join("<br>");if(typeof E<"u"&&E.alert){E.alert(t,{title:"Please complete this step"});return}window.alert(o.join(`
|
|
2
|
+
`).replace(/<[^>]+>/g,""))}function k(n){return String(n).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function y(n,o,t){const e=n.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const a=document.createElement("div");a.className=t==="success"?"fb-form-success":"fb-form-error",a.textContent=o,n.appendChild(a)}function L(n,o){if(n._formLogicRuntime=o,!n.parentNode||typeof MutationObserver>"u"||n._formLogicObserved)return;n._formLogicObserved=!0;const t=new MutationObserver(function(e){for(const a of e)for(const r of a.removedNodes)if(r===n||r.nodeType===1&&r.contains&&r.contains(n)){n._formLogicRuntime&&n._formLogicRuntime.destroy(),t.disconnect();return}});t.observe(n.parentNode,{childList:!0,subtree:!1})}function z(n){const o=n&&n.logic;return!!(o&&(o.visibility||o.requirement))}function T(n,o){const t={};return n.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const a=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),r=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":a?"chooser":e.type,l={...e.formConfig||{}};l.span==="full"&&o&&(l.span=o);const i={type:r,label:e.label||e.name,required:z(e)?!1:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...l}};e.minLength!==void 0&&(i.minLength=e.minLength),e.maxLength!==void 0&&(i.maxLength=e.maxLength),e.min!==void 0&&(i.min=e.min),e.max!==void 0&&(i.max=e.max),a&&(e.variant&&(i.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(i.multiple=!0),e.density&&(i.density=e.density),e.columns&&(i.columns=e.columns),e.accent&&(i.accent=e.accent),e.accentStyle&&(i.accentStyle=e.accentStyle),e.glow&&(i.glow=!0),e.glowColour&&(i.glowColour=e.glowColour),e.shadow&&(i.shadow=e.shadow),e.shadowColour&&(i.shadowColour=e.shadowColour)),t[e.name]=i}),t}function P(n){const o={};return n.forEach(function(t){if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(o[t.name]=typeof e=="object"?e.value:e)}}),o}function q(n,o){(o||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=n.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}function B(n,o){const t=[];let e=[],a=o||"Step 1",r="";return n.forEach(function(l){l.type==="page-break"?(t.push({title:a,description:r,fieldGroup:e}),e=[],a=l.label||"Step "+(t.length+1),r=l.description||""):l.type!=="spacer"&&e.push(l)}),t.push({title:a,description:r,fieldGroup:e}),t}const F="padding:.45rem .7rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.85em;flex-shrink:0;line-height:1.2;";function j(n){const o=document.createElement("div");o.style.cssText="position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:20px;";const t=document.createElement("div");t.style.cssText="background:var(--dm-surface-overlay,var(--dm-surface));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:10px;width:100%;max-width:560px;max-height:75vh;display:flex;flex-direction:column;gap:.6rem;padding:1rem;box-shadow:var(--dm-shadow-lg,0 12px 40px rgba(0,0,0,.35));";const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;justify-content:space-between;gap:.5rem;";const a=document.createElement("strong");a.textContent=n;const r=document.createElement("button");r.type="button",r.textContent="\xD7",r.setAttribute("aria-label","Close"),r.style.cssText=F+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(a),e.appendChild(r),t.appendChild(e);const l=document.createElement("div");l.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(l),o.appendChild(t);const i=m=>{m.key==="Escape"&&s()};function s(){document.removeEventListener("keydown",i),o.remove()}return r.addEventListener("click",s),o.addEventListener("click",m=>{m.target===o&&s()}),document.addEventListener("keydown",i),document.body.appendChild(o),{body:l,close:s}}function O(n){const{body:o,close:t}=j("Choose an icon"),e=document.createElement("input");e.type="text",e.placeholder="Search icons\u2026",e.className="form-input",e.style.cssText="padding:.45rem .6rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:var(--dm-input-bg,transparent);color:var(--dm-text);",o.appendChild(e);const a=document.createElement("div");a.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:4px;overflow-y:auto;min-height:0;",o.appendChild(a);const r=window.I&&typeof I.list=="function"?I.list():[],l=r.map(i=>{const s=document.createElement("button");s.type="button",s.title=i,s.dataset.iconName=i,s.style.cssText="display:flex;align-items:center;justify-content:center;padding:.55rem 0;border:1px solid transparent;border-radius:6px;background:transparent;color:inherit;cursor:pointer;";const m=document.createElement("span");return m.setAttribute("data-icon",i),m.setAttribute("data-icon-size","18"),s.appendChild(m),s.addEventListener("mouseenter",()=>{s.style.borderColor="var(--dm-border)"}),s.addEventListener("mouseleave",()=>{s.style.borderColor="transparent"}),s.addEventListener("click",()=>{t(),n(i)}),a.appendChild(s),s});if(!r.length){const i=document.createElement("p");i.textContent="Icon engine unavailable - type an icon name into the field instead.",a.appendChild(i)}window.I?.scan?.(a),e.addEventListener("input",()=>{const i=e.value.trim().toLowerCase();l.forEach(s=>{s.style.display=!i||s.dataset.iconName.includes(i)?"":"none"})}),e.focus()}async function D(){const n=typeof S<"u"&&S.get?S.get("auth_token"):null;if(!n)return{error:"auth"};const o=a=>fetch("/api/media",{headers:{Authorization:"Bearer "+a}});let t;try{if(t=await o(n),t.status===401&&S.get("auth_refresh_token")){const a=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:S.get("auth_refresh_token")})});if(a.ok){const{token:r}=await a.json();S.set("auth_token",r),t=await o(r)}}}catch{return{error:"load"}}if(!t.ok)return{error:t.status===401||t.status===403?"auth":"load"};const e=await t.json().catch(()=>[]);return{files:(Array.isArray(e)?e:[]).filter(a=>/\.(png|jpe?g|gif|webp|svg|avif)$/i.test(a.name||a.url||""))}}function M(n){const{body:o,close:t}=j("Choose an image"),e=document.createElement("p");e.textContent="Loading media library\u2026",e.style.cssText="margin:0;font-size:.85em;color:var(--dm-text-muted);",o.appendChild(e),D().then(({files:a,error:r})=>{if(r){e.textContent=r==="auth"?"Sign in with media access to browse the library - or paste an image URL into the field.":"Could not load the media library - paste an image URL into the field instead.";return}if(!a.length){e.textContent="No images in the media library yet.";return}e.remove();const l=document.createElement("div");l.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",a.forEach(i=>{const s=document.createElement("button");s.type="button",s.title=i.name||i.url,s.style.cssText="display:flex;flex-direction:column;gap:.25rem;padding:.35rem;border:1px solid var(--dm-border);border-radius:8px;background:transparent;color:inherit;cursor:pointer;min-width:0;";const m=document.createElement("img");m.src=i.url,m.alt=i.name||"",m.loading="lazy",m.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const d=document.createElement("span");d.textContent=i.name||i.url,d.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",s.appendChild(m),s.appendChild(d),s.addEventListener("click",()=>{t(),n(i.url)}),l.appendChild(s)}),o.appendChild(l)})}function N(n,o){n.value=o,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}function _(n){const o=document.createElement("div");return o.style.cssText="display:flex;align-items:center;gap:.5rem;",n.parentNode.insertBefore(o,n),o.appendChild(n),n.style.flex="1",n.style.minWidth="0",o}function R(n){const o=document.createElement("button");return o.type="button",o.textContent=n,o.style.cssText=F,o}function V(n){if(!window.I||typeof I.list!="function")return;const o=_(n),t=document.createElement("span");t.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);";const e=()=>{t.textContent="";const r=n.value.trim();if(!r)return;const l=document.createElement("span");l.setAttribute("data-icon",r),l.setAttribute("data-icon-size","16"),t.appendChild(l),window.I?.scan?.(t)};n.addEventListener("input",e),e();const a=R("Browse");a.addEventListener("click",()=>O(r=>{N(n,r),e()})),o.appendChild(t),o.appendChild(a)}function G(n){const o=_(n),t=document.createElement("img");t.alt="",t.style.cssText="width:2rem;height:2rem;flex-shrink:0;object-fit:cover;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);display:none;";const e=()=>{const r=n.value.trim();t.style.display=r?"":"none",r&&(t.src=r)};n.addEventListener("input",e),e();const a=R("Browse");a.addEventListener("click",()=>M(r=>{N(n,r),e()})),o.appendChild(t),o.appendChild(a)}export function enhancePickerFields(n,o){const t=typeof n=="string"?document.querySelector(n):n;t&&(o||[]).forEach(function(e){if(!e.name||e.type!=="icon"&&e.type!=="image")return;const a=t.querySelector('[name="'+e.name+'"]');!a||a.dataset.pickerEnhanced||(a.dataset.pickerEnhanced="1",e.type==="icon"?V(a):G(a))})}function x(n){const o=document.createElement("div");o.className="fb-form-honeypot",o.setAttribute("aria-hidden","true");const t=document.createElement("input");t.name="website",t.type="text",t.tabIndex=-1,t.autocomplete="url",t.placeholder="https://",o.appendChild(t);const e=document.createElement("input");e.name="_t",e.type="hidden",e.value=Date.now(),o.appendChild(e),n.appendChild(o)}function W(n,o){const t=n.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let a=0;o.forEach(function(r){if(r.type==="spacer"){const l=document.createElement("div");l.className="fb-spacer";const i=e[a];if(i)t.insertBefore(l,i);else{const s=t.querySelector('[type="submit"]');s?t.insertBefore(l,s):t.appendChild(l)}}else r.type!=="page-break"&&a++})}function w(n,o,t,e,a){const r=a||e,l=r.querySelector('[name="website"]')?.value||"",i=r.querySelector('[name="_t"]')?.value||"",s=r?Array.from(r.querySelectorAll('input[type="file"]')):[],m=s.some(c=>c.files&&c.files.length>0);let d,u;if(m){const c=new FormData;for(const[h,f]of Object.entries(o||{}))f!=null&&(s.some(g=>g.name===h)||c.append(h,typeof f=="object"?JSON.stringify(f):String(f)));for(const h of s)for(const f of h.files)c.append(h.name,f,f.name);c.append("_hp",l),c.append("_t",i),d=c,u={}}else{const c=Object.assign({},o,{_hp:l,_t:i});d=JSON.stringify(c),u={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+n,{method:"POST",headers:u,body:d}).then(c=>c.json().then(h=>({ok:c.ok,body:h}))).then(c=>{c.ok&&c.body.ok?(e.textContent="",y(e,c.body.message||t.successMessage||"Thank you.","success")):y(e,c.body.error||"Something went wrong.","error")}).catch(()=>{y(e,"Unable to submit. Please check your connection.","error")})}function J(n,o,t,e,a){const r=document.createElement("form");r.noValidate=!0,o.forEach(function(i){const s=document.createElement("div");s.className="form-group",s.style.marginBottom="1.25rem";const m=document.createElement("label");if(m.className="form-label",m.textContent=i.label||i.name,i.required){const u=document.createElement("span");u.textContent=" *",u.style.color="var(--dm-danger)",m.appendChild(u)}let d;i.type==="textarea"?(d=document.createElement("textarea"),d.rows=i.formConfig?.rows||4,d.className="form-input"):i.type==="select"?(d=document.createElement("select"),d.className="form-input",(i.options||[]).forEach(function(u){const c=document.createElement("option");c.value=typeof u=="string"?u:u.value??"",c.textContent=typeof u=="string"?u:u.label||c.value,d.appendChild(c)})):(d=document.createElement("input"),d.type=i.type==="icon"||i.type==="image"?"text":i.type||"text",d.className="form-input",i.placeholder&&(d.placeholder=i.placeholder),i.type==="file"&&(i.file?.accept&&(d.accept=i.file.accept),i.multiple&&(d.multiple=!0))),d.name=i.name,d.required=i.required||!1,s.appendChild(m),s.appendChild(d),r.appendChild(s)}),t.honeypot&&x(r);const l=document.createElement("button");l.type="submit",l.className="btn btn-primary",l.textContent=t.submitText||"Submit",r.appendChild(l),r.addEventListener("submit",function(i){i.preventDefault();const s={};if(o.forEach(function(m){const d=r.querySelector('[name="'+m.name+'"]');d&&(s[m.name]=d.value)}),window.FormLogicEngine&&a){const m=window.FormLogicEngine,d=[],u=[];if(o.forEach(function(c){if(m.evaluateFieldVisibility(c,s)==="hidden"){delete s[c.name];return}const f=m.evaluateFieldRequirement(c,s),g=s[c.name];f&&(!g||!String(g).trim())&&d.push(c.label||c.name);const p=m.validateField(c,g||"",s);p.length&&u.push(p[0].message)}),d.length||u.length){const c=[];d.length&&c.push("Required: "+d.join(", ")),u.length&&c.push(u.join("; ")),y(n,c.join(". "),"error");return}}n.classList.add("fb-form-loading"),l.disabled=!0,w(e,s,t,n,r).finally(function(){n.classList.remove("fb-form-loading"),l.disabled=!1})}),n.appendChild(r),enhancePickerFields(n,o),window.FormLogicEngine&&a&&o.some(i=>i.logic)&&new window.FormLogicEngine.FormLogicRuntime(a,n).init()}function U(n){const o=n.getAttribute("data-form");o&&fetch("/api/forms/"+o+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+o);return t.json()}).then(t=>{const e=t.fields||[],a=t.settings||{},r=document.createElement("div");r.className="fb-form-wrapper",n.appendChild(r);const l=e.some(i=>i.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const i=a.columns||1;if(l&&Domma.forms.wizard){const s=B(e,t.title),m=s.map(p=>p.fieldGroup),d=s.map(function(p){return{title:p.title,description:p.description,fields:T(p.fieldGroup,i)}});let u=0,c=null;const h=function(p){const b=window.FormLogicEngine;if(!b||!b.validateFields)return;const v=b.validateFields(r,m[u]||[]);v.valid||(p.preventDefault(),p.stopImmediatePropagation(),markInvalidFields(r,v.missing),showValidationPopup(v))},f=function(){if(q(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&e.some(p=>p.logic)&&(c&&c.destroy(),c=new window.FormLogicEngine.FormLogicRuntime(t,r),c.init(),L(r,c)),a.honeypot){const p=r.querySelector("form");p&&x(p)}r.querySelectorAll(".wizard-next, .wizard-submit").forEach(p=>p.addEventListener("click",h,!0))},g=Domma.forms.wizard(r,{schema:{steps:d},onSubmit:function(p){return w(o,p,a,r,null)},onStepChange:function(p){u=p,setTimeout(f,0)}});Promise.resolve(g).then(f)}else if(Domma.forms.render){const s=T(e,i),m=P(e),d=Domma.forms.render(r,s,m,{submitText:a.submitText||"Submit",layout:a.layout||"stacked",columns:i,onSubmit:function(u){return w(o,u,a,r,null)}});Promise.resolve(d).then(function(){if(q(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&e.some(u=>u.logic)){const u=new window.FormLogicEngine.FormLogicRuntime(t,r);u.init(),L(r,u)}if(e.some(u=>u.type==="spacer")&&W(r,e),a.honeypot){const u=r.querySelector("form");u&&x(u)}})}}else J(r,e.filter(i=>i.type!=="page-break"&&i.type!=="spacer"),a,o,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:var(--dm-danger);font-style:italic;",n.appendChild(e),console.warn("[forms]",t.message)})}
|