Czy jest funkcja podobna do window.find() dla obiektów nie window?

0

Witam

Chciałbym skorzystać z funkcji podobnej do window.find ale wyszukiwać tylko w obrębie jednego elementu np. div. Istnieje jakś funkcja podobna lub jakiś sposób zorientowania czy ograniczenia window.find do jednego elementu?

Powiedzmy, że chciałbym zmodyfikować taki kod:

 
var TRange=null;
function findString (str) 
{
 if (parseInt(navigator.appVersion)<4) return;
 var strFound;
 if (window.find) 
{
  strFound=self.find(str);
  if (!strFound) 
  {
   strFound=self.find(str,0,1);
   while (self.find(str,0,1)) continue;
  }
 }
}

0

A co to ma robić niby?

Może jQuery Ci pomoże?

0

funkcja window.find działa identycznie jak Ctrl+F w przeglądarce czyli "podświetla" a właściwie zaznacza szukany ciąg. Chodzi mi o taki sam efekt z tym, że chciałbym przeszukiwać tylko wybrany element strony a nie całe okno czyli w efekcie całą stronę (wszystkie jej elementy).

0

a ten window.find to działa w jakiej przeglądarce? Bo na pewno nie w każdej. Raczej jakieś durne "rozszerzenie" jednej z przeglądarek.

edit: aż sprawdziłem, działa tylko spod frajerfoxa z przeglądarek, które mam ;)

0

Funkcja działa też w Chrome. Tak czy inaczej może ktoś zna inne rozwiązanie problemu.

0

tu masz coś podobnego:
http://stackoverflow.com/questions/926580/find-text-string-using-jquery
(generalnie polecam google)

jedna z odpowiedzi pokazuje jak otoczyć spanem znaleziony ciąg (żeby go podświetlić). Problemem pewnie będzie coś takiego, że masz ciąg tekstu, w którym np jedno słowo jest pogrubione, i chcesz wyszukać ten ciąg... no ale może i na to znajdzie się rozwiązanie (a może nie potrzebujesz tego, bo chcesz wyszukiwać nieformatowany tekst?) gdzieś w czeluściach internetu, może sam zechcesz jakoś parsować tagi i dopisać brakującą funkcjonalność.

0

Ten wątek ze StackOverflow, do którego linkował @dzek69 , nie wydaje się za dobry. Samo pytanie jest lakoniczne. Co znaczy "chcę znaleźć tekst X na stronie"? Czy to znaczy, że chcemy stworzyć listę elementów, które zawierają ten tekst (to samo w sobie jest dość bez sensu, co opiszę dalej)? A może chcemy odpowiedzieć na pytanie, czy dany tekst w ogóle znajduje się na stronie?

Podświetlanie takie jak przy window.find() jest już lepiej sformułowanym problemem. Tyle że jest to problem trudny, więc jeśli możesz go jakoś ograniczyć, to powinieneś to zrobić.

W przypadku ogólnym, proponowane wyżej "parsowanie tagów" jest prawdopodobnie złym podejściem -- to sformułowanie sugeruje pracę na HTML-u, prawdopodobnie poprzez .innerHTML.

Zamiast tego, należałoby rekurencyjnie skakać po drzewie dokumentu. Przeglądać elementy i schodzić aż do węzłów tekstowych. Przeszukiwanie byłoby o tyle trudne, że trzeba by uwzględniać również takie przypadki:

Ala ma ko<span>ta</span>.

A my możemy szukać ciągu 'kot'. Powinniśmy zaznaczyć ten ciąg, mimo że ostatnia litera ('t') znajduje się w innym elemencie. Nie możemy po prostu połączyć rekurencyjnie wszystkich węzłów tekstowych na stronie i na nich dokonać przeszukiwania, bo musimy pamiętać kontekst -- miejsce w dokumencie, gdzie mamy ten tekst. Bo będziemy musieli zmodyfikować drzewo dokumentu, otaczając znaleziony tekst jakimś elementem, by potem podświetlić go jakoś w CSS!

Moglibyśmy użyć <span>a, ale bardziej semantyczny będzie <mark> z HTML-a 5 (wybór elementu nie ma jednak wpływu na trudność algorytmu).

NIE WOLNO jednak zagnieżdżać elementów "na zakładkę", w ten sposób:

<!-- Zły kod!!! -->
Ala ma <mark>ko<span>t</mark>a</span>.

Trzeba wszystkie węzły tekstowe uwzględniać oddzielnie, czyli w tym wypadku musielibyśmy użyć dwóch elementów <mark>:

Ala ma <mark>ko</mark><span><mark>t</mark>a</span>.

