Pytanie Czy karetka znajduje się w pierwszym wierszu obszaru tekstowego? W ostatnim wierszu?


Biorąc pod uwagę obszar tekstowy z czcionką o stałej szerokości, chcę wiedzieć na klawiszu, czy karetka (jak podana przez element.selectionEnd) znajduje się w pierwszym wierszu lub w ostatnim wierszu tekstu.

Enter image description here

Aby uniknąć złych odpowiedzi, oto kilka rozwiązań, które nie rób tego praca:

  • Dzielenie na \n: Zdanie może być podzielone na dwie linie, ponieważ jest zbyt długie na szerokość tekstu.
  • Pomiar tekstu przed karetą (na przykład poprzez skopiowanie tekstu do elementu div o tym samym stylu i zmierzenie wysokości przęsła): Niektóre znaki po karetka może zmienić punkt zawijania (zwykle między słowami).

Oto skrzypce do testów i usunięcie pewnej niejasności (tak, to jest textarea element, a to nie tylko jedna linia itp.): http://jsbin.com/qifezupu/4/edit

Uwagi:

  • Nie obchodzi mnie przeglądarka Internet Explorer 9- lub mobilna.
  • Potrzebuję niezawodnego rozwiązania, pracującego dla wszystkich stanowisk opiekuna.
  • Istnieje wiele trudnych szczegółów, które sprawiają, że większość pomysłów nie nadaje się do użytku w praktyce. Przed odpowiedzią proszę zbudować działające skrzypce.

11
2017-07-07 07:38


pochodzenie


Myślę, że z czystym textarea nie jest możliwe (moim zdaniem). Ale jeśli możesz użyć edytora, który analizuje czysty html, możesz określić, który wiersz jest ostatni, a który pierwszy. - Just code


Odpowiedzi:


Najlepsze rozwiązanie na teraz:

  • Utwórz tymczasowy element div z dwoma rozpiętościami i stylami CSS, aby naśladować (czcionka, zawijanie tekstu, paski przewijania) zachowanie zawijania tekstu.
  • Wypełnij pierwszy zakres tekstem przed karetką.
  • Wypełnij drugą rozpiętość tekstem za karetą.
  • Użyj przesunięcia.top i wysokości elementu przęseł, aby wiedzieć, czy jesteśmy w pierwszym wierszu, czy w ostatniej linii.

Czy mogę widzieć działa?

Zrobiłem skrzypce, które wyjaśnia, jak to działa: http://jsbin.com/qifezupu/31/edit

Jak tego użyć :

Zrobiłem wtyczkę jQuery: https://github.com/Canop/taliner.js

Oto pokrewna strona demonstracyjna: http://dystroy.org/demos/taliner/demo.html

Kod :

$.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;
}

Czy to naprawdę działa?

Wciąż jest problem. Jedyna informacja, jaką otrzymujemy w JavaScript na temat pozycji karetki to element.selectionEnd. A to jest bardzo słabe.

Oto możliwe pozycje karetki na textarea dwóch linii:

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

Jak widać, istnieje więcej możliwych pozycji karetki niż pozycji między znakami. Dokładniej, masz dwie różne pozycje przewijania między C i D, ale DOM nie zapewnia żadnego sposobu na rozróżnienie między nimi.

Oznacza to, że czasami, jeśli klikniesz na prawo od końca linii, biblioteka nie będzie w stanie stwierdzić, czy to koniec linii, czy początek następnego wiersza.


4
2017-07-07 08:37



Dziękujemy za udostępnienie rozwiązania. Próbuję osiągnąć tę samą funkcjonalność, ale w celu poruszania się pomiędzy wieloma elementami podlegającymi akceptacji, podłączonymi do zdarzeń klawiatury w górę / w dół (wydaje się to bardziej naturalne niż działanie tabulacji, która działa). Zastanawiam się, czy Rangy / Tim Down mógłby pomóc w rozwiązaniu tego problemu. - rorymorris


Istnieje kilka metod uzyskiwania pozycji wątku (w pikselach) wewnątrz textarea:
Przesunięcie pozycji karetki w polu tekstowym w pikselach

Ostrożnie, mogą mieć problemy z różnymi przeglądarkami.
Możesz ustawić predefiniowaną wysokość linii lub rozmiar czcionki, które później użyjesz, aby uzyskać pozycję karetki.

Nie testowałem żadnej z metod, ale załóżmy, że funkcja używana do uzyskania pozycji caret (w pikselach) zwraca wartość y komponent w odniesieniu do dna karetki.
Określasz wysokość linii 15 pikseli.
Powiedzmy, że metoda zwraca (20, 45). Obecna linia = y/ 15 = 45/15 = 3

JS Fiddle, aby zademonstrować, jak można to zrobić w oparciu o rozwiązanie Dana:
Bieżąca linia ze współrzędnych suportu

