2010-06-09 2 views
14

Esistono numerosi editor WYSIWYG disponibili su Internet, ma devo ancora trovarne uno che implementa una qualche forma di implementazione drag-n-drop.Drag-n-Drop su content Elementi editabili

È facile creare il proprio editor, ma voglio che l'utente sia in grado di trascinare elementi (cioè token) dall'esterno dell'area modificabile e farli cadere in una posizione a loro scelta all'interno dell'area modificabile .

È facile iniettare l'html in una posizione specifica di un elemento modificabile, ma come determinare il punto in cui deve essere il cursore quando l'utente sta trascinando un DIV su un elemento nell'area modificabile. Per illustrare meglio ciò che sto cercando di spiegare, vedere il seguente scenario.

L'area modificabile (sia un IFRAME in modalità di modifica o di un div con il suo attributo contentEditable impostata su true) contiene già il seguente testo:

"Caro, si prega di prendere nota di ...."

L'utente trascina ora un elemento che rappresenta un token da un elenco di elementi, sopra l'area modificabile, spostando il cursore sul testo finché il punto di inserimento non appare prima della virgola (,) nel testo come mostrato sopra. Quando l'utente rilascia il pulsante del mouse in quella posizione, verrà iniettato l'HTML che potrebbe comportare qualcosa del tipo:

"Gentile {NomeFirstutente}, si prega di prendere nota di ...".

Non so se qualcuno ha mai fatto qualcosa di simile a questo, o almeno sapere come si farebbe per farlo usando JavaScript.

Qualsiasi aiuto sarà molto apprezzato.

risposta

6

Qui è il mio approccio per risolvere il problema di elementi di trascinamento personalizzati su elementi modificabili. Il grosso problema è che non è possibile determinare l'offset del testo del cursore del mouse quando si passa sopra l'elemento modificabile. Ho provato a simulare un clic del mouse per impostare il cursore nella posizione desiderata ma non ha funzionato. Anche se così fosse, non si vedrebbe visivamente il posizionamento del cursore mentre si trascina, ma solo la goccia risultante.

Poiché è possibile associare eventi di passaggio del mouse a elementi e non a nodi di testo, è possibile impostare l'elemento modificabile come temporaneamente non modificabile. Trova tutti gli elementi e avvolgi ogni nodo di testo in un intervallo per non interrompere il flusso del testo. Ad ogni span dovrebbe essere assegnato un nome di classe in modo che possiamo trovarli di nuovo.

Dopo il wrapping, si dovrebbero trovare nuovamente tutti i nodi di testo avvolti e avvolgere ciascun carattere con un altro intervallo con un nome di classe che è possibile ritrovarli di nuovo.

Utilizzando la delega degli eventi è possibile aggiungere un evento all'elemento modificabile principale che applicherà uno stile a ogni intervallo di caratteri che visualizzerà il cursore, un'immagine GIF lampeggiante come sfondo.

Anche in questo caso, utilizzando la delega degli eventi, è necessario aggiungere un evento per l'evento mouse-up (evento di rilascio) su ciascun carattere. Ora è possibile determinare l'offset usando la posizione (offset) del carattere span all'interno del suo genitore (nodo di testo avvolto). Ora è possibile annullare tutto il wrapping, mantenendo un riferimento all'offset calcolato e annullando il wrapping mantenendo un riferimento al nodo di testo applicabile.

Utilizzando l'intervallo & oggetti di selezione del browser, ora è possibile impostare la selezione utilizzando l'offset calcolato sul nodo di testo applicabile e immettere l'HTML richiesto nella nuova selezione (posizione di inserimento), et viola!

Qui segue un frammento utilizzando jQuery che troverà textnodes, avvolgerli:

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

Per trovare ogni testo-nodo e avvolgere ogni personaggio, 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>"); 
}); 

Per annullare l'involucro:

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

Spero che questo approccio aiuta quelli che hanno problemi analoghi

+1

Probabilmente non è necessario applicare un evento mouseup delegato sui caratteri span come menzionato sopra, si potrebbe usare la proprietà evento originale dell'evento droppable per determinare se in realtà il draggable è stato rilasciato su un intervallo di caratteri. Solo FYI .... – Raybiez

1

Attualmente è in fase di sviluppo un'API HTML5 per fare questo, ma sfortunatamente IE non lo supporta. Modifica: Apparentemente IE supporta effettivamente il trascinamento della selezione, ma non ho molta familiarità con il suo funzionamento. Prova Googling "IE drag and drop".

prova a guardare questi siti:

+0

Un mio collega ha trovato una soluzione, è stato per lui che ho chiesto di porre una domanda. Inserirò la soluzione qui presto – Raybiez

+0

Ahimè, la sua soluzione non è realmente applicabile. La caccia è tornata su ... grrr – Raybiez

+0

@Raybiez Forse potresti modificare la tua domanda per aggiungere la soluzione che non ha funzionato? Ciò avrebbe anche l'effetto collaterale di riportare questa domanda sulla prima pagina. – Na7coldwater

2

Se capisco cosa stai dicendo, allora questo è solo un semplice trascinamento della selezione. La soluzione seguente dovrebbe essere vicina alla migliore risposta per FIREFOX. Sono sicuro che ci sono diverse funzioni per IE. Vai a http://www.html5rocks.com/en/tutorials/dnd/basics/ per ulteriore aiuto.

Impostare l'attributo "trascinabile" dell'oggetto che si desidera trascinare e impostare il metodo "ondragstart" dell'oggetto su "dragStartHandler" o qualsiasi altra funzione venga richiamata.

// 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

Grazie per la risposta, tuttavia questo si basa su HTML5 e l'applicazione doveva supportare i vecchi browser. Per la nuova applicazione aggiornata senza supporto del browser legacy questo approccio sarà più adatto. – Raybiez