Skakanie po DOM i dopasowywanie szukanej frazy jest upierdliwe właśnie dlatego, że początek szukanej frazy może być w jednym węźle, a koniec w drugim. Jeśli dopasowaliśmy 3 litery ze wzorca i doszliśmy do końca węzła, a wzorzec ma 5 liter, to niestety musimy zapamiętać naszą pozycję i końcówki wzorca szukać w następnym węźle, który może być na zupełnie innym poziomie zagnieżdżenia niż obecny. A co jeśli i w tym węźle będzie tylko 1 litera i będzie się ona zgadzała z wzorcem? Zostaje nam ostatnia, piąta litera wzorca -- i musimy szukać jej na początku kolejnego węzła (i zapamiętać kolejną pozycję).

Jest jeszcze jeden problem. W przypadku elementów wierszowych -- jak <span> powyżej -- CHCEMY kontynuować wyszukiwanie i podświetlać również wzorce, które rozciągają się na kilka takich elementów.

Ale co z elementami blokowymi?

<p>Ala ma ko</p><p>ta</p>

Ponieważ <p> to element blokowy, oznaczający paragraf, nie chcemy podkreślić 'ko' na końcu pierwszego paragrafu i 't' na początku następnego. A gdyby to były nie <p>, tylko <spany>, to chcielibyśmy zaznaczyć tekst! W każdym razie tak robią przeglądarki.

Zapewne nie zależy to od tego, jakiego elementu używamy, tylko od tego, jaką generuje on ramkę (własność display z CSS). Jeśli blokową (block), to przerywa szukany ciąg. Jeśli wierszową (inline), to nie. I to musielibyśmy uwzględnić, chcąc zaimplementować własne find().

Dlatego to zadanie jest trudne i niekoniecznie odpowiednie dla kogoś, kto nie jest jeszcze doświadczonym programistą.

0

jeśli nie przeszkadza Ci to że to będzie działać tylko w tych przeglądarkach które wspierają window.find to możesz zrobić zwykłe window.find, tekst się zaznaczy, potem dajesz window.getSelection() i w zwróconym elemencie masz informacje o zaznaczonym elemencie w anchorNode
teraz po prostu sprawdzasz czy ten element jest spokrewniony z elementem w którym chciałbyś szukać przeszukując parentNode'y - tutaj sprawę może ułatwić jQuery sprowadzając całość do jednej linijki:

var czy_element_jest_gdzie_trzeba = !!$(window.getSelection().anchorNode).closest('DIV#KTOREGO_SZUKASZ').length;

jak nie znajdziesz to wykonujesz wszystko od nowa, dopóki window.find nie zwróci false czyli nie będzie więcej elementów

możesz rozszerzyć działanie do IE używając findText czyli ogólnie nie tak źle (jedynie nie będzie działać w operze)

0

@unikalna_nazwa:
"trochę przesadzasz tylko komplikując niepotrzebnie problem - przeglądarki same sobie ustawiają i domykają właściwie tagi przy przypisywaniu do innerHTML - sprawdź sam. Nie widzę realnej potrzeby tracenia na to czasu tym bardziej że to komplikuje problem dość mocno ;)"

Może przesadzam, może nie. Na co dzień jestem raczej tworcą bibliotek niż kodu, który ma rozwiązać jakiś konkretny, dobrze określony problem w mocno ograniczonym środowisku, przy licznych założeniach. Nie zaczynam od wprowadzania założeń i ograniczeń dotyczących kompatybilności czy pracy innych skryptów na stronie. Podchodząc do problemu, raczej na początku (tj. po dowiedzeniu się, że nie ma na to gotowca czy API) myślę o uniwersalnym, kuloodpornym rozwiązaniu -- czasami oznacza to coś w stylu "brute force", tj. robienia pewnych rzeczy ręcznie, bez ułatwiaczy -- i wtedy robię analizę kosztów i optymalizacji.

Mówisz, że "niepotrzebnie komplikuję"? A ja nie jestem pewien, na ile bardziej skomplikowane byłoby skakanie po DOM w porównaniu do przeszukiwania innerHTML. Zauważ, że i w przypadku innerHTML nie mógłbyś korzystać po prostu z str.indexOf(), bo innerHTML zawiera też inne tagi HTML. Jak byś je parsował/odcedzał? Wyrażeniami regularnymi? Takie coś jest niebezpieczne i zapewne już na tym etapie musiałbyś zrezygnować ze 100% dokładności w przypadkach brzegowych. Ludzie często piszą regexpy, które wykrzaczają się np. na:

<span data-relation="n > 2" class="red">Foobar</span>

A przeglądarki to łykają. Choć akurat tym w przypadku .innerHTML nie musimy się martwić, bo przeglądarka zwróci &gt; zamiast pierwszego >. Ogólnie jednak, trzeba bardzo ostrożnie sprawdzić, czy regexpy do naszych zastosowań wystarczą, czy też aby parsować zawsze wszystko porządkie, potrzebujemy parsera SGML.