Dodałem zakres, w którym wyświetlana jest bieżąca linia. Niestety, moje testy w Chrome pokazują, że nie jest to w 100% poprawne: po wybraniu trzeciej linii za pomocą myszy oznacza to, że znajdujesz się w 4. linii.

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

Na końcu aktualizacja funkcja (w sekcji HTML) dodałem następujący wiersz:

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

2
2017-07-07 09:04



Wygląda to jak najlepsze rozwiązanie do tej pory - mniejsze błędy przeglądarki w przypadkach krawędzi nie wydają się łamać odpowiedniego zachowania. Cudos za znalezienie tego! - Falco


Inne rozwiązanie oparte na tym, co @Flater powiedział na temat dodawania szerokości tekstu. Pomysł (w skrócie) jest:

  1. Uzyskać szerokość z textarea
  2. Pobierz tekst przed położenie kursora i obliczyć jego szerokość
  3. Pobierz tekst po położenie kursora i obliczyć jego szerokość
  4. Jeśli przed tekstem> szerokość obszaru tekstowego lub nie zawiera linii łamania (jeśli tekst na pierwszej linii jest mniejszy), kursor jest nie w pierwszej linii
  5. Jeśli po tekście> szerokość pola tekstowego  lub nie zawiera linii podziału, kursor nie znajduje się na ostatniej linii

Kod:

$('#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);
});

#uchwyt jest div utworzone i ukryte (aby znaleźć szerokość tekstu).

PRÓBNY


2
2017-07-07 10:11



Nie miałem czasu sprawdzić, czy są łatwe do naprawienia, ale są dwa problemy: 1) nie daje właściwej odpowiedzi, jeśli umieścisz karetkę na początku drugiej linii 2) to nie działa na końcu pierwszej linii z ten tekst - Denys Séguret
Kolejny problem: zepsuje się, jeśli wpiszesz jakiś html w textarea (w moim rozwiązaniu rozwiązałem to używając text i niektóre ustawienia css). - Denys Séguret
@dystroy Poprawiłem to trochę po kilku błędach. Sprawdź to i daj mi znać. Zmiana rozmiaru nie jest jednak doskonała (po zmianie rozmiaru należy wpisać prawidłowy wynik zamiast poruszać kursorem). - I Can Has Kittenz
wciąż są problemy (testowane na chrom / linux) - Denys Séguret
@dystroy Masz rację, problem wydaje się, że nowe linie (automatycznie wykonane, ponieważ pole tekstowe jest mniejsze) nie mogą zostać wykryte. Nie mam opcji z tą metodą. - I Can Has Kittenz


Możesz zmierzyć długość fragmentu tekstu, umieszczając go w div i uzyskując szerokość tego div.

Krótko mówiąc, spójrz na to jsFiddle. Za każdym razem, gdy zmieniasz tekst w polu tekstowym, będziesz informowany o szerokości tekstu.

Więc sugeruję wykonanie następujących czynności:

  • Znajdź zarówno pierwszą, jak i ostatnią linię treści twojego textarea. Kolejne kroki odnoszą się do każdej linii.
  • Aby sprawdzić, czy linia jest zerwana z powodu szerokości obszaru tekstowego, użyj mojego sugerowanego fragmentu, aby sprawdzić, czy szerokość tekstu jest większa niż szerokość obszaru tekstowego.
  • Jeśli jest dłuższy, możesz rozpocząć iteracyjne sprawdzanie podłańcuchów linii. Jeśli znajdziesz taki, który pasuje do szerokości twojego pola tekstowego, możesz być pewny, że jest tam podział linii.

Nie jestem pewien, jakie działania chcesz podjąć, ale możesz użyć tej metody do przybliżenia miejsca, w którym znajduje się twój aparat. Jednak może nie być perfekcyjny w pikselach, ponieważ szerokość div zmienia się nieznacznie w stosunku do szerokości tekstu.

Oto fragment do pomiaru szerokości tekstu:

$(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") to ukryty div na stronie. Nic nadzwyczajnego, jedynym stosowanym CSS jest upewnienie się, że użytkownik go nie widzi.


1
2017-07-07 08:05



Jeśli uważasz, że to powinno działać, możesz spróbować dostosować swoje rozwiązanie skrzypce, które dałem ? Zauważ, że nie dbam o pozycję pikseli, właśnie dokładny pozycja linii karetki. - Denys Séguret


Oto skrzypce używające tej wtyczki jQuery (https://github.com/Codecademy/textarea-helper), aby uzyskać pozycję opiekuna (pozycja y jest tym, czego potrzebujesz): http://jsbin.com/qifezupu/11/edit

Niestety, jak się przekonacie, potrzebne są pewne korekty. To tylko pomysł.


0
2017-07-07 09:07