Przeglądarka: Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7
Mam nadzieję, że nikt nie zje mnie za długość tego posta! :)
Do przedmówcy, czyli Mirka [PL]. Oczywiście masz rację! Wystarczyło, jako pierwszą i ostatnią linijkę funkcji wstawić:
- Kod: Zaznacz cały
var st = txtarea.scrollTop;
txtarea.scrollTop = st;
i pozycja suwaka pionowego przewijania jest zapamiętywana.
Ja dodałem jeszcze od siebie:
txtarea.focus();, żeby po wstawieniu BBCode'u fokus wracał do pola edycyjnego. Dzięki temu można pisać dalej i nie trzeba klikać ponownie w pole.
Jednak Twój post zmobilizował, żeby dalej rozwijać i poprawiać do rozwiązanie, aby dostosować je w 100% do moich wymagań. Zdaję sobie sprawę, że jestem estetą i większość moich zmian to kosmetyczne poprawki lub bzdurki, którymi większość osób się nie przejmuje. Mimo wszystko - skoro zacząłem ten post - to czuję obowiązek go dokończyć i podzielić się tym, co udało się mi osiągnąć.
W pierwszej kolejności - wywaliłem cały kod odpowiedzialny za obsługę dziwactw w IE. Ja osobiście używam tego rozwiązania tylko w FF, a poza tym jestem zagorzałym fanem (czasem - fanatykiem) czystości kodu, usuwania zbędnych fragmentów oraz zgodności ze standardami. Na pewno nie mam zamiaru pisać oddzielnego kodu dla owej wieśniackiej przeglądarki. Dlatego, jeśli ktoś planuje wykorzystać to rozwiązanie na stronie, która będzie musiała działać też pod IE, musi pobrać oryginalną wersję kodu z
tej strony (gdzie cała ta "zabawa" się zaczęła) i dostosować ją do swoich potrzeb.
W drugiej kolejności wziąłem się za pozycję kursora. Drażniło mnie bardzo to, że mimo, iż jest zapamiętywana pozycja suwaka pionowego, to mimo wszystko kursor po każdym wstawieniu ląduje na końcu tekstu, a w miejscu wstawienia. Dodałem więc taki kod:
- Kod: Zaznacz cały
var str = lft + s2 + rgt;
txtarea.selectionStart = selStart + str.length;
txtarea.selectionEnd = selStart + str.length;
Dzięki temu, po wstawieniu BBCode kursor ląduje dokładnie za wstawką i można kontynuować pisanie od miejsca, w którym się ono skończyło.
Dokładnie to samo dzieje się, jeśli klawisz wstawiania naciśniemy, gdy nie jest zaznaczony żaden tekst. Wówczas kursor również ląduje na końcu wstawki. Ja jednak chciałem mieć funkcjonalność znaną np. z kEDa. Tam, jeśli brak jest zaznaczenia, to kursor po wstawieniu ląduje
wewnątrz wstawki (pomiędzy otwierającym i zamykającym fragmentem) i od razu można wpisać tekst, który ma być tą wstawką objęty. Bez konieczności przesuwania kursora. Powyższy kod został więc zmodyfikowany do takiej postaci:
- Kod: Zaznacz cały
if (selStart == selEnd)
{
var str = lft;
txtarea.selectionStart = selStart + str.length;
txtarea.selectionEnd = selStart + str.length;
}
else
{
var str = lft + s2 + rgt;
txtarea.selectionStart = selStart + str.length;
txtarea.selectionEnd = selStart + str.length;
}
Nie wiem, jak inni, ale ja wielokrotnie zaznaczam tekst w edytorze w ten sposób, że dwuklikam LKM w dowolnym miejscu, co powoduje zaznaczenie całego wyrazu. Jednakże, jeśli po wyrazie jest spacja to jest ona również brana w zaznaczenie. Gdy się potem wstawi wstawkę (np. pogrubienie) to obejmuje ono również tą spację. Niby bzdurka, ale mnie to drażni, więc postanowiłem to zmienić. Tym bardziej, że kod potrzebny do usunięcia tego to zaledwie dwie linijki:
- Kod: Zaznacz cały
var t = (txtarea.value).substring(selEnd - 1, selEnd);
if (t == ' ') selEnd--;
Mamy więc ostatecznie blokowanie automatycznego przesuwania się suwaka do początku po każdej wstawce, ignorowanie ostatniej spacji w zaznaczeniu, umieszczanie kursora po wstawce (gdy jest zaznaczony tekst), a nie na końcu całości. Lub wewnątrz wstawki (gdy nic nie było zaznaczone). I - cytując przedmówcę - twórcy phpBB i IPB mogliby się od nas uczyć! :P
Ostateczna wersja funkcji wygląda więc tak:
- Kod: Zaznacz cały
function insert_bbcode(txtarea, lft, rgt)
{
var st = txtarea.scrollTop;
var selLength = txtarea.textLength;
var selStart = txtarea.selectionStart;
var selEnd = txtarea.selectionEnd;
if (selEnd == 1 || selEnd == 2) selEnd = selLength;
var t = (txtarea.value).substring(selEnd - 1, selEnd);
if (t == ' ') selEnd--;
var s1 = (txtarea.value).substring(0, selStart);
var s2 = (txtarea.value).substring(selStart, selEnd)
var s3 = (txtarea.value).substring(selEnd, selLength);
txtarea.value = s1 + lft + s2 + rgt + s3;
if (selStart == selEnd)
{
var str = lft;
txtarea.selectionStart = selStart + str.length;
txtarea.selectionEnd = selStart + str.length;
}
else
{
var str = lft + s2 + rgt;
txtarea.selectionStart = selStart + str.length;
txtarea.selectionEnd = selStart + str.length;
}
txtarea.scrollTop = st;
txtarea.focus();
}
Dla zainteresowanych podaję też prostą funkcję, której również używam, a która wstawia adres URL sensowniej (moim zdaniem), niż robi to klawisz URL w tym forum, czy na IPB. Też ktoś mógłby to zaimportować tutaj:
- Kod: Zaznacz cały
function insert_bbcode_url(txtarea)
{
var my_link = prompt("Podaj adres URL:", "http://");
if (my_link != null)
{
lft = "[url=" + my_link + "]";
rgt = "[/url]";
insert_bbcode(txtarea, lft, rgt);
}
txtarea.focus();
return;
}
Nie wszystko jednak udało mi się tak prosto rozwiązać. Czy ktoś uprzejmie może mi wytłumaczyć, dlaczego Firefox totalnie olewa atrybut
accesskey? Nawet tutaj, w tym forum, są porobione skróty klawiszowe do klawiszy wstawiających wstawki BBCode. Co więcej - nawet jest help, który wyraźnie podaje te skróty, gdy się najedzie na odpowiedni klawisz. B to jest alt+b, Quote to alt+q i... tak dalej. Wszystko pięknie, ładnie - tylko szkoda, że to nie działa. Mogę do śmierci naciskać te kombinacje klawiszy i nic niestety nie jest wstawiane! :/
Brak obsługi
accesskey w Firefoxie zauważyłem już dużo wcześniej, zanim zacząłem myśleć o własnym edytorze BBCode. Dlatego już na etapie jego projektowania nawet nie liczyłem na tą funkcjonalność. Tu z pomocą znowu przyszło oryginalne rozwiązanie, znajdujące się na
tej stronie. Użyłem funkcji stamtąd, jedynie lekko ją poprawiając:
- Kod: Zaznacz cały
document.onkeypress = function (e)
{
ctrl = e.ctrlKey;
shft = e.shiftKey;
chr = e.charCode;
if (ctrl && shft && chr == 65) insert_bbcode_url(txtarea);
if (ctrl && shft && chr == 66) insert_bbcode(txtarea,'[b]','[/b]');
if (ctrl && shft && chr == 73) insert_bbcode(txtarea,'[i]','[/i]');
if (ctrl && shft && chr == 85) insert_bbcode(txtarea,'[u]','[/u]');
return true;
}
Tu w tym przypadku działa kombinacja Ctrl+Shift+a dla wstawiania adresu, b - dla pogrubienia, i - dla kursywy i u - dla podkreślenia. Ale łatwo można to rozbudować o kolejne skróty. Zastosowanie kombinacji dwóch klawiszy funkcyjnych (ctrl+alt) pozwala ominąć większość skrótów wbudowanych w Firefoxa. Bowiem w wersji tylko z altem np. zaraz po wstawieniu podkreślenia wyświetlało się źródło strony. A przy innych klawiszach działy się inne równie ciekawe rzeczy.
Na koniec chciałem jeszcze zapytać o jedną, prostą rzecz. Dlaczego takie coś nie działa:
- Kod: Zaznacz cały
<button type="button" onclick="insert_bbcode(document.edit_post.message, '\"[i]', '[/i]\"');">Cytat</button>
W konsoli błędów dostaję komunikat "
Unterminated string literal". Próbowałem różnych kombinacji - cudzysłowów pojedynczych i podwójnych i w żadnej wersji nie udało mi się osiągnąć zamierzonego celu. Jak więc przekazać cudzysłów jako parametr funkcji JS wywoływanej z poziomu XHTML?
Ufff... To chyba wszystko. Ponownie przepraszam tych, których przeraziła długość tego posta. Mam nadzieję, że mimo wszystko będzie on komuś przydatny.