Saltar al contenido

Cómo crear un buzón de sugerencias (cuadro de aviso en Javascript) dentro de un cuadro HTML con texto

Luego de de esta prolongada selección de datos resolvimos este apuro que tienen ciertos los usuarios. Te compartimos la solución y esperamos serte de gran ayuda.

Solución:

… sin embargo, no estoy seguro de si hay una manera de hacer clic en una palabra específica (podría haber más de una palabra en una oración), y también hay una manera de diseñar el cuadro de sugerencias y agregar una lista de palabras para elegir por haciendo clic en ellos.

Divida su problema en pasos. Esto le facilitará la comprensión del dominio del problema y el diseño de una solución. Por lo que pude deducir de su pregunta, los pasos generales y su implementación podrían ser como los que se describen a continuación.

Nota 1: La respuesta se basa en JavaScript puro. Recuerde que todos los marcos como jQuery, etc.son JavaScript solo abstraídos en un nivel superior. Es importante que primero aprenda JavaScript básico.

Nota 2: Proporcioné referencias de conceptos clave (para que pueda obtener más información y aprender de ellos) en forma de enlaces incrustados a lo largo de esta respuesta.

1) Configuración de marcado y JavaScript para palabras: Hay ciertas palabras que tienen sinónimos. Los sinónimos están disponibles en el propio marcado en el atributo de título. El marcado al que llegó está bien:

Margen:

I like apples. I like oranges.

Necesitamos poder identificar todas las palabras que llevan sinónimos, de modo que podamos usar Javascript para manipularlos. Estos se identifican en el marcado como i elementos con una clase llamada synonyms.

Javascript:

var words = [].slice.call(document.querySelectorAll('i.synonyms'));

querySelectorAll devuelve una lista de nodos, por lo que la forma más fácil de convertirlo en una matriz es llamar a slice en un prototipo de matriz. Necesitamos una matriz para poder iterarla más adelante.

2) Marcado y configuración de Javascript para el menú: Es necesario que aparezca un cuadro de sugerencias. Entonces, simplemente agregue un elemento que contenga sus sinónimos. Ya sabe que habrá una lista de sinónimos, por lo que semánticamente tiene sentido tener un elemento de lista. Y dale una identificación. Lo llenaremos dinámicamente más adelante.

