2010-06-09 11 views
14

Hay numerosos editores WYSIWYG disponibles en Internet, pero todavía no he encontrado ninguno que implemente alguna forma de implementación de arrastrar y soltar.Arrastrar y soltar en el contenido Elementos editables

Es fácil de crear su propio editor, pero quiero que el usuario sea capaz de arrastrar elementos (es decir. Tokens) desde fuera del área editable y hacer que se dejan caer en un lugar de su elección dentro del área editable .

Es fácil inyectar html en una ubicación específica de un elemento editable, pero ¿cómo se determina dónde debe estar el cursor cuando el usuario arrastra un DIV sobre algún elemento en el área editable? Para ilustrar mejor lo que trato de explicar, consulte la siguiente situación.

El área editable (ya sea un IFRAME en modo de edición o un DIV con su atributo contentEditable se define como true) ya contiene el siguiente texto:

"Estimado, por favor tome nota de ...."

El usuario ahora arrastra un elemento que representa algún token de una lista de elementos, sobre el área editable, moviendo el cursor sobre el texto hasta que el símbolo de intercalación aparece justo antes de la coma (,) en el texto como se muestra arriba. Cuando el usuario suelta el botón del mouse en esa ubicación, se inyectará HTML que podría dar como resultado algo como esto:

"Estimado {UserFirstName}, tome nota de ...".

No sé si alguien ha hecho algo similar a esto, o al menos saber cómo hacerlo con JavaScript.

Cualquier ayuda será muy apreciada.

Respuesta

6

Aquí está mi enfoque para resolver el problema de elementos de arrastre personalizados en elementos editables. El gran problema es que no se puede determinar el desplazamiento del texto del cursor del mouse al pasar el cursor sobre el elemento editable. Intenté simular un clic del mouse para configurar el símbolo de intercalación en la posición deseada, pero no funcionó. Incluso si lo hiciera, uno no vería visualmente la ubicación del cursor mientras lo arrastraba, sino solo la caída resultante.

Dado que se pueden vincular los eventos del mouse a los elementos y no a los nodos de texto, se puede establecer que el elemento editable sea temporalmente no editable. Encuentre todos los elementos y ajuste cada nodo de texto en un lapso para no interrumpir el flujo del texto. A cada tramo se le debe dar un nombre de clase para que podamos encontrarlos de nuevo.

Después de la envoltura, una vez más, debe encontrar todos los nodos de texto envueltos y ajustar cada carácter con otro lapso con un nombre de clase que uno puede encontrar de nuevo.

Al usar la delegación de eventos, se puede agregar un evento al elemento editable principal que aplicará un estilo a cada extensión de caracteres que mostrará el símbolo de intercalación, una imagen GIF parpadeante como fondo.

Nuevamente, usando la delegación de eventos, se debe agregar un evento para el evento de mouse (evento de caída) en cada carácter. Ahora se puede determinar el desplazamiento utilizando la posición (desplazamiento) del alcance del carácter dentro de su elemento primario (nodo de texto envuelto). Ahora se puede deshacer todo el ajuste, manteniendo una referencia al desplazamiento calculado y al deshacer el ajuste manteniendo una referencia al nodo de texto aplicable.

Utilizando los objetos de selección rango del & del navegador, ahora puede establecer la selección utilizando el desplazamiento calculado al nodo de texto aplicable e inyectar el HTML requerido en la nueva selección (posición de intercalación), et viola!

Aquí sigue un fragmento usando jQuery que encontrará textnodes, envolverlos:

editElement.find("*:not(.text-node)").contents().filter(function(){ 
    return this.nodeType != 1; 
}).wrap("<span class=\"text-node\"/>"); 

Para encontrar cada texto-nodo y envolver cada carácter, su uso:

editElement.find(".text-node").each(function() 
{ 
    var textnode = $(this), text = textnode.text(), result = []; 

    for (var i = 0; i < text.length; i++) result.push(text.substr(i, 1)); 

    textnode.html("<span class=\"char\">" 
     + result.join("</span><span class=\"char\">") + "</span>"); 
}); 

Para deshacer el envoltorio:

editElement.find(".text-node").each(function() 
{ 
    this.parentNode.replaceChild(document.createTextNode($(this).text()), this); 
}); 

Espero que este enfoque ayude a aquellos que tienen desafíos similares

+1

Probablemente no se requiera aplicar un evento de mouseup delegado en los espacios de caracteres como se mencionó anteriormente, se podría usar la propiedad de evento original del evento droppable para determinar si, de hecho, el elemento arrastrable se ha eliminado en un lapso de caracteres. Solo FYI .... – Raybiez

1

Actualmente se está desarrollando una API HTML5 para hacer esto, pero lamentablemente IE no lo admite. Editar: Aparentemente IE realmente admite arrastrar y soltar, pero no estoy muy familiarizado con la forma en que funciona. Pruebe Googling "IE drag and drop".

intente buscar en estos sitios:

+0

Un colega mío encontró una solución, fue por él que pregunté. Voy a publicar la solución aquí pronto – Raybiez

+0

Por desgracia, su solución no es realmente aplicable. La búsqueda está de vuelta ... grrr – Raybiez

+0

@Raybiez ¿Tal vez podría editar su pregunta para agregar la solución que no funcionó? Eso también tendría el efecto secundario de volver a colocar esta pregunta en la página principal. – Na7coldwater

2

Si entiendo lo que estás diciendo, entonces esto es solo un simple arrastrar y soltar. La siguiente solución debe estar cerca de la mejor respuesta para FIREFOX. Estoy seguro de que hay diferentes funciones para IE. Vaya a http://www.html5rocks.com/en/tutorials/dnd/basics/ para obtener más ayuda.

Establezca el atributo "arrastrable" del objeto que desea arrastrar y establezca el método "ondragstart" del objeto como "dragStartHandler" o como se llame a su función.

// You can set this to 'text/plain' if you don't want to insert HTML content 
var internalDNDType = 'text/html'; 

function dragStartHandler(event) { 
    // This is whatever html data you want to insert. 
    var textContent = "<b>"+userFirstName+"</b>"; 

    event.dataTransfer.setData(internalDNDType, textContent); 
    event.dataTransfer.effectAllowed = 'copy'; 
} 

function dragEnterHandler(event) 
{ 
    event.preventDefault(); 
    return false; 
} 

function dragOverHandler(event) 
{ 
    event.preventDefault(); 
    return false; 
} 

function dropHandler(event) { 
    event.preventDefault(); 
    event.stopPropogation(); 
    return false; 
} 
+0

Gracias por la respuesta, sin embargo, esto se basa en HTML5, y la aplicación tenía que admitir navegadores antiguos. Para la nueva aplicación actualizada sin soporte de navegador heredado, este enfoque será el más adecuado. – Raybiez