@keenthemes/ktui 1.0.19 ā 1.0.21
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 +690 -166
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +165 -31
- package/examples/image-input/file-upload-example.html +189 -0
- package/examples/select/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 +59 -5
- 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 +79 -12
- 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/config.js +1 -0
- package/lib/cjs/components/select/config.js.map +1 -1
- package/lib/cjs/components/select/dropdown.js +4 -2
- 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 +15 -5
- package/lib/cjs/components/select/search.js.map +1 -1
- package/lib/cjs/components/select/select.js +273 -32
- 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 +6 -0
- 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/stepper/stepper.js +59 -12
- package/lib/cjs/components/stepper/stepper.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 +59 -5
- 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 +78 -12
- 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/config.js +1 -0
- package/lib/esm/components/select/config.js.map +1 -1
- package/lib/esm/components/select/dropdown.js +4 -2
- 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 +16 -6
- package/lib/esm/components/select/search.js.map +1 -1
- package/lib/esm/components/select/select.js +273 -32
- 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 +6 -0
- 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/stepper/stepper.js +59 -12
- package/lib/esm/components/stepper/stepper.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 +2 -2
- package/src/components/component.ts +19 -4
- package/src/components/datatable/datatable-sort.ts +6 -0
- package/src/components/datatable/datatable.ts +98 -15
- package/src/components/datatable/types.ts +5 -1
- 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/config.ts +2 -0
- package/src/components/select/dropdown.ts +20 -11
- 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 +59 -44
- package/src/components/select/select.css +26 -17
- package/src/components/select/select.ts +472 -101
- package/src/components/select/tags.ts +9 -3
- package/src/components/select/templates.ts +10 -0
- package/src/components/select/utils.ts +55 -20
- package/src/components/select/variants.css +0 -1
- package/src/components/stepper/stepper.ts +2 -2
- 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,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>
|
|
@@ -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>
|
|
@@ -0,0 +1,227 @@
|
|
|
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>Test Optimizations</title>
|
|
7
|
+
<link rel="stylesheet" href="../../dist/styles.css">
|
|
8
|
+
<style>
|
|
9
|
+
.test-container {
|
|
10
|
+
max-width: 800px;
|
|
11
|
+
margin: 20px auto;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
}
|
|
14
|
+
.test-section {
|
|
15
|
+
margin-bottom: 20px;
|
|
16
|
+
padding: 15px;
|
|
17
|
+
border: 1px solid #e5e7eb;
|
|
18
|
+
border-radius: 8px;
|
|
19
|
+
background: white;
|
|
20
|
+
}
|
|
21
|
+
.metrics {
|
|
22
|
+
background: #f9fafb;
|
|
23
|
+
padding: 10px;
|
|
24
|
+
border-radius: 4px;
|
|
25
|
+
font-family: monospace;
|
|
26
|
+
font-size: 12px;
|
|
27
|
+
margin-top: 10px;
|
|
28
|
+
}
|
|
29
|
+
.success { color: #059669; }
|
|
30
|
+
.warning { color: #d97706; }
|
|
31
|
+
.error { color: #dc2626; }
|
|
32
|
+
</style>
|
|
33
|
+
</head>
|
|
34
|
+
<body class="bg-gray-50 min-h-screen">
|
|
35
|
+
<div class="test-container">
|
|
36
|
+
<h1>Remote Select Optimizations Test</h1>
|
|
37
|
+
|
|
38
|
+
<div class="test-section">
|
|
39
|
+
<h3>Performance Test: Multiple Remote Selects</h3>
|
|
40
|
+
<button onclick="testPerformance()" style="padding: 8px 16px; background: #3b82f6; color: white; border: none; border-radius: 4px; cursor: pointer;">
|
|
41
|
+
Test Performance (Create 10 Remote Selects)
|
|
42
|
+
</button>
|
|
43
|
+
<div id="performance-results" class="metrics">Click button to test...</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="test-section">
|
|
47
|
+
<h3>Functionality Test: Basic Remote Select</h3>
|
|
48
|
+
<label class="block mb-2 font-medium text-gray-700">Users from JSONPlaceholder</label>
|
|
49
|
+
<select
|
|
50
|
+
id="test-select"
|
|
51
|
+
data-kt-select
|
|
52
|
+
data-kt-select-remote="true"
|
|
53
|
+
data-kt-select-data-url="https://jsonplaceholder.typicode.com/users"
|
|
54
|
+
data-kt-select-data-field-value="id"
|
|
55
|
+
data-kt-select-data-field-text="name"
|
|
56
|
+
data-kt-select-enable-search="true"
|
|
57
|
+
data-kt-select-debug="true"
|
|
58
|
+
placeholder="Select a user..."
|
|
59
|
+
></select>
|
|
60
|
+
<div id="functionality-results" class="metrics">Initializing...</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div class="test-section">
|
|
64
|
+
<h3>Search Test: Remote Search Functionality</h3>
|
|
65
|
+
<label class="block mb-2 font-medium text-gray-700">Posts from JSONPlaceholder</label>
|
|
66
|
+
<select
|
|
67
|
+
id="search-test-select"
|
|
68
|
+
data-kt-select
|
|
69
|
+
data-kt-select-remote="true"
|
|
70
|
+
data-kt-select-data-url="https://jsonplaceholder.typicode.com/posts"
|
|
71
|
+
data-kt-select-data-field-value="id"
|
|
72
|
+
data-kt-select-data-field-text="title"
|
|
73
|
+
data-kt-select-enable-search="true"
|
|
74
|
+
data-kt-select-search-param="q"
|
|
75
|
+
data-kt-select-search-min-length="2"
|
|
76
|
+
data-kt-select-debug="true"
|
|
77
|
+
placeholder="Search posts..."
|
|
78
|
+
></select>
|
|
79
|
+
<div id="search-results" class="metrics">Ready for search testing...</div>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<script src="../../dist/ktui.js"></script>
|
|
84
|
+
<script>
|
|
85
|
+
// Performance test function
|
|
86
|
+
function testPerformance() {
|
|
87
|
+
const resultsDiv = document.getElementById('performance-results');
|
|
88
|
+
resultsDiv.innerHTML = 'Running performance test...';
|
|
89
|
+
|
|
90
|
+
const startTime = performance.now();
|
|
91
|
+
const instances = [];
|
|
92
|
+
|
|
93
|
+
// Create 10 remote select instances
|
|
94
|
+
for (let i = 0; i < 10; i++) {
|
|
95
|
+
const element = document.createElement('select');
|
|
96
|
+
element.setAttribute('data-kt-select', '');
|
|
97
|
+
element.setAttribute('data-kt-select-remote', 'true');
|
|
98
|
+
element.setAttribute('data-kt-select-data-url', 'https://jsonplaceholder.typicode.com/users');
|
|
99
|
+
element.setAttribute('data-kt-select-data-field-value', 'id');
|
|
100
|
+
element.setAttribute('data-kt-select-data-field-text', 'name');
|
|
101
|
+
element.setAttribute('data-kt-select-debug', 'false'); // Disable debug for performance
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const instance = new KTSelect(element);
|
|
105
|
+
instances.push(instance);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error(`Instance ${i} creation failed:`, error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const endTime = performance.now();
|
|
112
|
+
const duration = endTime - startTime;
|
|
113
|
+
|
|
114
|
+
// Cleanup
|
|
115
|
+
instances.forEach(instance => {
|
|
116
|
+
if (instance.dispose) instance.dispose();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
resultsDiv.innerHTML = `
|
|
120
|
+
<span class="${duration < 1000 ? 'success' : 'warning'}">
|
|
121
|
+
ā
Performance Test Results:<br>
|
|
122
|
+
⢠Created ${instances.length}/10 instances in ${duration.toFixed(2)}ms<br>
|
|
123
|
+
⢠Average: ${(duration / instances.length).toFixed(2)}ms per instance<br>
|
|
124
|
+
⢠Optimizations working: ${duration < 1000 ? 'YES' : 'NEEDS IMPROVEMENT'}
|
|
125
|
+
</span>
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Functionality test
|
|
130
|
+
function testFunctionality() {
|
|
131
|
+
const resultsDiv = document.getElementById('functionality-results');
|
|
132
|
+
const testSelect = document.getElementById('test-select');
|
|
133
|
+
|
|
134
|
+
if (testSelect && testSelect.instance) {
|
|
135
|
+
try {
|
|
136
|
+
// Test dropdown opening
|
|
137
|
+
testSelect.instance.openDropdown();
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
testSelect.instance.closeDropdown();
|
|
140
|
+
|
|
141
|
+
// Test search functionality
|
|
142
|
+
const searchInput = testSelect.instance.getSearchInput();
|
|
143
|
+
if (searchInput) {
|
|
144
|
+
searchInput.value = 'test';
|
|
145
|
+
searchInput.dispatchEvent(new Event('input'));
|
|
146
|
+
|
|
147
|
+
setTimeout(() => {
|
|
148
|
+
searchInput.value = '';
|
|
149
|
+
searchInput.dispatchEvent(new Event('input'));
|
|
150
|
+
|
|
151
|
+
resultsDiv.innerHTML = `
|
|
152
|
+
<span class="success">
|
|
153
|
+
ā
Functionality Test PASSED:<br>
|
|
154
|
+
⢠Instance created successfully<br>
|
|
155
|
+
⢠Dropdown opens/closes correctly<br>
|
|
156
|
+
⢠Search input works<br>
|
|
157
|
+
⢠Optimizations maintain functionality
|
|
158
|
+
</span>
|
|
159
|
+
`;
|
|
160
|
+
}, 1000);
|
|
161
|
+
}
|
|
162
|
+
}, 1000);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
resultsDiv.innerHTML = `
|
|
165
|
+
<span class="error">
|
|
166
|
+
ā Functionality Test FAILED:<br>
|
|
167
|
+
Error: ${error.message}
|
|
168
|
+
</span>
|
|
169
|
+
`;
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
resultsDiv.innerHTML = `
|
|
173
|
+
<span class="error">
|
|
174
|
+
ā Functionality Test FAILED:<br>
|
|
175
|
+
Remote select instance not found
|
|
176
|
+
</span>
|
|
177
|
+
`;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Search test
|
|
182
|
+
function testSearch() {
|
|
183
|
+
const resultsDiv = document.getElementById('search-results');
|
|
184
|
+
const searchSelect = document.getElementById('search-test-select');
|
|
185
|
+
|
|
186
|
+
if (searchSelect && searchSelect.instance) {
|
|
187
|
+
const searchInput = searchSelect.instance.getSearchInput();
|
|
188
|
+
if (searchInput) {
|
|
189
|
+
// Simulate typing
|
|
190
|
+
searchInput.value = 'qui';
|
|
191
|
+
searchInput.dispatchEvent(new Event('input'));
|
|
192
|
+
|
|
193
|
+
setTimeout(() => {
|
|
194
|
+
searchInput.value = '';
|
|
195
|
+
searchInput.dispatchEvent(new Event('input'));
|
|
196
|
+
|
|
197
|
+
resultsDiv.innerHTML = `
|
|
198
|
+
<span class="success">
|
|
199
|
+
ā
Search Test PASSED:<br>
|
|
200
|
+
⢠Search input responds to input<br>
|
|
201
|
+
⢠Remote search triggers correctly<br>
|
|
202
|
+
⢠Optimized rendering works
|
|
203
|
+
</span>
|
|
204
|
+
`;
|
|
205
|
+
}, 2000);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Initialize tests
|
|
211
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
212
|
+
try {
|
|
213
|
+
KTSelect.init();
|
|
214
|
+
|
|
215
|
+
// Wait for initialization to complete
|
|
216
|
+
setTimeout(() => {
|
|
217
|
+
testFunctionality();
|
|
218
|
+
testSearch();
|
|
219
|
+
}, 2000);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
document.getElementById('functionality-results').innerHTML =
|
|
222
|
+
'<span class="error">ā Failed to initialize KTSelect: ' + error.message + '</span>';
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
</script>
|
|
226
|
+
</body>
|
|
227
|
+
</html>
|
|
@@ -0,0 +1,151 @@
|
|
|
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>Remote Search Test</title>
|
|
8
|
+
<link rel="stylesheet" href="../../dist/styles.css">
|
|
9
|
+
<style>
|
|
10
|
+
.test-container {
|
|
11
|
+
max-width: 600px;
|
|
12
|
+
margin: 20px auto;
|
|
13
|
+
padding: 20px;
|
|
14
|
+
}
|
|
15
|
+
.test-section {
|
|
16
|
+
margin-bottom: 30px;
|
|
17
|
+
padding: 20px;
|
|
18
|
+
border: 1px solid #e5e7eb;
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
background: white;
|
|
21
|
+
}
|
|
22
|
+
.test-section h3 {
|
|
23
|
+
margin-top: 0;
|
|
24
|
+
color: #374151;
|
|
25
|
+
}
|
|
26
|
+
.debug-info {
|
|
27
|
+
background: #f9fafb;
|
|
28
|
+
padding: 10px;
|
|
29
|
+
border-radius: 4px;
|
|
30
|
+
font-family: monospace;
|
|
31
|
+
font-size: 12px;
|
|
32
|
+
margin-top: 10px;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
35
|
+
</head>
|
|
36
|
+
|
|
37
|
+
<body class="bg-gray-50 min-h-screen">
|
|
38
|
+
<div class="test-container">
|
|
39
|
+
<h1>Remote Select Search Test</h1>
|
|
40
|
+
|
|
41
|
+
<div class="test-section">
|
|
42
|
+
<h3>Test 1: Basic Remote Search</h3>
|
|
43
|
+
<label class="block mb-2 font-medium text-gray-700">Users from JSONPlaceholder</label>
|
|
44
|
+
<select
|
|
45
|
+
data-kt-select
|
|
46
|
+
data-kt-select-remote="true"
|
|
47
|
+
data-kt-select-data-url="https://jsonplaceholder.typicode.com/users"
|
|
48
|
+
data-kt-select-data-field-value="id"
|
|
49
|
+
data-kt-select-data-field-text="name"
|
|
50
|
+
data-kt-select-enable-search="true"
|
|
51
|
+
data-kt-select-search-param="q"
|
|
52
|
+
data-kt-select-search-min-length="2"
|
|
53
|
+
data-kt-select-search-debounce="300"
|
|
54
|
+
data-kt-select-debug="true"
|
|
55
|
+
placeholder="Search users..."
|
|
56
|
+
></select>
|
|
57
|
+
<div class="debug-info">
|
|
58
|
+
<strong>Expected behavior:</strong> Type at least 2 characters to search users. Options should display with proper text content.
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div class="test-section">
|
|
63
|
+
<h3>Test 2: Posts with Custom Field Mapping</h3>
|
|
64
|
+
<label class="block mb-2 font-medium text-gray-700">Posts from JSONPlaceholder</label>
|
|
65
|
+
<select
|
|
66
|
+
data-kt-select
|
|
67
|
+
data-kt-select-remote="true"
|
|
68
|
+
data-kt-select-data-url="https://jsonplaceholder.typicode.com/posts"
|
|
69
|
+
data-kt-select-data-field-value="id"
|
|
70
|
+
data-kt-select-data-field-text="title"
|
|
71
|
+
data-kt-select-enable-search="true"
|
|
72
|
+
data-kt-select-search-param="q"
|
|
73
|
+
data-kt-select-search-min-length="3"
|
|
74
|
+
data-kt-select-search-debounce="500"
|
|
75
|
+
data-kt-select-debug="true"
|
|
76
|
+
placeholder="Search posts..."
|
|
77
|
+
></select>
|
|
78
|
+
<div class="debug-info">
|
|
79
|
+
<strong>Expected behavior:</strong> Type at least 3 characters to search posts. Should show post titles as options.
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="test-section">
|
|
84
|
+
<h3>Test 3: Error Handling</h3>
|
|
85
|
+
<label class="block mb-2 font-medium text-gray-700">Invalid URL Test</label>
|
|
86
|
+
<select
|
|
87
|
+
data-kt-select
|
|
88
|
+
data-kt-select-remote="true"
|
|
89
|
+
data-kt-select-data-url="https://invalid-url-that-does-not-exist.com/api/data"
|
|
90
|
+
data-kt-select-data-field-value="id"
|
|
91
|
+
data-kt-select-data-field-text="name"
|
|
92
|
+
data-kt-select-enable-search="true"
|
|
93
|
+
data-kt-select-search-param="q"
|
|
94
|
+
data-kt-select-search-min-length="1"
|
|
95
|
+
data-kt-select-search-debounce="300"
|
|
96
|
+
data-kt-select-debug="true"
|
|
97
|
+
placeholder="This should show error..."
|
|
98
|
+
></select>
|
|
99
|
+
<div class="debug-info">
|
|
100
|
+
<strong>Expected behavior:</strong> Should show error message and restore original state after 2 seconds.
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div class="test-section">
|
|
105
|
+
<h3>Console Debug Info</h3>
|
|
106
|
+
<div class="debug-info">
|
|
107
|
+
Open browser developer tools console to see debug information about the remote search functionality.
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<script src="../../dist/ktui.js"></script>
|
|
113
|
+
<script src="validation-test.js"></script>
|
|
114
|
+
<script>
|
|
115
|
+
// Initialize KTSelect components
|
|
116
|
+
KTSelect.init();
|
|
117
|
+
|
|
118
|
+
// Add some console logging for testing
|
|
119
|
+
console.log('Remote Select Test Page Loaded');
|
|
120
|
+
console.log('All KTSelect components should be initialized with debug logging enabled');
|
|
121
|
+
|
|
122
|
+
// Run validation tests after a short delay to ensure everything is loaded
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
console.log('\nš Running End-to-End Validation Tests...');
|
|
125
|
+
|
|
126
|
+
// Test real API interaction
|
|
127
|
+
const testSelect = document.querySelector('select[data-kt-select-remote="true"]');
|
|
128
|
+
if (testSelect && testSelect.instance) {
|
|
129
|
+
console.log('ā
E2E Test 1 PASSED: Remote select instance found');
|
|
130
|
+
|
|
131
|
+
// Test dropdown opening
|
|
132
|
+
try {
|
|
133
|
+
testSelect.instance.openDropdown();
|
|
134
|
+
console.log('ā
E2E Test 2 PASSED: Dropdown opens successfully');
|
|
135
|
+
|
|
136
|
+
// Test dropdown closing
|
|
137
|
+
setTimeout(() => {
|
|
138
|
+
testSelect.instance.closeDropdown();
|
|
139
|
+
console.log('ā
E2E Test 3 PASSED: Dropdown closes successfully');
|
|
140
|
+
}, 1000);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.log('ā E2E Test 2-3 FAILED: Dropdown operation error:', error.message);
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
console.log('ā E2E Test 1 FAILED: Remote select instance not found');
|
|
146
|
+
}
|
|
147
|
+
}, 2000);
|
|
148
|
+
</script>
|
|
149
|
+
</body>
|
|
150
|
+
|
|
151
|
+
</html>
|