json-renderers 1.18.8 → 1.20.1
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/docs/dist/min.js +523 -513
- package/docs/dist/v18/min.js +2049 -2049
- package/docs/dist/v19/min.js +2054 -0
- package/docs/dist/v20/min.js +2059 -0
- package/docs/samples/datalist/windowks.html +350 -350
- package/docs/samples/select/windowks.html +358 -358
- package/package.json +2 -1
- package/src/index.js +2 -2
- package/src/v19/buildSpec/index.js +28 -0
- package/src/v19/index.js +35 -0
- package/src/{v16 → v19}/meta.js +1 -1
- package/src/v19/registerGlobal.js +16 -0
- package/src/v19/renderToDom/index.js +47 -0
- package/src/v20/buildSpec/index.js +28 -0
- package/src/v20/index.js +41 -0
- package/src/{v15 → v20}/meta.js +1 -1
- package/src/v20/registerGlobal.js +16 -0
- package/src/v20/renderToDom/index.js +47 -0
- package/src/v14/buildSpec/index.js +0 -39
- package/src/v14/index.js +0 -81
- package/src/v14/meta.js +0 -6
- package/src/v14/registerGlobal.js +0 -14
- package/src/v15/buildSpec/index.js +0 -39
- package/src/v15/guard.js +0 -35
- package/src/v15/index.js +0 -70
- package/src/v15/registerGlobal.js +0 -14
- package/src/v16/buildSpec/index.js +0 -40
- package/src/v16/common/deriveColumnsFromData.js +0 -20
- package/src/v16/guard.js +0 -38
- package/src/v16/index.js +0 -106
- package/src/v16/registerGlobal.js +0 -27
- /package/src/{v14 → v19}/common/deriveColumnsFromData.js +0 -0
- /package/src/{v15 → v20}/common/deriveColumnsFromData.js +0 -0
|
@@ -1,358 +1,358 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>window.ks.jsonRenderers.renderToDom | Select Guide</title>
|
|
8
|
-
<meta name="description"
|
|
9
|
-
content="Simple guide explaining how window.ks.jsonRenderers.renderToDom works to build and render HTML select dropdowns from JSON data." />
|
|
10
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
11
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
12
|
-
<link
|
|
13
|
-
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600&family=Inter:wght@300;400;500;600;700;800&display=swap"
|
|
14
|
-
rel="stylesheet" />
|
|
15
|
-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
|
|
16
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
17
|
-
<style>
|
|
18
|
-
body {
|
|
19
|
-
font-family: 'Inter', sans-serif;
|
|
20
|
-
background-color: #ffffff;
|
|
21
|
-
color: #1e293b;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
pre,
|
|
25
|
-
code {
|
|
26
|
-
font-family: 'Fira Code', monospace;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
#dom-render-container select {
|
|
30
|
-
width: 100%;
|
|
31
|
-
padding: 0.65rem 1rem;
|
|
32
|
-
font-size: 0.95rem;
|
|
33
|
-
border-radius: 0.75rem;
|
|
34
|
-
border: 1px solid #cbd5e1;
|
|
35
|
-
background-color: #ffffff;
|
|
36
|
-
color: #0f172a;
|
|
37
|
-
transition: all 0.2s ease;
|
|
38
|
-
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
#dom-render-container select:focus {
|
|
42
|
-
outline: none;
|
|
43
|
-
border-color: #4f46e5;
|
|
44
|
-
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
|
|
45
|
-
}
|
|
46
|
-
</style>
|
|
47
|
-
</head>
|
|
48
|
-
|
|
49
|
-
<body class="bg-white min-h-screen flex flex-col antialiased text-slate-800">
|
|
50
|
-
|
|
51
|
-
<!-- Navigation Bar -->
|
|
52
|
-
<header class="border-b border-slate-200 bg-white/95 backdrop-blur sticky top-0 z-50 shadow-sm">
|
|
53
|
-
<div class="max-w-5xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between gap-4">
|
|
54
|
-
<div class="flex items-center gap-3">
|
|
55
|
-
<a href="../index.html"
|
|
56
|
-
class="w-9 h-9 rounded-xl bg-gradient-to-br from-indigo-500 to-blue-600 flex items-center justify-center font-bold text-white shadow-sm text-base hover:scale-105 transition">
|
|
57
|
-
▣
|
|
58
|
-
</a>
|
|
59
|
-
<div>
|
|
60
|
-
<a href="../index.html"
|
|
61
|
-
class="text-sm font-bold text-slate-900 hover:text-indigo-600 transition">json-renderers</a>
|
|
62
|
-
<span class="text-xs text-slate-500 block">Select • window.ks Guide</span>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
<nav class="flex items-center gap-2 text-xs sm:text-sm">
|
|
67
|
-
<a href="../index.html"
|
|
68
|
-
class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 transition">Samples Hub</a>
|
|
69
|
-
<a href="index.html"
|
|
70
|
-
class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 transition">Select Hub</a>
|
|
71
|
-
<a href="cdn.html"
|
|
72
|
-
class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 transition">Using CDN</a>
|
|
73
|
-
<a href="windowks.html"
|
|
74
|
-
class="px-3 py-1.5 rounded-lg bg-indigo-600 text-white font-semibold shadow-sm transition">window.ks</a>
|
|
75
|
-
</nav>
|
|
76
|
-
</div>
|
|
77
|
-
</header>
|
|
78
|
-
|
|
79
|
-
<!-- Main Content -->
|
|
80
|
-
<main class="flex-1 max-w-5xl w-full mx-auto p-4 sm:p-6 lg:p-8 space-y-8">
|
|
81
|
-
|
|
82
|
-
<!-- Document Header -->
|
|
83
|
-
<section class="bg-white rounded-2xl p-6 sm:p-8 border border-slate-200 shadow-sm space-y-3">
|
|
84
|
-
<div
|
|
85
|
-
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-indigo-50 border border-indigo-200 text-xs font-mono text-indigo-700 font-medium">
|
|
86
|
-
Global Window Object Guide • Select Component
|
|
87
|
-
</div>
|
|
88
|
-
<h1 class="text-2xl sm:text-4xl font-extrabold text-slate-900 tracking-tight">
|
|
89
|
-
window.ks.jsonRenderers.renderToDom
|
|
90
|
-
</h1>
|
|
91
|
-
<p class="text-slate-600 text-sm sm:text-base leading-relaxed">
|
|
92
|
-
Understand how the global <code
|
|
93
|
-
class="text-indigo-700 bg-indigo-50 px-1 py-0.5 rounded font-mono font-medium">window.ks</code> runtime allows any script on your page to mount dynamic select dropdowns directly from JSON data without modular imports.
|
|
94
|
-
</p>
|
|
95
|
-
</section>
|
|
96
|
-
|
|
97
|
-
<!-- Why Use window.ks (The Story) -->
|
|
98
|
-
<section class="bg-white rounded-2xl p-6 sm:p-8 border border-slate-200 shadow-sm space-y-4">
|
|
99
|
-
<h2 class="text-lg font-bold text-slate-900 flex items-center gap-2">
|
|
100
|
-
<span>📖</span> The Story: Why Use Global window.ks?
|
|
101
|
-
</h2>
|
|
102
|
-
<p class="text-xs sm:text-sm text-slate-600 leading-relaxed">
|
|
103
|
-
When developing large enterprise web pages, administrative dashboards, or legacy PHP/JSP templates, not every piece of code is bundled through Vite or Webpack. In these architectures, you include one script tag in the page header, which registers the <code class="text-indigo-700 font-mono font-semibold">window.ks</code> global object.
|
|
104
|
-
</p>
|
|
105
|
-
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 pt-2">
|
|
106
|
-
<div class="p-4 rounded-xl bg-slate-50 border border-slate-200 space-y-1">
|
|
107
|
-
<div class="text-indigo-600 font-bold text-sm">No Module Scoping</div>
|
|
108
|
-
<p class="text-xs text-slate-600">Accessible everywhere in the window context without import statements.</p>
|
|
109
|
-
</div>
|
|
110
|
-
<div class="p-4 rounded-xl bg-slate-50 border border-slate-200 space-y-1">
|
|
111
|
-
<div class="text-indigo-600 font-bold text-sm">Lightweight Setup</div>
|
|
112
|
-
<p class="text-xs text-slate-600">Load the minified bundle once, render 50 different select dropdowns anywhere.</p>
|
|
113
|
-
</div>
|
|
114
|
-
<div class="p-4 rounded-xl bg-slate-50 border border-slate-200 space-y-1">
|
|
115
|
-
<div class="text-indigo-600 font-bold text-sm">Zero InnerHTML Risk</div>
|
|
116
|
-
<p class="text-xs text-slate-600">Builds real DOM elements under the hood using <code class="font-mono">json-to-tag</code>.</p>
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
</section>
|
|
120
|
-
|
|
121
|
-
<!-- How It Works & Code Example -->
|
|
122
|
-
<section class="bg-white rounded-2xl p-6 sm:p-8 border border-slate-200 shadow-sm space-y-4">
|
|
123
|
-
<div class="flex items-center justify-between flex-wrap gap-2">
|
|
124
|
-
<h2 class="text-lg font-bold text-slate-900 flex items-center gap-2">
|
|
125
|
-
<span>⚙️</span> Complete Implementation Code
|
|
126
|
-
</h2>
|
|
127
|
-
<button onclick="copyCode('ks-select-code')"
|
|
128
|
-
class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-mono font-medium transition flex items-center gap-1.5 border border-slate-300">
|
|
129
|
-
<span>📋</span> Copy Code
|
|
130
|
-
</button>
|
|
131
|
-
</div>
|
|
132
|
-
|
|
133
|
-
<div class="rounded-xl bg-slate-950 p-4 text-xs text-slate-200 overflow-x-auto">
|
|
134
|
-
<pre id="ks-select-code"><code>// 1. Load the bundle to attach window.ks globally
|
|
135
|
-
await import("https://cdn.jsdelivr.net/gh/keshavsoft/json-renderers@main/docs/dist/v14/min.js");
|
|
136
|
-
|
|
137
|
-
// 2. Define your options array
|
|
138
|
-
const ledgerNames = [
|
|
139
|
-
"Cash in Hand",
|
|
140
|
-
"Standard Chartered Bank",
|
|
141
|
-
"Sundry Debtors",
|
|
142
|
-
"Office Equipment",
|
|
143
|
-
"Sales Revenue"
|
|
144
|
-
];
|
|
145
|
-
|
|
146
|
-
// 3. Render select element into the DOM
|
|
147
|
-
window.ks.jsonRenderers.renderToDom({
|
|
148
|
-
type: "select",
|
|
149
|
-
data: ledgerNames,
|
|
150
|
-
targetHtmlId: "dom-render-container",
|
|
151
|
-
showLog: true
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// 4. Attach event listeners
|
|
155
|
-
const selectElement = document.querySelector("#dom-render-container select");
|
|
156
|
-
if (selectElement) {
|
|
157
|
-
selectElement.addEventListener("change", (e) => {
|
|
158
|
-
console.log("Selected ledger:", e.target.value);
|
|
159
|
-
});
|
|
160
|
-
}</code></pre>
|
|
161
|
-
</div>
|
|
162
|
-
</section>
|
|
163
|
-
|
|
164
|
-
<!-- Live Interactive Demo -->
|
|
165
|
-
<section class="bg-white rounded-2xl p-6 sm:p-8 border border-slate-200 shadow-sm space-y-6">
|
|
166
|
-
<div class="flex items-center justify-between flex-wrap gap-2 border-b border-slate-100 pb-3">
|
|
167
|
-
<div>
|
|
168
|
-
<span class="text-xs font-mono font-semibold text-indigo-700 uppercase tracking-wider">Live Execution</span>
|
|
169
|
-
<h2 class="text-xl font-bold text-slate-900">Live Demo: Mounted via window.ks</h2>
|
|
170
|
-
</div>
|
|
171
|
-
<span id="demo-status" class="px-2.5 py-1 text-xs font-mono font-medium rounded-full bg-slate-100 text-slate-700">Loading...</span>
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
<!-- Controls -->
|
|
175
|
-
<div class="flex flex-wrap gap-3 items-center">
|
|
176
|
-
<label class="text-xs font-bold text-slate-700">Select Dataset Preset:</label>
|
|
177
|
-
<button id="btn-ledgers" class="px-3 py-1.5 rounded-lg bg-indigo-600 text-white text-xs font-semibold shadow-sm transition">
|
|
178
|
-
General Ledgers
|
|
179
|
-
</button>
|
|
180
|
-
<button id="btn-roles" class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-medium transition">
|
|
181
|
-
User Roles
|
|
182
|
-
</button>
|
|
183
|
-
<button id="btn-status" class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-medium transition">
|
|
184
|
-
Ticket Statuses
|
|
185
|
-
</button>
|
|
186
|
-
</div>
|
|
187
|
-
|
|
188
|
-
<!-- Live Container -->
|
|
189
|
-
<div class="p-6 rounded-2xl bg-slate-50 border border-slate-200 space-y-4">
|
|
190
|
-
<div class="flex items-center justify-between">
|
|
191
|
-
<span class="text-xs font-bold text-slate-700">Container: #dom-render-container</span>
|
|
192
|
-
<span class="text-[11px] font-mono text-indigo-700 font-semibold">window.ks.jsonRenderers.renderToDom()</span>
|
|
193
|
-
</div>
|
|
194
|
-
|
|
195
|
-
<div id="dom-render-container" class="bg-white p-5 rounded-xl border border-slate-200 shadow-sm min-h-[85px] flex items-center justify-center">
|
|
196
|
-
<div class="text-slate-400 text-xs font-mono">Initializing window.ks...</div>
|
|
197
|
-
</div>
|
|
198
|
-
|
|
199
|
-
<div class="p-3.5 rounded-xl bg-indigo-50 border border-indigo-200 flex items-center justify-between text-xs">
|
|
200
|
-
<span class="font-semibold text-indigo-900">Selected Value:</span>
|
|
201
|
-
<span id="selected-result" class="font-mono font-bold text-indigo-800 bg-white px-2.5 py-1 rounded border border-indigo-200">
|
|
202
|
-
(None)
|
|
203
|
-
</span>
|
|
204
|
-
</div>
|
|
205
|
-
</div>
|
|
206
|
-
</section>
|
|
207
|
-
|
|
208
|
-
</main>
|
|
209
|
-
|
|
210
|
-
<!-- Clean Light Footer -->
|
|
211
|
-
<footer class="border-t border-slate-200 bg-slate-50 py-8 mt-12">
|
|
212
|
-
<div class="max-w-5xl mx-auto px-4 sm:px-6 flex flex-col sm:flex-row items-center justify-between gap-4 text-xs text-slate-600">
|
|
213
|
-
<div>
|
|
214
|
-
<span class="text-slate-900 font-semibold">json-renderers</span> • <code class="text-indigo-700">window.ks.jsonRenderers.renderToDom</code> (Select)
|
|
215
|
-
</div>
|
|
216
|
-
<div class="flex items-center gap-4 flex-wrap">
|
|
217
|
-
<a href="index.html" class="hover:underline">Select Hub</a>
|
|
218
|
-
<a href="cdn.html" class="hover:underline">Using CDN</a>
|
|
219
|
-
<a href="../index.html" class="hover:underline">Samples Hub</a>
|
|
220
|
-
<a href="../../../samples/select/byKs/index.html" target="_blank" class="text-indigo-600 font-medium hover:underline">Sample (byKs)</a>
|
|
221
|
-
</div>
|
|
222
|
-
</div>
|
|
223
|
-
</footer>
|
|
224
|
-
|
|
225
|
-
<!-- Script executing window.ks.jsonRenderers.renderToDom -->
|
|
226
|
-
<script type="module">
|
|
227
|
-
const demoStatus = document.getElementById("demo-status");
|
|
228
|
-
const container = document.getElementById("dom-render-container");
|
|
229
|
-
const selectedResult = document.getElementById("selected-result");
|
|
230
|
-
|
|
231
|
-
// 1. Load the bundle to attach window.ks globally
|
|
232
|
-
try {
|
|
233
|
-
await import("../dist/v14/min.js");
|
|
234
|
-
} catch {
|
|
235
|
-
try {
|
|
236
|
-
await import("https://cdn.jsdelivr.net/gh/keshavsoft/json-renderers@main/docs/dist/v14/min.js");
|
|
237
|
-
} catch (e) {
|
|
238
|
-
console.warn("Could not load dist/v14/min.js", e);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const datasets = {
|
|
243
|
-
ledgers: [
|
|
244
|
-
"Cash in Hand",
|
|
245
|
-
"Standard Chartered Bank",
|
|
246
|
-
"Sundry Debtors Account",
|
|
247
|
-
"Office Equipment Capital",
|
|
248
|
-
"Sales Revenue Primary",
|
|
249
|
-
"Salaries Payable"
|
|
250
|
-
],
|
|
251
|
-
roles: [
|
|
252
|
-
"System Administrator",
|
|
253
|
-
"Engineering Team Lead",
|
|
254
|
-
"Security Compliance Officer",
|
|
255
|
-
"Content Manager",
|
|
256
|
-
"Read-Only Guest"
|
|
257
|
-
],
|
|
258
|
-
status: [
|
|
259
|
-
"New / Unassigned",
|
|
260
|
-
"In Investigation",
|
|
261
|
-
"Awaiting Customer Response",
|
|
262
|
-
"Resolved & Verified",
|
|
263
|
-
"Archived"
|
|
264
|
-
]
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
let activeData = datasets.ledgers;
|
|
268
|
-
|
|
269
|
-
function renderSelectWithKs() {
|
|
270
|
-
demoStatus.textContent = "Rendering...";
|
|
271
|
-
demoStatus.className = "px-2.5 py-1 text-xs font-mono font-medium rounded-full bg-amber-100 text-amber-800";
|
|
272
|
-
|
|
273
|
-
let mounted = null;
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
if (window.ks && window.ks.jsonRenderers && typeof window.ks.jsonRenderers.renderToDom === "function") {
|
|
277
|
-
window.ks.jsonRenderers.renderToDom({
|
|
278
|
-
type: "select",
|
|
279
|
-
data: activeData,
|
|
280
|
-
targetHtmlId: "dom-render-container",
|
|
281
|
-
showLog: true
|
|
282
|
-
});
|
|
283
|
-
mounted = container.querySelector("select");
|
|
284
|
-
}
|
|
285
|
-
} catch (err) {
|
|
286
|
-
console.warn("window.ks error:", err);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (!mounted) {
|
|
290
|
-
container.innerHTML = "";
|
|
291
|
-
const select = document.createElement("select");
|
|
292
|
-
select.className = "form-select";
|
|
293
|
-
activeData.forEach(item => {
|
|
294
|
-
const opt = document.createElement("option");
|
|
295
|
-
opt.value = item;
|
|
296
|
-
opt.textContent = item;
|
|
297
|
-
select.appendChild(opt);
|
|
298
|
-
});
|
|
299
|
-
container.appendChild(select);
|
|
300
|
-
mounted = select;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (mounted) {
|
|
304
|
-
selectedResult.textContent = mounted.value || activeData[0] || "(None)";
|
|
305
|
-
mounted.addEventListener("change", (e) => {
|
|
306
|
-
selectedResult.textContent = e.target.value;
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
demoStatus.textContent = `Mounted (${activeData.length} items)`;
|
|
311
|
-
demoStatus.className = "px-2.5 py-1 text-xs font-mono font-medium rounded-full bg-emerald-100 text-emerald-800";
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Button controls
|
|
315
|
-
const btnLedgers = document.getElementById("btn-ledgers");
|
|
316
|
-
const btnRoles = document.getElementById("btn-roles");
|
|
317
|
-
const btnStatus = document.getElementById("btn-status");
|
|
318
|
-
|
|
319
|
-
function setActiveBtn(active) {
|
|
320
|
-
[btnLedgers, btnRoles, btnStatus].forEach(b => {
|
|
321
|
-
b.className = "px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-medium transition";
|
|
322
|
-
});
|
|
323
|
-
active.className = "px-3 py-1.5 rounded-lg bg-indigo-600 text-white text-xs font-semibold shadow-sm transition";
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
btnLedgers.addEventListener("click", () => {
|
|
327
|
-
setActiveBtn(btnLedgers);
|
|
328
|
-
activeData = datasets.ledgers;
|
|
329
|
-
renderSelectWithKs();
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
btnRoles.addEventListener("click", () => {
|
|
333
|
-
setActiveBtn(btnRoles);
|
|
334
|
-
activeData = datasets.roles;
|
|
335
|
-
renderSelectWithKs();
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
btnStatus.addEventListener("click", () => {
|
|
339
|
-
setActiveBtn(btnStatus);
|
|
340
|
-
activeData = datasets.status;
|
|
341
|
-
renderSelectWithKs();
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
window.copyCode = (id) => {
|
|
345
|
-
const code = document.getElementById(id);
|
|
346
|
-
if (!code) return;
|
|
347
|
-
navigator.clipboard.writeText(code.textContent).then(() => {
|
|
348
|
-
alert("Code copied to clipboard!");
|
|
349
|
-
});
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
// Initial render
|
|
353
|
-
setTimeout(renderSelectWithKs, 100);
|
|
354
|
-
</script>
|
|
355
|
-
|
|
356
|
-
</body>
|
|
357
|
-
|
|
358
|
-
</html>
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>window.ks.jsonRenderers.renderToDom | Select Guide</title>
|
|
8
|
+
<meta name="description"
|
|
9
|
+
content="Simple guide explaining how window.ks.jsonRenderers.renderToDom works to build and render HTML select dropdowns from JSON data." />
|
|
10
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
11
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
12
|
+
<link
|
|
13
|
+
href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600&family=Inter:wght@300;400;500;600;700;800&display=swap"
|
|
14
|
+
rel="stylesheet" />
|
|
15
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
|
|
16
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
17
|
+
<style>
|
|
18
|
+
body {
|
|
19
|
+
font-family: 'Inter', sans-serif;
|
|
20
|
+
background-color: #ffffff;
|
|
21
|
+
color: #1e293b;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pre,
|
|
25
|
+
code {
|
|
26
|
+
font-family: 'Fira Code', monospace;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#dom-render-container select {
|
|
30
|
+
width: 100%;
|
|
31
|
+
padding: 0.65rem 1rem;
|
|
32
|
+
font-size: 0.95rem;
|
|
33
|
+
border-radius: 0.75rem;
|
|
34
|
+
border: 1px solid #cbd5e1;
|
|
35
|
+
background-color: #ffffff;
|
|
36
|
+
color: #0f172a;
|
|
37
|
+
transition: all 0.2s ease;
|
|
38
|
+
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#dom-render-container select:focus {
|
|
42
|
+
outline: none;
|
|
43
|
+
border-color: #4f46e5;
|
|
44
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
|
|
45
|
+
}
|
|
46
|
+
</style>
|
|
47
|
+
</head>
|
|
48
|
+
|
|
49
|
+
<body class="bg-white min-h-screen flex flex-col antialiased text-slate-800">
|
|
50
|
+
|
|
51
|
+
<!-- Navigation Bar -->
|
|
52
|
+
<header class="border-b border-slate-200 bg-white/95 backdrop-blur sticky top-0 z-50 shadow-sm">
|
|
53
|
+
<div class="max-w-5xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between gap-4">
|
|
54
|
+
<div class="flex items-center gap-3">
|
|
55
|
+
<a href="../index.html"
|
|
56
|
+
class="w-9 h-9 rounded-xl bg-gradient-to-br from-indigo-500 to-blue-600 flex items-center justify-center font-bold text-white shadow-sm text-base hover:scale-105 transition">
|
|
57
|
+
▣
|
|
58
|
+
</a>
|
|
59
|
+
<div>
|
|
60
|
+
<a href="../index.html"
|
|
61
|
+
class="text-sm font-bold text-slate-900 hover:text-indigo-600 transition">json-renderers</a>
|
|
62
|
+
<span class="text-xs text-slate-500 block">Select • window.ks Guide</span>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<nav class="flex items-center gap-2 text-xs sm:text-sm">
|
|
67
|
+
<a href="../index.html"
|
|
68
|
+
class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 transition">Samples Hub</a>
|
|
69
|
+
<a href="index.html"
|
|
70
|
+
class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 transition">Select Hub</a>
|
|
71
|
+
<a href="cdn.html"
|
|
72
|
+
class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 transition">Using CDN</a>
|
|
73
|
+
<a href="windowks.html"
|
|
74
|
+
class="px-3 py-1.5 rounded-lg bg-indigo-600 text-white font-semibold shadow-sm transition">window.ks</a>
|
|
75
|
+
</nav>
|
|
76
|
+
</div>
|
|
77
|
+
</header>
|
|
78
|
+
|
|
79
|
+
<!-- Main Content -->
|
|
80
|
+
<main class="flex-1 max-w-5xl w-full mx-auto p-4 sm:p-6 lg:p-8 space-y-8">
|
|
81
|
+
|
|
82
|
+
<!-- Document Header -->
|
|
83
|
+
<section class="bg-white rounded-2xl p-6 sm:p-8 border border-slate-200 shadow-sm space-y-3">
|
|
84
|
+
<div
|
|
85
|
+
class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-indigo-50 border border-indigo-200 text-xs font-mono text-indigo-700 font-medium">
|
|
86
|
+
Global Window Object Guide • Select Component
|
|
87
|
+
</div>
|
|
88
|
+
<h1 class="text-2xl sm:text-4xl font-extrabold text-slate-900 tracking-tight">
|
|
89
|
+
window.ks.jsonRenderers.renderToDom
|
|
90
|
+
</h1>
|
|
91
|
+
<p class="text-slate-600 text-sm sm:text-base leading-relaxed">
|
|
92
|
+
Understand how the global <code
|
|
93
|
+
class="text-indigo-700 bg-indigo-50 px-1 py-0.5 rounded font-mono font-medium">window.ks</code> runtime allows any script on your page to mount dynamic select dropdowns directly from JSON data without modular imports.
|
|
94
|
+
</p>
|
|
95
|
+
</section>
|
|
96
|
+
|
|
97
|
+
<!-- Why Use window.ks (The Story) -->
|
|
98
|
+
<section class="bg-white rounded-2xl p-6 sm:p-8 border border-slate-200 shadow-sm space-y-4">
|
|
99
|
+
<h2 class="text-lg font-bold text-slate-900 flex items-center gap-2">
|
|
100
|
+
<span>📖</span> The Story: Why Use Global window.ks?
|
|
101
|
+
</h2>
|
|
102
|
+
<p class="text-xs sm:text-sm text-slate-600 leading-relaxed">
|
|
103
|
+
When developing large enterprise web pages, administrative dashboards, or legacy PHP/JSP templates, not every piece of code is bundled through Vite or Webpack. In these architectures, you include one script tag in the page header, which registers the <code class="text-indigo-700 font-mono font-semibold">window.ks</code> global object.
|
|
104
|
+
</p>
|
|
105
|
+
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 pt-2">
|
|
106
|
+
<div class="p-4 rounded-xl bg-slate-50 border border-slate-200 space-y-1">
|
|
107
|
+
<div class="text-indigo-600 font-bold text-sm">No Module Scoping</div>
|
|
108
|
+
<p class="text-xs text-slate-600">Accessible everywhere in the window context without import statements.</p>
|
|
109
|
+
</div>
|
|
110
|
+
<div class="p-4 rounded-xl bg-slate-50 border border-slate-200 space-y-1">
|
|
111
|
+
<div class="text-indigo-600 font-bold text-sm">Lightweight Setup</div>
|
|
112
|
+
<p class="text-xs text-slate-600">Load the minified bundle once, render 50 different select dropdowns anywhere.</p>
|
|
113
|
+
</div>
|
|
114
|
+
<div class="p-4 rounded-xl bg-slate-50 border border-slate-200 space-y-1">
|
|
115
|
+
<div class="text-indigo-600 font-bold text-sm">Zero InnerHTML Risk</div>
|
|
116
|
+
<p class="text-xs text-slate-600">Builds real DOM elements under the hood using <code class="font-mono">json-to-tag</code>.</p>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</section>
|
|
120
|
+
|
|
121
|
+
<!-- How It Works & Code Example -->
|
|
122
|
+
<section class="bg-white rounded-2xl p-6 sm:p-8 border border-slate-200 shadow-sm space-y-4">
|
|
123
|
+
<div class="flex items-center justify-between flex-wrap gap-2">
|
|
124
|
+
<h2 class="text-lg font-bold text-slate-900 flex items-center gap-2">
|
|
125
|
+
<span>⚙️</span> Complete Implementation Code
|
|
126
|
+
</h2>
|
|
127
|
+
<button onclick="copyCode('ks-select-code')"
|
|
128
|
+
class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-mono font-medium transition flex items-center gap-1.5 border border-slate-300">
|
|
129
|
+
<span>📋</span> Copy Code
|
|
130
|
+
</button>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div class="rounded-xl bg-slate-950 p-4 text-xs text-slate-200 overflow-x-auto">
|
|
134
|
+
<pre id="ks-select-code"><code>// 1. Load the bundle to attach window.ks globally
|
|
135
|
+
await import("https://cdn.jsdelivr.net/gh/keshavsoft/json-renderers@main/docs/dist/v14/min.js");
|
|
136
|
+
|
|
137
|
+
// 2. Define your options array
|
|
138
|
+
const ledgerNames = [
|
|
139
|
+
"Cash in Hand",
|
|
140
|
+
"Standard Chartered Bank",
|
|
141
|
+
"Sundry Debtors",
|
|
142
|
+
"Office Equipment",
|
|
143
|
+
"Sales Revenue"
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
// 3. Render select element into the DOM
|
|
147
|
+
window.ks.jsonRenderers.renderToDom({
|
|
148
|
+
type: "select",
|
|
149
|
+
data: ledgerNames,
|
|
150
|
+
targetHtmlId: "dom-render-container",
|
|
151
|
+
showLog: true
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// 4. Attach event listeners
|
|
155
|
+
const selectElement = document.querySelector("#dom-render-container select");
|
|
156
|
+
if (selectElement) {
|
|
157
|
+
selectElement.addEventListener("change", (e) => {
|
|
158
|
+
console.log("Selected ledger:", e.target.value);
|
|
159
|
+
});
|
|
160
|
+
}</code></pre>
|
|
161
|
+
</div>
|
|
162
|
+
</section>
|
|
163
|
+
|
|
164
|
+
<!-- Live Interactive Demo -->
|
|
165
|
+
<section class="bg-white rounded-2xl p-6 sm:p-8 border border-slate-200 shadow-sm space-y-6">
|
|
166
|
+
<div class="flex items-center justify-between flex-wrap gap-2 border-b border-slate-100 pb-3">
|
|
167
|
+
<div>
|
|
168
|
+
<span class="text-xs font-mono font-semibold text-indigo-700 uppercase tracking-wider">Live Execution</span>
|
|
169
|
+
<h2 class="text-xl font-bold text-slate-900">Live Demo: Mounted via window.ks</h2>
|
|
170
|
+
</div>
|
|
171
|
+
<span id="demo-status" class="px-2.5 py-1 text-xs font-mono font-medium rounded-full bg-slate-100 text-slate-700">Loading...</span>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<!-- Controls -->
|
|
175
|
+
<div class="flex flex-wrap gap-3 items-center">
|
|
176
|
+
<label class="text-xs font-bold text-slate-700">Select Dataset Preset:</label>
|
|
177
|
+
<button id="btn-ledgers" class="px-3 py-1.5 rounded-lg bg-indigo-600 text-white text-xs font-semibold shadow-sm transition">
|
|
178
|
+
General Ledgers
|
|
179
|
+
</button>
|
|
180
|
+
<button id="btn-roles" class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-medium transition">
|
|
181
|
+
User Roles
|
|
182
|
+
</button>
|
|
183
|
+
<button id="btn-status" class="px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-medium transition">
|
|
184
|
+
Ticket Statuses
|
|
185
|
+
</button>
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<!-- Live Container -->
|
|
189
|
+
<div class="p-6 rounded-2xl bg-slate-50 border border-slate-200 space-y-4">
|
|
190
|
+
<div class="flex items-center justify-between">
|
|
191
|
+
<span class="text-xs font-bold text-slate-700">Container: #dom-render-container</span>
|
|
192
|
+
<span class="text-[11px] font-mono text-indigo-700 font-semibold">window.ks.jsonRenderers.renderToDom()</span>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div id="dom-render-container" class="bg-white p-5 rounded-xl border border-slate-200 shadow-sm min-h-[85px] flex items-center justify-center">
|
|
196
|
+
<div class="text-slate-400 text-xs font-mono">Initializing window.ks...</div>
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<div class="p-3.5 rounded-xl bg-indigo-50 border border-indigo-200 flex items-center justify-between text-xs">
|
|
200
|
+
<span class="font-semibold text-indigo-900">Selected Value:</span>
|
|
201
|
+
<span id="selected-result" class="font-mono font-bold text-indigo-800 bg-white px-2.5 py-1 rounded border border-indigo-200">
|
|
202
|
+
(None)
|
|
203
|
+
</span>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</section>
|
|
207
|
+
|
|
208
|
+
</main>
|
|
209
|
+
|
|
210
|
+
<!-- Clean Light Footer -->
|
|
211
|
+
<footer class="border-t border-slate-200 bg-slate-50 py-8 mt-12">
|
|
212
|
+
<div class="max-w-5xl mx-auto px-4 sm:px-6 flex flex-col sm:flex-row items-center justify-between gap-4 text-xs text-slate-600">
|
|
213
|
+
<div>
|
|
214
|
+
<span class="text-slate-900 font-semibold">json-renderers</span> • <code class="text-indigo-700">window.ks.jsonRenderers.renderToDom</code> (Select)
|
|
215
|
+
</div>
|
|
216
|
+
<div class="flex items-center gap-4 flex-wrap">
|
|
217
|
+
<a href="index.html" class="hover:underline">Select Hub</a>
|
|
218
|
+
<a href="cdn.html" class="hover:underline">Using CDN</a>
|
|
219
|
+
<a href="../index.html" class="hover:underline">Samples Hub</a>
|
|
220
|
+
<a href="../../../samples/select/byKs/index.html" target="_blank" class="text-indigo-600 font-medium hover:underline">Sample (byKs)</a>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
</footer>
|
|
224
|
+
|
|
225
|
+
<!-- Script executing window.ks.jsonRenderers.renderToDom -->
|
|
226
|
+
<script type="module">
|
|
227
|
+
const demoStatus = document.getElementById("demo-status");
|
|
228
|
+
const container = document.getElementById("dom-render-container");
|
|
229
|
+
const selectedResult = document.getElementById("selected-result");
|
|
230
|
+
|
|
231
|
+
// 1. Load the bundle to attach window.ks globally
|
|
232
|
+
try {
|
|
233
|
+
await import("../dist/v14/min.js");
|
|
234
|
+
} catch {
|
|
235
|
+
try {
|
|
236
|
+
await import("https://cdn.jsdelivr.net/gh/keshavsoft/json-renderers@main/docs/dist/v14/min.js");
|
|
237
|
+
} catch (e) {
|
|
238
|
+
console.warn("Could not load dist/v14/min.js", e);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const datasets = {
|
|
243
|
+
ledgers: [
|
|
244
|
+
"Cash in Hand",
|
|
245
|
+
"Standard Chartered Bank",
|
|
246
|
+
"Sundry Debtors Account",
|
|
247
|
+
"Office Equipment Capital",
|
|
248
|
+
"Sales Revenue Primary",
|
|
249
|
+
"Salaries Payable"
|
|
250
|
+
],
|
|
251
|
+
roles: [
|
|
252
|
+
"System Administrator",
|
|
253
|
+
"Engineering Team Lead",
|
|
254
|
+
"Security Compliance Officer",
|
|
255
|
+
"Content Manager",
|
|
256
|
+
"Read-Only Guest"
|
|
257
|
+
],
|
|
258
|
+
status: [
|
|
259
|
+
"New / Unassigned",
|
|
260
|
+
"In Investigation",
|
|
261
|
+
"Awaiting Customer Response",
|
|
262
|
+
"Resolved & Verified",
|
|
263
|
+
"Archived"
|
|
264
|
+
]
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
let activeData = datasets.ledgers;
|
|
268
|
+
|
|
269
|
+
function renderSelectWithKs() {
|
|
270
|
+
demoStatus.textContent = "Rendering...";
|
|
271
|
+
demoStatus.className = "px-2.5 py-1 text-xs font-mono font-medium rounded-full bg-amber-100 text-amber-800";
|
|
272
|
+
|
|
273
|
+
let mounted = null;
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
if (window.ks && window.ks.jsonRenderers && typeof window.ks.jsonRenderers.renderToDom === "function") {
|
|
277
|
+
window.ks.jsonRenderers.renderToDom({
|
|
278
|
+
type: "select",
|
|
279
|
+
data: activeData,
|
|
280
|
+
targetHtmlId: "dom-render-container",
|
|
281
|
+
showLog: true
|
|
282
|
+
});
|
|
283
|
+
mounted = container.querySelector("select");
|
|
284
|
+
}
|
|
285
|
+
} catch (err) {
|
|
286
|
+
console.warn("window.ks error:", err);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!mounted) {
|
|
290
|
+
container.innerHTML = "";
|
|
291
|
+
const select = document.createElement("select");
|
|
292
|
+
select.className = "form-select";
|
|
293
|
+
activeData.forEach(item => {
|
|
294
|
+
const opt = document.createElement("option");
|
|
295
|
+
opt.value = item;
|
|
296
|
+
opt.textContent = item;
|
|
297
|
+
select.appendChild(opt);
|
|
298
|
+
});
|
|
299
|
+
container.appendChild(select);
|
|
300
|
+
mounted = select;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (mounted) {
|
|
304
|
+
selectedResult.textContent = mounted.value || activeData[0] || "(None)";
|
|
305
|
+
mounted.addEventListener("change", (e) => {
|
|
306
|
+
selectedResult.textContent = e.target.value;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
demoStatus.textContent = `Mounted (${activeData.length} items)`;
|
|
311
|
+
demoStatus.className = "px-2.5 py-1 text-xs font-mono font-medium rounded-full bg-emerald-100 text-emerald-800";
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Button controls
|
|
315
|
+
const btnLedgers = document.getElementById("btn-ledgers");
|
|
316
|
+
const btnRoles = document.getElementById("btn-roles");
|
|
317
|
+
const btnStatus = document.getElementById("btn-status");
|
|
318
|
+
|
|
319
|
+
function setActiveBtn(active) {
|
|
320
|
+
[btnLedgers, btnRoles, btnStatus].forEach(b => {
|
|
321
|
+
b.className = "px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-medium transition";
|
|
322
|
+
});
|
|
323
|
+
active.className = "px-3 py-1.5 rounded-lg bg-indigo-600 text-white text-xs font-semibold shadow-sm transition";
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
btnLedgers.addEventListener("click", () => {
|
|
327
|
+
setActiveBtn(btnLedgers);
|
|
328
|
+
activeData = datasets.ledgers;
|
|
329
|
+
renderSelectWithKs();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
btnRoles.addEventListener("click", () => {
|
|
333
|
+
setActiveBtn(btnRoles);
|
|
334
|
+
activeData = datasets.roles;
|
|
335
|
+
renderSelectWithKs();
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
btnStatus.addEventListener("click", () => {
|
|
339
|
+
setActiveBtn(btnStatus);
|
|
340
|
+
activeData = datasets.status;
|
|
341
|
+
renderSelectWithKs();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
window.copyCode = (id) => {
|
|
345
|
+
const code = document.getElementById(id);
|
|
346
|
+
if (!code) return;
|
|
347
|
+
navigator.clipboard.writeText(code.textContent).then(() => {
|
|
348
|
+
alert("Code copied to clipboard!");
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// Initial render
|
|
353
|
+
setTimeout(renderSelectWithKs, 100);
|
|
354
|
+
</script>
|
|
355
|
+
|
|
356
|
+
</body>
|
|
357
|
+
|
|
358
|
+
</html>
|