2014-07-07 11 views
11

Data un'area di testo con un carattere di larghezza non fissa, desidero sapere sulla chiave su se il segno di omissione (come indicato da element.selectionEnd) è nella prima riga o nell'ultima riga del testo.Il segno di omissione si trova sulla prima riga della textarea? Sull'ultima riga?

Enter image description here

Per evitare risposte negative, qui ci sono alcune soluzioni che Non lavoro:

  • Splitting su \n: Una frase può essere suddiviso in due linee, perché è troppo lungo per la larghezza della textarea.
  • Misurazione del testo prima del cursore (ad esempio copiando il testo in un div con lo stesso stile e misurando l'altezza dello span): Alcuni caratteri dopo il il cursore può cambiare il punto di avvolgimento (di solito tra le parole).

Ecco un violino per le prove e per rimuovere una certa ambiguità (sì, è un elemento textarea, e non è solo una linea, ecc): http://jsbin.com/qifezupu/4/edit

Note:

  • I non preoccuparti di Internet Explorer 9 o dei browser mobili.
  • Ho bisogno di una soluzione affidabile, che funzioni per tutte le posizioni del cursore.
  • Ci sono molti dettagli complicati che rendono praticamente inutilizzabili molte idee, per favore costruite un violino funzionante prima di rispondere.
+0

Penso che con puro 'textarea' non è possibile (a mio parere) Ma se è possibile utilizzare alcuni editor di cui analizzare una html puro allora si può definire quale linea è l'ultimo e quale è il primo . –

risposta

4

La soluzione migliore per la società:

  • Creare un div temporanea con due campate, e gli stili CSS fatte per imitare (tipo di carattere, wordwrapping, barre di scorrimento) il comportamento avvolgimento del textarea.
  • Riempi il primo span con il testo prima del punto di inserimento.
  • Riempire la seconda estensione con il testo dopo il segno di omissione.
  • Usa l'offset.top e l'altezza dell'elemento degli span per sapere se siamo sulla prima riga o sull'ultima riga.

Posso vedere che funziona?

Ho fatto un violino, che rende evidente come funziona: http://jsbin.com/qifezupu/31/edit

Come si usa:

Ho fatto un plugin jQuery: https://github.com/Canop/taliner.js

Ecco la pagina di dimostrazione relativi: http://dystroy.org/demos/taliner/demo.html

Il codice:

$.fn.taliner = function(){ 

    var $t = this, 
     $d = $('<div>').appendTo('body'), 
     $s1 = $('<span>').text('a').appendTo($d), 
     $s2 = $('<span>').appendTo($d), 
     lh = $s1.height(); 

    $d.css({ 
     width: $t.width(), 
     height: $t.height(), 
     font: $t.css('font'), 
     fontFamily: $t.css('fontFamily'), // for FF/linux 
     fontSize: $t.css('fontSize'), 
     whiteSpace : 'pre-wrap', 
     wordWrap : 'break-word', 
     overflowY: 'auto', 
     position: 'fixed', 
     bottom: 0, 
     left: 0, 
     padding: 0, 
     zIndex: 666 
    }); 

    var lh = $s1.height(), 
     input = this[0], 
     se = input.selectionEnd, 
     v = input.value, 
     res = {}; 

    $s1.text(v); 
    res.linesNumber = $s1.height()/lh|0; 

    $s1.text(v.slice(0, se)); 
    $s2.text(v.slice(se)); 
    res.caretOnFirstLine = input.selectionEnd===0 
     || ($s1.height()<=lh && $s1.offset().top===$s2.offset().top); 
    res.caretOnLastLine = $s2.height()===lh; 

    $d.remove(); 
    return res; 
} 

Funziona davvero?

C'è ancora un problema. L'unica informazione che otteniamo in JavaScript riguardo la posizione del cursore è element.selectionEnd. E questo è molto povero.

Ecco le possibili posizioni Caret su una textarea due linee:

| A | B | C | 
| D | E | 

Come si può vedere, ci sono più posizioni possibili Caret di posizioni fra caratteri. Più precisamente, ci sono due diverse posizioni di caret tra C e D ma il DOM non fornisce alcun modo per distinguerle.

Ciò significa che a volte, se si fa clic a destra della fine della riga, la libreria non sarà in grado di stabilire se è la fine della riga o l'inizio della riga successiva.

+0

Grazie per aver condiviso la tua soluzione. Sto cercando di ottenere la stessa funzionalità, ma per navigare tra più elementi contenteditable, agganciati agli eventi tastiera up/down (questo sembra più naturale di tabbing, che funziona). Mi chiedo se Rangy/Tim Down potrebbe aiutare con questo problema. – rorymorris

1

È possibile misurare la lunghezza di un pezzo di testo inserendolo in un div e ottenendo la larghezza di tale div.

In breve, guarda questo jsFiddle. Ogni volta che cambi il testo nella casella di testo, sarai avvisato della larghezza del testo.

Quindi suggerirei di fare quanto segue:

  • trovare sia la prima e l'ultima riga del contenuto del vostro textarea. I prossimi passi si applicano a entrambe le linee.
  • Per verificare se una linea è interrotta a causa della larghezza della textarea, utilizzare il snippet suggerito per verificare se la larghezza del testo è maggiore della larghezza della textarea.
  • Se è più lungo, è possibile iniziare iterativamente il controllo delle sottostringhe della linea. Se ne trovi uno che corrisponde alla larghezza della tua textarea, puoi essere certo che è dove si trova l'interruzione di riga.

Non sono sicuro dell'azione che si desidera eseguire, ma è possibile utilizzare questo metodo per approssimare il punto in cui si trova il cursore. Potrebbe non essere pixel perfetto anche se, poiché la larghezza div varia leggermente rispetto alla larghezza del testo.

Ecco il frammento di codice per misurare la larghezza del testo:

$(document).ready(function() { 

    $("#txtbox").keyup(function() { 
     var the_Text = $("#txtbox").val(); 

     var width = $("#testdiv").text(the_Text).width(); 

     alert("The text width is : " + width + " px"); 
    }); 

}); 

$("#testdiv") è un div nascosto nella pagina. Niente di stravagante, l'unico CSS usato è quello di assicurarsi che l'utente non lo veda.

+1

Se pensi che questo dovrebbe funzionare, puoi provare ad adattare la tua soluzione a [il violino che ho dato] (http://jsbin.com/qifezupu/4/edit)? Nota che non mi interessa la posizione dei pixel, solo la posizione * esatta * della linea del cursore. –

2

Ci sono diversi metodi per ottenere posizione del cursore (in pixel) all'interno di una textarea:
Offset possition of the caret in a textarea in pixels

attenti, potrebbero avere problemi con diversi browser.
È possibile impostare un'altezza di linea o una dimensione di carattere predefiniti che verranno utilizzati in un secondo momento per ottenere la posizione del cursore.

Non ho provato nessuno dei metodi, ma supponiamo che la funzione utilizzata per ottenere la posizione di inserimento (in pixel) restituisca il componente y rispetto al fondo del cursore.
Si specifica un'altezza di riga di 15 px.
Diciamo che restituisce il metodo (20, 45).linea di corrente = y/15 = 45/15 = 3

JS Fiddle per dimostrare come può essere fatto sulla base di una soluzione di Dan:
Current line from caret coordinates

ho aggiunto un arco in cui viene visualizzata la riga corrente. Purtroppo, i miei test su Chrome mostrano che questo non è accurato al 100%: quando si seleziona la terza linea con il mouse, si dice che si è sulla quarta linea.

Line: 
<span id="line">0</span> 

Alla fine della funzione aggiornamento (nella sezione HTML) ho aggiunto la seguente linea:

//24 is the top padding of the textarea 
//16 is the line-height 
line.innerText = (coordinates.top - 24)/16; 
+0

Questa è la soluzione migliore fino ad ora - i bug dei browser più piccoli ai casi limite non sembrano comportare un comportamento rilevante. Cudos per aver trovato questo! – Falco

2

Un'altra soluzione basata su ciò che @Flater ha detto sull'aggiunta della larghezza del testo. L'idea (in sintesi) è:

  1. Prendi il larghezza del textarea
  2. ottenere il testo prima la posizione del cursore e calcolare la sua larghezza
  3. ottenere il testo dopo la posizione del cursore e calcolare la sua larghezza
  4. Se prima del testo> larghezza dell'area di testo o non contiene interruzione di riga (nel caso in cui il testo sulla prima riga sia inferiore), il cursore è non sulla prima linea
  5. Se il dopo il testo> larghezza dell'area di testo o non contiene la linea-break, il cursore non è in ultima riga

Codice:

$('#t').keyup(function(e){ 
    first_line="true"; 
    last_line="true"; 
    text = $(this).val(); 
    width = $(this).width(); 
    var cursorPosition = $(this).prop("selectionStart"); 
    txtBeforeCaret = text.substring(0, cursorPosition); 
    txtAfterCaret = text.substring(cursorPosition); 
    widthBefore = $('#holder').text(txtBeforeCaret).width(); 
    widthAfter = $('#holder').text(txtAfterCaret).width(); 
    match1 = txtBeforeCaret.match(/\n/); 
    if(txtAfterCaret!==null){match2=txtAfterCaret.match(/\n/g);} 
    if(widthBefore>width || match1){first_line="false";} 
    if(widthAfter>width || (match2!==null && match2.length)) {last_line="false";} 
    $('#f').html(first_line); 
    $('#l').html(last_line); 
}); 

#holder è un div creato e nascosto (per trovare la larghezza del testo).

DEMO

+0

Non ho avuto il tempo di vedere se sono facili da risolvere ma ci sono due problemi: 1) non dà la risposta giusta se si mette il cursore all'inizio della seconda riga 2) non lo fa lavoro alla fine della prima riga con [questo testo] (http://jsbin.com/hacicitu/1/edit) –

+0

Un altro problema: si interrompe se si digita un html nella textarea (nella mia soluzione l'ho risolto usando ' text' e alcune impostazioni css). –

+0

@dystroy L'ho corretto un po 'dopo alcuni errori. Provalo e fammi sapere. Il ridimensionamento non è perfetto tuttavia (quando ridimensionato, è necessario digitare l'output corretto invece di spostare il cursore). –

Problemi correlati