luanfreitas5/Bubble_Prompter
0
1const inputText = document.getElementById('input-text');2const bubbleContainer = document.getElementById('bubble-container');3const replaceSpacesButton = document.getElementById('replace-spaces-button');4const replaceUnderscoreButton = document.getElementById('replace-underscore-button');5const revertUnderscoreButton = document.getElementById('revert-underscore-button');6const replaceLineBreaksButton = document.getElementById('replace-linebreaks-button');7const replaceCommasButton = document.getElementById('replace-commas-button');8const removeDuplicatesButton = document.getElementById('remove-duplicates-button');9const revertSpacesButton = document.getElementById('revert-spaces-button');10const copyButton = document.getElementById('copy-button');11const undoButton = document.getElementById('undo-button');12const redoButton = document.getElementById('redo-button');13const deleteModeButton = document.getElementById('delete-mode-button');14const emphasisModeButton = document.getElementById('emphasis-mode-button');15const mitigateModeButton = document.getElementById('mitigate-mode-button');16const literalParenthesisButton = document.getElementById('literal-parenthesis-button');17const fictionalParenthesisButton = document.getElementById('fictional-parenthesis-button');18 19const bubbleColors = {};20 21let history = [];22let historyIndex = -1;23 24let deleteModeEnabled = false;25 26let emphasisModeEnabled = false;27 28let mitigateModeEnabled = false;29 30inputText.addEventListener('input', handleTextChange);31replaceSpacesButton.addEventListener('click', replaceSpaces);32replaceUnderscoreButton.addEventListener('click', replaceUnderscores);33revertUnderscoreButton.addEventListener('click', revertUnderscores);34replaceLineBreaksButton.addEventListener('click', replaceLineBreaks);35replaceCommasButton.addEventListener('click', replaceCommas);36removeDuplicatesButton.addEventListener('click', removeDuplicates);37revertSpacesButton.addEventListener('click', revertSpaces);38copyButton.addEventListener('click', copyToClipboard);39undoButton.addEventListener('click', undoChanges);40redoButton.addEventListener('click', redoChanges);41deleteModeButton.addEventListener('click', toggleDeleteMode);42emphasisModeButton.addEventListener('click', toggleEmphasisMode);43mitigateModeButton.addEventListener('click', toggleMitigateMode);44literalParenthesisButton.addEventListener('click', literalParenthesis);45fictionalParenthesisButton.addEventListener('click', fictionalParenthesis);46 47const sortable = new Sortable(bubbleContainer, {48 animation: 250,49 ghostClass: 'ghost',50 onEnd: handleBubbleChange,51 disabled: deleteModeEnabled || emphasisModeEnabled || mitigateModeEnabled52});53 54function handleTextChange() {55 const text = inputText.value;56 57 if (history.length === 0) {58 history.push('');59 historyIndex++;60 }61 62 if (text !== history[historyIndex]) {63 if (historyIndex < history.length - 1) {64 65 history.splice(historyIndex + 1);66 }67 68 history.push(text);69 historyIndex++;70 71 updateBubbles();72 updateButtonStates();73 }74}75 76function handleBubbleChange() {77 const conceptList = Array.from(bubbleContainer.getElementsByClassName('bubble')).map(bubble => bubble.textContent.trim());78 inputText.value = conceptList.join(', ');79 handleTextChange();80}81 82function updateBubbles() {83 bubbleContainer.innerHTML = '';84 const text = inputText.value.trim();85 86 if (text === '') return;87 88 const concepts = text.split(', ');89 90 concepts.forEach(concept => {91 const bubble = createBubble(concept);92 bubbleContainer.appendChild(bubble);93 });94}95 96function createBubble(text) {97 const bubble = document.createElement('div');98 bubble.classList.add('bubble');99 100 if (!bubbleColors.hasOwnProperty(text)) {101 bubbleColors[text] = getRandomColor();102 }103 104 bubble.style.backgroundColor = bubbleColors[text];105 106 const bubbleText = document.createElement('span');107 bubbleText.classList.add('bubble-text');108 bubbleText.innerText = text;109 110 bubble.appendChild(bubbleText);111 112 if (deleteModeEnabled) {113 bubble.classList.add('delete-mode');114 bubble.addEventListener('click', deleteBubble);115 }116 117 if (emphasisModeEnabled) {118 bubble.classList.add('emphasis-mode');119 bubble.addEventListener('click', emphasizeBubble);120 }121 122 if (mitigateModeEnabled) {123 bubble.classList.add('mitigate-mode');124 bubble.addEventListener('click', mitigateBubble);125 }126 127 return bubble;128}129 130function getRandomColor() {131 const h = Math.floor(Math.random() * 360);132 const s = Math.floor(Math.random() * 30) + 50;133 const l = Math.floor(Math.random() * 40) + 30;134 135 return `hsl(${h}, ${s}%, ${l}%)`;136}137 138function updateButtonStates() {139 undoButton.disabled = historyIndex === 0;140 redoButton.disabled = historyIndex === history.length - 1;141}142 143function replaceSpaces() {144 let text = inputText.value;145 146 text = text.replace(/,(\S)/g, ', $1');147 text = text.replace(/ {2,}/g, ' ');148 text = text.replace(/([^,])\s+/g, '$1, ');149 150 inputText.value = text;151 handleTextChange();152}153 154function revertSpaces() {155 const text = inputText.value;156 const replacedText = text.replace(/, /g, ' ');157 inputText.value = replacedText;158 handleTextChange();159}160 161function replaceUnderscores() {162 const text = inputText.value;163 const replacedText = text.replace(/_/g, ' ');164 inputText.value = replacedText;165 handleTextChange();166}167 168function revertUnderscores() {169 const text = inputText.value;170 const replacedText = text.replace(/([^,]) /g, '$1_');171 inputText.value = replacedText;172 handleTextChange();173}174 175function replaceLineBreaks() {176 const text = inputText.value;177 const replacedText = text.replace(/\n/g, ', ');178 inputText.value = replacedText;179 handleTextChange();180}181 182function replaceCommas() {183 const text = inputText.value;184 const step1 = text.replace(/,,/g, ',');185 const step2 = step1.replace(/, ,/g, ', ');186 const step3 = step2.trimRight();187 const step4 = step3.replace(/,$/, '');188 const step5 = step4.replace(/^,/, '');189 const step6 = step5.replace(/, /g, ', ');190 const replacedText = step6.replace(/^ /, '');191 192 inputText.value = replacedText;193 handleTextChange();194}195 196function removeDuplicates() {197 const text = inputText.value;198 const concepts = text.split(', ');199 200 const uniqueConcepts = [...new Set(concepts)];201 202 inputText.value = uniqueConcepts.join(', ');203 handleTextChange();204}205 206 207function copyToClipboard() {208 inputText.select();209 inputText.setSelectionRange(0, 99999);210 document.execCommand('copy');211}212 213function literalParenthesis() {214 const inputText = document.getElementById('input-text');215 const text = inputText.value;216 217 // Reemplazar ' (' que no estén precedidos por una ',' y el paréntesis de cierre siguiente más cercano218 let replacedText = text.replace(/([^,]) \((.*?)\)/g, '$1 \\($2\\)');219 220 // Reemplazar '_(' y el paréntesis de cierre siguiente más cercano221 replacedText = replacedText.replace(/_\((.*?)\)/g, '_\\($1\\)');222 223 inputText.value = replacedText;224 handleTextChange();225}226 227 228function fictionalParenthesis() {229 const inputText = document.getElementById('input-text');230 const text = inputText.value;231 232 // Reemplazar '\(' por '('233 let replacedText = text.replace(/\\\(/g, '(');234 235 // Reemplazar '\)' por ')'236 replacedText = replacedText.replace(/\\\)/g, ')');237 238 inputText.value = replacedText;239 handleTextChange();240}241 242document.getElementById('download-text-file-button').addEventListener('click', showFilenameInput);243 244function showFilenameInput() {245 const inputText = document.getElementById('input-text').value;246 const currentDate = new Date();247 248 const year = currentDate.getFullYear();249 const month = String(currentDate.getMonth() + 1).padStart(2, '0');250 const day = String(currentDate.getDate()).padStart(2, '0');251 const hours = String(currentDate.getHours()).padStart(2, '0');252 const minutes = String(currentDate.getMinutes()).padStart(2, '0');253 254 const formattedDate = `${year}-${month}-${day}_${hours}-${minutes}`;255 const defaultFileName = `Bubble Prompter_${formattedDate}.txt`;256 257 let container = document.getElementById('custom-filename-container');258 259 if (!container) {260 container = document.createElement('div');261 container.id = 'custom-filename-container';262 document.body.appendChild(container);263 264 const input = document.createElement('input');265 input.type = 'text';266 input.id = 'custom-filename';267 container.appendChild(input);268 269 const confirmButton = document.createElement('button');270 confirmButton.innerText = '✅';271 confirmButton.classList.add('confirm-button'); // Agregar clase272 confirmButton.addEventListener('click', downloadTextFile);273 container.appendChild(confirmButton);274 275 const cancelButton = document.createElement('button');276 cancelButton.innerText = '❌';277 cancelButton.classList.add('cancel-button'); // Agregar clase278 cancelButton.addEventListener('click', hideFilenameInput);279 container.appendChild(cancelButton);280 281 document.addEventListener('click', function(event) {282 if (!container.contains(event.target) && event.target !== document.getElementById('download-text-file-button')) {283 hideFilenameInput();284 }285 });286 287 input.addEventListener('keydown', function(event) {288 if (event.key === 'Enter') {289 downloadTextFile();290 }291 });292 }293 294 container.style.display = 'block';295 container.style.top = `${document.getElementById('download-text-file-button').offsetTop + document.getElementById('download-text-file-button').offsetHeight}px`;296 container.style.left = `${document.getElementById('download-text-file-button').offsetLeft}px`;297 298 const input = document.getElementById('custom-filename');299 input.value = defaultFileName;300 input.select();301 input.focus();302}303 304function hideFilenameInput() {305 const container = document.getElementById('custom-filename-container');306 if (container) {307 container.style.display = 'none';308 }309}310 311function downloadTextFile() {312 const inputText = document.getElementById('input-text').value;313 let customFilename = document.getElementById('custom-filename').value.trim();314 315 // Añadir .txt si no está presente316 if (!customFilename.endsWith('.txt')) {317 customFilename += '.txt';318 }319 320 const fileName = customFilename ? customFilename : 'Bubble Prompter.txt';321 322 const blob = new Blob([inputText], { type: 'text/plain' });323 324 const link = document.createElement('a');325 link.href = URL.createObjectURL(blob);326 link.download = fileName;327 328 document.body.appendChild(link);329 link.click();330 document.body.removeChild(link);331 332 hideFilenameInput();333}334 335document.getElementById('load-text-file-button').addEventListener('click', loadTextFile);336 337function loadTextFile() {338 const fileInput = document.createElement('input');339 fileInput.type = 'file';340 fileInput.accept = '.txt';341 342 fileInput.addEventListener('change', (event) => {343 const file = event.target.files[0];344 if (file) {345 const reader = new FileReader();346 reader.onload = (e) => {347 const inputText = document.getElementById('input-text');348 let currentText = inputText.value;349 350 // Añadir una coma y un espacio si el campo de texto no está vacío351 if (currentText) {352 currentText += ', ';353 }354 355 // Añadir el contenido del archivo356 inputText.value = currentText + e.target.result;357 handleTextChange();358 };359 reader.readAsText(file);360 }361 });362 363 // Simular un clic en el input de archivo para abrir el cuadro de diálogo de archivo364 fileInput.click();365}366 367document.addEventListener('DOMContentLoaded', function() {368 const inputText = document.getElementById('input-text');369 370 // Evitar comportamiento por defecto de arrastrar y soltar371 ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {372 inputText.addEventListener(eventName, preventDefaults, false);373 document.body.addEventListener(eventName, preventDefaults, false);374 });375 376 // Añadir clases para los estilos de arrastrar y soltar377 ['dragenter', 'dragover'].forEach(eventName => {378 inputText.addEventListener(eventName, () => inputText.classList.add('highlight'), false);379 });380 381 ['dragleave', 'drop'].forEach(eventName => {382 inputText.addEventListener(eventName, () => inputText.classList.remove('highlight'), false);383 });384 385 // Manejar el evento de soltar386 inputText.addEventListener('drop', handleDrop, false);387 388 function preventDefaults(e) {389 e.preventDefault();390 e.stopPropagation();391 }392 393 function handleDrop(e) {394 const dt = e.dataTransfer;395 const files = dt.files;396 397 if (files.length) {398 const file = files[0];399 if (file.type === "text/plain") {400 const reader = new FileReader();401 reader.onload = (e) => {402 let currentText = inputText.value;403 404 // Añadir una coma y un espacio si el campo de texto no está vacío405 if (currentText) {406 currentText += ', ';407 }408 409 // Añadir el contenido del archivo410 inputText.value = currentText + e.target.result;411 handleTextChange();412 };413 reader.readAsText(file);414 } else {415 alert("Please drop a valid .txt file.");416 }417 }418 }419});420 421 422function undoChanges() {423 if (historyIndex > 0) {424 historyIndex--;425 inputText.value = history[historyIndex];426 updateBubbles();427 updateButtonStates();428 }429}430 431function redoChanges() {432 if (historyIndex < history.length - 1) {433 historyIndex++;434 inputText.value = history[historyIndex];435 updateBubbles();436 updateButtonStates();437 }438}439 440function toggleDeleteMode() {441 deleteModeEnabled = !deleteModeEnabled;442 deleteModeButton.classList.toggle('active');443 444 if (deleteModeEnabled) {445 emphasisModeEnabled = false;446 emphasisModeButton.classList.remove('active');447 mitigateModeEnabled = false;448 mitigateModeButton.classList.remove('active');449 }450 451 sortable.option('disabled', deleteModeEnabled);452 bubbleContainer.classList.toggle('delete-mode-container');453 454 const bubbles = bubbleContainer.getElementsByClassName('bubble');455 456 for (let i = 0; i < bubbles.length; i++) {457 const bubble = bubbles[i];458 bubble.classList.remove('emphasis-mode');459 bubble.classList.remove('mitigate-mode');460 if (deleteModeEnabled) {461 bubble.classList.add('delete-mode');462 bubble.removeEventListener('click', emphasizeBubble);463 bubble.removeEventListener('click', mitigateBubble);464 bubble.addEventListener('click', deleteBubble);465 } else {466 bubble.classList.remove('delete-mode');467 bubble.removeEventListener('click', deleteBubble);468 }469 }470}471 472function toggleEmphasisMode() {473 emphasisModeEnabled = !emphasisModeEnabled;474 emphasisModeButton.classList.toggle('active');475 476 if (emphasisModeEnabled) {477 deleteModeEnabled = false;478 deleteModeButton.classList.remove('active');479 mitigateModeEnabled = false;480 mitigateModeButton.classList.remove('active');481 }482 483 sortable.option('disabled', emphasisModeEnabled);484 bubbleContainer.classList.toggle('emphasis-mode-container');485 486 const bubbles = bubbleContainer.getElementsByClassName('bubble');487 488 for (let i = 0; i < bubbles.length; i++) {489 const bubble = bubbles[i];490 bubble.classList.remove('delete-mode');491 bubble.classList.remove('mitigate-mode');492 if (emphasisModeEnabled) {493 bubble.classList.add('emphasis-mode');494 bubble.removeEventListener('click', deleteBubble);495 bubble.removeEventListener('click', mitigateBubble);496 bubble.addEventListener('click', emphasizeBubble);497 } else {498 bubble.classList.remove('emphasis-mode');499 bubble.removeEventListener('click', emphasizeBubble);500 }501 }502}503 504function toggleMitigateMode() {505 mitigateModeEnabled = !mitigateModeEnabled;506 mitigateModeButton.classList.toggle('active');507 508 if (mitigateModeEnabled) {509 deleteModeEnabled = false;510 deleteModeButton.classList.remove('active');511 emphasisModeEnabled = false;512 emphasisModeButton.classList.remove('active');513 }514 515 sortable.option('disabled', mitigateModeEnabled);516 bubbleContainer.classList.toggle('mitigate-mode-container');517 518 const bubbles = bubbleContainer.getElementsByClassName('bubble');519 520 for (let i = 0; i < bubbles.length; i++) {521 const bubble = bubbles[i];522 bubble.classList.remove('delete-mode');523 bubble.classList.remove('emphasis-mode');524 if (mitigateModeEnabled) {525 bubble.classList.add('mitigate-mode');526 bubble.removeEventListener('click', deleteBubble);527 bubble.removeEventListener('click', emphasizeBubble);528 bubble.addEventListener('click', mitigateBubble);529 } else {530 bubble.classList.remove('mitigate-mode');531 bubble.removeEventListener('click', mitigateBubble);532 }533 }534}535 536function deleteBubble(event) {537 const bubble = event.target.closest('.bubble');538 const bubbleText = bubble.querySelector('.bubble-text');539 const nextComma = bubbleText.nextSibling;540 541 bubble.remove();542 543 if (nextComma && nextComma.nodeType === Node.TEXT_NODE && nextComma.textContent.trim() === ',') {544 nextComma.remove();545 }546 547 handleBubbleChange();548}549 550function emphasizeBubble(event) {551 const bubble = event.target.closest('.bubble');552 const bubbleText = bubble.querySelector('.bubble-text');553 const text = bubbleText.innerText.trim();554 555 if (text.startsWith('[') && text.endsWith(']')) {556 bubbleText.innerText = text.slice(1, -1);557 } else {558 bubbleText.innerText = `(${text})`;559 }560 561 handleBubbleChange();562}563 564function mitigateBubble(event) {565 const bubble = event.target.closest('.bubble');566 const bubbleText = bubble.querySelector('.bubble-text');567 const text = bubbleText.innerText.trim();568 569 if (text.startsWith('(') && text.endsWith(')')) {570 bubbleText.innerText = text.slice(1, -1);571 } else {572 bubbleText.innerText = `[${text}]`;573 }574 575 handleBubbleChange();576}577 578document.addEventListener('DOMContentLoaded', function() {579 let words = [];580 let categoriesData = {};581 582 // Datos de respaldo583 const backupData = {584 'Composition and Style': {585 'Style': [586 {587 type: 'subcategory',588 name: 'Classic',589 items: [590 { type: 'word', name: 'Elegant' },591 { type: 'word', name: 'Traditional' }592 ]593 },594 {595 type: 'subcategory',596 name: 'Modern',597 items: [598 { type: 'word', name: 'Sleek' },599 { type: 'word', name: 'Minimalist' }600 ]601 }602 ],603 'Composition': [604 { type: 'word', name: 'Balanced' },605 { type: 'word', name: 'Dynamic' }606 ]607 },608 'Body': {609 'Head': [610 {611 type: 'subcategory',612 name: 'Facial Features',613 items: [614 { type: 'word', name: 'Eyes' },615 { type: 'word', name: 'Nose' }616 ]617 },618 {619 type: 'subcategory',620 name: 'Hair',621 items: [622 { type: 'word', name: 'Curly' },623 { type: 'word', name: 'Straight' }624 ]625 }626 ],627 'Torso': [628 { type: 'word', name: 'Chest' },629 { type: 'word', name: 'Back' }630 ]631 }632 };633 634 // Archivos CSV a cargar635 const csvFiles = [636 'Composition.csv',637 'Body.csv',638 'Clothes.csv',639 'Activity.csv',640 'Objects.csv',641 'Creatures.csv',642 'Plants.csv',643 'World.csv',644 'NSFW.csv',645 'More.csv'646 ];647 648 const categoryEmojis = {649 'Composition': '🖼️',650 'Body': '🧏🏻♀️',651 'Clothes': '👒',652 'Activity': '🤺',653 'Objects': '🎸',654 'Creatures': '🐈',655 'Plants': '☘️',656 'World': '🌍',657 'NSFW': '🍑',658 'More': '📚'659 };660 661 const categoryDropdownButton = document.getElementById('category-dropdown-button');662 const categoryDropdown = document.getElementById('category-dropdown');663 const randomWordButton = document.getElementById('random-word-button');664 665 categoryDropdownButton.addEventListener('click', toggleCategoryDropdown);666 randomWordButton.addEventListener('click', addRandomWordToInput);667 document.addEventListener('click', closeDropdownOutsideClick);668 669 function toggleCategoryDropdown() {670 categoryDropdown.classList.toggle('hidden');671 }672 673 function closeDropdownOutsideClick(event) {674 if (!categoryDropdown.contains(event.target) && event.target !== categoryDropdownButton) {675 categoryDropdown.classList.add('hidden');676 }677 }678 679 async function loadCSVFiles() {680 for (const file of csvFiles) {681 try {682 const response = await fetch(file);683 if (!response.ok) throw new Error(`Error al cargar ${file}`);684 const text = await response.text();685 processCSVData(file.split('.csv')[0], text);686 } catch (error) {687 console.error(error);688 // Usa datos de respaldo en caso de error689 const categoryName = file.split('.csv')[0];690 if (backupData[categoryName]) {691 categoriesData[categoryName] = backupData[categoryName];692 }693 }694 }695 696 renderCategories();697 populateWordsForAutocomplete();698 }699 700 function processCSVData(categoryName, csvText) {701 const lines = csvText.split('\n').map(line => line.trim()).filter(line => line.length > 0);702 const headers = lines[0].split(',');703 704 if (!categoriesData[categoryName]) {705 categoriesData[categoryName] = {};706 }707 708 headers.forEach((header, index) => {709 if (!categoriesData[categoryName][header]) {710 categoriesData[categoryName][header] = [];711 }712 713 let currentSubcategory = null;714 let currentSubSubcategory = null;715 716 for (let i = 1; i < lines.length; i++) {717 const wordsInLine = lines[i].split(',');718 const word = wordsInLine[index].trim();719 720 if (word) {721 // Si la palabra tiene una celda vacía directamente sobre ella en la misma columna722 if (i > 1 && lines[i - 1].split(',')[index].trim() === '') {723 if (currentSubcategory) {724 currentSubSubcategory = { type: 'subsubcategory', name: word, items: [] };725 currentSubcategory.items.push(currentSubSubcategory);726 } else {727 currentSubcategory = { type: 'subcategory', name: word, items: [] };728 categoriesData[categoryName][header].push(currentSubcategory);729 }730 } else if (currentSubSubcategory) {731 currentSubSubcategory.items.push({ type: 'word', name: word });732 } else if (currentSubcategory) {733 currentSubcategory.items.push({ type: 'word', name: word });734 } else {735 categoriesData[categoryName][header].push({ type: 'word', name: word });736 }737 } else {738 if (currentSubSubcategory) {739 currentSubSubcategory = null;740 } else {741 currentSubcategory = null;742 }743 }744 }745 });746 }747 748 function renderCategories() {749 categoryDropdown.innerHTML = '';750 751 for (const [categoryName, subcategories] of Object.entries(categoriesData)) {752 const categoryItem = document.createElement('div');753 categoryItem.classList.add('category-item');754 755 const emojiSpan = document.createElement('span');756 emojiSpan.classList.add('category-emoji');757 emojiSpan.innerText = categoryEmojis[categoryName] || '';758 759 const nameSpan = document.createElement('span');760 nameSpan.innerText = categoryName;761 762 categoryItem.appendChild(emojiSpan);763 categoryItem.appendChild(nameSpan);764 765 categoryItem.addEventListener('click', () => toggleSubcategory(categoryItem, subcategories));766 categoryDropdown.appendChild(categoryItem);767 }768 }769 770 function toggleSubcategory(categoryItem, subcategories) {771 if (categoryItem.nextElementSibling && categoryItem.nextElementSibling.classList.contains('subcategory-container')) {772 categoryItem.nextElementSibling.remove();773 } else {774 const subcategoryContainer = document.createElement('div');775 subcategoryContainer.classList.add('subcategory-container');776 777 for (const [subcategoryName, items] of Object.entries(subcategories)) {778 const subcategoryItem = document.createElement('div');779 subcategoryItem.classList.add('subcategory-item');780 subcategoryItem.innerText = subcategoryName;781 782 // Crear botón para añadir palabra aleatoria783 const randomButton = document.createElement('button');784 randomButton.innerText = '🎲';785 randomButton.classList.add('random-word-button');786 randomButton.addEventListener('click', (e) => {787 e.stopPropagation();788 addRandomWordFromSubcategory(items);789 handleTextChange();790 });791 792 subcategoryItem.appendChild(randomButton);793 subcategoryItem.addEventListener('click', (e) => {794 e.stopPropagation();795 toggleItems(subcategoryItem, items);796 });797 subcategoryContainer.appendChild(subcategoryItem);798 }799 800 categoryItem.insertAdjacentElement('afterend', subcategoryContainer);801 }802 }803 804 function toggleItems(subcategoryItem, items) {805 if (subcategoryItem.nextElementSibling && subcategoryItem.nextElementSibling.classList.contains('item-container')) {806 subcategoryItem.nextElementSibling.remove();807 } else {808 const itemContainer = document.createElement('div');809 itemContainer.classList.add('item-container');810 811 items.forEach(item => {812 const itemElement = document.createElement('div');813 itemElement.classList.add(item.type === 'subcategory' || item.type === 'subsubcategory' ? 'subcategory-item' : 'word-item');814 itemElement.innerText = item.name;815 816 // Si es subcategoría o sub-subcategoría, añadir botón de palabra aleatoria817 if (item.type === 'subcategory' || item.type === 'subsubcategory') {818 const randomButton = document.createElement('button');819 randomButton.innerText = '🎲';820 randomButton.classList.add('random-word-button');821 randomButton.addEventListener('click', (e) => {822 e.stopPropagation();823 addRandomWordFromSubcategory(item.items);824 handleTextChange();825 });826 827 itemElement.appendChild(randomButton);828 }829 830 if (item.type === 'subcategory' || item.type === 'subsubcategory') {831 itemElement.addEventListener('click', (e) => {832 e.stopPropagation();833 toggleItems(itemElement, item.items);834 });835 } else {836 itemElement.addEventListener('click', () => addItemToInput(item.name));837 }838 839 itemContainer.appendChild(itemElement);840 });841 842 subcategoryItem.insertAdjacentElement('afterend', itemContainer);843 }844 }845 846 function addItemToInput(word) {847 const inputText = document.getElementById('input-text');848 inputText.value += (inputText.value ? ', ' : '') + word;849 updateBubbles();850 }851 852 function populateWordsForAutocomplete() {853 words = [];854 for (const category of Object.values(categoriesData)) {855 for (const subcategory of Object.values(category)) {856 for (const item of subcategory) {857 if (item.type === 'word') {858 words.push(item.name);859 } else if (item.type === 'subcategory' || item.type === 'subsubcategory') {860 item.items.forEach(subItem => {861 if (subItem.type === 'word') {862 words.push(subItem.name);863 }864 });865 }866 }867 }868 }869 console.log('Palabras cargadas para autocompletador:', words);870 }871 872 function addRandomWordToInput() {873 if (words.length === 0) return;874 const randomWord = words[Math.floor(Math.random() * words.length)];875 addItemToInput(randomWord);876 }877 878 function addRandomWordFromSubcategory(subcategoryItems) {879 const subcategoryWords = subcategoryItems.flatMap(item => item.type === 'word' ? [item.name] : item.items.map(subItem => subItem.name));880 if (subcategoryWords.length === 0) return;881 const randomWord = subcategoryWords[Math.floor(Math.random() * subcategoryWords.length)];882 addItemToInput(randomWord);883 }884 885 const input = document.getElementById('autocomplete-input');886 const autocompleteList = document.getElementById('autocomplete-list');887 888 // Función que maneja tanto el evento de 'input' como de 'focus'889 function handleAutocomplete() {890 const value = input.value.toLowerCase();891 console.log('Valor de entrada:', value); // Verifica el valor de entrada892 893 if (!value) {894 autocompleteList.innerHTML = '';895 return;896 }897 898 // Filtra y ordena las palabras que empiezan con el valor ingresado, sin distinguir mayúsculas899 const startsWith = words900 .filter(word => word.toLowerCase().startsWith(value))901 .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));902 903 // Filtra y ordena las palabras que contienen el valor ingresado pero no empiezan con él, sin distinguir mayúsculas904 const contains = words905 .filter(word => word.toLowerCase().includes(value) && !word.toLowerCase().startsWith(value))906 .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));907 908 // Crear un conjunto para filtrar palabras únicas909 const uniqueSuggestions = new Set([...startsWith, ...contains]);910 911 // Convertir el conjunto a un array y tomar las primeras 20 sugerencias912 const suggestions = Array.from(uniqueSuggestions).slice(0, 20);913 914 console.log('Sugerencias encontradas:', suggestions); // Verifica las sugerencias encontradas915 916 autocompleteList.innerHTML = suggestions.map(suggestion => `<div>${suggestion}</div>`).join('');917 918 autocompleteList.querySelectorAll('div').forEach(item => {919 item.addEventListener('click', function() {920 const selectedWord = this.textContent;921 const inputText = document.getElementById('input-text');922 inputText.value += (inputText.value ? ', ' : '') + selectedWord;923 updateBubbles();924 input.value = ''; // Limpia el campo de autocompletado925 autocompleteList.innerHTML = ''; // Limpia las sugerencias926 input.focus(); // Enfoca el campo de autocompletado927 });928 });929 }930 931 // Escucha tanto al evento de 'input' como al de 'focus'932 input.addEventListener('input', handleAutocomplete);933 input.addEventListener('focus', handleAutocomplete);934 935 document.addEventListener('click', function(event) {936 if (event.target !== input) {937 autocompleteList.innerHTML = '';938 handleTextChange();939 }940 });941 942 loadCSVFiles();943});