lisichatbot 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +112 -17
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -161,6 +161,7 @@ function renderOptions(options, field, isSingleSelect = true) {
|
|
|
161
161
|
input.name = field;
|
|
162
162
|
input.value = valueStr;
|
|
163
163
|
input.checked = false; // Ensure unchecked initially
|
|
164
|
+
input.onclick = (e) => e.stopPropagation(); // Prevent click bubbling
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
// Find and ensure tick icon is hidden initially
|
|
@@ -186,18 +187,98 @@ function renderOptions(options, field, isSingleSelect = true) {
|
|
|
186
187
|
elements.messages.appendChild(optionsWrapper);
|
|
187
188
|
scrollToBottom();
|
|
188
189
|
|
|
189
|
-
// Add click handlers
|
|
190
|
+
// Add click handlers with proper event handling
|
|
190
191
|
const optionElements = optionsWrapper.querySelectorAll('[data-chat-input-element="container"]');
|
|
191
192
|
optionElements.forEach(el => {
|
|
192
|
-
|
|
193
|
+
// Clear any existing onclick
|
|
194
|
+
el.onclick = null;
|
|
195
|
+
|
|
196
|
+
// Add new click handler with stopPropagation
|
|
197
|
+
el.onclick = (e) => {
|
|
198
|
+
e.stopPropagation(); // Prevent bubbling
|
|
199
|
+
e.preventDefault(); // Prevent default behavior
|
|
200
|
+
handleOptionClick(el, field, isSingleSelect);
|
|
201
|
+
};
|
|
193
202
|
});
|
|
194
203
|
}
|
|
195
204
|
|
|
205
|
+
// =============================================================================
|
|
206
|
+
// TEXT/NUMBER INPUT RENDERING
|
|
207
|
+
// =============================================================================
|
|
208
|
+
|
|
209
|
+
function renderTextInput(field, inputType = 'text') {
|
|
210
|
+
if (!elements.messages) return;
|
|
211
|
+
|
|
212
|
+
// Determine input type attribute value
|
|
213
|
+
const inputTypeAttr = inputType === 'number' ? 'number-input' : 'text-input';
|
|
214
|
+
|
|
215
|
+
// Find existing input element in HTML by data-chat-element
|
|
216
|
+
const inputSelector = `[data-chat-element="${inputTypeAttr}"]`;
|
|
217
|
+
const existingInput = document.querySelector(inputSelector);
|
|
218
|
+
|
|
219
|
+
if (!existingInput) {
|
|
220
|
+
console.error(`Element with ${inputSelector} not found in HTML. Please add it to your HTML.`);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Clone existing input element
|
|
225
|
+
const clone = existingInput.cloneNode(true);
|
|
226
|
+
|
|
227
|
+
// Make clone visible
|
|
228
|
+
clone.style.display = '';
|
|
229
|
+
|
|
230
|
+
// Set data attributes
|
|
231
|
+
clone.setAttribute('data-field', field);
|
|
232
|
+
|
|
233
|
+
// Find the actual input element
|
|
234
|
+
const inputElement = clone.querySelector('[data-chat-input-element="input"]');
|
|
235
|
+
if (inputElement) {
|
|
236
|
+
inputElement.setAttribute('data-field', field);
|
|
237
|
+
inputElement.name = field;
|
|
238
|
+
inputElement.value = '';
|
|
239
|
+
inputElement.type = inputType === 'number' ? 'number' : 'text';
|
|
240
|
+
|
|
241
|
+
// Add input event to enable Next button when user types
|
|
242
|
+
inputElement.oninput = (e) => {
|
|
243
|
+
const value = inputType === 'number' ? parseFloat(e.target.value) : e.target.value;
|
|
244
|
+
|
|
245
|
+
// Save value
|
|
246
|
+
chatState.data[field] = value;
|
|
247
|
+
chatState.currentSelection = { field, value, name: value };
|
|
248
|
+
|
|
249
|
+
// Enable Next button if there's a value
|
|
250
|
+
if (value !== '' && value !== null && !isNaN(value)) {
|
|
251
|
+
enableNextButton();
|
|
252
|
+
} else {
|
|
253
|
+
disableNextButton();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Append to messages
|
|
259
|
+
elements.messages.appendChild(clone);
|
|
260
|
+
scrollToBottom();
|
|
261
|
+
|
|
262
|
+
// Focus the input
|
|
263
|
+
if (inputElement) {
|
|
264
|
+
setTimeout(() => inputElement.focus(), 100);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
196
268
|
// =============================================================================
|
|
197
269
|
// OPTION CLICK HANDLER USING CUSTOM ATTRIBUTES
|
|
198
270
|
// =============================================================================
|
|
199
271
|
|
|
200
272
|
function handleOptionClick(element, field, isSingleSelect) {
|
|
273
|
+
// Prevent rapid double-clicks
|
|
274
|
+
const now = Date.now();
|
|
275
|
+
const lastClick = element.getAttribute('data-last-click');
|
|
276
|
+
if (lastClick && (now - parseInt(lastClick)) < 300) {
|
|
277
|
+
console.log('Ignored double-click');
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
element.setAttribute('data-last-click', now.toString());
|
|
281
|
+
|
|
201
282
|
// Find elements using custom attributes
|
|
202
283
|
const tickIcon = element.querySelector('[data-chat-input-element="tick-icon"]');
|
|
203
284
|
const input = element.querySelector('[data-chat-input-element="input"]');
|
|
@@ -207,6 +288,13 @@ function handleOptionClick(element, field, isSingleSelect) {
|
|
|
207
288
|
const optionName = element.getAttribute('data-name');
|
|
208
289
|
const inputType = element.getAttribute('data-chat-element');
|
|
209
290
|
|
|
291
|
+
const mode = isSingleSelect ? 'Single-select' : 'Multi-select';
|
|
292
|
+
console.log(`${mode} clicked:`, {
|
|
293
|
+
field,
|
|
294
|
+
value: valueStr,
|
|
295
|
+
name: optionName
|
|
296
|
+
});
|
|
297
|
+
|
|
210
298
|
// Parse value
|
|
211
299
|
let value;
|
|
212
300
|
try {
|
|
@@ -245,19 +333,11 @@ function handleOptionClick(element, field, isSingleSelect) {
|
|
|
245
333
|
// Multi-select
|
|
246
334
|
const isChecked = !element.classList.contains('cf-checked');
|
|
247
335
|
|
|
248
|
-
console.log('Multi-select clicked:', {
|
|
249
|
-
field,
|
|
250
|
-
value,
|
|
251
|
-
isChecked,
|
|
252
|
-
selectedBackground: config.selectedBackground
|
|
253
|
-
});
|
|
254
|
-
|
|
255
336
|
if (isChecked) {
|
|
256
337
|
element.classList.add('cf-checked');
|
|
257
338
|
element.style.setProperty('background-color', config.selectedBackground, 'important');
|
|
258
339
|
if (tickIcon) {
|
|
259
340
|
tickIcon.style.setProperty('display', 'block', 'important');
|
|
260
|
-
console.log('Tick icon shown for:', optionName);
|
|
261
341
|
}
|
|
262
342
|
if (input) input.checked = true;
|
|
263
343
|
|
|
@@ -273,7 +353,7 @@ function handleOptionClick(element, field, isSingleSelect) {
|
|
|
273
353
|
chatState.data[field].push(value);
|
|
274
354
|
}
|
|
275
355
|
|
|
276
|
-
console.log(
|
|
356
|
+
console.log(`✅ Added "${optionName}" - Total selected:`, chatState.data[field]);
|
|
277
357
|
} else {
|
|
278
358
|
element.classList.remove('cf-checked');
|
|
279
359
|
element.style.setProperty('background-color', 'transparent', 'important');
|
|
@@ -287,7 +367,7 @@ function handleOptionClick(element, field, isSingleSelect) {
|
|
|
287
367
|
);
|
|
288
368
|
}
|
|
289
369
|
|
|
290
|
-
console.log(
|
|
370
|
+
console.log(`❌ Removed "${optionName}" - Total selected:`, chatState.data[field]);
|
|
291
371
|
}
|
|
292
372
|
|
|
293
373
|
// Get all selected names using custom attribute
|
|
@@ -399,12 +479,27 @@ async function showNextStep() {
|
|
|
399
479
|
|
|
400
480
|
// Add options if input exists
|
|
401
481
|
if (nextStep.input) {
|
|
402
|
-
const
|
|
403
|
-
renderOptions(nextStep.input.options, nextStep.input.field, isSingleSelect);
|
|
482
|
+
const inputType = nextStep.inputType || 'single-select'; // Default to single-select
|
|
404
483
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
484
|
+
if (inputType === 'text' || inputType === 'number') {
|
|
485
|
+
// Render text or number input
|
|
486
|
+
renderTextInput(nextStep.input.field, inputType);
|
|
487
|
+
|
|
488
|
+
// Disable Next button initially (enabled when user types)
|
|
489
|
+
if (inputRequired) {
|
|
490
|
+
disableNextButton();
|
|
491
|
+
} else {
|
|
492
|
+
enableNextButton();
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
// Render options (single-select or multi-select)
|
|
496
|
+
const isSingleSelect = inputType === 'single-select';
|
|
497
|
+
renderOptions(nextStep.input.options, nextStep.input.field, isSingleSelect);
|
|
498
|
+
|
|
499
|
+
// Enable Next button if input not required (default behavior)
|
|
500
|
+
if (!inputRequired) {
|
|
501
|
+
enableNextButton();
|
|
502
|
+
}
|
|
408
503
|
}
|
|
409
504
|
} else {
|
|
410
505
|
// Auto-advance for steps without input
|