Tak czy siak, te tagi, komentarze, sekcje CDATA trzeba odcedzać. A raczej: przeskakiwać. Bo potem chcemy przecież wstawić w kod nasze tagi <mark>, nie tracąc formatowania. Więc samo wycięcie nie-tekstu nic nam nie daje: znaleźlibyśmy pozycję w tekście, gdzie chcemy wstawić podkreślenie, ale ma się ona nijak do pozycji w HTML-u.

Operowanie na innerHTML-u nie musi być więc aż tak prostsze jak skakanie po drzewie, gdzie całkowicie odpada nam parsowanie HTML-a, bo robi to za nas przeglądarka.

Na szybko przychodzą mi jeszcze do głowy dwa ograniczenia metody z innerHTML.

Wspomniałem wyżej o różnicach wynikających z renderowania elementów, do których należą fragmenty szukanego ciągu. Że jeśli szukana fraza rozciąga się na kilka elementów wierszowych, to powinniśmy ją podświetlić. A jeśli na kilka blokowych, to już nie. Jak to sprawdzisz, nie odwołując się do aktualnych, wyliczonych stylów danego elementu, dostępnych z poziomu DOM (CSSOM)? CSS może zmieniać typ ramki generowanej przez element, więc nie wystarczy samo rozgraniczenie, że jeśli to <p> to blokowy, a jeśli <span> to wierszowy. Za pomocą innerHTML-a tego po prostu nie sprawdzisz, więc w kolejnych przypadkach brzegowych (?) kod zawiedzie.

I drugi problem: mapilulowanie innerHTML-em danego elementu wywala z niego wszystkie elementy i wstawia nowe. Wszystkie dane doczepione do starych elementów za pomocą JS (zła praktyka, ale ludzie tak piszą) przepadają. Wszystkie event-handlery też -- a doczepianie ich to już normalna praktyka. Trzeba więc nałożyć na programistę-użytkownika kolejne ograniczenia. Np. ograniczenie czasowe "odpal skrypt podświetlający tylko raz, zanim inne skrypty zaczną działać" (i wtedy przepada możliwość zmiany szukanej frazy w locie, tracimy więc funkcjonalność). Albo ograniczenie jakościowe/API: "wewnątrz elementów, w których ma dzialać podświetlanie, używaj wyłącznie delegacji zdarzeń". Oczywiście, niekiedy frazy możemy szukać w całym dokumencie i wtedy musielibyśmy delegować wszystkie zdarzenia (!) aż do <body>. Oczywiście, twórcy bibliotek i skryptów JS-owych -- lightboxów, menu itd. -- tego nie robią, więc część z tych skryptów nie działałaby w części przypadków.

Co z tego wynika? Nie wiem, nie musi wynikać ostateczna decyzja. Przyznaję się np. bez bicia, że nie przeanalizowałem API dostępnego w przeglądarkach i nie chciało mi się nawet sprawdzić, gdzie jest to window.find() -- nie interesuje mnie to w tym momencie. Gdybym to ja miał napisać tę funkcjonalność, na pewno dogłębnie bym to sprawdził.

Nie znamy też ograniczeń, jakie autor tematu może sobie narzucić. Jeśli chce napisać coś, co zadziała tylko w jednej aplikacji, pisanej przez niego, w dodatku tylko w określonym miejscu zawartości, to użycie innerHTML może okazać się wystarczające. Tego jednak na tę chwilę nie wiemy -- gdyby autor był naszym klientem, musielibyśmy przeprowadzić odpowiedni wywiad i jeszcze wziąć poprawkę na to, na ile jego zdanie może się zmienić i na ile opłacalne biznesowo byłoby zaproponowanie ogólniejszego rozwiązania. To mnie jednak też w tym momencie nie interesuje.

Zainteresowało mnie, jak może wyglądać porządne, ogólne rozwiązanie tego problemu i postanowiłem zrobić sobie tutaj małą analizę, która może, ale nie musi przydać się autorowi i innym forumowiczom. Choćby jako eksperyment myślowy czy wgląd w problemy, z jakimi muszą zmagać się twórcy bibliotek.

Czasami opłaca się zrobić coś porządnie i ogólnie (choć... nie zawsze!). Ja np. pracuję w kilkunastoosobowym zespole przy relatywnie sporych projektach, tworzonych przez kilkuosobowe (2-5) "podzespoły". Napisanie paru tysięcy linii kodu bibliotek do jednego projektu nie jest tu niczym niespotykanym. Jeśli rozwiązania te są ogólne, są potem reużywane na kilku (czy więcej) rodzinach portali. Jeśli ogólności brakuje, przy nowym portalu są po prostu wyrzucane i robione od nowa -- czy to w wersji ogólnej, czy kolejnej wersji szczególnej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1