Margen:

    Javascript:

    var menu = document.getElementById('synonymMenu');
    

    3) Debería aparecer el menú del buzón de sugerencias: cada vez que se hace clic en una palabra de este tipo. Por lo tanto, necesitamos agregar un detector de eventos en todas esas palabras que escucharán un evento de clic. Ya tenemos las palabras en la variable words en el paso uno anterior. Simplemente iteramos y agregamos el detector de eventos para ejecutar la función manageMenu. Definiremos esa función más adelante. Mientras estamos en eso, también almacenamos en caché la palabra existente en un atributo de datos para poder usarla más tarde, usando setAttribute.

    words.forEach(function(wrd) 
        wrd.setAttribute('data-word', wrd.textContent);
        wrd.addEventListener('click', manageMenu);
    );
    

    4) Reemplazar palabra con el sinónimo seleccionado: siempre que se haga clic en un sinónimo en el menú del buzón de sugerencias. Por lo tanto, también debemos agregar un detector de eventos de clic a la lista de sinónimos. Ya tenemos el menú almacenado en la variable menu en el paso 2 anterior. Simplemente agregue el oyente para ejecutar la función applySynonym. Definiremos esa función más adelante.

    menu.addEventListener('click', applySynonym);
    

    5) También tenemos que cerrar el buzón de sugerencias que cuelga: Podríamos hacer eso haciendo clic en cualquier parte del cuerpo. Simplemente agregue otro controlador de eventos de clic en el cuerpo. Ejecutar función toggleMenu con un hide parámetro. Definirá esta función más adelante.

    document.body.addEventListener('click', function() 
        toggleMenu('hide');
    );
    

    6) Cree una lista de sinónimos a partir del atributo title y muestre: en el menú del buzón de sugerencias, cuando se hace clic en la palabra. Que definiremos en el manageMenu función que declaramos en el paso 3. La explicación está en los comentarios del código.

    function manageMenu(e) ');
    
        // iterate array creating an li and anchor for each synonym
        // createElement creates a new element
        // appendChild adds an element to another
        synonyms.forEach(function(syn) 
            optn = document.createElement('li');
            link = document.createElement('a');
            link.setAttribute('href', '#'); link.textContent = syn;
            // add anchor to li, and the li to the menu
            optn.appendChild(link); menu.appendChild(optn);
        );
        // stop propagation of click, so that it doesn't go to body
        e.stopPropagation(); 
    
    

    Las referencias clave para usted en el código anterior se refieren al uso del objeto de evento y su objetivo, obtener la posición de la palabra en relación con la ventana gráfica, createElement, appendChild y stopPropagation

    7) Se debe agregar un sinónimo a la palabra original.: y se muestra en su lugar, una vez que se hace clic en un sinónimo. Esto lo definiremos en el applySynonym función a la que hicimos referencia en el paso 4.

    function applySynonym(e) 
        var txt = '';
    
        // Because we added event listener to the parent ul element, 
        // we have to check if the clicked element is the anchor or not
        if (e.target.tagName != 'A')  return false; 
    
        // We retrieve the orginal text from the data attribute, 
        // which we cached in step 6 above. And append current anchor's text
        txt += '';
        txt += e.target.textContent + '';
        // replace the text of the word
        currentWord.textContent = txt;
        toggleMenu('hide'); // hide the suggestion box menu
        // stop propagation of click, so that it doesn't go to body
        // prevent default so that clicking anchor doesn't jump to top
        e.stopPropagation(); e.preventDefault();
    
    

    Las referencias clave para usted en el código anterior son sobre preventDefault.

    8) Definimos el resto de funciones auxiliares:

    function toggleMenu(mode) 
        if (mode == 'show')  menu.style.display = 'block'; 
        if (mode == 'hide')  menu.style.display = 'none'; 
    
    
    function clearMenu() 
        // we loop the child nodes of menu ul element, 
        // remove the last child (last li) of that ul element, 
        // until it does not has-child-nodes.
        while (menu.hasChildNodes())  
            menu.removeChild(menu.lastChild); 
        
    
    

    Las referencias clave para usted en el código anterior son sobre hasChildNodes, removeChild y lastChild.

    9) Definir la presentación mediante CSS, especialmente haciendo que el menú se posicione absolutamente, ocultándolo en la primera carga y también embelleciendo la presentación:

    ul#synonymMenu 
        position: absolute; display: none;
        ...
        border: 1px solid #bbb; background-color: #efefef;
    
    

    10) Prueba.

    Demostración de violín: https://jsfiddle.net/abhitalks/zske2aoh/

    Fragmento de demostración:

    (function() 
    	var menu = document.getElementById('synonymMenu'), 
    		words = [].slice.call(document.querySelectorAll('i.synonyms')), 
    		currentWord = null
    	;
    	
    	words.forEach(function(wrd) 
    		wrd.setAttribute('data-word', wrd.textContent);
    		wrd.addEventListener('click', manageMenu);
    	);
    	menu.addEventListener('click', applySynonym);
    	document.body.addEventListener('click', function() 
    		toggleMenu('hide');
    	);
    
    	function manageMenu(e) ');
    		synonyms.forEach(function(syn) 
    			optn = document.createElement('li');
    			link = document.createElement('a');
    			link.setAttribute('href', '#'); link.textContent = syn;
    			optn.appendChild(link); menu.appendChild(optn);
    		);
    		e.stopPropagation();
    	
    	
    	function applySynonym(e) 
    		var txt = '';
    		if (e.target.tagName != 'A')  return false; 
    		txt += '';
    		txt += e.target.textContent + '';
    		currentWord.textContent = txt;
    		toggleMenu('hide');
    		e.stopPropagation(); e.preventDefault();
    	
    	
    	function toggleMenu(mode) 
    		if (mode == 'show')  menu.style.display = 'block'; 
    		if (mode == 'hide')  menu.style.display = 'none'; 
    	
    	
    	function clearMenu() 
    		while (menu.hasChildNodes())  
    			menu.removeChild(menu.lastChild); 
    		
    	
    	
    )();
    *  font-family: sans-serif; 
    html, body  height: 100%; 
    i.synonyms  cursor: pointer; color: #333; 
    ul#synonymMenu 
    	position: absolute; display: none;
    	width: auto; max-height: 120px; 
    	overflow: hidden; overflow-y: auto;
    	list-style: none; padding: 0; margin: 0; 
    	border: 1px solid #bbb; background-color: #efefef;
    	box-shadow: 0px 0px 6px 1px rgba(128,128,128,0.3);
    
    ul#synonymMenu > li  display: block; 
    ul#synonymMenu a  
    	display: block; padding: 4px 20px 4px 6px; 
    	color: #333; font-size: 0.9em; text-decoration: none;
    
    ul#synonymMenu a:hover 
    	background-color: #99b;
    

    I like apples. I like oranges.


      Editar:

      Según los comentarios de Op, el código se ha actualizado para adaptarse a múltiples selecciones de sinónimos a través de casillas de verificación. La complejidad adicional consiste en agregar casillas de verificación en lugar de anclas simples, cambiar los detectores de eventos por los mismos estilos actualizados y la lógica para retener la selección preexistente en los clics repetidos.

      Violín actualizado: https://jsfiddle.net/abhitalks/ffpL4f7k/

      Fragmento actualizado:

      (function() 
      	var menu = document.getElementById('synonymMenu'), 
      		menuWrap = document.getElementById('menuWrapper'),
      		okButton = document.getElementById('synOk'), 
      		words = [].slice.call(document.querySelectorAll('i.synonyms')), 
      		currentWord = null
      	;
      	
      	words.forEach(function(wrd) 
      		wrd.setAttribute('data-word', wrd.textContent);
      		wrd.addEventListener('click', manageMenu);
      	);
      	okButton.addEventListener('click', applySynonym);
      	document.body.addEventListener('click', function(e)  
      		if (isDescendant(menuWrapper, e.target)) 
      			return;
      		
      		toggleMenu('hide');
      	);
      
      	function manageMenu(e) ');
      		synonyms.forEach(function(syn) 
      			opt = document.createElement('li'); 
      			lbl = document.createElement('label');
      			chk = document.createElement('input'); 
      			chk.setAttribute('type', 'checkbox'); 
      			txt = document.createTextNode(syn);
      			lbl.appendChild(chk); 
      			lbl.appendChild(txt); 
      			opt.appendChild(lbl); 
      			menu.appendChild(opt);
      		);
      		preSelect(existing);
      		e.stopPropagation();
      	
      	
      	function preSelect(existing) 
      		var labels = [].slice.call(menu.querySelectorAll('label'));
      		labels.forEach(function(lbl) 
      			if (existing.indexOf(lbl.textContent) > -1) 
      				lbl.firstChild.checked = true;
      			
      		);
      	
      	
      	function applySynonym(e) 
      		var txt = '', labels, checked, selected;
      		labels = [].slice.call(menu.querySelectorAll('label'));
      		checked = labels.filter(function(lbl)
      			return lbl.firstChild.checked;
      		);
      		selected = checked.map(function(lbl)
      			return lbl.textContent;
      		).join('
      	
      	function toggleMenu(mode) 
      		if (mode == 'show')  menuWrap.style.display = 'block'; 
      		if (mode == 'hide')  menuWrap.style.display = 'none'; 
      	
      	
      	function clearMenu() 
      		while (menu.hasChildNodes())  
      			menu.removeChild(menu.lastChild); 
      		
      	
      	
      	function isDescendant(parent, child) 
      		 var node = child.parentNode;
      		 while (node != null) 
      			 if (node == parent) 
      				 return true;
      			 
      			 node = node.parentNode;
      		 
      		 return false;
      	
      
      )();
      *  font-family: sans-serif; box-sizing: border-box; 
      html, body  height: 100%; 
      div.wrap  
      	border: 1px solid #ddd; max-height: 480px; 
      	padding: 4px 22px 4px 4px; font-size: 0.9em;
      	overflow: hidden; overflow-y: auto;
      
      i.synonyms  cursor: pointer; color: #333; 
      div#menuWrapper 
      	position: absolute; display: none; width: 128px; 
      	padding: 4px; margin: 0; 
      	border: 1px solid #bbb; background-color: #efefef;
      	box-shadow: 0px 0px 6px 1px rgba(128,128,128,0.3);
      
      ul#synonymMenu 
      	max-height: 120px; 
      	overflow: hidden; overflow-y: auto;
      	list-style: none; padding: 0; margin: 0; 
      
      ul#synonymMenu > li  display: block; 
      ul#synonymMenu label  
      	display: block; color: #333; font-size: 0.9em; 
      	padding: 2px 18px 2px 4px; 
      
      ul#synonymMenu label:hover  background-color: #99b; 
      button#synOk  padding: 2px; width: 100%; 

      I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges.

      I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges.

      I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges. I like apples. I like oranges.


      Creo que creo el siguiente componente jQuery que se adapta a sus necesidades.
      Aquí está el jsbin si lo prefiere.

      //jquery component
      $.fn.synonyms = function(options)
        options = $.extend(, ', options);
        this.each(function(elKey, el)
          var $el = $(el),
              originalText = $el.text(),
              originalTextSpan = $(''+originalText+'');
          $el.html(originalTextSpan);
          var suggestionBox = '
      '; $.each($el.attr('data-synonyms').split(options.separator), function(key, suggestion) suggestionBox+=''+suggestion+' - '; ); suggestionBox = suggestionBox.slice(0, -2); suggestionBox += '
      '; suggestionBox = $(suggestionBox); suggestionBox.css( display: 'none' ); $el.click(function() suggestionBox.toggle(); ); suggestionBox.on('click','span',function() var selectedText = $(this).text(); originalTextSpan.text(''+selectedText+''); onSelected(selectedText); ); $el.append(suggestionBox); ); function onSelected(selectedText) if(options.onSelected) options.onSelected(selectedText); ; // How to use the component $(function() $('[data-synonyms]').synonyms( onSelected: function(selectedText) alert('you selected:'+selectedText); ); );
      div[data-synonyms]
        display: inline;
        position: relative;
        cursor: pointer;
        text-decoration: underline;
      
      div[data-synonyms] > div
        white-space: nowrap;
        position: absolute;
        top: 1.2em;
        left: 0;
        background: #fff;
        border: 1px solid #bbb;
        padding: 2px;
      
      div[data-synonyms] > div > span
        text-decoration: underline;
        cursor: pointer;
      
      
      
      
      
        
        
        JS Bin
      
      
        I 
      like
      apples. Carrots are the
      best
      though.

      $(document).ready(function() 
        $("b").on("click", function() ').join('
      b 
        color: red;
        cursor: pointer;
      
      
      
      

      I like apples, particularily if they are ripe.

      Comentarios y calificaciones del tutorial

      Si para ti ha sido de utilidad nuestro artículo, agradeceríamos que lo compartas con el resto entusiastas de la programación y nos ayudes a dar difusión a este contenido.

      ¡Haz clic para puntuar esta entrada!
      (Votos: 2 Promedio: 4.5)



      Utiliza Nuestro Buscador

      Deja una respuesta

      Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *