@livenetworks/ashlar 2.2.0 → 2.2.2
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/assets/brand/android-chrome-192x192.png +0 -0
- package/assets/brand/android-chrome-512x512.png +0 -0
- package/assets/brand/apple-touch-icon.png +0 -0
- package/assets/brand/favicon-16x16.png +0 -0
- package/assets/brand/favicon-32x32.png +0 -0
- package/assets/brand/favicon-48x48.png +0 -0
- package/assets/brand/favicon-dark-128x128.png +0 -0
- package/assets/brand/favicon-dark-16x16.png +0 -0
- package/assets/brand/favicon-dark-180x180.png +0 -0
- package/assets/brand/favicon-dark-192x192.png +0 -0
- package/assets/brand/favicon-dark-256x256.png +0 -0
- package/assets/brand/favicon-dark-32x32.png +0 -0
- package/assets/brand/favicon-dark-48x48.png +0 -0
- package/assets/brand/favicon-dark-512x512.png +0 -0
- package/assets/brand/favicon-dark-64x64.png +0 -0
- package/assets/brand/favicon-dark.ico +0 -0
- package/assets/brand/favicon-dark.png +0 -0
- package/assets/brand/favicon-light-128x128.png +0 -0
- package/assets/brand/favicon-light-16x16.png +0 -0
- package/assets/brand/favicon-light-180x180.png +0 -0
- package/assets/brand/favicon-light-192x192.png +0 -0
- package/assets/brand/favicon-light-256x256.png +0 -0
- package/assets/brand/favicon-light-32x32.png +0 -0
- package/assets/brand/favicon-light-48x48.png +0 -0
- package/assets/brand/favicon-light-512x512.png +0 -0
- package/assets/brand/favicon-light-64x64.png +0 -0
- package/assets/brand/favicon-light.ico +0 -0
- package/assets/brand/favicon-light.png +0 -0
- package/assets/brand/favicon.ico +0 -0
- package/assets/brand/favicon.png +0 -0
- package/assets/brand/favicon.svg +12 -0
- package/assets/brand/ln-ashlar-emblem-dark-128.png +0 -0
- package/assets/brand/ln-ashlar-emblem-dark-16.png +0 -0
- package/assets/brand/ln-ashlar-emblem-dark-256.png +0 -0
- package/assets/brand/ln-ashlar-emblem-dark-32.png +0 -0
- package/assets/brand/ln-ashlar-emblem-dark-64.png +0 -0
- package/assets/brand/ln-ashlar-emblem-dark.png +0 -0
- package/assets/brand/ln-ashlar-emblem-light-128.png +0 -0
- package/assets/brand/ln-ashlar-emblem-light-16.png +0 -0
- package/assets/brand/ln-ashlar-emblem-light-256.png +0 -0
- package/assets/brand/ln-ashlar-emblem-light-32.png +0 -0
- package/assets/brand/ln-ashlar-emblem-light-64.png +0 -0
- package/assets/brand/ln-ashlar-emblem-light.png +0 -0
- package/assets/brand/ln-ashlar-logo-dark-128.png +0 -0
- package/assets/brand/ln-ashlar-logo-dark-256.png +0 -0
- package/assets/brand/ln-ashlar-logo-dark-512.png +0 -0
- package/assets/brand/ln-ashlar-logo-dark.png +0 -0
- package/assets/brand/ln-ashlar-logo-light-128.png +0 -0
- package/assets/brand/ln-ashlar-logo-light-256.png +0 -0
- package/assets/brand/ln-ashlar-logo-light-512.png +0 -0
- package/assets/brand/ln-ashlar-logo-light.png +0 -0
- package/assets/brand/site.webmanifest +41 -0
- package/assets/brand/source/ln-ashlar-icon-dark-1024.png +0 -0
- package/assets/brand/source/ln-ashlar-icon-dark-uncropped-1024.png +0 -0
- package/assets/brand/source/ln-ashlar-icon-light-1024.png +0 -0
- package/assets/brand/source/ln-ashlar-icon-light-uncropped-1024.png +0 -0
- package/assets/flags/ad.svg +150 -0
- package/assets/flags/ae.svg +6 -0
- package/assets/flags/af.svg +81 -0
- package/assets/flags/ag.svg +14 -0
- package/assets/flags/ai.svg +29 -0
- package/assets/flags/al.svg +5 -0
- package/assets/flags/am.svg +5 -0
- package/assets/flags/ao.svg +13 -0
- package/assets/flags/aq.svg +5 -0
- package/assets/flags/ar.svg +32 -0
- package/assets/flags/arab.svg +109 -0
- package/assets/flags/as.svg +72 -0
- package/assets/flags/asean.svg +13 -0
- package/assets/flags/at.svg +4 -0
- package/assets/flags/au.svg +8 -0
- package/assets/flags/aw.svg +186 -0
- package/assets/flags/ax.svg +18 -0
- package/assets/flags/az.svg +8 -0
- package/assets/flags/ba.svg +12 -0
- package/assets/flags/bb.svg +6 -0
- package/assets/flags/bd.svg +4 -0
- package/assets/flags/be.svg +7 -0
- package/assets/flags/bf.svg +7 -0
- package/assets/flags/bg.svg +5 -0
- package/assets/flags/bh.svg +4 -0
- package/assets/flags/bi.svg +15 -0
- package/assets/flags/bj.svg +14 -0
- package/assets/flags/bl.svg +5 -0
- package/assets/flags/bm.svg +97 -0
- package/assets/flags/bn.svg +36 -0
- package/assets/flags/bo.svg +673 -0
- package/assets/flags/bq.svg +5 -0
- package/assets/flags/br.svg +45 -0
- package/assets/flags/bs.svg +13 -0
- package/assets/flags/bt.svg +89 -0
- package/assets/flags/bv.svg +13 -0
- package/assets/flags/bw.svg +7 -0
- package/assets/flags/by.svg +18 -0
- package/assets/flags/bz.svg +145 -0
- package/assets/flags/ca.svg +4 -0
- package/assets/flags/cc.svg +19 -0
- package/assets/flags/cd.svg +5 -0
- package/assets/flags/cefta.svg +13 -0
- package/assets/flags/cf.svg +15 -0
- package/assets/flags/cg.svg +12 -0
- package/assets/flags/ch.svg +9 -0
- package/assets/flags/ci.svg +7 -0
- package/assets/flags/ck.svg +9 -0
- package/assets/flags/cl.svg +13 -0
- package/assets/flags/cm.svg +15 -0
- package/assets/flags/cn.svg +11 -0
- package/assets/flags/co.svg +7 -0
- package/assets/flags/cp.svg +7 -0
- package/assets/flags/cr.svg +7 -0
- package/assets/flags/cu.svg +13 -0
- package/assets/flags/cv.svg +13 -0
- package/assets/flags/cw.svg +14 -0
- package/assets/flags/cx.svg +15 -0
- package/assets/flags/cy.svg +6 -0
- package/assets/flags/cz.svg +5 -0
- package/assets/flags/de.svg +5 -0
- package/assets/flags/dg.svg +130 -0
- package/assets/flags/dj.svg +13 -0
- package/assets/flags/dk.svg +5 -0
- package/assets/flags/dm.svg +152 -0
- package/assets/flags/do.svg +121 -0
- package/assets/flags/dz.svg +5 -0
- package/assets/flags/eac.svg +48 -0
- package/assets/flags/ec.svg +138 -0
- package/assets/flags/ee.svg +5 -0
- package/assets/flags/eg.svg +38 -0
- package/assets/flags/eh.svg +16 -0
- package/assets/flags/er.svg +8 -0
- package/assets/flags/es-ct.svg +4 -0
- package/assets/flags/es-ga.svg +187 -0
- package/assets/flags/es-pv.svg +5 -0
- package/assets/flags/es.svg +544 -0
- package/assets/flags/et.svg +14 -0
- package/assets/flags/eu.svg +28 -0
- package/assets/flags/fi.svg +5 -0
- package/assets/flags/fj.svg +120 -0
- package/assets/flags/fk.svg +90 -0
- package/assets/flags/fm.svg +11 -0
- package/assets/flags/fo.svg +12 -0
- package/assets/flags/fr.svg +5 -0
- package/assets/flags/ga.svg +7 -0
- package/assets/flags/gb-eng.svg +5 -0
- package/assets/flags/gb-nir.svg +132 -0
- package/assets/flags/gb-sct.svg +4 -0
- package/assets/flags/gb-wls.svg +9 -0
- package/assets/flags/gb.svg +7 -0
- package/assets/flags/gd.svg +27 -0
- package/assets/flags/ge.svg +6 -0
- package/assets/flags/gf.svg +5 -0
- package/assets/flags/gg.svg +9 -0
- package/assets/flags/gh.svg +6 -0
- package/assets/flags/gi.svg +32 -0
- package/assets/flags/gl.svg +4 -0
- package/assets/flags/gm.svg +14 -0
- package/assets/flags/gn.svg +7 -0
- package/assets/flags/gp.svg +5 -0
- package/assets/flags/gq.svg +23 -0
- package/assets/flags/gr.svg +16 -0
- package/assets/flags/gs.svg +133 -0
- package/assets/flags/gt.svg +204 -0
- package/assets/flags/gu.svg +19 -0
- package/assets/flags/gw.svg +13 -0
- package/assets/flags/gy.svg +9 -0
- package/assets/flags/hk.svg +8 -0
- package/assets/flags/hm.svg +8 -0
- package/assets/flags/hn.svg +18 -0
- package/assets/flags/hr.svg +58 -0
- package/assets/flags/ht.svg +116 -0
- package/assets/flags/hu.svg +7 -0
- package/assets/flags/ic.svg +7 -0
- package/assets/flags/id.svg +4 -0
- package/assets/flags/ie.svg +7 -0
- package/assets/flags/il.svg +14 -0
- package/assets/flags/im.svg +36 -0
- package/assets/flags/in.svg +25 -0
- package/assets/flags/io.svg +130 -0
- package/assets/flags/iq.svg +10 -0
- package/assets/flags/ir.svg +219 -0
- package/assets/flags/is.svg +12 -0
- package/assets/flags/it.svg +7 -0
- package/assets/flags/je.svg +62 -0
- package/assets/flags/jm.svg +8 -0
- package/assets/flags/jo.svg +16 -0
- package/assets/flags/jp.svg +11 -0
- package/assets/flags/ke.svg +23 -0
- package/assets/flags/kg.svg +4 -0
- package/assets/flags/kh.svg +61 -0
- package/assets/flags/ki.svg +36 -0
- package/assets/flags/km.svg +16 -0
- package/assets/flags/kn.svg +14 -0
- package/assets/flags/kp.svg +15 -0
- package/assets/flags/kr.svg +24 -0
- package/assets/flags/kw.svg +13 -0
- package/assets/flags/ky.svg +103 -0
- package/assets/flags/kz.svg +36 -0
- package/assets/flags/la.svg +12 -0
- package/assets/flags/lb.svg +15 -0
- package/assets/flags/lc.svg +8 -0
- package/assets/flags/li.svg +43 -0
- package/assets/flags/lk.svg +22 -0
- package/assets/flags/lr.svg +14 -0
- package/assets/flags/ls.svg +8 -0
- package/assets/flags/lt.svg +7 -0
- package/assets/flags/lu.svg +5 -0
- package/assets/flags/lv.svg +6 -0
- package/assets/flags/ly.svg +13 -0
- package/assets/flags/ma.svg +4 -0
- package/assets/flags/mc.svg +6 -0
- package/assets/flags/md.svg +70 -0
- package/assets/flags/me.svg +116 -0
- package/assets/flags/mf.svg +5 -0
- package/assets/flags/mg.svg +7 -0
- package/assets/flags/mh.svg +7 -0
- package/assets/flags/mk.svg +5 -0
- package/assets/flags/ml.svg +7 -0
- package/assets/flags/mm.svg +12 -0
- package/assets/flags/mn.svg +14 -0
- package/assets/flags/mo.svg +9 -0
- package/assets/flags/mp.svg +86 -0
- package/assets/flags/mq.svg +5 -0
- package/assets/flags/mr.svg +6 -0
- package/assets/flags/ms.svg +29 -0
- package/assets/flags/mt.svg +58 -0
- package/assets/flags/mu.svg +8 -0
- package/assets/flags/mv.svg +6 -0
- package/assets/flags/mw.svg +10 -0
- package/assets/flags/mx.svg +382 -0
- package/assets/flags/my.svg +26 -0
- package/assets/flags/mz.svg +21 -0
- package/assets/flags/na.svg +16 -0
- package/assets/flags/nc.svg +13 -0
- package/assets/flags/ne.svg +6 -0
- package/assets/flags/nf.svg +9 -0
- package/assets/flags/ng.svg +6 -0
- package/assets/flags/ni.svg +129 -0
- package/assets/flags/nl.svg +5 -0
- package/assets/flags/no.svg +7 -0
- package/assets/flags/np.svg +13 -0
- package/assets/flags/nr.svg +12 -0
- package/assets/flags/nu.svg +10 -0
- package/assets/flags/nz.svg +36 -0
- package/assets/flags/om.svg +115 -0
- package/assets/flags/pa.svg +14 -0
- package/assets/flags/pc.svg +33 -0
- package/assets/flags/pe.svg +4 -0
- package/assets/flags/pf.svg +19 -0
- package/assets/flags/pg.svg +9 -0
- package/assets/flags/ph.svg +6 -0
- package/assets/flags/pk.svg +15 -0
- package/assets/flags/pl.svg +6 -0
- package/assets/flags/pm.svg +5 -0
- package/assets/flags/pn.svg +53 -0
- package/assets/flags/pr.svg +13 -0
- package/assets/flags/ps.svg +6 -0
- package/assets/flags/pt.svg +57 -0
- package/assets/flags/pw.svg +11 -0
- package/assets/flags/py.svg +157 -0
- package/assets/flags/qa.svg +4 -0
- package/assets/flags/re.svg +5 -0
- package/assets/flags/ro.svg +7 -0
- package/assets/flags/rs.svg +292 -0
- package/assets/flags/ru.svg +5 -0
- package/assets/flags/rw.svg +13 -0
- package/assets/flags/sa.svg +25 -0
- package/assets/flags/sb.svg +13 -0
- package/assets/flags/sc.svg +7 -0
- package/assets/flags/sd.svg +13 -0
- package/assets/flags/se.svg +4 -0
- package/assets/flags/sg.svg +13 -0
- package/assets/flags/sh-ac.svg +689 -0
- package/assets/flags/sh-hl.svg +164 -0
- package/assets/flags/sh-ta.svg +76 -0
- package/assets/flags/sh.svg +7 -0
- package/assets/flags/si.svg +18 -0
- package/assets/flags/sj.svg +7 -0
- package/assets/flags/sk.svg +9 -0
- package/assets/flags/sl.svg +7 -0
- package/assets/flags/sm.svg +75 -0
- package/assets/flags/sn.svg +8 -0
- package/assets/flags/so.svg +11 -0
- package/assets/flags/sr.svg +6 -0
- package/assets/flags/ss.svg +8 -0
- package/assets/flags/st.svg +16 -0
- package/assets/flags/sv.svg +593 -0
- package/assets/flags/sx.svg +56 -0
- package/assets/flags/sy.svg +6 -0
- package/assets/flags/sz.svg +34 -0
- package/assets/flags/tc.svg +50 -0
- package/assets/flags/td.svg +7 -0
- package/assets/flags/tf.svg +15 -0
- package/assets/flags/tg.svg +14 -0
- package/assets/flags/th.svg +7 -0
- package/assets/flags/tj.svg +22 -0
- package/assets/flags/tk.svg +5 -0
- package/assets/flags/tl.svg +13 -0
- package/assets/flags/tm.svg +204 -0
- package/assets/flags/tn.svg +4 -0
- package/assets/flags/to.svg +10 -0
- package/assets/flags/tr.svg +8 -0
- package/assets/flags/tt.svg +5 -0
- package/assets/flags/tv.svg +9 -0
- package/assets/flags/tw.svg +34 -0
- package/assets/flags/tz.svg +13 -0
- package/assets/flags/ua.svg +6 -0
- package/assets/flags/ug.svg +30 -0
- package/assets/flags/um.svg +9 -0
- package/assets/flags/un.svg +16 -0
- package/assets/flags/us.svg +9 -0
- package/assets/flags/uy.svg +28 -0
- package/assets/flags/uz.svg +30 -0
- package/assets/flags/va.svg +190 -0
- package/assets/flags/vc.svg +8 -0
- package/assets/flags/ve.svg +26 -0
- package/assets/flags/vg.svg +59 -0
- package/assets/flags/vi.svg +28 -0
- package/assets/flags/vn.svg +11 -0
- package/assets/flags/vu.svg +21 -0
- package/assets/flags/wf.svg +5 -0
- package/assets/flags/ws.svg +7 -0
- package/assets/flags/xk.svg +5 -0
- package/assets/flags/xx.svg +4 -0
- package/assets/flags/ye.svg +7 -0
- package/assets/flags/yt.svg +5 -0
- package/assets/flags/za.svg +17 -0
- package/assets/flags/zm.svg +27 -0
- package/assets/flags/zw.svg +21 -0
- package/components/ln-data-coordinator/ln-data-coordinator.js +1 -1
- package/components/ln-date/ln-date.js +1 -1
- package/components/ln-debug/ln-debug.js +1 -1
- package/components/ln-debug/src/generated-attributes.js +306 -304
- package/components/ln-external-links/ln-external-links.js +1 -1
- package/components/ln-filter/ln-filter.js +1 -1
- package/components/ln-obfuscator/ln-obfuscator.js +1 -1
- package/components/ln-sort/ln-sort.js +1 -1
- package/components/ln-table/ln-table.js +1 -1
- package/components/ln-table-coordinator/ln-table-coordinator.js +1 -1
- package/components/ln-toast/ln-toast.js +1 -1
- package/components/ln-translations/README.md +202 -120
- package/components/ln-translations/ln-translations.js +1 -1
- package/components/ln-translations/ln-translations.schema.json +136 -120
- package/components/ln-translations/src/ln-translations.js +354 -295
- package/components/ln-translations/src/translations-model.js +221 -0
- package/components/ln-validate/ln-validate.js +1 -1
- package/ln-ashlar.html-data.json +1832 -1824
- package/package.json +2 -1
- package/theme/components/_translations.scss +118 -111
- package/theme/config/_breakpoints.scss +8 -0
- package/theme/config/mixins/_app-shell.scss +14 -0
- package/theme/config/mixins/_card.scss +7 -4
- package/theme/config/mixins/_count.scss +48 -0
- package/theme/config/mixins/_dropdown.scss +5 -1
- package/theme/config/mixins/_index.scss +1 -0
- package/theme/config/mixins/_nav.scss +3 -11
- package/theme/config/mixins/_popover.scss +12 -1
- package/theme/config/mixins/_translations.scss +126 -124
- package/theme/presentation/_effects.scss +68 -0
- package/theme/presentation/_navbar.scss +72 -1
- package/theme/presentation/_typography.scss +13 -0
- package/web-types.json +2365 -2351
|
@@ -1,120 +1,202 @@
|
|
|
1
|
-
# ln-translations
|
|
2
|
-
|
|
3
|
-
> Applied to a form element (`<form data-ln-translations data-ln-translations-default="en">`). It coordinates translatable input containers (`[data-ln-translatable="field"]`), dynamically cloning the inner form controls with deterministic nested names (`trans[lang][field]`) when languages are added, and synchronizes active language badges and dropdown menus via `<template>` elements. It manages no network transport or validation, submitting cloned fields natively through the standard `<form>` submission pipeline.
|
|
4
|
-
|
|
5
|
-
A zero-dependency, event-driven **Form Translation Coordinator** that manages inline multi-lingual inputs by dynamically cloning translatable fields on-demand.
|
|
6
|
-
|
|
7
|
-
Instead of writing custom layout handlers to manage multi-language fields, this
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
</
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
1
|
+
# ln-translations
|
|
2
|
+
|
|
3
|
+
> Applied to a form element (`<form data-ln-translations data-ln-translations-default="en">`). It coordinates translatable input containers (`[data-ln-translatable="field"]`), dynamically cloning the inner form controls with deterministic nested names (`trans[lang][field]`) when languages are added, and synchronizes active language badges and dropdown menus via `<template>` elements. It manages no network transport or validation, submitting cloned fields natively through the standard `<form>` submission pipeline.
|
|
4
|
+
|
|
5
|
+
A zero-dependency, event-driven **Form Translation Coordinator** that manages inline multi-lingual inputs by dynamically cloning translatable fields on-demand.
|
|
6
|
+
|
|
7
|
+
Instead of writing custom layout handlers to manage multi-language fields, this coordinator intercepts locale additions and removals, duplicates translatable fields with deterministic nested naming conventions, and handles pre-rendered server payloads automatically.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Core Behavior & Responsibility
|
|
12
|
+
|
|
13
|
+
- **Inline field cloning:** wraps translatable form fields via `data-ln-translatable`; when a language is activated (`addLanguage`), scans for translatable fields in the DOM, clones the wrapper's original `<input>`/`<textarea>`/`<select>` and appends the clone flagged with `data-ln-translatable-lang="{lang}"`.
|
|
14
|
+
- **Deterministic name generation:** cloned inputs get a nested array `name`, e.g. `trans[en][title]`, or `product[trans][en][title]` when the wrapper declares `data-ln-translations-prefix="product"`.
|
|
15
|
+
- **Menu & badge synchronization:** renders the available-language dropdown menu and the active-language badge list from two `<template>` elements (`ln-translations-menu-item`, `ln-translations-badge`), keeping both in sync on every add/remove.
|
|
16
|
+
- **Server-rendered hydration:** on init, scans the container for existing `[data-ln-translatable-lang]` elements and treats any language found there (other than the default) as already active, rebuilding the menu and badges accordingly — no `addLanguage()` call required.
|
|
17
|
+
|
|
18
|
+
The JavaScript source follows the Two-Tier Archetype: domain logic and algorithms are isolated in [translations-model.js](./src/translations-model.js), while the DOM coordinator shell is implemented in [ln-translations.js](./src/ln-translations.js).
|
|
19
|
+
|
|
20
|
+
> [!IMPORTANT]
|
|
21
|
+
> **What the component does NOT do (Orthogonality Doctrine):**
|
|
22
|
+
> - **Does NOT perform AJAX:** it only manipulates form fields in the DOM; submission is handled by the native `<form>` or `ln-form`.
|
|
23
|
+
> - **Does NOT open its own modals or dialogs:** the language menu is delegated to `ln-dropdown` + `ln-toggle`; the component never manages overlay state itself.
|
|
24
|
+
> - **Does NOT hardcode translatable field names or locale lists:** the active locales list is configurable via `data-ln-translations-locales` JSON or dictionary, and the translatable field names are declared via `data-ln-translatable` attributes.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Minimal HTML Markup & Usage Variants
|
|
29
|
+
|
|
30
|
+
### Base HTML Markup
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<form data-ln-translations data-ln-translations-default="en">
|
|
34
|
+
<header>
|
|
35
|
+
<h3>Company Info</h3>
|
|
36
|
+
<div class="ln-translations__actions">
|
|
37
|
+
<ul data-ln-translations-active></ul>
|
|
38
|
+
<div data-ln-dropdown>
|
|
39
|
+
<button type="button" data-ln-translations-add data-ln-toggle-for="trans-menu" aria-label="Add translation">
|
|
40
|
+
<svg class="ln-icon" aria-hidden="true"><use href="#ln-icon-world"></use></svg>
|
|
41
|
+
</button>
|
|
42
|
+
<ul id="trans-menu" data-ln-toggle></ul>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</header>
|
|
46
|
+
|
|
47
|
+
<main>
|
|
48
|
+
<div class="form-element">
|
|
49
|
+
<label for="company-name">Name</label>
|
|
50
|
+
<input type="text" id="company-name" name="name" value="Acme Corp">
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="form-element" data-ln-translatable="tagline">
|
|
54
|
+
<label for="company-tagline">Tagline</label>
|
|
55
|
+
<input type="text" id="company-tagline" name="tagline" value="Quality since 1990">
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div class="form-element" data-ln-translatable="scope" data-ln-translations-prefix="company">
|
|
59
|
+
<label for="company-scope">Scope</label>
|
|
60
|
+
<textarea id="company-scope" name="company[scope]">Food and beverage production</textarea>
|
|
61
|
+
</div>
|
|
62
|
+
</main>
|
|
63
|
+
</form>
|
|
64
|
+
|
|
65
|
+
<!-- Required global templates — declare once per page -->
|
|
66
|
+
<template data-ln-template="ln-translations-badge">
|
|
67
|
+
<li>
|
|
68
|
+
<p data-ln-translations-lang>
|
|
69
|
+
<span></span>
|
|
70
|
+
<button type="button" aria-label="Remove">
|
|
71
|
+
<svg class="ln-icon ln-icon--sm" aria-hidden="true"><use href="#ln-icon-x"></use></svg>
|
|
72
|
+
</button>
|
|
73
|
+
</p>
|
|
74
|
+
</li>
|
|
75
|
+
</template>
|
|
76
|
+
|
|
77
|
+
<template data-ln-template="ln-translations-menu-item">
|
|
78
|
+
<li><button type="button" data-ln-translations-lang></button></li>
|
|
79
|
+
</template>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Variant: Server-Rendered / Pre-Hydrated Translations
|
|
83
|
+
|
|
84
|
+
When translations are already rendered server-side, mark each pre-rendered field with `data-ln-translatable-lang="{lang}"`. On init the component scans for these attributes, treats every non-default language found as already active, and renders the matching menu/badge state — no `addLanguage()` call needed.
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<form data-ln-translations data-ln-translations-default="en">
|
|
88
|
+
<main>
|
|
89
|
+
<div class="form-element" data-ln-translatable="title">
|
|
90
|
+
<label for="doc-title">Title</label>
|
|
91
|
+
<input type="text" id="doc-title" name="title" value="Information Security">
|
|
92
|
+
<input data-ln-translatable-lang="en" name="trans[en][title]" value="Information Security" placeholder="English translation">
|
|
93
|
+
</div>
|
|
94
|
+
</main>
|
|
95
|
+
</form>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 3. Declarative API Contract (Attributes & Events)
|
|
101
|
+
|
|
102
|
+
### Attributes Table
|
|
103
|
+
|
|
104
|
+
| Attribute | Element | Type / Values | Default | Description |
|
|
105
|
+
|---|---|---|---|---|
|
|
106
|
+
| `data-ln-translations` | Container (`<form>`) | Marker | — | Initializes the translations coordinator on the container element. |
|
|
107
|
+
| `data-ln-translations-default` | Container | `String` | `""` | Default primary language code (e.g. `en`). Flags original translatable inputs on init. |
|
|
108
|
+
| `data-ln-translations-placeholder` | Container | `String` | `"{lang} translation"` | Placeholder label pattern for cloned translation inputs; `{lang}` is replaced with language display name. |
|
|
109
|
+
| `data-ln-translations-remove-label` | Container | `String` | `"Remove {lang}"` | Accessible label template for translation removal buttons; `{lang}` is replaced with language display name. |
|
|
110
|
+
| `data-ln-translations-locales` | Container | `JSON` | `{"en":"English","sq":"Shqip","sr":"Srpski"}` | JSON object mapping language codes to display labels. Auto-parsed via `attrJson`. |
|
|
111
|
+
| `data-ln-translations-dict` | Container | `String` | — | Dictionary key prefix mapping for translatable labels (`placeholder`, `remove-label`). |
|
|
112
|
+
| `data-ln-translations-menu` | Menu container | Marker | — | Explicit menu container holding available language buttons (inside or alongside `data-ln-dropdown`). |
|
|
113
|
+
| `data-ln-translations-active` | `<ul>` | Marker | — | Marks the mount container where active-language badges are rendered. |
|
|
114
|
+
| `data-ln-translations-add` | `<button>` | Trigger | — | Marks the trigger button that opens the language menu; hidden automatically once all languages are active. |
|
|
115
|
+
| `data-ln-translatable` | Field wrapper | `String` (field name) | — *(required)* | Marks a translatable field group; value is the field name used in generated `name` attributes. |
|
|
116
|
+
| `data-ln-translations-prefix` | Field wrapper | `String` | `""` | Optional name prefix for nested entities, e.g. `items[1]` produces `items[1][trans][en][title]`. |
|
|
117
|
+
| `data-ln-translatable-lang` | `<input>`, `<textarea>`, `<select>` | `String` (language code) | — | Marks a cloned or server-rendered translation field for a specific language. |
|
|
118
|
+
| `data-ln-translations-lang` | Inside templates | `String` (language code) | — *(required)* | Required anchor attribute inside both templates — populated with target language code and bindings. |
|
|
119
|
+
|
|
120
|
+
### Programmatic JS API
|
|
121
|
+
|
|
122
|
+
The initialized instance is exposed on the container element via `dom.lnTranslations`.
|
|
123
|
+
|
|
124
|
+
| Helper | Signature | Returns | Description |
|
|
125
|
+
|---|---|---|---|
|
|
126
|
+
| `dom.lnTranslations.addLanguage` | `(lang: String, values?: Object)` | `void` | Activates `lang`, clones translatable fields (optionally seeded with `values` keyed by field name), updates menu/badges, and dispatches add lifecycle events. |
|
|
127
|
+
| `dom.lnTranslations.removeLanguage` | `(lang: String)` | `void` | Deactivates `lang`, removes its cloned fields, updates menu/badges, and dispatches remove lifecycle events. |
|
|
128
|
+
| `dom.lnTranslations.hasLanguage` | `(lang: String)` | `Boolean` | Returns whether `lang` is currently active. |
|
|
129
|
+
| `dom.lnTranslations.getActiveLanguages` | `()` | `Set<String>` | Returns a new `Set` copy of the active languages. |
|
|
130
|
+
| `dom.lnTranslations.destroy` | `()` | `void` | Removes non-default clones, cleans auto-tagged attributes, detaches request listeners, and deletes instance. |
|
|
131
|
+
|
|
132
|
+
### Events API
|
|
133
|
+
|
|
134
|
+
| Event | Direction | Cancelable | Description | `detail` Object |
|
|
135
|
+
|---|---|---|---|---|
|
|
136
|
+
| `ln-translations:request-add` | Listens | No | Requests activation of a language programmatically. | `{ lang: String, values?: Object }` |
|
|
137
|
+
| `ln-translations:request-remove` | Listens | No | Requests deactivation of a language programmatically. | `{ lang: String }` |
|
|
138
|
+
| `ln-translations:before-add` | Emits | Yes | Fires before a language's fields are cloned. `preventDefault()` aborts activation. | `{ target: HTMLElement, lang: String, langName: String }` |
|
|
139
|
+
| `ln-translations:added` | Emits | No | Fires after a language's fields are cloned and menu/badges are updated. | `{ target: HTMLElement, lang: String, langName: String }` |
|
|
140
|
+
| `ln-translations:before-remove` | Emits | Yes | Fires before a language's cloned fields are removed. `preventDefault()` aborts removal. | `{ target: HTMLElement, lang: String }` |
|
|
141
|
+
| `ln-translations:removed` | Emits | No | Fires after a language's cloned fields are removed and menu/badges are updated. | `{ target: HTMLElement, lang: String }` |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 4. CSS Styling & Behavioral Concept
|
|
146
|
+
|
|
147
|
+
`ln-translations` co-locates production SCSS: reusable mixins in `theme/config/mixins/_translations.scss` and selector bindings in `theme/components/_translations.scss`.
|
|
148
|
+
|
|
149
|
+
- **Per-language flag icons (CSS data-driven):** every `[data-ln-translatable-lang]` field, active badge, and dropdown button gets a flag icon keyed by ISO 639-1 -> ISO 3166-1 country lookup (`/assets/flags/{country}.svg`).
|
|
150
|
+
- **CSS Logical Properties:** spacing and positioning use `padding-inline-start`, `margin-inline-start`, and `padding-block`.
|
|
151
|
+
- **Cloning semantics:** `cloneNode(false)` is used for translatable inputs/textareas and `cloneNode(true)` for selects. Duplicate `id` attributes are explicitly stripped (`removeAttribute('id')`).
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 5. Accessibility (ARIA) & Common Pitfalls
|
|
156
|
+
|
|
157
|
+
- **Dynamic labels & placeholders:** cloned fields receive `placeholder` and `aria-label` matching `{langName} translation` (e.g. `English translation`), and badge remove buttons carry `aria-label="Remove {langName}"`.
|
|
158
|
+
- **Keyboard-native controls:** all interactive items (dropdown items, triggers, badge close buttons) are native `<button type="button">`.
|
|
159
|
+
- **Missing Templates Warning:** without both global `<template data-ln-template="ln-translations-badge">` and `<template data-ln-template="ln-translations-menu-item">` present on the page, `cloneTemplateScoped` returns `null` and badges/menu items cannot render.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 6. Sequence & Lifecycle Flow
|
|
164
|
+
|
|
165
|
+
```mermaid
|
|
166
|
+
sequenceDiagram
|
|
167
|
+
autonumber
|
|
168
|
+
actor User
|
|
169
|
+
participant Menu as Menu Item [data-ln-translations-lang]
|
|
170
|
+
participant Comp as ln-translations Engine
|
|
171
|
+
participant Wrapper as [data-ln-translatable]
|
|
172
|
+
participant Dropdown as Dropdown Menu
|
|
173
|
+
participant Badges as [data-ln-translations-active]
|
|
174
|
+
|
|
175
|
+
User->>Menu: Click language item
|
|
176
|
+
Menu->>Comp: addLanguage(lang)
|
|
177
|
+
Comp->>Comp: Emit ln-translations:before-add (cancelable)
|
|
178
|
+
alt Prevented
|
|
179
|
+
Comp->>Comp: Abort - no clones created
|
|
180
|
+
else Approved
|
|
181
|
+
Comp->>Comp: Add lang to activeLanguages Set
|
|
182
|
+
loop For each [data-ln-translatable] wrapper
|
|
183
|
+
Comp->>Wrapper: Find original input/textarea/select
|
|
184
|
+
Comp->>Comp: cloneNode() & removeAttribute('id')
|
|
185
|
+
Comp->>Comp: Set name = buildFieldName(field, lang, prefix)
|
|
186
|
+
Comp->>Comp: Set placeholder & aria-label
|
|
187
|
+
Comp->>Wrapper: Insert clone after original
|
|
188
|
+
end
|
|
189
|
+
Comp->>Dropdown: _updateDropdown() - remove lang, hide trigger if none remain
|
|
190
|
+
Comp->>Badges: _updateBadges() - render badge from template
|
|
191
|
+
Comp->>Comp: Emit ln-translations:added
|
|
192
|
+
end
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 7. Related Components & Coordinators
|
|
198
|
+
|
|
199
|
+
- [`ln-form`](../ln-form/README.md) — submits the generated `trans[lang][field]` fields as standard native form data.
|
|
200
|
+
- [`ln-dropdown`](../ln-dropdown/README.md) — provides dropdown menu positioning and dismissal behavior for language selection.
|
|
201
|
+
- [`ln-toggle`](../ln-toggle/README.md) — binary open/close state primitive that `ln-dropdown` coordinates.
|
|
202
|
+
- [`ln-validate`](../ln-validate/README.md) — validates cloned translation fields according to standard HTML constraints.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){"use strict";function N(){if(typeof window>"u")return!1;if(window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink)return!0;if(typeof document<"u"){if(document.documentElement&&document.documentElement.hasAttribute("data-ln-debug"))return!0;if(document.body)return document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null}return!1}function _(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let i=null;for(let l=1;l<t.length;l++)if(t[l]&&t[l].nodeType===1){i=t[l];break}if(!_(i))return}e.apply(console,t)}}function S(e,t,o){const i=o||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,i),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:i}))}function T(e,t,o){const i=o||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,i);const l=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:i});return e.dispatchEvent(l),l}function C(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){C(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function ae(e){const t=e.querySelector('input[name="_method"]');return((t&&t.value!==""?t.value:e.method)||"").toUpperCase()}function se(e,t){const o=!!(t&&t.typed),i=t&&t.exclude,l={},a=e.elements,r={};if(o)for(let s=0;s<a.length;s++){const n=a[s];n.name&&n.type==="checkbox"&&!n.disabled&&(r[n.name]=(r[n.name]||0)+1)}for(let s=0;s<a.length;s++){const n=a[s];if(!(!n.name||n.disabled||n.type==="file"||n.type==="submit"||n.type==="button")&&!(i&&n.matches&&n.matches(i)))if(n.type==="checkbox")o&&r[n.name]===1?l[n.name]=n.checked:(l[n.name]||(l[n.name]=[]),n.checked&&l[n.name].push(n.value));else if(n.type==="radio")n.checked&&(l[n.name]=n.value);else if(n.type==="select-multiple"){l[n.name]=[];for(let c=0;c<n.options.length;c++)n.options[c].selected&&l[n.name].push(n.options[c].value)}else if(o&&n.type==="hidden")l[n.name]=n.value;else if(o&&(n.type==="number"||n.type==="range")){const c=Number(n.value);l[n.name]=n.value===""||isNaN(c)?null:c}else l[n.name]=n.value}return l}function ce(e){if(typeof e!="string")return!!e;const t=e.trim().toLowerCase();return t!=="false"&&t!=="0"&&t!==""&&t!=="off"&&t!=="no"}function de(e,t){const o=e.elements,i=[],l={};for(let a=0;a<o.length;a++){const r=o[a];r.name&&r.type==="checkbox"&&(l[r.name]=(l[r.name]||0)+1)}for(let a=0;a<o.length;a++){const r=o[a];if(r.type==="file"||r.type==="submit"||r.type==="button")continue;const s=r.getAttribute("data-ln-fill-as")||r.name;if(!s||!(s in t))continue;const n=t[s];if(r.type==="checkbox"){if(Array.isArray(n))r.checked=n.indexOf(r.value)!==-1;else if(l[r.name]>1){const c=String(n).split(",").map(function(u){return u.trim()});r.checked=c.indexOf(r.value)!==-1}else r.checked=ce(n);i.push(r)}else if(r.type==="radio")r.checked=r.value===String(n),i.push(r);else if(r.type==="select-multiple"){if(Array.isArray(n))for(let c=0;c<r.options.length;c++)r.options[c].selected=n.indexOf(r.options[c].value)!==-1;i.push(r)}else r.value=n,r.tagName==="SELECT"&&n!=null&&r.setAttribute("data-ln-value",n),i.push(r)}return i}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.populateForm=de,window.lnCore.serializeForm=se,window.lnCore.resolveFormMethod=ae);const $={};function ue(e,t){$[e]=t}function fe(e){return $[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=ue,window.lnCore.getDataMapper=fe);function we(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,C(function(){new MutationObserver(function(){S(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const B={};function he(e,t){if(!e||typeof t!="object")return;const o=e.toLowerCase().split("-")[0];B[o]=t}function ge(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return B[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=he,window.lnCore.getLocaleFallback=ge,window.lnCore.ensureLocaleObserver=we);const x={};function L(e,t){x[e]||(x[e]=document.querySelector('[data-ln-template="'+e+'"]'));const o=x[e];return o?o.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function M(e,t){if(!e||!t)return e;const o=e.querySelectorAll("[data-ln-field]");for(let r=0;r<o.length;r++){const s=o[r],n=s.getAttribute("data-ln-field");t[n]!=null&&(s.textContent=t[n])}const i=e.querySelectorAll("[data-ln-attr]");for(let r=0;r<i.length;r++){const s=i[r],n=s.getAttribute("data-ln-attr").split(",");for(let c=0;c<n.length;c++){const u=n[c].trim().split(":");if(u.length!==2)continue;const d=u[0].trim(),f=u[1].trim();t[f]!=null&&s.setAttribute(d,t[f])}}const l=e.querySelectorAll("[data-ln-show]");for(let r=0;r<l.length;r++){const s=l[r],n=s.getAttribute("data-ln-show");n in t&&s.classList.toggle("hidden",!t[n])}const a=e.querySelectorAll("[data-ln-class]");for(let r=0;r<a.length;r++){const s=a[r],n=s.getAttribute("data-ln-class").split(",");for(let c=0;c<n.length;c++){const u=n[c].trim().split(":");if(u.length!==2)continue;const d=u[0].trim(),f=u[1].trim();f in t&&s.classList.toggle(d,!!t[f])}}return e}function pe(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const o=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let i=0;i<o.length;i++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",o[i],t??null),o[i].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)M(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let o=0;o<t.length;o++)t[o].textContent=""}})));function j(e,t){if(!e||!t)return e;const o=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;o.nextNode();){const a=o.currentNode;a.textContent.indexOf("{{")!==-1&&(a.textContent=a.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(r,s){return t[s]!==void 0?t[s]:""}))}const i=function(a,r){return t[r]!==void 0?t[r]:""},l=Array.from(e.querySelectorAll("*"));e.nodeType===1&&l.push(e);for(let a=0;a<l.length;a++){const r=l[a],s=r.attributes;for(let n=0;n<s.length;n++){const c=s[n];c.value.indexOf("{{")!==-1&&r.setAttribute(c.name,c.value.replace(/\{\{\s*(\w+)\s*\}\}/g,i))}}return e}function be(e,t,o,i,l,a){const r={};for(let n=0;n<e.children.length;n++){const c=e.children[n],u=c.getAttribute("data-ln-render-key");u&&(r[u]=c)}const s=document.createDocumentFragment();for(let n=0;n<t.length;n++){const c=t[n],u=String(i(c));let d=r[u];if(d)l(d,c,n);else{const f=L(o,a);if(!f||(j(f,c),d=f.firstElementChild,!d))continue;d.setAttribute("data-ln-render-key",u),l(d,c,n)}s.appendChild(d)}e.textContent="",e.appendChild(s)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=j,window.lnCore.fill=M,window.lnCore.lnFill=pe,window.lnCore.renderList=be);function p(e,t,o){const i=e.getAttribute(t);return i===null?o:i}function U(e,t,o){const i=parseInt(e.getAttribute(t),10);return isNaN(i)?o:i}function W(e,t,o=!1){const i=e.getAttribute(t);if(i===null)return!!o;const l=i.trim().toLowerCase();return!(l==="false"||l==="0")}function P(e,t){return(e.getAttribute(t)||"").split(",").map(o=>o.trim()).filter(Boolean)}const k=new Map;function V(e,t){const o=(e?e.join("|"):"")+"::"+t;if(k.has(o))return k.get(o);const i=new Set(e||[]),l=function(a,r){const s=a.getAttribute(r);return s!==null&&i.has(s)?s:t};return k.set(o,l),l}function H(e,t,o){const i=parseFloat(e.getAttribute(t));return isNaN(i)?o:i}function K(e,t,o){const i=e.getAttribute(t);if(!i)return o;try{return JSON.parse(i)}catch{return o}}function J(e,t,o,i,l){if(!e||t===null)return!0;const a=i||"ln-component",r=e.type;if(r==="trigger"||r==="marker"||r==="string"||r==="list"||!r||t===""&&e.fallback!==void 0)return!0;const s=n=>{l?console.warn(n,l):console.warn(n)};if(r==="boolean"){const n=t.trim().toLowerCase();return n!==""&&n!=="true"&&n!=="false"&&n!=="1"&&n!=="0"?(s(`[${a}] Invalid value "${t}" for boolean attribute "${o}". Allowed: "true", "false", or presence-only.`),!1):!0}if(r==="enum"){const n=e.values||[];return n.includes(t)?!0:(s(`[${a}] Invalid value "${t}" for attribute "${o}". Allowed: ${n.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(r==="integer"){if(!/^-?\d+$/.test(t))return s(`[${a}] Invalid integer "${t}" for attribute "${o}". Fallback: ${e.fallback}.`),!1;const n=parseInt(t,10);return e.min!==void 0&&n<e.min?(s(`[${a}] Value ${n} for attribute "${o}" is less than min (${e.min}).`),!1):e.max!==void 0&&n>e.max?(s(`[${a}] Value ${n} for attribute "${o}" is greater than max (${e.max}).`),!1):!0}if(r==="float")return isNaN(Number(t))?(s(`[${a}] Invalid float "${t}" for attribute "${o}". Fallback: ${e.fallback}.`),!1):!0;if(r==="json")try{return JSON.parse(t),!0}catch(n){return s(`[${a}] Invalid JSON for attribute "${o}": ${n.message}. Fallback: ${e.fallback}.`),!1}return!0}function Q(e,t,o){for(const i in o){const[l,a,r]=o[i];Object.defineProperty(e,i,{get:function(){return l(t,a,r)},enumerable:!0,configurable:!0})}return e}function G(e){const t={};for(const o in e){const i=e[o];if(!i||!i.prop)continue;let l=i.read;if(!l&&i.type)switch(i.type){case"enum":l=V(i.values,i.fallback);break;case"integer":l=U;break;case"float":l=H;break;case"boolean":l=W;break;case"list":l=P;break;case"json":l=K;break;case"string":default:l=p;break}l||(l=p),t[i.prop]=[l,o,i.fallback]}return t}function me(e){const t={};for(const o in e){const i=e[o];i&&i.effect&&(t[o]=i.effect)}return Object.keys(t).length?t:null}function ye(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const o in e.effects)t.add(o);if(e.onAttrChange&&e.declared)for(const o of e.declared)t.add(o);return t}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.defineAttrs=Q,window.lnCore.attrSpec=G,window.lnCore.attrStr=p,window.lnCore.attrInt=U,window.lnCore.attrBool=W,window.lnCore.attrList=P,window.lnCore.attrEnum=V,window.lnCore.attrFloat=H,window.lnCore.attrJson=K);function A(e,t){if(!e[t.attribute]){window.lnCore._persistSink&&e.hasAttribute&&e.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(e,t.selector);try{e[t.attribute]=new t.ComponentFn(e)}catch(o){console.error("["+t.attribute+"] init failed",e,o)}}}function z(e,t,o,i){if(e.nodeType!==1)return;const a=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",r={selector:t,attribute:o,ComponentFn:i};if(e.matches&&e.matches(a)&&A(e,r),e.querySelectorAll){const s=e.querySelectorAll(a);for(let n=0;n<s.length;n++)A(s[n],r)}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function Ce(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function Ae(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function X(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function ve(e){const t=X(),o=e.observed||[];for(let i=0;i<o.length;i++){const l=o[i];t.byAttr.has(l)||t.byAttr.set(l,[]),t.byAttr.get(l).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const i in e.attributes){t.byDeclaredAttr.has(i)||t.byDeclaredAttr.set(i,[]);const l=t.byDeclaredAttr.get(i);l.some(a=>a.componentTag===e.componentTag)||l.push({spec:e.attributes[i],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const i=ye(e);if(i===null)t.reactiveWildcard.push(e);else for(const l of i)t.byReactive.has(l)||t.byReactive.set(l,[]),t.byReactive.get(l).push(e)}e.persist&&t.persist.push(e)}function Y(e,t,o,i){for(let l=0;l<e.length;l++){const a=e[l];if(!t[a.attribute])continue;const r=a.effects&&a.effects[o];r?r(t,o,i):a.onAttrChange&&(!a.declared||a.declared.has(o))&&a.onAttrChange(t,o,i)}}function _e(e){const t=e.attributeName,o=t.indexOf("data-ln-")===0,i=X(),l=i.byAttr.get(t),a=N()&&i.byDeclaredAttr&&i.byDeclaredAttr.has(t);if(!o&&!l&&!a)return;const r=e.target;if(e.oldValue!==r.getAttribute(t)){if(a&&_(r)){const s=i.byDeclaredAttr.get(t),n=r.getAttribute(t);for(let c=0;c<s.length;c++)J(s[c].spec,n,t,s[c].componentTag,r)}if(window.lnCore._debugSink&&(o||l)&&window.lnCore._debugSink("attr",t,r,{oldValue:e.oldValue,newValue:r.getAttribute(t)}),o){const s=i.byReactive.get(t);s&&Y(s,r,t,e.oldValue),i.reactiveWildcard.length&&Y(i.reactiveWildcard,r,t,e.oldValue)}if(l)for(let s=0;s<l.length;s++){const n=l[s];if(n.handler){n.handler(r,t,e.oldValue);continue}n.onAttributeChange&&r[n.attribute]?n.onAttributeChange(r,t):(z(r,n.selector,n.attribute,n.ComponentFn),n.onInit&&n.onInit(r))}}}function Se(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,C(function(){new MutationObserver(function(t){for(let o=0;o<t.length;o++)try{_e(t[o])}catch(i){console.error("[ln-core] mutation handler failed",t[o].target,i)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function E(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function q(){return window.lnCore=window.lnCore||{},window.lnCore._subtreeRegistry=window.lnCore._subtreeRegistry||[]}function Z(e,t){if(!document.contains(e))if(t.attribute){const o=e[t.attribute];if(o&&typeof o.destroy=="function")try{o.destroy()}catch(i){console.error("["+t.attribute+"] destroy failed",e,i)}delete e[t.attribute]}else t.onDestroy&&t.onDestroy(e)}function ee(e){const t=E();if(!t.length)return;const o=e.target;if(o){const l=o.nodeType===1?o:o.parentElement;if(l&&(l.isContentEditable||l.closest&&l.closest('[contenteditable]:not([contenteditable="false"])')))return}const i=q();if(e.target&&i.length)for(let l=0;l<i.length;l++){const a=i[l],r=a.query,s=e.target.nodeType===1?e.target.matches&&e.target.matches(r)?e.target:e.target.closest?e.target.closest(r):null:e.target.parentElement&&e.target.parentElement.closest?e.target.parentElement.closest(r):null;s&&a.onSubtreeChange(s,e)}for(let l=0;l<e.addedNodes.length;l++){const a=e.addedNodes[l];if(a.nodeType!==1)continue;const r=!!(a.firstElementChild||a.children&&a.children.length);for(let s=0;s<t.length;s++){const n=t[s],c=n.query;if(c&&(a.matches&&a.matches(c)&&(n.ComponentFn&&A(a,n),n.onInit&&n.onInit(a)),r&&a.querySelectorAll)){const u=a.querySelectorAll(c);for(let d=0;d<u.length;d++)n.ComponentFn&&A(u[d],n),n.onInit&&n.onInit(u[d])}}}for(let l=0;l<e.removedNodes.length;l++){const a=e.removedNodes[l];if(a.nodeType!==1||document.contains(a))continue;const r=!!(a.firstElementChild||a.children&&a.children.length);for(let s=0;s<t.length;s++){const n=t[s],c=n.query;if(c&&(a.matches&&a.matches(c)&&Z(a,n),r&&a.querySelectorAll)){const u=a.querySelectorAll(c);for(let d=0;d<u.length;d++)Z(u[d],n)}}}}function te(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,C(function(){const e=new MutationObserver(function(t){for(let o=0;o<t.length;o++){const i=t[o];if(i.type==="childList")try{ee(i)}catch(l){console.error("[ln-core] lifecycle handler failed",i.target,l)}}});window.lnCore._lifecycleObserver=e,e.observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function xe(e){if(typeof window>"u")return e();window.lnCore=window.lnCore||{};const t=window.lnCore._lifecycleObserver;if(!t)return e();const o=t.takeRecords();for(let i=0;i<o.length;i++){const l=o[i];if(l.type==="childList")try{ee(l)}catch(a){console.error("[ln-core] lifecycle handler failed",l.target,a)}}t.disconnect();try{return e()}finally{t.observe(document.body,{childList:!0,subtree:!0})}}function Le(e){E().push(e),e.onSubtreeChange&&e.query&&q().push(e),te()}function ne(e,t,o,i,l={}){const a=l.extraAttributes||[],r=l.onAttributeChange||null,s=l.onSubtreeChange||null,n=l.onInit||null,c=l.onAttrChange||null,u=l.effects||null,d=l.attributes||null,f=d?me(d):u,h=d?new Set(Object.keys(d)):null,m=l.persist||null;function w(D){const g=D||document.body;if(z(g,e,t,o),d&&N())for(const y in d){const He=d[y],R=Array.from(g.querySelectorAll("["+y+"]"));g.matches&&g.matches("["+y+"]")&&R.push(g);for(let I=0;I<R.length;I++){const F=R[I];_(F)&&J(He,F.getAttribute(y),y,i,F)}}n&&n(g)}const b=[];if(e.indexOf("[")!==-1){const D=/\[([\w-]+)/g;let g;for(;(g=D.exec(e))!==null;)b.push(g[1])}else b.push(e);ve({selector:e,attribute:t,componentTag:i,attributes:d,ComponentFn:o,onInit:n,observed:b.concat(a),onAttributeChange:r,onAttrChange:c,effects:f,declared:h,persist:m}),Se();const v=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1,oe=l.subtreeQuery||(v?e:"["+e+"]"),ie={selector:e,attribute:t,ComponentFn:o,onInit:n,onSubtreeChange:s,query:oe};E().push(ie),s&&oe&&q().push(ie),te(),window[t]=w,typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerComponent=ne,window.lnCore.observeLifecycle=Le,window.lnCore.withoutLifecycle=xe);function le(){Ce()>0?Ae(function(){w(document.body)}):w(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",le):le(),w}function re(e){return(e||"").replace(/^#/,"")}function O(e){const t=e===void 0?location.hash:e,o={},i=re(t);if(!i)return o;const l=i.split("&");for(let a=0;a<l.length;a++){const r=l[a];if(!r)continue;const s=r.indexOf(":"),n=s>-1?r.slice(0,s):r,c=s>-1?r.slice(s+1):"";if(n)try{o[n]=decodeURIComponent(c)}catch{o[n]=c}}return o}function ke(e){if(!e)return null;const t=O();return e in t?t[e]:null}function Ee(e,t){if(!e)return;const o=O();t==null?delete o[e]:o[e]=String(t);const l=Object.keys(o).map(function(a){const r=o[a];return r===""?a:a+":"+encodeURIComponent(r)}).join("&");re(location.hash)!==l&&(location.hash=l)}function qe(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function Oe(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const o=e.getAttribute("data-ln-hash");if(o&&o.trim()!=="")return o.trim();const i=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return i?t?i+"-"+t:i:t||null}function De(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Re(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function Ie(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Fe(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const o=e.slice(0,t),i=e.slice(t+1),l=i?i.split(",").map(function(a){try{return decodeURIComponent(a)}catch{return a}}).filter(Boolean):[];return{key:o,values:l}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=O,window.lnCore.hashGet=ke,window.lnCore.hashSet=Ee,window.lnCore.hashLinkClick=qe,window.lnCore.resolveHashNamespace=Oe,window.lnCore.hashSortEncode=De,window.lnCore.hashSortDecode=Re,window.lnCore.hashFilterEncode=Ie,window.lnCore.hashFilterDecode=Fe);function Ne(e){return(e||"").replace(/^\?/,"")}function Te(e){const t=e===void 0?typeof window<"u"?window.location.search:"":e,o={},i=Ne(t);if(!i)return o;const l=new URLSearchParams(i);for(const[a,r]of l.entries())o[a]=r;return o}function $e(e){if(!e||typeof window>"u")return null;const t=new URLSearchParams(window.location.search);return t.has(e)?t.get(e):null}function Be(e,t){if(!e||typeof window>"u")return;const o=new URL(window.location.href);if(t==null||t===""?o.searchParams.delete(e):o.searchParams.set(e,String(t)),o.search===window.location.search)return;const i=o.pathname+o.search+o.hash;window.history.replaceState(window.history.state,"",i)}function Me(e,t){if(!e||!e.hasAttribute("data-ln-query"))return null;const o=e.getAttribute("data-ln-query");if(o&&o.trim()!=="")return o.trim();const i=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return i?t?i+"_"+t:i:t||null}function je(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Ue(e,t){if(e&&typeof e=="string"){if(e.endsWith(".asc"))return{fieldOrColumn:e.slice(0,-4),direction:"asc"};if(e.endsWith(".desc"))return{fieldOrColumn:e.slice(0,-5),direction:"desc"}}if(t&&typeof t=="object"){const o=t.sort_field||t.sort_by;if(o){const i=t.sort_dir&&String(t.sort_dir).toLowerCase()==="desc"?"desc":"asc";return{fieldOrColumn:o,direction:i}}}return null}function We(e){return!Array.isArray(e)||e.length===0?null:e.map(encodeURIComponent).join(",")}function Pe(e){return!e||typeof e!="string"?[]:e.split(",").map(function(t){try{return decodeURIComponent(t.trim())}catch{return t.trim()}}).filter(Boolean)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.queryParse=Te,window.lnCore.queryGet=$e,window.lnCore.querySet=Be,window.lnCore.resolveQueryParam=Me,window.lnCore.querySortEncode=je,window.lnCore.querySortDecode=Ue,window.lnCore.queryFilterEncode=We,window.lnCore.queryFilterDecode=Pe);function Ve(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.uuid=Ve),(function(){const e="data-ln-translations",t="lnTranslations";if(window[t]!==void 0)return;const o={"data-ln-translations":{type:"marker",description:"Mounts multi-language translation manager on form container"},"data-ln-translations-default":{prop:"defaultLang",read:p,type:"string",fallback:"",description:"Default primary language code (e.g. en)"},"data-ln-translations-placeholder":{prop:"placeholderLabel",read:p,type:"string",fallback:"{lang} translation",description:"Placeholder label pattern for cloned translation inputs"},"data-ln-translations-remove-label":{prop:"removeLabel",read:p,type:"string",fallback:"Remove {lang}",description:"Accessible label template for translation removal buttons"},"data-ln-translations-locales":{prop:"_localesRaw",read:p,type:"json",fallback:"",description:"JSON dictionary of supported locale codes and display labels"},"data-ln-translations-active":{type:"marker",description:"Container holding active language badge tags"},"data-ln-translations-add":{type:"string",description:"Trigger button action to add specified language translation fields"},"data-ln-translations-lang":{type:"string",description:"Language code associated with active language badge"},"data-ln-translations-prefix":{type:"string",description:"Prefix format pattern for cloned translated field names"},"data-ln-translatable":{type:"marker",description:"Marks form control as translatable into multiple languages"},"data-ln-translatable-lang":{type:"string",description:"Language code assigned to specific translatable input instance"}},i=G(o),l={en:"English",sq:"Shqip",sr:"Srpski"};function a(r){if(this.dom=r,Q(this,r,i),this.activeLanguages=new Set,this.badgesEl=r.querySelector("[data-ln-translations-active]"),this.menuEl=r.querySelector("[data-ln-dropdown] > [data-ln-toggle]"),this.locales=l,this._localesRaw)try{this.locales=JSON.parse(this._localesRaw)}catch{console.warn("[ln-translations] Invalid JSON in data-ln-translations-locales")}this._applyDefaultLang(),this._updateDropdown();const s=this;return this._onRequestAdd=function(n){n.detail&&n.detail.lang&&s.addLanguage(n.detail.lang)},this._onRequestRemove=function(n){n.detail&&n.detail.lang&&s.removeLanguage(n.detail.lang)},r.addEventListener("ln-translations:request-add",this._onRequestAdd),r.addEventListener("ln-translations:request-remove",this._onRequestRemove),this._detectExisting(),this}a.prototype._applyDefaultLang=function(){if(!this.defaultLang)return;const r=this.dom.querySelectorAll("[data-ln-translatable]");for(const s of r){const n=s.querySelectorAll("input:not([data-ln-translatable-lang]), textarea:not([data-ln-translatable-lang]), select:not([data-ln-translatable-lang])");for(const c of n)c.setAttribute("data-ln-translatable-lang",this.defaultLang)}},a.prototype._detectExisting=function(){const r=this.dom.querySelectorAll("[data-ln-translatable-lang]");for(const s of r){const n=s.getAttribute("data-ln-translatable-lang");n&&n!==this.defaultLang&&this.activeLanguages.add(n)}this.activeLanguages.size>0&&(this._updateBadges(),this._updateDropdown())},a.prototype._updateDropdown=function(){if(!this.menuEl)return;this.menuEl.textContent="";const r=this;let s=0;for(const c in this.locales){if(!this.locales.hasOwnProperty(c)||this.activeLanguages.has(c))continue;s++;const u=L("ln-translations-menu-item","ln-translations");if(!u)return;const d=u.querySelector("[data-ln-translations-lang]");d.setAttribute("data-ln-translations-lang",c),d.textContent=this.locales[c],d.addEventListener("click",function(f){f.ctrlKey||f.metaKey||f.button===1||(f.preventDefault(),f.stopPropagation(),r.menuEl.getAttribute("data-ln-toggle")==="open"&&r.menuEl.setAttribute("data-ln-toggle","close"),r.addLanguage(c))}),this.menuEl.appendChild(u)}const n=this.dom.querySelector("[data-ln-translations-add]");n&&(n.hidden=s===0)},a.prototype._updateBadges=function(){if(!this.badgesEl)return;this.badgesEl.textContent="";const r=this;this.activeLanguages.forEach(function(s){const n=L("ln-translations-badge","ln-translations");if(!n)return;const c=n.querySelector("[data-ln-translations-lang]");c.setAttribute("data-ln-translations-lang",s);const u=c.querySelector("span");u.textContent=r.locales[s]||s.toUpperCase();const d=c.querySelector("button"),f=r.locales[s]||s.toUpperCase();d.setAttribute("aria-label",r.removeLabel.replace("{lang}",f)),d.addEventListener("click",function(h){h.ctrlKey||h.metaKey||h.button===1||(h.preventDefault(),h.stopPropagation(),r.removeLanguage(s))}),r.badgesEl.appendChild(n)})},a.prototype.addLanguage=function(r,s){if(this.activeLanguages.has(r))return;const n=this.locales[r]||r;if(T(this.dom,"ln-translations:before-add",{target:this.dom,lang:r,langName:n}).defaultPrevented)return;this.activeLanguages.add(r),s=s||{};const u=this.dom.querySelectorAll("[data-ln-translatable]");for(const d of u){const f=d.getAttribute("data-ln-translatable"),h=d.getAttribute("data-ln-translations-prefix")||"",m=d.querySelector(this.defaultLang?'[data-ln-translatable-lang="'+this.defaultLang+'"]':"input:not([data-ln-translatable-lang]), textarea:not([data-ln-translatable-lang]), select:not([data-ln-translatable-lang])");if(!m)continue;const w=m.cloneNode(m.tagName==="SELECT");h?w.name=h+"[trans]["+r+"]["+f+"]":w.name="trans["+r+"]["+f+"]",w.value=s[f]!==void 0?s[f]:"",w.removeAttribute("id"),"placeholder"in w&&(w.placeholder=this.placeholderLabel.replace("{lang}",n)),w.setAttribute("data-ln-translatable-lang",r);const b=d.querySelectorAll('[data-ln-translatable-lang]:not([data-ln-translatable-lang="'+this.defaultLang+'"])'),v=b.length>0?b[b.length-1]:m;v.parentNode.insertBefore(w,v.nextSibling)}this._updateDropdown(),this._updateBadges(),S(this.dom,"ln-translations:added",{target:this.dom,lang:r,langName:n})},a.prototype.removeLanguage=function(r){if(!this.activeLanguages.has(r)||T(this.dom,"ln-translations:before-remove",{target:this.dom,lang:r}).defaultPrevented)return;const n=this.dom.querySelectorAll('[data-ln-translatable-lang="'+r+'"]');for(const c of n)c.parentNode.removeChild(c);this.activeLanguages.delete(r),this._updateDropdown(),this._updateBadges(),S(this.dom,"ln-translations:removed",{target:this.dom,lang:r})},a.prototype.getActiveLanguages=function(){return new Set(this.activeLanguages)},a.prototype.hasLanguage=function(r){return this.activeLanguages.has(r)},a.prototype.destroy=function(){if(!this.dom[t])return;const r=this.defaultLang,s=this.dom.querySelectorAll("[data-ln-translatable-lang]");for(const n of s)n.getAttribute("data-ln-translatable-lang")!==r&&n.parentNode.removeChild(n);this.dom.removeEventListener("ln-translations:request-add",this._onRequestAdd),this.dom.removeEventListener("ln-translations:request-remove",this._onRequestRemove),delete this.dom[t]},ne(e,t,a,"ln-translations",{attributes:o})})()})();
|
|
1
|
+
(function(){"use strict";function B(){if(typeof window>"u")return!1;if(window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink)return!0;if(typeof document<"u"){if(document.documentElement&&document.documentElement.hasAttribute("data-ln-debug"))return!0;if(document.body)return document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null}return!1}function S(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let l=null;for(let i=1;i<t.length;i++)if(t[i]&&t[i].nodeType===1){l=t[i];break}if(!S(l))return}e.apply(console,t)}}function x(e,t,n){const l=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,l),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:l}))}function $(e,t,n){const l=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,l);const i=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:l});return e.dispatchEvent(i),i}function A(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){A(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function M(e){return!!(!e||e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||typeof e.button=="number"&&e.button!==0)}function ue(e){const t=e.querySelector('input[name="_method"]');return((t&&t.value!==""?t.value:e.method)||"").toUpperCase()}function de(e,t){const n=!!(t&&t.typed),l=t&&t.exclude,i={},a=e.elements,o={};if(n)for(let s=0;s<a.length;s++){const r=a[s];r.name&&r.type==="checkbox"&&!r.disabled&&(o[r.name]=(o[r.name]||0)+1)}for(let s=0;s<a.length;s++){const r=a[s];if(!(!r.name||r.disabled||r.type==="file"||r.type==="submit"||r.type==="button")&&!(l&&r.matches&&r.matches(l)))if(r.type==="checkbox")n&&o[r.name]===1?i[r.name]=r.checked:(i[r.name]||(i[r.name]=[]),r.checked&&i[r.name].push(r.value));else if(r.type==="radio")r.checked&&(i[r.name]=r.value);else if(r.type==="select-multiple"){i[r.name]=[];for(let c=0;c<r.options.length;c++)r.options[c].selected&&i[r.name].push(r.options[c].value)}else if(n&&r.type==="hidden")i[r.name]=r.value;else if(n&&(r.type==="number"||r.type==="range")){const c=Number(r.value);i[r.name]=r.value===""||isNaN(c)?null:c}else i[r.name]=r.value}return i}function fe(e){if(typeof e!="string")return!!e;const t=e.trim().toLowerCase();return t!=="false"&&t!=="0"&&t!==""&&t!=="off"&&t!=="no"}function ge(e,t){const n=e.elements,l=[],i={};for(let a=0;a<n.length;a++){const o=n[a];o.name&&o.type==="checkbox"&&(i[o.name]=(i[o.name]||0)+1)}for(let a=0;a<n.length;a++){const o=n[a];if(o.type==="file"||o.type==="submit"||o.type==="button")continue;const s=o.getAttribute("data-ln-fill-as")||o.name;if(!s||!(s in t))continue;const r=t[s];if(o.type==="checkbox"){if(Array.isArray(r))o.checked=r.indexOf(o.value)!==-1;else if(i[o.name]>1){const c=String(r).split(",").map(function(u){return u.trim()});o.checked=c.indexOf(o.value)!==-1}else o.checked=fe(r);l.push(o)}else if(o.type==="radio")o.checked=o.value===String(r),l.push(o);else if(o.type==="select-multiple"){if(Array.isArray(r))for(let c=0;c<o.options.length;c++)o.options[c].selected=r.indexOf(o.options[c].value)!==-1;l.push(o)}else o.value=r,o.tagName==="SELECT"&&r!=null&&o.setAttribute("data-ln-value",r),l.push(o)}return l}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.populateForm=ge,window.lnCore.serializeForm=de,window.lnCore.resolveFormMethod=ue);const j={};function he(e,t){j[e]=t}function we(e){return j[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=he,window.lnCore.getDataMapper=we);function pe(e){const t=e?e.closest("[lang]"):null,n=(t?t.getAttribute("lang")||t.lang:null)||(typeof document<"u"&&document.documentElement?document.documentElement.getAttribute("lang")||document.documentElement.lang:null)||(typeof navigator<"u"?navigator.language:null);return n?n.trim():"en-US"}function be(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,A(function(){new MutationObserver(function(){x(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const U={};function me(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];U[n]=t}function ye(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return U[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=me,window.lnCore.getLocaleFallback=ye,window.lnCore.ensureLocaleObserver=be);const L={};function v(e,t){L[e]||(L[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=L[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function W(e,t,n){if(e){const l=e.querySelector('[data-ln-template="'+t+'"]');if(l)return l.content.cloneNode(!0)}return v(t,n)}function P(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let o=0;o<n.length;o++){const s=n[o],r=s.getAttribute("data-ln-field");t[r]!=null&&(s.textContent=t[r])}const l=e.querySelectorAll("[data-ln-attr]");for(let o=0;o<l.length;o++){const s=l[o],r=s.getAttribute("data-ln-attr").split(",");for(let c=0;c<r.length;c++){const u=r[c].trim().split(":");if(u.length!==2)continue;const d=u[0].trim(),f=u[1].trim();t[f]!=null&&s.setAttribute(d,t[f])}}const i=e.querySelectorAll("[data-ln-show]");for(let o=0;o<i.length;o++){const s=i[o],r=s.getAttribute("data-ln-show");r in t&&s.classList.toggle("hidden",!t[r])}const a=e.querySelectorAll("[data-ln-class]");for(let o=0;o<a.length;o++){const s=a[o],r=s.getAttribute("data-ln-class").split(",");for(let c=0;c<r.length;c++){const u=r[c].trim().split(":");if(u.length!==2)continue;const d=u[0].trim(),f=u[1].trim();f in t&&s.classList.toggle(d,!!t[f])}}return e}function Ce(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let l=0;l<n.length;l++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[l],t??null),n[l].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)P(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function V(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const a=n.currentNode;a.textContent.indexOf("{{")!==-1&&(a.textContent=a.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(o,s){return t[s]!==void 0?t[s]:""}))}const l=function(a,o){return t[o]!==void 0?t[o]:""},i=Array.from(e.querySelectorAll("*"));e.nodeType===1&&i.push(e);for(let a=0;a<i.length;a++){const o=i[a],s=o.attributes;for(let r=0;r<s.length;r++){const c=s[r];c.value.indexOf("{{")!==-1&&o.setAttribute(c.name,c.value.replace(/\{\{\s*(\w+)\s*\}\}/g,l))}}return e}function Ae(e,t,n,l,i,a){const o={};for(let r=0;r<e.children.length;r++){const c=e.children[r],u=c.getAttribute("data-ln-render-key");u&&(o[u]=c)}const s=document.createDocumentFragment();for(let r=0;r<t.length;r++){const c=t[r],u=String(l(c));let d=o[u];if(d)i(d,c,r);else{const f=v(n,a);if(!f||(V(f,c),d=f.firstElementChild,!d))continue;d.setAttribute("data-ln-render-key",u),i(d,c,r)}s.appendChild(d)}e.textContent="",e.appendChild(s)}function ve(e,t){const n={},l=e.querySelectorAll("["+t+"]");for(let i=0;i<l.length;i++)n[l[i].getAttribute(t)]=l[i].textContent,l[i].remove();return n}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=V,window.lnCore.fill=P,window.lnCore.lnFill=Ce,window.lnCore.renderList=Ae);function p(e,t,n){const l=e.getAttribute(t);return l===null?n:l}function H(e,t,n){const l=parseInt(e.getAttribute(t),10);return isNaN(l)?n:l}function K(e,t,n=!1){const l=e.getAttribute(t);if(l===null)return!!n;const i=l.trim().toLowerCase();return!(i==="false"||i==="0")}function Q(e,t){return(e.getAttribute(t)||"").split(",").map(n=>n.trim()).filter(Boolean)}const k=new Map;function J(e,t){const n=(e?e.join("|"):"")+"::"+t;if(k.has(n))return k.get(n);const l=new Set(e||[]),i=function(a,o){const s=a.getAttribute(o);return s!==null&&l.has(s)?s:t};return k.set(n,i),i}function z(e,t,n){const l=parseFloat(e.getAttribute(t));return isNaN(l)?n:l}function E(e,t,n){const l=e.getAttribute(t);if(!l)return n;try{return JSON.parse(l)}catch{return n}}function G(e,t,n,l,i){if(!e||t===null)return!0;const a=l||"ln-component",o=e.type;if(o==="trigger"||o==="marker"||o==="string"||o==="list"||!o||t===""&&e.fallback!==void 0)return!0;const s=r=>{i?console.warn(r,i):console.warn(r)};if(o==="boolean"){const r=t.trim().toLowerCase();return r!==""&&r!=="true"&&r!=="false"&&r!=="1"&&r!=="0"?(s(`[${a}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(o==="enum"){const r=e.values||[];return r.includes(t)?!0:(s(`[${a}] Invalid value "${t}" for attribute "${n}". Allowed: ${r.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(o==="integer"){if(!/^-?\d+$/.test(t))return s(`[${a}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const r=parseInt(t,10);return e.min!==void 0&&r<e.min?(s(`[${a}] Value ${r} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&r>e.max?(s(`[${a}] Value ${r} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(o==="float")return isNaN(Number(t))?(s(`[${a}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(o==="json")try{return JSON.parse(t),!0}catch(r){return s(`[${a}] Invalid JSON for attribute "${n}": ${r.message}. Fallback: ${e.fallback}.`),!1}return!0}function X(e,t,n){for(const l in n){const[i,a,o]=n[l];Object.defineProperty(e,l,{get:function(){return i(t,a,o)},enumerable:!0,configurable:!0})}return e}function Y(e){const t={};for(const n in e){const l=e[n];if(!l||!l.prop)continue;let i=l.read;if(!i&&l.type)switch(l.type){case"enum":i=J(l.values,l.fallback);break;case"integer":i=H;break;case"float":i=z;break;case"boolean":i=K;break;case"list":i=Q;break;case"json":i=E;break;case"string":default:i=p;break}i||(i=p),t[l.prop]=[i,n,l.fallback]}return t}function _e(e){const t={};for(const n in e){const l=e[n];l&&l.effect&&(t[n]=l.effect)}return Object.keys(t).length?t:null}function Se(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.defineAttrs=X,window.lnCore.attrSpec=Y,window.lnCore.attrStr=p,window.lnCore.attrInt=H,window.lnCore.attrBool=K,window.lnCore.attrList=Q,window.lnCore.attrEnum=J,window.lnCore.attrFloat=z,window.lnCore.attrJson=E);function _(e,t){if(!e[t.attribute]){window.lnCore._persistSink&&e.hasAttribute&&e.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(e,t.selector);try{e[t.attribute]=new t.ComponentFn(e)}catch(n){console.error("["+t.attribute+"] init failed",e,n)}}}function Z(e,t,n,l){if(e.nodeType!==1)return;const a=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",o={selector:t,attribute:n,ComponentFn:l};if(e.matches&&e.matches(a)&&_(e,o),e.querySelectorAll){const s=e.querySelectorAll(a);for(let r=0;r<s.length;r++)_(s[r],o)}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function xe(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function Le(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function ee(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function ke(e){const t=ee(),n=e.observed||[];for(let l=0;l<n.length;l++){const i=n[l];t.byAttr.has(i)||t.byAttr.set(i,[]),t.byAttr.get(i).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const l in e.attributes){t.byDeclaredAttr.has(l)||t.byDeclaredAttr.set(l,[]);const i=t.byDeclaredAttr.get(l);i.some(a=>a.componentTag===e.componentTag)||i.push({spec:e.attributes[l],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const l=Se(e);if(l===null)t.reactiveWildcard.push(e);else for(const i of l)t.byReactive.has(i)||t.byReactive.set(i,[]),t.byReactive.get(i).push(e)}e.persist&&t.persist.push(e)}function te(e,t,n,l){for(let i=0;i<e.length;i++){const a=e[i];if(!t[a.attribute])continue;const o=a.effects&&a.effects[n];o?o(t,n,l):a.onAttrChange&&(!a.declared||a.declared.has(n))&&a.onAttrChange(t,n,l)}}function Ee(e){const t=e.attributeName,n=t.indexOf("data-ln-")===0,l=ee(),i=l.byAttr.get(t),a=B()&&l.byDeclaredAttr&&l.byDeclaredAttr.has(t);if(!n&&!i&&!a)return;const o=e.target;if(e.oldValue!==o.getAttribute(t)){if(a&&S(o)){const s=l.byDeclaredAttr.get(t),r=o.getAttribute(t);for(let c=0;c<s.length;c++)G(s[c].spec,r,t,s[c].componentTag,o)}if(window.lnCore._debugSink&&(n||i)&&window.lnCore._debugSink("attr",t,o,{oldValue:e.oldValue,newValue:o.getAttribute(t)}),n){const s=l.byReactive.get(t);s&&te(s,o,t,e.oldValue),l.reactiveWildcard.length&&te(l.reactiveWildcard,o,t,e.oldValue)}if(i)for(let s=0;s<i.length;s++){const r=i[s];if(r.handler){r.handler(o,t,e.oldValue);continue}r.onAttributeChange&&o[r.attribute]?r.onAttributeChange(o,t):(Z(o,r.selector,r.attribute,r.ComponentFn),r.onInit&&r.onInit(o))}}}function qe(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{Ee(t[n])}catch(l){console.error("[ln-core] mutation handler failed",t[n].target,l)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function q(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function D(){return window.lnCore=window.lnCore||{},window.lnCore._subtreeRegistry=window.lnCore._subtreeRegistry||[]}function ne(e,t){if(!document.contains(e))if(t.attribute){const n=e[t.attribute];if(n&&typeof n.destroy=="function")try{n.destroy()}catch(l){console.error("["+t.attribute+"] destroy failed",e,l)}delete e[t.attribute]}else t.onDestroy&&t.onDestroy(e)}function re(e){const t=q();if(!t.length)return;const n=e.target;if(n){const i=n.nodeType===1?n:n.parentElement;if(i&&(i.isContentEditable||i.closest&&i.closest('[contenteditable]:not([contenteditable="false"])')))return}const l=D();if(e.target&&l.length)for(let i=0;i<l.length;i++){const a=l[i],o=a.query,s=e.target.nodeType===1?e.target.matches&&e.target.matches(o)?e.target:e.target.closest?e.target.closest(o):null:e.target.parentElement&&e.target.parentElement.closest?e.target.parentElement.closest(o):null;s&&a.onSubtreeChange(s,e)}for(let i=0;i<e.addedNodes.length;i++){const a=e.addedNodes[i];if(a.nodeType!==1)continue;const o=!!(a.firstElementChild||a.children&&a.children.length);for(let s=0;s<t.length;s++){const r=t[s],c=r.query;if(c&&(a.matches&&a.matches(c)&&(r.ComponentFn&&_(a,r),r.onInit&&r.onInit(a)),o&&a.querySelectorAll)){const u=a.querySelectorAll(c);for(let d=0;d<u.length;d++)r.ComponentFn&&_(u[d],r),r.onInit&&r.onInit(u[d])}}}for(let i=0;i<e.removedNodes.length;i++){const a=e.removedNodes[i];if(a.nodeType!==1||document.contains(a))continue;const o=!!(a.firstElementChild||a.children&&a.children.length);for(let s=0;s<t.length;s++){const r=t[s],c=r.query;if(c&&(a.matches&&a.matches(c)&&ne(a,r),o&&a.querySelectorAll)){const u=a.querySelectorAll(c);for(let d=0;d<u.length;d++)ne(u[d],r)}}}}function oe(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,A(function(){const e=new MutationObserver(function(t){for(let n=0;n<t.length;n++){const l=t[n];if(l.type==="childList")try{re(l)}catch(i){console.error("[ln-core] lifecycle handler failed",l.target,i)}}});window.lnCore._lifecycleObserver=e,e.observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function De(e){if(typeof window>"u")return e();window.lnCore=window.lnCore||{};const t=window.lnCore._lifecycleObserver;if(!t)return e();const n=t.takeRecords();for(let l=0;l<n.length;l++){const i=n[l];if(i.type==="childList")try{re(i)}catch(a){console.error("[ln-core] lifecycle handler failed",i.target,a)}}t.disconnect();try{return e()}finally{t.observe(document.body,{childList:!0,subtree:!0})}}function Oe(e){q().push(e),e.onSubtreeChange&&e.query&&D().push(e),oe()}function ie(e,t,n,l,i={}){const a=i.extraAttributes||[],o=i.onAttributeChange||null,s=i.onSubtreeChange||null,r=i.onInit||null,c=i.onAttrChange||null,u=i.effects||null,d=i.attributes||null,f=d?_e(d):u,b=d?new Set(Object.keys(d)):null,R=i.persist||null;function h(N){const w=N||document.body;if(Z(w,e,t,n),d&&B())for(const C in d){const tt=d[C],I=Array.from(w.querySelectorAll("["+C+"]"));w.matches&&w.matches("["+C+"]")&&I.push(w);for(let F=0;F<I.length;F++){const T=I[F];S(T)&&G(tt,T.getAttribute(C),C,l,T)}}r&&r(w)}const g=[];if(e.indexOf("[")!==-1){const N=/\[([\w-]+)/g;let w;for(;(w=N.exec(e))!==null;)g.push(w[1])}else g.push(e);ke({selector:e,attribute:t,componentTag:l,attributes:d,ComponentFn:n,onInit:r,observed:g.concat(a),onAttributeChange:o,onAttrChange:c,effects:f,declared:b,persist:R}),qe();const m=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1,y=i.subtreeQuery||(m?e:"["+e+"]"),se={selector:e,attribute:t,ComponentFn:n,onInit:r,onSubtreeChange:s,query:y};q().push(se),s&&y&&D().push(se),oe(),window[t]=h,typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerComponent=ie,window.lnCore.observeLifecycle=Oe,window.lnCore.withoutLifecycle=De);function ce(){xe()>0?Le(function(){h(document.body)}):h(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",ce):ce(),h}function le(e){return(e||"").replace(/^#/,"")}function O(e){const t=e===void 0?location.hash:e,n={},l=le(t);if(!l)return n;const i=l.split("&");for(let a=0;a<i.length;a++){const o=i[a];if(!o)continue;const s=o.indexOf(":"),r=s>-1?o.slice(0,s):o,c=s>-1?o.slice(s+1):"";if(r)try{n[r]=decodeURIComponent(c)}catch{n[r]=c}}return n}function Re(e){if(!e)return null;const t=O();return e in t?t[e]:null}function Ne(e,t){if(!e)return;const n=O();t==null?delete n[e]:n[e]=String(t);const i=Object.keys(n).map(function(a){const o=n[a];return o===""?a:a+":"+encodeURIComponent(o)}).join("&");le(location.hash)!==i&&(location.hash=i)}function Ie(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function Fe(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const l=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return l?t?l+"-"+t:l:t||null}function Te(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Be(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function $e(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Me(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),l=e.slice(t+1),i=l?l.split(",").map(function(a){try{return decodeURIComponent(a)}catch{return a}}).filter(Boolean):[];return{key:n,values:i}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=O,window.lnCore.hashGet=Re,window.lnCore.hashSet=Ne,window.lnCore.hashLinkClick=Ie,window.lnCore.resolveHashNamespace=Fe,window.lnCore.hashSortEncode=Te,window.lnCore.hashSortDecode=Be,window.lnCore.hashFilterEncode=$e,window.lnCore.hashFilterDecode=Me);function je(e){return(e||"").replace(/^\?/,"")}function Ue(e){const t=e===void 0?typeof window<"u"?window.location.search:"":e,n={},l=je(t);if(!l)return n;const i=new URLSearchParams(l);for(const[a,o]of i.entries())n[a]=o;return n}function We(e){if(!e||typeof window>"u")return null;const t=new URLSearchParams(window.location.search);return t.has(e)?t.get(e):null}function Pe(e,t){if(!e||typeof window>"u")return;const n=new URL(window.location.href);if(t==null||t===""?n.searchParams.delete(e):n.searchParams.set(e,String(t)),n.search===window.location.search)return;const l=n.pathname+n.search+n.hash;window.history.replaceState(window.history.state,"",l)}function Ve(e,t){if(!e||!e.hasAttribute("data-ln-query"))return null;const n=e.getAttribute("data-ln-query");if(n&&n.trim()!=="")return n.trim();const l=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return l?t?l+"_"+t:l:t||null}function He(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Ke(e,t){if(e&&typeof e=="string"){if(e.endsWith(".asc"))return{fieldOrColumn:e.slice(0,-4),direction:"asc"};if(e.endsWith(".desc"))return{fieldOrColumn:e.slice(0,-5),direction:"desc"}}if(t&&typeof t=="object"){const n=t.sort_field||t.sort_by;if(n){const l=t.sort_dir&&String(t.sort_dir).toLowerCase()==="desc"?"desc":"asc";return{fieldOrColumn:n,direction:l}}}return null}function Qe(e){return!Array.isArray(e)||e.length===0?null:e.map(encodeURIComponent).join(",")}function Je(e){return!e||typeof e!="string"?[]:e.split(",").map(function(t){try{return decodeURIComponent(t.trim())}catch{return t.trim()}}).filter(Boolean)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.queryParse=Ue,window.lnCore.queryGet=We,window.lnCore.querySet=Pe,window.lnCore.resolveQueryParam=Ve,window.lnCore.querySortEncode=He,window.lnCore.querySortDecode=Ke,window.lnCore.queryFilterEncode=Qe,window.lnCore.queryFilterDecode=Je);function ze(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.uuid=ze);function Ge(e,t,n=""){return!e||!t?"":n?`${n}[trans][${t}][${e}]`:`trans[${t}][${e}]`}function Xe(e,t){return(e||"{lang} translation").replaceAll("{lang}",t||"")}function Ye(e,t){return(e||"Remove {lang}").replaceAll("{lang}",t||"")}function Ze(e,t={}){if(!e)return{...t};if(typeof e=="object"&&e!==null&&!Array.isArray(e))return{...e};if(typeof e=="string")try{const n=JSON.parse(e);if(typeof n=="object"&&n!==null&&!Array.isArray(n))return n}catch{}return{...t}}function ae(e,t={},n=""){if(!e)return"";if(t&&t[e])return t[e];if(typeof Intl<"u"&&typeof Intl.DisplayNames=="function")try{const i=new Intl.DisplayNames(n?[n]:void 0,{type:"language",fallback:"none"}).of(e);if(i)return i}catch{}return e}function et(e,t,n=""){if(!e||typeof e!="object")return[];const l=t instanceof Set?t:new Set(t||[]),i=(n||"").toLowerCase().trim(),a=[];for(const[o,s]of Object.entries(e)){const r=o.toLowerCase().trim();!l.has(o)&&!l.has(r)&&(!i||r!==i)&&a.push([o,s])}return a}(function(){const e="data-ln-translations",t="lnTranslations";if(window[t]!==void 0)return;const n={"data-ln-translations":{type:"marker",description:"Mounts multi-language translation coordinator on form container"},"data-ln-translations-default":{prop:"defaultLang",read:p,type:"string",fallback:"",description:"Default primary language code (e.g. en)"},"data-ln-translations-placeholder":{prop:"placeholderLabel",read:p,type:"string",fallback:"{lang} translation",description:"Placeholder label pattern for cloned translation inputs"},"data-ln-translations-remove-label":{prop:"removeLabel",read:p,type:"string",fallback:"Remove {lang}",description:"Accessible label template for translation removal buttons"},"data-ln-translations-locales":{prop:"_localesRaw",read:E,type:"json",fallback:null,description:"JSON dictionary of supported locale codes and display labels"},"data-ln-translations-dict":{type:"string",description:"Dictionary key prefix mapping for translatable labels"},"data-ln-translations-menu":{type:"marker",description:"Menu container holding available language items"},"data-ln-translations-active":{type:"marker",description:"Container holding active language badge tags"},"data-ln-translations-add":{type:"trigger",description:"Trigger button to open translation language menu"},"data-ln-translations-lang":{type:"string",description:"Language code associated with active language badge or menu item"},"data-ln-translations-prefix":{type:"string",description:"Prefix format pattern for nested translatable field names"},"data-ln-translatable":{type:"string",description:"Marks form control container as translatable, value is field name"},"data-ln-translatable-lang":{type:"string",description:"Language code assigned to specific translatable input instance"}},l=Y(n);function i(a){this.dom=a,X(this,a,l),this.dict=ve(a,"data-ln-translations-dict"),this.locale=pe(a),this.activeLanguages=new Set,this.badgesEl=a.querySelector("[data-ln-translations-active]"),this.menuEl=a.querySelector("[data-ln-translations-menu]")||a.querySelector("[data-ln-dropdown] > [data-ln-toggle]"),this.locales=Ze(this._localesRaw,{}),this._applyDefaultLang();const o=this;return this.menuEl&&(this._boundMenuClick=function(s){if(M(s))return;const r=s.target.closest("button[data-ln-translations-lang]");if(!r||!o.menuEl.contains(r))return;s.preventDefault(),s.stopPropagation();const c=r.getAttribute("data-ln-translations-lang");o.menuEl.getAttribute("data-ln-toggle")==="open"&&o.menuEl.setAttribute("data-ln-toggle","close"),c&&o.addLanguage(c)},this.menuEl.addEventListener("click",this._boundMenuClick)),this.badgesEl&&(this._boundBadgesClick=function(s){if(M(s))return;const r=s.target.closest("button");if(!r||!o.badgesEl.contains(r))return;const c=r.closest("[data-ln-translations-lang]"),u=c?c.getAttribute("data-ln-translations-lang"):null;u&&(s.preventDefault(),s.stopPropagation(),o.removeLanguage(u))},this.badgesEl.addEventListener("click",this._boundBadgesClick)),this._updateDropdown(),this._onRequestAdd=function(s){s.detail&&s.detail.lang&&o.addLanguage(s.detail.lang,s.detail.values)},this._onRequestRemove=function(s){s.detail&&s.detail.lang&&o.removeLanguage(s.detail.lang)},a.addEventListener("ln-translations:request-add",this._onRequestAdd),a.addEventListener("ln-translations:request-remove",this._onRequestRemove),this._detectExisting(),this}i.prototype._applyDefaultLang=function(){if(!this.defaultLang)return;const a=this.dom.querySelectorAll("[data-ln-translatable]");for(const o of a){const s=o.querySelectorAll("input:not([data-ln-translatable-lang]), textarea:not([data-ln-translatable-lang]), select:not([data-ln-translatable-lang])");for(const r of s)r.setAttribute("data-ln-translatable-lang",this.defaultLang)}},i.prototype._detectExisting=function(){const a=this.dom.querySelectorAll("[data-ln-translatable-lang]");for(const o of a){const s=o.getAttribute("data-ln-translatable-lang");s&&s!==this.defaultLang&&this.activeLanguages.add(s)}this.activeLanguages.size>0&&(this._updateBadges(),this._updateDropdown())},i.prototype._updateDropdown=function(){if(!this.menuEl)return;this.menuEl.textContent="";const a=et(this.locales,this.activeLanguages,this.defaultLang);for(let s=0;s<a.length;s++){const[r,c]=a[s],u=W(this.dom,"ln-translations-menu-item")||v("ln-translations-menu-item","ln-translations");if(!u)return;const d=u.querySelector("[data-ln-translations-lang]");d&&(d.setAttribute("data-ln-translations-lang",r),d.textContent=c,this.menuEl.appendChild(u))}const o=this.dom.querySelector("[data-ln-translations-add]");o&&(o.hidden=a.length===0)},i.prototype._updateBadges=function(){if(!this.badgesEl)return;this.badgesEl.textContent="";const a=this,o=this.dict&&this.dict["remove-label"]||this.removeLabel;this.activeLanguages.forEach(function(s){const r=W(a.dom,"ln-translations-badge")||v("ln-translations-badge","ln-translations");if(!r)return;const c=r.querySelector("[data-ln-translations-lang]");if(!c)return;c.setAttribute("data-ln-translations-lang",s);const u=ae(s,a.locales,a.locale),d=c.querySelector("span");d&&(d.textContent=u);const f=c.querySelector("button");f&&f.setAttribute("aria-label",Ye(o,u)),a.badgesEl.appendChild(r)})},i.prototype.addLanguage=function(a,o){if(!a||a===this.defaultLang||this.activeLanguages.has(a))return;const s=ae(a,this.locales,this.locale);if($(this.dom,"ln-translations:before-add",{target:this.dom,lang:a,langName:s}).defaultPrevented)return;this.activeLanguages.add(a),o=o||{};const c=this.dict&&this.dict.placeholder||this.placeholderLabel,u=Xe(c,s),d=this.dom.querySelectorAll("[data-ln-translatable]");for(const f of d){const b=f.getAttribute("data-ln-translatable"),R=f.getAttribute("data-ln-translations-prefix")||"",h=f.querySelector('[data-ln-translatable-lang="'+this.defaultLang+'"]')||f.querySelector("input, textarea, select");if(!h)continue;const g=h.cloneNode(h.tagName==="SELECT");g.name=Ge(b,a,R),g.value=o[b]!==void 0?o[b]:"",g.removeAttribute("id"),"placeholder"in g&&(g.placeholder=u),g.setAttribute("aria-label",u),g.setAttribute("data-ln-translatable-lang",a);const m=f.querySelectorAll("[data-ln-translatable-lang]"),y=m.length>0?m[m.length-1]:h;y.parentNode.insertBefore(g,y.nextSibling)}this._updateDropdown(),this._updateBadges(),x(this.dom,"ln-translations:added",{target:this.dom,lang:a,langName:s})},i.prototype.removeLanguage=function(a){if(!a||a===this.defaultLang||!this.activeLanguages.has(a)||$(this.dom,"ln-translations:before-remove",{target:this.dom,lang:a}).defaultPrevented)return;const s=this.dom.querySelectorAll('[data-ln-translatable-lang="'+a+'"]');for(const r of s)r.parentNode.removeChild(r);this.activeLanguages.delete(a),this._updateDropdown(),this._updateBadges(),x(this.dom,"ln-translations:removed",{target:this.dom,lang:a})},i.prototype.getActiveLanguages=function(){return new Set(this.activeLanguages)},i.prototype.hasLanguage=function(a){return this.activeLanguages.has(a)},i.prototype.destroy=function(){if(!this.dom[t])return;for(const o of this.activeLanguages){const s=this.dom.querySelectorAll('[data-ln-translatable-lang="'+o+'"]');for(const r of s)r.parentNode.removeChild(r)}this.badgesEl&&(this.badgesEl.textContent="",this._boundBadgesClick&&(this.badgesEl.removeEventListener("click",this._boundBadgesClick),this._boundBadgesClick=null)),this.menuEl&&(this.menuEl.textContent="",this._boundMenuClick&&(this.menuEl.removeEventListener("click",this._boundMenuClick),this._boundMenuClick=null));const a=this.dom.querySelector("[data-ln-translations-add]");a&&(a.hidden=!1),this.dom.removeEventListener("ln-translations:request-add",this._onRequestAdd),this.dom.removeEventListener("ln-translations:request-remove",this._onRequestRemove),this.activeLanguages.clear(),delete this.dom[t]},ie(e,t,i,"ln-translations",{attributes:n})})()})();
|