Spaces:
Running
Running
| const inputText = document.getElementById('input-text'); | |
| const bubbleContainer = document.getElementById('bubble-container'); | |
| const replaceSpacesButton = document.getElementById('replace-spaces-button'); | |
| const replaceUnderscoreButton = document.getElementById('replace-underscore-button'); | |
| const revertUnderscoreButton = document.getElementById('revert-underscore-button'); | |
| const replaceLineBreaksButton = document.getElementById('replace-linebreaks-button'); | |
| const replaceCommasButton = document.getElementById('replace-commas-button'); | |
| const removeDuplicatesButton = document.getElementById('remove-duplicates-button'); | |
| const revertSpacesButton = document.getElementById('revert-spaces-button'); | |
| const copyButton = document.getElementById('copy-button'); | |
| const undoButton = document.getElementById('undo-button'); | |
| const redoButton = document.getElementById('redo-button'); | |
| const deleteModeButton = document.getElementById('delete-mode-button'); | |
| const emphasisModeButton = document.getElementById('emphasis-mode-button'); | |
| const mitigateModeButton = document.getElementById('mitigate-mode-button'); | |
| const literalParenthesisButton = document.getElementById('literal-parenthesis-button'); | |
| const fictionalParenthesisButton = document.getElementById('fictional-parenthesis-button'); | |
| const bubbleColors = {}; | |
| let history = []; | |
| let historyIndex = -1; | |
| let deleteModeEnabled = false; | |
| let emphasisModeEnabled = false; | |
| let mitigateModeEnabled = false; | |
| inputText.addEventListener('input', handleTextChange); | |
| replaceSpacesButton.addEventListener('click', replaceSpaces); | |
| replaceUnderscoreButton.addEventListener('click', replaceUnderscores); | |
| revertUnderscoreButton.addEventListener('click', revertUnderscores); | |
| replaceLineBreaksButton.addEventListener('click', replaceLineBreaks); | |
| replaceCommasButton.addEventListener('click', replaceCommas); | |
| removeDuplicatesButton.addEventListener('click', removeDuplicates); | |
| revertSpacesButton.addEventListener('click', revertSpaces); | |
| copyButton.addEventListener('click', copyToClipboard); | |
| undoButton.addEventListener('click', undoChanges); | |
| redoButton.addEventListener('click', redoChanges); | |
| deleteModeButton.addEventListener('click', toggleDeleteMode); | |
| emphasisModeButton.addEventListener('click', toggleEmphasisMode); | |
| mitigateModeButton.addEventListener('click', toggleMitigateMode); | |
| literalParenthesisButton.addEventListener('click', literalParenthesis); | |
| fictionalParenthesisButton.addEventListener('click', fictionalParenthesis); | |
| const sortable = new Sortable(bubbleContainer, { | |
| animation: 250, | |
| ghostClass: 'ghost', | |
| onEnd: handleBubbleChange, | |
| disabled: deleteModeEnabled || emphasisModeEnabled || mitigateModeEnabled | |
| }); | |
| function handleTextChange() { | |
| const text = inputText.value; | |
| if (history.length === 0) { | |
| history.push(''); | |
| historyIndex++; | |
| } | |
| if (text !== history[historyIndex]) { | |
| if (historyIndex < history.length - 1) { | |
| history.splice(historyIndex + 1); | |
| } | |
| history.push(text); | |
| historyIndex++; | |
| updateBubbles(); | |
| updateButtonStates(); | |
| } | |
| } | |
| function handleBubbleChange() { | |
| const conceptList = Array.from(bubbleContainer.getElementsByClassName('bubble')).map(bubble => bubble.textContent.trim()); | |
| inputText.value = conceptList.join(', '); | |
| handleTextChange(); | |
| } | |
| function updateBubbles() { | |
| bubbleContainer.innerHTML = ''; | |
| const text = inputText.value.trim(); | |
| if (text === '') return; | |
| const concepts = text.split(', '); | |
| concepts.forEach(concept => { | |
| const bubble = createBubble(concept); | |
| bubbleContainer.appendChild(bubble); | |
| }); | |
| } | |
| function createBubble(text) { | |
| const bubble = document.createElement('div'); | |
| bubble.classList.add('bubble'); | |
| if (!bubbleColors.hasOwnProperty(text)) { | |
| bubbleColors[text] = getRandomColor(); | |
| } | |
| bubble.style.backgroundColor = bubbleColors[text]; | |
| const bubbleText = document.createElement('span'); | |
| bubbleText.classList.add('bubble-text'); | |
| bubbleText.innerText = text; | |
| bubble.appendChild(bubbleText); | |
| if (deleteModeEnabled) { | |
| bubble.classList.add('delete-mode'); | |
| bubble.addEventListener('click', deleteBubble); | |
| } | |
| if (emphasisModeEnabled) { | |
| bubble.classList.add('emphasis-mode'); | |
| bubble.addEventListener('click', emphasizeBubble); | |
| } | |
| if (mitigateModeEnabled) { | |
| bubble.classList.add('mitigate-mode'); | |
| bubble.addEventListener('click', mitigateBubble); | |
| } | |
| return bubble; | |
| } | |
| function getRandomColor() { | |
| const h = Math.floor(Math.random() * 360); | |
| const s = Math.floor(Math.random() * 30) + 50; | |
| const l = Math.floor(Math.random() * 40) + 30; | |
| return `hsl(${h}, ${s}%, ${l}%)`; | |
| } | |
| function updateButtonStates() { | |
| undoButton.disabled = historyIndex === 0; | |
| redoButton.disabled = historyIndex === history.length - 1; | |
| } | |
| function replaceSpaces() { | |
| let text = inputText.value; | |
| text = text.replace(/,(\S)/g, ', $1'); | |
| text = text.replace(/ {2,}/g, ' '); | |
| text = text.replace(/([^,])\s+/g, '$1, '); | |
| inputText.value = text; | |
| handleTextChange(); | |
| } | |
| function revertSpaces() { | |
| const text = inputText.value; | |
| const replacedText = text.replace(/, /g, ' '); | |
| inputText.value = replacedText; | |
| handleTextChange(); | |
| } | |
| function replaceUnderscores() { | |
| const text = inputText.value; | |
| const replacedText = text.replace(/_/g, ' '); | |
| inputText.value = replacedText; | |
| handleTextChange(); | |
| } | |
| function revertUnderscores() { | |
| const text = inputText.value; | |
| const replacedText = text.replace(/([^,]) /g, '$1_'); | |
| inputText.value = replacedText; | |
| handleTextChange(); | |
| } | |
| function replaceLineBreaks() { | |
| const text = inputText.value; | |
| const replacedText = text.replace(/\n/g, ', '); | |
| inputText.value = replacedText; | |
| handleTextChange(); | |
| } | |
| function replaceCommas() { | |
| const text = inputText.value; | |
| const step1 = text.replace(/,,/g, ','); | |
| const step2 = step1.replace(/, ,/g, ', '); | |
| const step3 = step2.trimRight(); | |
| const step4 = step3.replace(/,$/, ''); | |
| const step5 = step4.replace(/^,/, ''); | |
| const step6 = step5.replace(/, /g, ', '); | |
| const replacedText = step6.replace(/^ /, ''); | |
| inputText.value = replacedText; | |
| handleTextChange(); | |
| } | |
| function removeDuplicates() { | |
| const text = inputText.value; | |
| const concepts = text.split(', '); | |
| const uniqueConcepts = [...new Set(concepts)]; | |
| inputText.value = uniqueConcepts.join(', '); | |
| handleTextChange(); | |
| } | |
| function copyToClipboard() { | |
| inputText.select(); | |
| inputText.setSelectionRange(0, 99999); | |
| document.execCommand('copy'); | |
| } | |
| function literalParenthesis() { | |
| const inputText = document.getElementById('input-text'); | |
| const text = inputText.value; | |
| // Reemplazar ' (' que no estén precedidos por una ',' y el paréntesis de cierre siguiente más cercano | |
| let replacedText = text.replace(/([^,]) \((.*?)\)/g, '$1 \\($2\\)'); | |
| // Reemplazar '_(' y el paréntesis de cierre siguiente más cercano | |
| replacedText = replacedText.replace(/_\((.*?)\)/g, '_\\($1\\)'); | |
| inputText.value = replacedText; | |
| handleTextChange(); | |
| } | |
| function fictionalParenthesis() { | |
| const inputText = document.getElementById('input-text'); | |
| const text = inputText.value; | |
| // Reemplazar '\(' por '(' | |
| let replacedText = text.replace(/\\\(/g, '('); | |
| // Reemplazar '\)' por ')' | |
| replacedText = replacedText.replace(/\\\)/g, ')'); | |
| inputText.value = replacedText; | |
| handleTextChange(); | |
| } | |
| document.getElementById('download-text-file-button').addEventListener('click', showFilenameInput); | |
| function showFilenameInput() { | |
| const inputText = document.getElementById('input-text').value; | |
| const currentDate = new Date(); | |
| const year = currentDate.getFullYear(); | |
| const month = String(currentDate.getMonth() + 1).padStart(2, '0'); | |
| const day = String(currentDate.getDate()).padStart(2, '0'); | |
| const hours = String(currentDate.getHours()).padStart(2, '0'); | |
| const minutes = String(currentDate.getMinutes()).padStart(2, '0'); | |
| const formattedDate = `${year}-${month}-${day}_${hours}-${minutes}`; | |
| const defaultFileName = `Bubble Prompter_${formattedDate}.txt`; | |
| let container = document.getElementById('custom-filename-container'); | |
| if (!container) { | |
| container = document.createElement('div'); | |
| container.id = 'custom-filename-container'; | |
| document.body.appendChild(container); | |
| const input = document.createElement('input'); | |
| input.type = 'text'; | |
| input.id = 'custom-filename'; | |
| container.appendChild(input); | |
| const confirmButton = document.createElement('button'); | |
| confirmButton.innerText = '✅'; | |
| confirmButton.classList.add('confirm-button'); // Agregar clase | |
| confirmButton.addEventListener('click', downloadTextFile); | |
| container.appendChild(confirmButton); | |
| const cancelButton = document.createElement('button'); | |
| cancelButton.innerText = '❌'; | |
| cancelButton.classList.add('cancel-button'); // Agregar clase | |
| cancelButton.addEventListener('click', hideFilenameInput); | |
| container.appendChild(cancelButton); | |
| document.addEventListener('click', function(event) { | |
| if (!container.contains(event.target) && event.target !== document.getElementById('download-text-file-button')) { | |
| hideFilenameInput(); | |
| } | |
| }); | |
| input.addEventListener('keydown', function(event) { | |
| if (event.key === 'Enter') { | |
| downloadTextFile(); | |
| } | |
| }); | |
| } | |
| container.style.display = 'block'; | |
| container.style.top = `${document.getElementById('download-text-file-button').offsetTop + document.getElementById('download-text-file-button').offsetHeight}px`; | |
| container.style.left = `${document.getElementById('download-text-file-button').offsetLeft}px`; | |
| const input = document.getElementById('custom-filename'); | |
| input.value = defaultFileName; | |
| input.select(); | |
| input.focus(); | |
| } | |
| function hideFilenameInput() { | |
| const container = document.getElementById('custom-filename-container'); | |
| if (container) { | |
| container.style.display = 'none'; | |
| } | |
| } | |
| function downloadTextFile() { | |
| const inputText = document.getElementById('input-text').value; | |
| let customFilename = document.getElementById('custom-filename').value.trim(); | |
| // Añadir .txt si no está presente | |
| if (!customFilename.endsWith('.txt')) { | |
| customFilename += '.txt'; | |
| } | |
| const fileName = customFilename ? customFilename : 'Bubble Prompter.txt'; | |
| const blob = new Blob([inputText], { type: 'text/plain' }); | |
| const link = document.createElement('a'); | |
| link.href = URL.createObjectURL(blob); | |
| link.download = fileName; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| hideFilenameInput(); | |
| } | |
| document.getElementById('load-text-file-button').addEventListener('click', loadTextFile); | |
| function loadTextFile() { | |
| const fileInput = document.createElement('input'); | |
| fileInput.type = 'file'; | |
| fileInput.accept = '.txt'; | |
| fileInput.addEventListener('change', (event) => { | |
| const file = event.target.files[0]; | |
| if (file) { | |
| const reader = new FileReader(); | |
| reader.onload = (e) => { | |
| const inputText = document.getElementById('input-text'); | |
| let currentText = inputText.value; | |
| // Añadir una coma y un espacio si el campo de texto no está vacío | |
| if (currentText) { | |
| currentText += ', '; | |
| } | |
| // Añadir el contenido del archivo | |
| inputText.value = currentText + e.target.result; | |
| handleTextChange(); | |
| }; | |
| reader.readAsText(file); | |
| } | |
| }); | |
| // Simular un clic en el input de archivo para abrir el cuadro de diálogo de archivo | |
| fileInput.click(); | |
| } | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const inputText = document.getElementById('input-text'); | |
| // Evitar comportamiento por defecto de arrastrar y soltar | |
| ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { | |
| inputText.addEventListener(eventName, preventDefaults, false); | |
| document.body.addEventListener(eventName, preventDefaults, false); | |
| }); | |
| // Añadir clases para los estilos de arrastrar y soltar | |
| ['dragenter', 'dragover'].forEach(eventName => { | |
| inputText.addEventListener(eventName, () => inputText.classList.add('highlight'), false); | |
| }); | |
| ['dragleave', 'drop'].forEach(eventName => { | |
| inputText.addEventListener(eventName, () => inputText.classList.remove('highlight'), false); | |
| }); | |
| // Manejar el evento de soltar | |
| inputText.addEventListener('drop', handleDrop, false); | |
| function preventDefaults(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| } | |
| function handleDrop(e) { | |
| const dt = e.dataTransfer; | |
| const files = dt.files; | |
| if (files.length) { | |
| const file = files[0]; | |
| if (file.type === "text/plain") { | |
| const reader = new FileReader(); | |
| reader.onload = (e) => { | |
| let currentText = inputText.value; | |
| // Añadir una coma y un espacio si el campo de texto no está vacío | |
| if (currentText) { | |
| currentText += ', '; | |
| } | |
| // Añadir el contenido del archivo | |
| inputText.value = currentText + e.target.result; | |
| handleTextChange(); | |
| }; | |
| reader.readAsText(file); | |
| } else { | |
| alert("Please drop a valid .txt file."); | |
| } | |
| } | |
| } | |
| }); | |
| function undoChanges() { | |
| if (historyIndex > 0) { | |
| historyIndex--; | |
| inputText.value = history[historyIndex]; | |
| updateBubbles(); | |
| updateButtonStates(); | |
| } | |
| } | |
| function redoChanges() { | |
| if (historyIndex < history.length - 1) { | |
| historyIndex++; | |
| inputText.value = history[historyIndex]; | |
| updateBubbles(); | |
| updateButtonStates(); | |
| } | |
| } | |
| function toggleDeleteMode() { | |
| deleteModeEnabled = !deleteModeEnabled; | |
| deleteModeButton.classList.toggle('active'); | |
| if (deleteModeEnabled) { | |
| emphasisModeEnabled = false; | |
| emphasisModeButton.classList.remove('active'); | |
| mitigateModeEnabled = false; | |
| mitigateModeButton.classList.remove('active'); | |
| } | |
| sortable.option('disabled', deleteModeEnabled); | |
| bubbleContainer.classList.toggle('delete-mode-container'); | |
| const bubbles = bubbleContainer.getElementsByClassName('bubble'); | |
| for (let i = 0; i < bubbles.length; i++) { | |
| const bubble = bubbles[i]; | |
| bubble.classList.remove('emphasis-mode'); | |
| bubble.classList.remove('mitigate-mode'); | |
| if (deleteModeEnabled) { | |
| bubble.classList.add('delete-mode'); | |
| bubble.removeEventListener('click', emphasizeBubble); | |
| bubble.removeEventListener('click', mitigateBubble); | |
| bubble.addEventListener('click', deleteBubble); | |
| } else { | |
| bubble.classList.remove('delete-mode'); | |
| bubble.removeEventListener('click', deleteBubble); | |
| } | |
| } | |
| } | |
| function toggleEmphasisMode() { | |
| emphasisModeEnabled = !emphasisModeEnabled; | |
| emphasisModeButton.classList.toggle('active'); | |
| if (emphasisModeEnabled) { | |
| deleteModeEnabled = false; | |
| deleteModeButton.classList.remove('active'); | |
| mitigateModeEnabled = false; | |
| mitigateModeButton.classList.remove('active'); | |
| } | |
| sortable.option('disabled', emphasisModeEnabled); | |
| bubbleContainer.classList.toggle('emphasis-mode-container'); | |
| const bubbles = bubbleContainer.getElementsByClassName('bubble'); | |
| for (let i = 0; i < bubbles.length; i++) { | |
| const bubble = bubbles[i]; | |
| bubble.classList.remove('delete-mode'); | |
| bubble.classList.remove('mitigate-mode'); | |
| if (emphasisModeEnabled) { | |
| bubble.classList.add('emphasis-mode'); | |
| bubble.removeEventListener('click', deleteBubble); | |
| bubble.removeEventListener('click', mitigateBubble); | |
| bubble.addEventListener('click', emphasizeBubble); | |
| } else { | |
| bubble.classList.remove('emphasis-mode'); | |
| bubble.removeEventListener('click', emphasizeBubble); | |
| } | |
| } | |
| } | |
| function toggleMitigateMode() { | |
| mitigateModeEnabled = !mitigateModeEnabled; | |
| mitigateModeButton.classList.toggle('active'); | |
| if (mitigateModeEnabled) { | |
| deleteModeEnabled = false; | |
| deleteModeButton.classList.remove('active'); | |
| emphasisModeEnabled = false; | |
| emphasisModeButton.classList.remove('active'); | |
| } | |
| sortable.option('disabled', mitigateModeEnabled); | |
| bubbleContainer.classList.toggle('mitigate-mode-container'); | |
| const bubbles = bubbleContainer.getElementsByClassName('bubble'); | |
| for (let i = 0; i < bubbles.length; i++) { | |
| const bubble = bubbles[i]; | |
| bubble.classList.remove('delete-mode'); | |
| bubble.classList.remove('emphasis-mode'); | |
| if (mitigateModeEnabled) { | |
| bubble.classList.add('mitigate-mode'); | |
| bubble.removeEventListener('click', deleteBubble); | |
| bubble.removeEventListener('click', emphasizeBubble); | |
| bubble.addEventListener('click', mitigateBubble); | |
| } else { | |
| bubble.classList.remove('mitigate-mode'); | |
| bubble.removeEventListener('click', mitigateBubble); | |
| } | |
| } | |
| } | |
| function deleteBubble(event) { | |
| const bubble = event.target.closest('.bubble'); | |
| const bubbleText = bubble.querySelector('.bubble-text'); | |
| const nextComma = bubbleText.nextSibling; | |
| bubble.remove(); | |
| if (nextComma && nextComma.nodeType === Node.TEXT_NODE && nextComma.textContent.trim() === ',') { | |
| nextComma.remove(); | |
| } | |
| handleBubbleChange(); | |
| } | |
| function emphasizeBubble(event) { | |
| const bubble = event.target.closest('.bubble'); | |
| const bubbleText = bubble.querySelector('.bubble-text'); | |
| const text = bubbleText.innerText.trim(); | |
| if (text.startsWith('[') && text.endsWith(']')) { | |
| bubbleText.innerText = text.slice(1, -1); | |
| } else { | |
| bubbleText.innerText = `(${text})`; | |
| } | |
| handleBubbleChange(); | |
| } | |
| function mitigateBubble(event) { | |
| const bubble = event.target.closest('.bubble'); | |
| const bubbleText = bubble.querySelector('.bubble-text'); | |
| const text = bubbleText.innerText.trim(); | |
| if (text.startsWith('(') && text.endsWith(')')) { | |
| bubbleText.innerText = text.slice(1, -1); | |
| } else { | |
| bubbleText.innerText = `[${text}]`; | |
| } | |
| handleBubbleChange(); | |
| } | |
| document.addEventListener('DOMContentLoaded', function() { | |
| let words = []; | |
| let categoriesData = {}; | |
| // Datos de respaldo | |
| const backupData = { | |
| 'Composition and Style': { | |
| 'Style': [ | |
| { | |
| type: 'subcategory', | |
| name: 'Classic', | |
| items: [ | |
| { type: 'word', name: 'Elegant' }, | |
| { type: 'word', name: 'Traditional' } | |
| ] | |
| }, | |
| { | |
| type: 'subcategory', | |
| name: 'Modern', | |
| items: [ | |
| { type: 'word', name: 'Sleek' }, | |
| { type: 'word', name: 'Minimalist' } | |
| ] | |
| } | |
| ], | |
| 'Composition': [ | |
| { type: 'word', name: 'Balanced' }, | |
| { type: 'word', name: 'Dynamic' } | |
| ] | |
| }, | |
| 'Body': { | |
| 'Head': [ | |
| { | |
| type: 'subcategory', | |
| name: 'Facial Features', | |
| items: [ | |
| { type: 'word', name: 'Eyes' }, | |
| { type: 'word', name: 'Nose' } | |
| ] | |
| }, | |
| { | |
| type: 'subcategory', | |
| name: 'Hair', | |
| items: [ | |
| { type: 'word', name: 'Curly' }, | |
| { type: 'word', name: 'Straight' } | |
| ] | |
| } | |
| ], | |
| 'Torso': [ | |
| { type: 'word', name: 'Chest' }, | |
| { type: 'word', name: 'Back' } | |
| ] | |
| } | |
| }; | |
| // Archivos CSV a cargar | |
| const csvFiles = [ | |
| 'Composition.csv', | |
| 'Body.csv', | |
| 'Clothes.csv', | |
| 'Activity.csv', | |
| 'Objects.csv', | |
| 'Creatures.csv', | |
| 'Plants.csv', | |
| 'World.csv', | |
| 'NSFW.csv', | |
| 'More.csv' | |
| ]; | |
| const categoryEmojis = { | |
| 'Composition': '🖼️', | |
| 'Body': '🧏🏻♀️', | |
| 'Clothes': '👒', | |
| 'Activity': '🤺', | |
| 'Objects': '🎸', | |
| 'Creatures': '🐈', | |
| 'Plants': '☘️', | |
| 'World': '🌍', | |
| 'NSFW': '🍑', | |
| 'More': '📚' | |
| }; | |
| const categoryDropdownButton = document.getElementById('category-dropdown-button'); | |
| const categoryDropdown = document.getElementById('category-dropdown'); | |
| const randomWordButton = document.getElementById('random-word-button'); | |
| categoryDropdownButton.addEventListener('click', toggleCategoryDropdown); | |
| randomWordButton.addEventListener('click', addRandomWordToInput); | |
| document.addEventListener('click', closeDropdownOutsideClick); | |
| function toggleCategoryDropdown() { | |
| categoryDropdown.classList.toggle('hidden'); | |
| } | |
| function closeDropdownOutsideClick(event) { | |
| if (!categoryDropdown.contains(event.target) && event.target !== categoryDropdownButton) { | |
| categoryDropdown.classList.add('hidden'); | |
| } | |
| } | |
| async function loadCSVFiles() { | |
| for (const file of csvFiles) { | |
| try { | |
| const response = await fetch(file); | |
| if (!response.ok) throw new Error(`Error al cargar ${file}`); | |
| const text = await response.text(); | |
| processCSVData(file.split('.csv')[0], text); | |
| } catch (error) { | |
| console.error(error); | |
| // Usa datos de respaldo en caso de error | |
| const categoryName = file.split('.csv')[0]; | |
| if (backupData[categoryName]) { | |
| categoriesData[categoryName] = backupData[categoryName]; | |
| } | |
| } | |
| } | |
| renderCategories(); | |
| populateWordsForAutocomplete(); | |
| } | |
| function processCSVData(categoryName, csvText) { | |
| const lines = csvText.split('\n').map(line => line.trim()).filter(line => line.length > 0); | |
| const headers = lines[0].split(','); | |
| if (!categoriesData[categoryName]) { | |
| categoriesData[categoryName] = {}; | |
| } | |
| headers.forEach((header, index) => { | |
| if (!categoriesData[categoryName][header]) { | |
| categoriesData[categoryName][header] = []; | |
| } | |
| let currentSubcategory = null; | |
| let currentSubSubcategory = null; | |
| for (let i = 1; i < lines.length; i++) { | |
| const wordsInLine = lines[i].split(','); | |
| const word = wordsInLine[index].trim(); | |
| if (word) { | |
| // Si la palabra tiene una celda vacía directamente sobre ella en la misma columna | |
| if (i > 1 && lines[i - 1].split(',')[index].trim() === '') { | |
| if (currentSubcategory) { | |
| currentSubSubcategory = { type: 'subsubcategory', name: word, items: [] }; | |
| currentSubcategory.items.push(currentSubSubcategory); | |
| } else { | |
| currentSubcategory = { type: 'subcategory', name: word, items: [] }; | |
| categoriesData[categoryName][header].push(currentSubcategory); | |
| } | |
| } else if (currentSubSubcategory) { | |
| currentSubSubcategory.items.push({ type: 'word', name: word }); | |
| } else if (currentSubcategory) { | |
| currentSubcategory.items.push({ type: 'word', name: word }); | |
| } else { | |
| categoriesData[categoryName][header].push({ type: 'word', name: word }); | |
| } | |
| } else { | |
| if (currentSubSubcategory) { | |
| currentSubSubcategory = null; | |
| } else { | |
| currentSubcategory = null; | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| function renderCategories() { | |
| categoryDropdown.innerHTML = ''; | |
| for (const [categoryName, subcategories] of Object.entries(categoriesData)) { | |
| const categoryItem = document.createElement('div'); | |
| categoryItem.classList.add('category-item'); | |
| const emojiSpan = document.createElement('span'); | |
| emojiSpan.classList.add('category-emoji'); | |
| emojiSpan.innerText = categoryEmojis[categoryName] || ''; | |
| const nameSpan = document.createElement('span'); | |
| nameSpan.innerText = categoryName; | |
| categoryItem.appendChild(emojiSpan); | |
| categoryItem.appendChild(nameSpan); | |
| categoryItem.addEventListener('click', () => toggleSubcategory(categoryItem, subcategories)); | |
| categoryDropdown.appendChild(categoryItem); | |
| } | |
| } | |
| function toggleSubcategory(categoryItem, subcategories) { | |
| if (categoryItem.nextElementSibling && categoryItem.nextElementSibling.classList.contains('subcategory-container')) { | |
| categoryItem.nextElementSibling.remove(); | |
| } else { | |
| const subcategoryContainer = document.createElement('div'); | |
| subcategoryContainer.classList.add('subcategory-container'); | |
| for (const [subcategoryName, items] of Object.entries(subcategories)) { | |
| const subcategoryItem = document.createElement('div'); | |
| subcategoryItem.classList.add('subcategory-item'); | |
| subcategoryItem.innerText = subcategoryName; | |
| // Crear botón para añadir palabra aleatoria | |
| const randomButton = document.createElement('button'); | |
| randomButton.innerText = '🎲'; | |
| randomButton.classList.add('random-word-button'); | |
| randomButton.addEventListener('click', (e) => { | |
| e.stopPropagation(); | |
| addRandomWordFromSubcategory(items); | |
| handleTextChange(); | |
| }); | |
| subcategoryItem.appendChild(randomButton); | |
| subcategoryItem.addEventListener('click', (e) => { | |
| e.stopPropagation(); | |
| toggleItems(subcategoryItem, items); | |
| }); | |
| subcategoryContainer.appendChild(subcategoryItem); | |
| } | |
| categoryItem.insertAdjacentElement('afterend', subcategoryContainer); | |
| } | |
| } | |
| function toggleItems(subcategoryItem, items) { | |
| if (subcategoryItem.nextElementSibling && subcategoryItem.nextElementSibling.classList.contains('item-container')) { | |
| subcategoryItem.nextElementSibling.remove(); | |
| } else { | |
| const itemContainer = document.createElement('div'); | |
| itemContainer.classList.add('item-container'); | |
| items.forEach(item => { | |
| const itemElement = document.createElement('div'); | |
| itemElement.classList.add(item.type === 'subcategory' || item.type === 'subsubcategory' ? 'subcategory-item' : 'word-item'); | |
| itemElement.innerText = item.name; | |
| // Si es subcategoría o sub-subcategoría, añadir botón de palabra aleatoria | |
| if (item.type === 'subcategory' || item.type === 'subsubcategory') { | |
| const randomButton = document.createElement('button'); | |
| randomButton.innerText = '🎲'; | |
| randomButton.classList.add('random-word-button'); | |
| randomButton.addEventListener('click', (e) => { | |
| e.stopPropagation(); | |
| addRandomWordFromSubcategory(item.items); | |
| handleTextChange(); | |
| }); | |
| itemElement.appendChild(randomButton); | |
| } | |
| if (item.type === 'subcategory' || item.type === 'subsubcategory') { | |
| itemElement.addEventListener('click', (e) => { | |
| e.stopPropagation(); | |
| toggleItems(itemElement, item.items); | |
| }); | |
| } else { | |
| itemElement.addEventListener('click', () => addItemToInput(item.name)); | |
| } | |
| itemContainer.appendChild(itemElement); | |
| }); | |
| subcategoryItem.insertAdjacentElement('afterend', itemContainer); | |
| } | |
| } | |
| function addItemToInput(word) { | |
| const inputText = document.getElementById('input-text'); | |
| inputText.value += (inputText.value ? ', ' : '') + word; | |
| updateBubbles(); | |
| } | |
| function populateWordsForAutocomplete() { | |
| words = []; | |
| for (const category of Object.values(categoriesData)) { | |
| for (const subcategory of Object.values(category)) { | |
| for (const item of subcategory) { | |
| if (item.type === 'word') { | |
| words.push(item.name); | |
| } else if (item.type === 'subcategory' || item.type === 'subsubcategory') { | |
| item.items.forEach(subItem => { | |
| if (subItem.type === 'word') { | |
| words.push(subItem.name); | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| } | |
| console.log('Palabras cargadas para autocompletador:', words); | |
| } | |
| function addRandomWordToInput() { | |
| if (words.length === 0) return; | |
| const randomWord = words[Math.floor(Math.random() * words.length)]; | |
| addItemToInput(randomWord); | |
| } | |
| function addRandomWordFromSubcategory(subcategoryItems) { | |
| const subcategoryWords = subcategoryItems.flatMap(item => item.type === 'word' ? [item.name] : item.items.map(subItem => subItem.name)); | |
| if (subcategoryWords.length === 0) return; | |
| const randomWord = subcategoryWords[Math.floor(Math.random() * subcategoryWords.length)]; | |
| addItemToInput(randomWord); | |
| } | |
| const input = document.getElementById('autocomplete-input'); | |
| const autocompleteList = document.getElementById('autocomplete-list'); | |
| // Función que maneja tanto el evento de 'input' como de 'focus' | |
| function handleAutocomplete() { | |
| const value = input.value.toLowerCase(); | |
| console.log('Valor de entrada:', value); // Verifica el valor de entrada | |
| if (!value) { | |
| autocompleteList.innerHTML = ''; | |
| return; | |
| } | |
| // Filtra y ordena las palabras que empiezan con el valor ingresado, sin distinguir mayúsculas | |
| const startsWith = words | |
| .filter(word => word.toLowerCase().startsWith(value)) | |
| .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())); | |
| // Filtra y ordena las palabras que contienen el valor ingresado pero no empiezan con él, sin distinguir mayúsculas | |
| const contains = words | |
| .filter(word => word.toLowerCase().includes(value) && !word.toLowerCase().startsWith(value)) | |
| .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())); | |
| // Crear un conjunto para filtrar palabras únicas | |
| const uniqueSuggestions = new Set([...startsWith, ...contains]); | |
| // Convertir el conjunto a un array y tomar las primeras 20 sugerencias | |
| const suggestions = Array.from(uniqueSuggestions).slice(0, 20); | |
| console.log('Sugerencias encontradas:', suggestions); // Verifica las sugerencias encontradas | |
| autocompleteList.innerHTML = suggestions.map(suggestion => `<div>${suggestion}</div>`).join(''); | |
| autocompleteList.querySelectorAll('div').forEach(item => { | |
| item.addEventListener('click', function() { | |
| const selectedWord = this.textContent; | |
| const inputText = document.getElementById('input-text'); | |
| inputText.value += (inputText.value ? ', ' : '') + selectedWord; | |
| updateBubbles(); | |
| input.value = ''; // Limpia el campo de autocompletado | |
| autocompleteList.innerHTML = ''; // Limpia las sugerencias | |
| input.focus(); // Enfoca el campo de autocompletado | |
| }); | |
| }); | |
| } | |
| // Escucha tanto al evento de 'input' como al de 'focus' | |
| input.addEventListener('input', handleAutocomplete); | |
| input.addEventListener('focus', handleAutocomplete); | |
| document.addEventListener('click', function(event) { | |
| if (event.target !== input) { | |
| autocompleteList.innerHTML = ''; | |
| handleTextChange(); | |
| } | |
| }); | |
| loadCSVFiles(); | |
| }); |