Sembra che non ci sia un modo semplice per farlo, ho il seguente esempio di lavoro. C'è un po 'di elaborazione quindi è un po' lento e può essere fuori dal personaggio dispari quando si muove su e giù tra i paragrafi.
Si prega di informarmi di eventuali miglioramenti che possono essere apportati.
http://jsfiddle.net/zQUhV/47/
Quello che ho fatto è dividere il paragrafo per ogni opera, inserirli in un nuovo elemento a uno a uno, controllando per un cambiamento di altezza - quando non cambia una nuova linea è stato aggiunto .
Questa funzione restituisce un array di oggetti riga che contiene il testo della linea, a partire indice e indice di fine:
(function($) {
$.fn.lines = function(){
words = this.text().split(" "); //split text into each word
lines = [];
hiddenElement = this.clone(); //copies font settings and width
hiddenElement.empty();//clear text
hiddenElement.css("visibility", "hidden");
jQuery('body').append(hiddenElement); // height doesn't exist until inserted into document
hiddenElement.text('i'); //add character to get height
height = hiddenElement.height();
hiddenElement.empty();
startIndex = -1; // quick fix for now - offset by one to get the line indexes working
jQuery.each(words, function() {
lineText = hiddenElement.text(); // get text before new word appended
hiddenElement.text(lineText + " " + this);
if(hiddenElement.height() > height) { // if new line
lines.push({text: lineText, startIndex: startIndex, endIndex: (lineText.length + startIndex)}); // push lineText not hiddenElement.text() other wise each line will have 1 word too many
startIndex = startIndex + lineText.length +1;
hiddenElement.text(this); //first word of the next line
}
});
lines.push({text: hiddenElement.text(), startIndex: startIndex, endIndex: (hiddenElement.text().length + startIndex)}); // push last line
hiddenElement.remove();
lines[0].startIndex = 0; //quick fix for now - adjust first line index
return lines;
}
})(jQuery);
Ora è possibile utilizzare che per misurare il numero di carattere fino al punto della cursore e applicare questo quando si attraversa il paragrafo per mantenere la posizione del cursore rispetto all'inizio della linea. Tuttavia, ciò può produrre risultati estremamente imprecisi se si considera la larghezza di una "i" per la larghezza di una "m".
Invece sarebbe meglio per trovare la larghezza della linea fino al punto del cursore:
function distanceToCaret(textElement,caretIndex){
line = findLineViaCaret(textElement,caretIndex);
if(line.startIndex == 0) {
// +1 needed for substring to be correct but only first line?
relativeIndex = caretIndex - line.startIndex +1;
} else {
relativeIndex = caretIndex - line.startIndex;
}
textToCaret = line.text.substring(0, relativeIndex);
hiddenElement = textElement.clone(); //copies font settings and width
hiddenElement.empty();//clear text
hiddenElement.css("visibility", "hidden");
hiddenElement.css("width", "auto"); //so width can be measured
hiddenElement.css("display", "inline-block"); //so width can be measured
jQuery('body').append(hiddenElement); // doesn't exist until inserted into document
hiddenElement.text(textToCaret); //add to get width
width = hiddenElement.width();
hiddenElement.remove();
return width;
}
function findLineViaCaret(textElement,caretIndex){
jQuery.each(textElement.lines(), function() {
if(this.startIndex <= caretIndex && this.endIndex >= caretIndex) {
r = this;
return false; // exits loop
}
});
return r;
}
Poi dividere la linea di tiro fino in personaggi e trovare il punto che più vicino corrisponde alla larghezza di cui sopra da parte aggiungendo i caratteri uno per uno fino a raggiungere il punto:
function getCaretViaWidth(textElement, lineNo, width) {
line = textElement.lines()[lineNo-1];
lineCharacters = line.text.replace(/^\s+|\s+$/g, '').split("");
hiddenElement = textElement.clone(); //copies font settings and width
hiddenElement.empty();//clear text
hiddenElement.css("visibility", "hidden");
hiddenElement.css("width", "auto"); //so width can be measured
hiddenElement.css("display", "inline-block"); //so width can be measured
jQuery('body').append(hiddenElement); // doesn't exist until inserted into document
if(width == 0) { //if width is 0 index is at start
caretIndex = line.startIndex;
} else {// else loop through each character until width is reached
hiddenElement.empty();
jQuery.each(lineCharacters, function() {
text = hiddenElement.text();
prevWidth = hiddenElement.width();
hiddenElement.text(text + this);
elWidth = hiddenElement.width();
caretIndex = hiddenElement.text().length + line.startIndex;
if(hiddenElement.width() > width) {
// check whether character after width or before width is closest
if(Math.abs(width - prevWidth) < Math.abs(width - elWidth)) {
caretIndex = caretIndex -1; // move index back one if previous is closes
}
return false;
}
});
}
hiddenElement.remove();
return caretIndex;
}
che con la seguente funzione keydown è sufficiente per attraversare abbastanza accuratamente tra contentedita ble paragrafi:
$(document).on('keydown', 'p[contenteditable="true"]', function(e) {
//if cursor on first line & up arrow key
if(e.which == 38 && (cursorIndex() < $(this).lines()[0].text.length)) {
e.preventDefault();
if ($(this).prev().is('p')) {
prev = $(this).prev('p');
getDistanceToCaret = distanceToCaret($(this), cursorIndex());
lineNumber = prev.lines().length;
caretPosition = getCaretViaWidth(prev, lineNumber, getDistanceToCaret);
prev.focus();
setCaret(prev.get(0), caretPosition);
}
// if cursor on last line & down arrow
} else if(e.which == 40 && cursorIndex() >= $(this).lastLine().startIndex && cursorIndex() <= ($(this).lastLine().startIndex + $(this).lastLine().text.length)) {
e.preventDefault();
if ($(this).next().is('p')) {
next = $(this).next('p');
getDistanceToCaret = distanceToCaret($(this), cursorIndex());
caretPosition = getCaretViaWidth(next, 1, getDistanceToCaret);
next.focus();
setCaret(next.get(0), caretPosition);
}
//if start of paragraph and left arrow
} else if(e.which == 37 && cursorIndex() == 0) {
e.preventDefault();
if ($(this).prev().is('p')) {
prev = $(this).prev('p');
prev.focus();
setCaret(prev.get(0), prev.text().length);
}
// if end of paragraph and right arrow
} else if(e.which == 39 && cursorIndex() == $(this).text().length) {
e.preventDefault();
if ($(this).next().is('p')) {
$(this).next('p').focus();
}
};
Cosa stai cercando di fare che il normale funzionamento dei tasti freccia non funzioni? – kennebec
Dire che il cursore si trova nella riga superiore del terzo paragrafo e che la freccia su è premuta, vorrei che salisse nella rom in basso del secondo paragrafo. –
Ho implementato qualcosa di simile prima. Non c'è modo di farlo in tutti i browser se non misurando noiosamente le posizioni e le dimensioni dei personaggi. –