@keenthemes/ktui 1.0.20 → 1.0.22
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/dist/ktui.js +423 -148
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +161 -31
- package/examples/datatable/sorting-test.html +398 -0
- package/examples/image-input/file-upload-example.html +189 -0
- package/examples/select/modal.html +3 -1
- package/examples/select/{remote-data_.html → remote-data.html} +5 -0
- package/examples/select/test-optimizations.html +227 -0
- package/examples/select/test-remote-search.html +151 -0
- package/examples/sticky/README.md +158 -0
- package/examples/sticky/debug-sticky.html +144 -0
- package/examples/sticky/test-runner.html +175 -0
- package/examples/sticky/test-sticky-logic.js +369 -0
- package/examples/sticky/test-sticky-positioning.html +386 -0
- package/examples/toast/example.html +52 -0
- package/lib/cjs/components/component.js +5 -3
- package/lib/cjs/components/component.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-sort.js +4 -0
- package/lib/cjs/components/datatable/datatable-sort.js.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +13 -3
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/image-input/image-input.js +10 -2
- package/lib/cjs/components/image-input/image-input.js.map +1 -1
- package/lib/cjs/components/select/combobox.js +50 -20
- package/lib/cjs/components/select/combobox.js.map +1 -1
- package/lib/cjs/components/select/dropdown.js +5 -6
- package/lib/cjs/components/select/dropdown.js.map +1 -1
- package/lib/cjs/components/select/index.js.map +1 -1
- package/lib/cjs/components/select/option.js +2 -1
- package/lib/cjs/components/select/option.js.map +1 -1
- package/lib/cjs/components/select/remote.js +50 -50
- package/lib/cjs/components/select/remote.js.map +1 -1
- package/lib/cjs/components/select/search.js +7 -5
- package/lib/cjs/components/select/search.js.map +1 -1
- package/lib/cjs/components/select/select.js +199 -33
- package/lib/cjs/components/select/select.js.map +1 -1
- package/lib/cjs/components/select/tags.js +3 -1
- package/lib/cjs/components/select/tags.js.map +1 -1
- package/lib/cjs/components/select/templates.js.map +1 -1
- package/lib/cjs/components/select/utils.js +23 -10
- package/lib/cjs/components/select/utils.js.map +1 -1
- package/lib/cjs/components/sticky/sticky.js +52 -14
- package/lib/cjs/components/sticky/sticky.js.map +1 -1
- package/lib/esm/components/component.js +5 -3
- package/lib/esm/components/component.js.map +1 -1
- package/lib/esm/components/datatable/datatable-sort.js +4 -0
- package/lib/esm/components/datatable/datatable-sort.js.map +1 -1
- package/lib/esm/components/datatable/datatable.js +13 -3
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/image-input/image-input.js +10 -2
- package/lib/esm/components/image-input/image-input.js.map +1 -1
- package/lib/esm/components/select/combobox.js +50 -20
- package/lib/esm/components/select/combobox.js.map +1 -1
- package/lib/esm/components/select/dropdown.js +5 -6
- package/lib/esm/components/select/dropdown.js.map +1 -1
- package/lib/esm/components/select/index.js +1 -1
- package/lib/esm/components/select/index.js.map +1 -1
- package/lib/esm/components/select/option.js +2 -1
- package/lib/esm/components/select/option.js.map +1 -1
- package/lib/esm/components/select/remote.js +50 -50
- package/lib/esm/components/select/remote.js.map +1 -1
- package/lib/esm/components/select/search.js +8 -6
- package/lib/esm/components/select/search.js.map +1 -1
- package/lib/esm/components/select/select.js +199 -33
- package/lib/esm/components/select/select.js.map +1 -1
- package/lib/esm/components/select/tags.js +3 -1
- package/lib/esm/components/select/tags.js.map +1 -1
- package/lib/esm/components/select/templates.js.map +1 -1
- package/lib/esm/components/select/utils.js +23 -10
- package/lib/esm/components/select/utils.js.map +1 -1
- package/lib/esm/components/sticky/sticky.js +52 -14
- package/lib/esm/components/sticky/sticky.js.map +1 -1
- package/package.json +1 -1
- package/src/components/component.ts +12 -11
- package/src/components/datatable/datatable-sort.ts +6 -0
- package/src/components/datatable/datatable.ts +95 -81
- package/src/components/image-input/image-input.ts +11 -2
- package/src/components/image-input/types.ts +1 -0
- package/src/components/input/input-group.css +1 -1
- package/src/components/input/input.css +1 -1
- package/src/components/scrollable/scrollable.css +3 -3
- package/src/components/select/combobox.ts +84 -34
- package/src/components/select/dropdown.ts +21 -14
- package/src/components/select/index.ts +6 -1
- package/src/components/select/option.ts +7 -6
- package/src/components/select/remote.ts +51 -52
- package/src/components/select/search.ts +51 -45
- package/src/components/select/select.css +12 -11
- package/src/components/select/select.ts +371 -102
- package/src/components/select/tags.ts +9 -3
- package/src/components/select/templates.ts +1 -4
- package/src/components/select/utils.ts +55 -20
- package/src/components/select/variants.css +0 -1
- package/src/components/sticky/sticky.ts +47 -16
- package/src/components/sticky/types.ts +3 -0
- package/src/components/table/table.css +1 -1
- package/src/components/textarea/textarea.css +1 -1
- package/src/components/toast/toast.css +84 -47
- package/src/components/toast/types.ts +3 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>KT DataTable Sorting Test - Official Structure</title>
|
|
7
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
8
|
+
<link rel="stylesheet" href="../../dist/styles.css">
|
|
9
|
+
<style>
|
|
10
|
+
/* Custom styles for the test */
|
|
11
|
+
.test-container {
|
|
12
|
+
max-width: 1200px;
|
|
13
|
+
margin: 0 auto;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
}
|
|
16
|
+
.test-header {
|
|
17
|
+
background: #f8f9fa;
|
|
18
|
+
padding: 20px;
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
margin-bottom: 20px;
|
|
21
|
+
}
|
|
22
|
+
.test-controls {
|
|
23
|
+
display: flex;
|
|
24
|
+
gap: 10px;
|
|
25
|
+
margin-bottom: 20px;
|
|
26
|
+
flex-wrap: wrap;
|
|
27
|
+
}
|
|
28
|
+
.test-button {
|
|
29
|
+
background: #007bff;
|
|
30
|
+
color: white;
|
|
31
|
+
border: none;
|
|
32
|
+
padding: 8px 16px;
|
|
33
|
+
border-radius: 4px;
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
}
|
|
36
|
+
.test-button:hover {
|
|
37
|
+
background: #0056b3;
|
|
38
|
+
}
|
|
39
|
+
.test-status {
|
|
40
|
+
padding: 10px;
|
|
41
|
+
border-radius: 4px;
|
|
42
|
+
margin-top: 10px;
|
|
43
|
+
font-weight: bold;
|
|
44
|
+
}
|
|
45
|
+
.test-pass {
|
|
46
|
+
background: #d4edda;
|
|
47
|
+
color: #155724;
|
|
48
|
+
border: 1px solid #c3e6cb;
|
|
49
|
+
}
|
|
50
|
+
.test-fail {
|
|
51
|
+
background: #f8d7da;
|
|
52
|
+
color: #721c24;
|
|
53
|
+
border: 1px solid #f5c6cb;
|
|
54
|
+
}
|
|
55
|
+
</style>
|
|
56
|
+
</head>
|
|
57
|
+
<body>
|
|
58
|
+
<div class="test-container">
|
|
59
|
+
<div class="test-header">
|
|
60
|
+
<h1 class="text-2xl font-bold mb-4">KT DataTable Sorting Test - Official Structure</h1>
|
|
61
|
+
<p class="text-gray-600 mb-4">
|
|
62
|
+
This test uses the official KTUI DataTable HTML structure from the documentation
|
|
63
|
+
and verifies that sorting functionality works correctly after table updates,
|
|
64
|
+
pagination, and search operations. The sorting fix should restore click handlers
|
|
65
|
+
after each table redraw.
|
|
66
|
+
</p>
|
|
67
|
+
|
|
68
|
+
<div class="test-controls">
|
|
69
|
+
<button class="test-button" onclick="testSorting()">Test Sorting</button>
|
|
70
|
+
<button class="test-button" onclick="testPagination()">Test Pagination</button>
|
|
71
|
+
<button class="test-button" onclick="testSearch()">Test Search</button>
|
|
72
|
+
<button class="test-button" onclick="testReload()">Test Reload</button>
|
|
73
|
+
<button class="test-button" onclick="clearStatus()">Clear Status</button>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div id="test-status"></div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<!-- Search Input -->
|
|
80
|
+
<div class="mb-4">
|
|
81
|
+
<input
|
|
82
|
+
type="text"
|
|
83
|
+
id="search-input"
|
|
84
|
+
placeholder="Search data..."
|
|
85
|
+
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
86
|
+
data-kt-datatable-search="#sorting-test-table"
|
|
87
|
+
>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<!-- DataTable Container using official structure -->
|
|
91
|
+
<div class="kt-card">
|
|
92
|
+
<div class="kt-card-table" data-kt-datatable="true" data-kt-datatable-page-size="5" data-kt-datatable-state-save="true">
|
|
93
|
+
<div class="kt-table-wrapper kt-scrollable">
|
|
94
|
+
<table id="sorting-test-table" class="kt-table" data-kt-datatable-table="true">
|
|
95
|
+
<thead>
|
|
96
|
+
<tr>
|
|
97
|
+
<th scope="col" class="w-20" data-kt-datatable-column="id">
|
|
98
|
+
<span class="kt-table-col">
|
|
99
|
+
<span class="kt-table-col-label">ID</span>
|
|
100
|
+
<span class="kt-table-col-sort"></span>
|
|
101
|
+
</span>
|
|
102
|
+
</th>
|
|
103
|
+
<th scope="col" class="w-32" data-kt-datatable-column="name">
|
|
104
|
+
<span class="kt-table-col">
|
|
105
|
+
<span class="kt-table-col-label">Name</span>
|
|
106
|
+
<span class="kt-table-col-sort"></span>
|
|
107
|
+
</span>
|
|
108
|
+
</th>
|
|
109
|
+
<th scope="col" class="w-40" data-kt-datatable-column="email">
|
|
110
|
+
<span class="kt-table-col">
|
|
111
|
+
<span class="kt-table-col-label">Email</span>
|
|
112
|
+
<span class="kt-table-col-sort"></span>
|
|
113
|
+
</span>
|
|
114
|
+
</th>
|
|
115
|
+
<th scope="col" class="w-32" data-kt-datatable-column="department">
|
|
116
|
+
<span class="kt-table-col">
|
|
117
|
+
<span class="kt-table-col-label">Department</span>
|
|
118
|
+
<span class="kt-table-col-sort"></span>
|
|
119
|
+
</span>
|
|
120
|
+
</th>
|
|
121
|
+
<th scope="col" class="w-24" data-kt-datatable-column="salary">
|
|
122
|
+
<span class="kt-table-col">
|
|
123
|
+
<span class="kt-table-col-label">Salary</span>
|
|
124
|
+
<span class="kt-table-col-sort"></span>
|
|
125
|
+
</span>
|
|
126
|
+
</th>
|
|
127
|
+
<th scope="col" class="w-24" data-kt-datatable-column="status">
|
|
128
|
+
<span class="kt-table-col">
|
|
129
|
+
<span class="kt-table-col-label">Status</span>
|
|
130
|
+
<span class="kt-table-col-sort"></span>
|
|
131
|
+
</span>
|
|
132
|
+
</th>
|
|
133
|
+
</tr>
|
|
134
|
+
</thead>
|
|
135
|
+
<tbody>
|
|
136
|
+
<tr>
|
|
137
|
+
<td>1</td>
|
|
138
|
+
<td>John Doe</td>
|
|
139
|
+
<td>john.doe@example.com</td>
|
|
140
|
+
<td>Engineering</td>
|
|
141
|
+
<td>$75,000</td>
|
|
142
|
+
<td><span class="kt-badge kt-badge-success">Active</span></td>
|
|
143
|
+
</tr>
|
|
144
|
+
<tr>
|
|
145
|
+
<td>2</td>
|
|
146
|
+
<td>Jane Smith</td>
|
|
147
|
+
<td>jane.smith@example.com</td>
|
|
148
|
+
<td>Marketing</td>
|
|
149
|
+
<td>$65,000</td>
|
|
150
|
+
<td><span class="kt-badge kt-badge-success">Active</span></td>
|
|
151
|
+
</tr>
|
|
152
|
+
<tr>
|
|
153
|
+
<td>3</td>
|
|
154
|
+
<td>Mike Johnson</td>
|
|
155
|
+
<td>mike.johnson@example.com</td>
|
|
156
|
+
<td>Engineering</td>
|
|
157
|
+
<td>$80,000</td>
|
|
158
|
+
<td><span class="kt-badge kt-badge-destructive">Inactive</span></td>
|
|
159
|
+
</tr>
|
|
160
|
+
<tr>
|
|
161
|
+
<td>4</td>
|
|
162
|
+
<td>Sarah Wilson</td>
|
|
163
|
+
<td>sarah.wilson@example.com</td>
|
|
164
|
+
<td>Sales</td>
|
|
165
|
+
<td>$70,000</td>
|
|
166
|
+
<td><span class="kt-badge kt-badge-success">Active</span></td>
|
|
167
|
+
</tr>
|
|
168
|
+
<tr>
|
|
169
|
+
<td>5</td>
|
|
170
|
+
<td>David Brown</td>
|
|
171
|
+
<td>david.brown@example.com</td>
|
|
172
|
+
<td>HR</td>
|
|
173
|
+
<td>$60,000</td>
|
|
174
|
+
<td><span class="kt-badge kt-badge-success">Active</span></td>
|
|
175
|
+
</tr>
|
|
176
|
+
<tr>
|
|
177
|
+
<td>6</td>
|
|
178
|
+
<td>Lisa Davis</td>
|
|
179
|
+
<td>lisa.davis@example.com</td>
|
|
180
|
+
<td>Engineering</td>
|
|
181
|
+
<td>$85,000</td>
|
|
182
|
+
<td><span class="kt-badge kt-badge-primary">Verified</span></td>
|
|
183
|
+
</tr>
|
|
184
|
+
<tr>
|
|
185
|
+
<td>7</td>
|
|
186
|
+
<td>Tom Anderson</td>
|
|
187
|
+
<td>tom.anderson@example.com</td>
|
|
188
|
+
<td>Marketing</td>
|
|
189
|
+
<td>$68,000</td>
|
|
190
|
+
<td><span class="kt-badge kt-badge-destructive">Inactive</span></td>
|
|
191
|
+
</tr>
|
|
192
|
+
<tr>
|
|
193
|
+
<td>8</td>
|
|
194
|
+
<td>Emma Taylor</td>
|
|
195
|
+
<td>emma.taylor@example.com</td>
|
|
196
|
+
<td>Sales</td>
|
|
197
|
+
<td>$72,000</td>
|
|
198
|
+
<td><span class="kt-badge kt-badge-success">Active</span></td>
|
|
199
|
+
</tr>
|
|
200
|
+
<tr>
|
|
201
|
+
<td>9</td>
|
|
202
|
+
<td>Chris Miller</td>
|
|
203
|
+
<td>chris.miller@example.com</td>
|
|
204
|
+
<td>Engineering</td>
|
|
205
|
+
<td>$78,000</td>
|
|
206
|
+
<td><span class="kt-badge kt-badge-success">Active</span></td>
|
|
207
|
+
</tr>
|
|
208
|
+
<tr>
|
|
209
|
+
<td>10</td>
|
|
210
|
+
<td>Amy Garcia</td>
|
|
211
|
+
<td>amy.garcia@example.com</td>
|
|
212
|
+
<td>HR</td>
|
|
213
|
+
<td>$62,000</td>
|
|
214
|
+
<td><span class="kt-badge kt-badge-success">Active</span></td>
|
|
215
|
+
</tr>
|
|
216
|
+
</tbody>
|
|
217
|
+
</table>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<!-- Pagination Info -->
|
|
221
|
+
<div class="flex items-center justify-between mt-4">
|
|
222
|
+
<div class="flex items-center space-x-2">
|
|
223
|
+
<span class="text-sm text-gray-700">Show</span>
|
|
224
|
+
<select data-kt-datatable-size="true" class="border border-gray-300 rounded px-2 py-1">
|
|
225
|
+
<option value="5">5</option>
|
|
226
|
+
<option value="10" selected>10</option>
|
|
227
|
+
<option value="20">20</option>
|
|
228
|
+
<option value="50">50</option>
|
|
229
|
+
</select>
|
|
230
|
+
<span class="text-sm text-gray-700">entries</span>
|
|
231
|
+
</div>
|
|
232
|
+
<div data-kt-datatable-info="true" class="text-sm text-gray-700"></div>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<!-- Pagination Controls -->
|
|
236
|
+
<div class="flex justify-center mt-4">
|
|
237
|
+
<div data-kt-datatable-pagination="true" class="flex space-x-1"></div>
|
|
238
|
+
</div>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<!-- Load KTUI -->
|
|
244
|
+
<script src="../../dist/ktui.js"></script>
|
|
245
|
+
|
|
246
|
+
<script>
|
|
247
|
+
let datatableInstance = null;
|
|
248
|
+
|
|
249
|
+
// Initialize the datatable when page loads
|
|
250
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
251
|
+
// Wait a bit for the DOM to be fully ready
|
|
252
|
+
setTimeout(() => {
|
|
253
|
+
try {
|
|
254
|
+
// Initialize KTUI components using official method
|
|
255
|
+
if (typeof KTDataTable !== 'undefined') {
|
|
256
|
+
KTDataTable.init();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Get the datatable instance using official API
|
|
260
|
+
const container = document.querySelector('[data-kt-datatable="true"]');
|
|
261
|
+
if (container) {
|
|
262
|
+
datatableInstance = KTDataTable.getInstance(container);
|
|
263
|
+
if (datatableInstance) {
|
|
264
|
+
updateStatus('✅ DataTable initialized successfully using official API!', 'pass');
|
|
265
|
+
} else {
|
|
266
|
+
updateStatus('❌ Failed to get DataTable instance', 'fail');
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
updateStatus('❌ DataTable container not found', 'fail');
|
|
270
|
+
}
|
|
271
|
+
} catch (error) {
|
|
272
|
+
updateStatus('❌ Error initializing DataTable: ' + error.message, 'fail');
|
|
273
|
+
}
|
|
274
|
+
}, 100);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Test sorting functionality using official API
|
|
278
|
+
function testSorting() {
|
|
279
|
+
if (!datatableInstance) {
|
|
280
|
+
updateStatus('❌ DataTable not initialized', 'fail');
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
// Test sorting by name column using official API
|
|
286
|
+
datatableInstance.sort('name');
|
|
287
|
+
updateStatus('✅ Sorting test passed! Used official sort() API on name column.', 'pass');
|
|
288
|
+
|
|
289
|
+
// Test sorting by salary column
|
|
290
|
+
setTimeout(() => {
|
|
291
|
+
datatableInstance.sort('salary');
|
|
292
|
+
updateStatus('✅ Sorting test passed! Also tested salary column sorting with official API.', 'pass');
|
|
293
|
+
}, 1000);
|
|
294
|
+
|
|
295
|
+
} catch (error) {
|
|
296
|
+
updateStatus('❌ Sorting test failed: ' + error.message, 'fail');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Test pagination using official API
|
|
301
|
+
function testPagination() {
|
|
302
|
+
if (!datatableInstance) {
|
|
303
|
+
updateStatus('❌ DataTable not initialized', 'fail');
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
// Set page size to 5 to enable pagination using official API
|
|
309
|
+
datatableInstance.setPageSize(5);
|
|
310
|
+
updateStatus('✅ Pagination test passed! Used official setPageSize(5) API. Now test sorting on different pages.', 'pass');
|
|
311
|
+
|
|
312
|
+
// Go to page 2 using official API
|
|
313
|
+
setTimeout(() => {
|
|
314
|
+
datatableInstance.goPage(2);
|
|
315
|
+
updateStatus('✅ Pagination test passed! Used official goPage(2) API. Try clicking column headers to sort.', 'pass');
|
|
316
|
+
}, 500);
|
|
317
|
+
|
|
318
|
+
} catch (error) {
|
|
319
|
+
updateStatus('❌ Pagination test failed: ' + error.message, 'fail');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Test search functionality using official API
|
|
324
|
+
function testSearch() {
|
|
325
|
+
if (!datatableInstance) {
|
|
326
|
+
updateStatus('❌ DataTable not initialized', 'fail');
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
// Test search using official API
|
|
332
|
+
datatableInstance.search('John');
|
|
333
|
+
updateStatus('✅ Search test passed! Used official search("John") API. Try sorting the filtered results.', 'pass');
|
|
334
|
+
|
|
335
|
+
// Clear search after 3 seconds
|
|
336
|
+
setTimeout(() => {
|
|
337
|
+
datatableInstance.search('');
|
|
338
|
+
updateStatus('✅ Search test passed! Used official search("") API to clear. Sorting should still work.', 'pass');
|
|
339
|
+
}, 3000);
|
|
340
|
+
|
|
341
|
+
} catch (error) {
|
|
342
|
+
updateStatus('❌ Search test failed: ' + error.message, 'fail');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Test reload functionality using official API
|
|
347
|
+
function testReload() {
|
|
348
|
+
if (!datatableInstance) {
|
|
349
|
+
updateStatus('❌ DataTable not initialized', 'fail');
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
// Reload the table using official API
|
|
355
|
+
datatableInstance.reload();
|
|
356
|
+
updateStatus('✅ Reload test passed! Used official reload() API. Try sorting now.', 'pass');
|
|
357
|
+
|
|
358
|
+
} catch (error) {
|
|
359
|
+
updateStatus('❌ Reload test failed: ' + error.message, 'fail');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Update status display
|
|
364
|
+
function updateStatus(message, type) {
|
|
365
|
+
const statusDiv = document.getElementById('test-status');
|
|
366
|
+
statusDiv.innerHTML = message;
|
|
367
|
+
statusDiv.className = `test-status ${type === 'pass' ? 'test-pass' : 'test-fail'}`;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Clear status
|
|
371
|
+
function clearStatus() {
|
|
372
|
+
const statusDiv = document.getElementById('test-status');
|
|
373
|
+
statusDiv.innerHTML = '';
|
|
374
|
+
statusDiv.className = 'test-status';
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Add manual testing instructions based on official documentation
|
|
378
|
+
console.log('🔧 Manual Testing Instructions (Official KTUI API):');
|
|
379
|
+
console.log('1. Click on any column header to test sorting');
|
|
380
|
+
console.log('2. Try pagination and then click headers to sort');
|
|
381
|
+
console.log('3. Use search and then try sorting filtered results');
|
|
382
|
+
console.log('4. All sorting should work consistently!');
|
|
383
|
+
console.log('5. Check browser dev tools for any console errors');
|
|
384
|
+
console.log('');
|
|
385
|
+
console.log('📚 This test uses the official KTUI DataTable structure from:');
|
|
386
|
+
console.log(' https://ktui.io/docs/datatable');
|
|
387
|
+
console.log('');
|
|
388
|
+
console.log('🔧 Official API Methods tested:');
|
|
389
|
+
console.log(' - KTDataTable.init()');
|
|
390
|
+
console.log(' - KTDataTable.getInstance()');
|
|
391
|
+
console.log(' - datatable.sort()');
|
|
392
|
+
console.log(' - datatable.setPageSize()');
|
|
393
|
+
console.log(' - datatable.goPage()');
|
|
394
|
+
console.log(' - datatable.search()');
|
|
395
|
+
console.log(' - datatable.reload()');
|
|
396
|
+
</script>
|
|
397
|
+
</body>
|
|
398
|
+
</html>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>KTUI Image Input - File Upload Example</title>
|
|
7
|
+
<link rel="stylesheet" href="../../dist/styles.css">
|
|
8
|
+
<style>
|
|
9
|
+
body { padding: 2rem; font-family: Arial, sans-serif; }
|
|
10
|
+
.example-section { margin: 2rem 0; padding: 1rem; border: 1px solid #ddd; }
|
|
11
|
+
.test-result { margin: 0.5rem 0; padding: 0.5rem; background: #f5f5f5; }
|
|
12
|
+
.success { background: #d4edda; color: #155724; }
|
|
13
|
+
.error { background: #f8d7da; color: #721c24; }
|
|
14
|
+
.info { background: #d1ecf1; color: #0c5460; }
|
|
15
|
+
.code-block { background: #f8f9fa; padding: 1rem; border-radius: 4px; margin: 1rem 0; }
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<h1>KTUI Image Input - File Upload Example</h1>
|
|
20
|
+
<p>This example demonstrates how to use the KTUI Image Input component with proper file upload functionality.</p>
|
|
21
|
+
|
|
22
|
+
<div class="example-section">
|
|
23
|
+
<h2>Image Input Component</h2>
|
|
24
|
+
<div class="kt-image-input size-16" data-kt-image-input="true">
|
|
25
|
+
<input accept=".png, .jpg, .jpeg" name="avatar" type="file">
|
|
26
|
+
<input name="avatar_remove" type="hidden"/>
|
|
27
|
+
<button class="kt-image-input-remove" data-kt-image-input-remove="true" type="button">
|
|
28
|
+
<i class="ki-filled ki-cross"></i>
|
|
29
|
+
</button>
|
|
30
|
+
<div class="kt-image-input-placeholder" data-kt-image-input-placeholder="true">
|
|
31
|
+
<div class="kt-image-input-preview" data-kt-image-input-preview="true"></div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="example-section">
|
|
37
|
+
<h2>Testing Controls</h2>
|
|
38
|
+
<button onclick="testFileAccess()">Test File Access</button>
|
|
39
|
+
<button onclick="testPublicMethods()">Test Public Methods</button>
|
|
40
|
+
<button onclick="testFormSubmission()">Test Form Submission</button>
|
|
41
|
+
<button onclick="clearResults()">Clear Results</button>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="example-section">
|
|
45
|
+
<h2>Test Results</h2>
|
|
46
|
+
<div id="test-results"></div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="example-section">
|
|
50
|
+
<h2>Form Submission Example</h2>
|
|
51
|
+
<p>This form demonstrates how to properly handle file uploads with KTUI Image Input:</p>
|
|
52
|
+
<form id="test-form" onsubmit="handleFormSubmit(event)">
|
|
53
|
+
<div class="kt-image-input size-16" data-kt-image-input="true">
|
|
54
|
+
<input accept=".png, .jpg, .jpeg" name="test_image" type="file">
|
|
55
|
+
<input name="test_image_remove" type="hidden"/>
|
|
56
|
+
<button class="kt-image-input-remove" data-kt-image-input-remove="true" type="button">
|
|
57
|
+
<i class="ki-filled ki-cross"></i>
|
|
58
|
+
</button>
|
|
59
|
+
<div class="kt-image-input-placeholder" data-kt-image-input-placeholder="true">
|
|
60
|
+
<div class="kt-image-input-preview" data-kt-image-input-preview="true"></div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
<button type="submit">Submit Form</button>
|
|
64
|
+
</form>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="example-section">
|
|
68
|
+
<h2>Usage Code Example</h2>
|
|
69
|
+
<div class="code-block">
|
|
70
|
+
<h3>HTML Structure</h3>
|
|
71
|
+
<pre><code><div class="kt-image-input size-16" data-kt-image-input="true">
|
|
72
|
+
<input accept=".png, .jpg, .jpeg" name="avatar" type="file">
|
|
73
|
+
<input name="avatar_remove" type="hidden"/>
|
|
74
|
+
<button class="kt-image-input-remove" data-kt-image-input-remove="true" type="button">
|
|
75
|
+
<i class="ki-filled ki-cross"></i>
|
|
76
|
+
</button>
|
|
77
|
+
<div class="kt-image-input-placeholder" data-kt-image-input-placeholder="true">
|
|
78
|
+
<div class="kt-image-input-preview" data-kt-image-input-preview="true"></div>
|
|
79
|
+
</div>
|
|
80
|
+
</div></code></pre>
|
|
81
|
+
|
|
82
|
+
<h3>JavaScript - File Upload</h3>
|
|
83
|
+
<pre><code>// Get the KTUI Image Input instance
|
|
84
|
+
const imageInput = KTImageInput.getInstance(element);
|
|
85
|
+
|
|
86
|
+
// Access the selected file for form submission
|
|
87
|
+
const selectedFile = imageInput.getSelectedFile();
|
|
88
|
+
if (selectedFile) {
|
|
89
|
+
const formData = new FormData();
|
|
90
|
+
formData.append('image', selectedFile);
|
|
91
|
+
// Submit formData to server
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check component state
|
|
95
|
+
if (imageInput.isEmpty()) {
|
|
96
|
+
console.log('No file selected');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (imageInput.isChanged()) {
|
|
100
|
+
console.log('File has been selected');
|
|
101
|
+
}</code></pre>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<script src="../../dist/ktui.min.js"></script>
|
|
106
|
+
<script>
|
|
107
|
+
let imageInputInstance = null;
|
|
108
|
+
|
|
109
|
+
// Initialize when DOM is ready
|
|
110
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
111
|
+
const element = document.querySelector('[data-kt-image-input]');
|
|
112
|
+
if (element) {
|
|
113
|
+
imageInputInstance = KTImageInput.getInstance(element);
|
|
114
|
+
addResult('Component initialized successfully', 'success');
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
function addResult(message, type = 'info') {
|
|
119
|
+
const results = document.getElementById('test-results');
|
|
120
|
+
const div = document.createElement('div');
|
|
121
|
+
div.className = `test-result ${type}`;
|
|
122
|
+
div.textContent = `${new Date().toLocaleTimeString()}: ${message}`;
|
|
123
|
+
results.appendChild(div);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function testFileAccess() {
|
|
127
|
+
if (!imageInputInstance) {
|
|
128
|
+
addResult('Image input instance not found', 'error');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const file = imageInputInstance.getSelectedFile();
|
|
133
|
+
if (file) {
|
|
134
|
+
addResult(`File access successful: ${file.name} (${file.size} bytes)`, 'success');
|
|
135
|
+
} else {
|
|
136
|
+
addResult('No file selected', 'info');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function testPublicMethods() {
|
|
141
|
+
if (!imageInputInstance) {
|
|
142
|
+
addResult('Image input instance not found', 'error');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const isEmpty = imageInputInstance.isEmpty();
|
|
147
|
+
const isChanged = imageInputInstance.isChanged();
|
|
148
|
+
|
|
149
|
+
addResult(`isEmpty(): ${isEmpty}`, isEmpty ? 'info' : 'success');
|
|
150
|
+
addResult(`isChanged(): ${isChanged}`, isChanged ? 'success' : 'info');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function testFormSubmission() {
|
|
154
|
+
const form = document.getElementById('test-form');
|
|
155
|
+
const fileInput = form.querySelector('input[type="file"]');
|
|
156
|
+
const formData = new FormData(form);
|
|
157
|
+
|
|
158
|
+
addResult('Form data created', 'info');
|
|
159
|
+
|
|
160
|
+
if (fileInput.files.length > 0) {
|
|
161
|
+
addResult(`File in form: ${fileInput.files[0].name}`, 'success');
|
|
162
|
+
} else {
|
|
163
|
+
addResult('No file in form data (expected - input is cleared for UI)', 'info');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Test with KTUI instance
|
|
167
|
+
const formImageInput = KTImageInput.getInstance(form.querySelector('[data-kt-image-input]'));
|
|
168
|
+
if (formImageInput) {
|
|
169
|
+
const selectedFile = formImageInput.getSelectedFile();
|
|
170
|
+
if (selectedFile) {
|
|
171
|
+
addResult(`KTUI file access: ${selectedFile.name}`, 'success');
|
|
172
|
+
} else {
|
|
173
|
+
addResult('No file in KTUI instance', 'error');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function handleFormSubmit(event) {
|
|
179
|
+
event.preventDefault();
|
|
180
|
+
addResult('Form submission intercepted for testing', 'info');
|
|
181
|
+
testFormSubmission();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function clearResults() {
|
|
185
|
+
document.getElementById('test-results').innerHTML = '';
|
|
186
|
+
}
|
|
187
|
+
</script>
|
|
188
|
+
</body>
|
|
189
|
+
</html>
|
|
@@ -30,12 +30,14 @@
|
|
|
30
30
|
class="absolute top-3 right-3 text-gray-400 hover:text-gray-600 focus:outline-none"
|
|
31
31
|
aria-label="Close Modal">×</button>
|
|
32
32
|
<h2 class="text-lg font-semibold mb-4">Select a Field</h2>
|
|
33
|
+
<!-- Note: dropdownContainer is set to "#selectModal" to attach dropdown to modal container -->
|
|
33
34
|
<select
|
|
34
35
|
class="kt-select"
|
|
35
36
|
data-kt-select="true"
|
|
36
37
|
data-kt-select-placeholder="Select a framework..."
|
|
37
38
|
data-kt-select-config='{
|
|
38
|
-
"optionsClass": "kt-scrollable overflow-auto max-h-[250px]"
|
|
39
|
+
"optionsClass": "kt-scrollable overflow-auto max-h-[250px]",
|
|
40
|
+
"dropdownContainer": "#selectModal"
|
|
39
41
|
}'
|
|
40
42
|
>
|
|
41
43
|
<option value="react">React</option>
|
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
data-kt-select-data-field-value="id"
|
|
22
22
|
data-kt-select-data-field-text="name"
|
|
23
23
|
data-kt-select-enable-search="true"
|
|
24
|
+
data-kt-select-search-param="q"
|
|
25
|
+
data-kt-select-search-min-length="2"
|
|
26
|
+
data-kt-select-search-debounce="300"
|
|
27
|
+
data-kt-select-debug="true"
|
|
28
|
+
placeholder="Search users..."
|
|
24
29
|
></select>
|
|
25
30
|
|
|
26
31
|
</div>
|