Jak umieścić linki w dokumencie w konkretnych miejscach?

0

Dla każdego elementu <p> przeprowadzam analizę zawartego w nim tekstu pod kątem możliwości zalinkowania go. Czyli np. dla elementu:

<p>Jakiś tekst bardzo ciekawy</p>

otrzymuję:

<p>Jakiś tekst <a href="http://bardzo.pl">bardzo</a> ciekawy</p>

Na stronie podmieniam więc outerHTML elementu <p> na nową i mam linki.
Niestety, takie rozwiązanie odpina wszystkie zdarzenia przypięte zarówno do <p> jak i jego dzieci. Podejście takie jest więc nieakceptowalne. Próbuję rozkminić, jak uzyskać ten efekt prawilnie, czyli modyfikując strukturę DOM elementu.

Chciałabym więc:

  1. utworzyć nowy element <a> - spoko, proste
  2. wstawić ten element w odpowiednie miejsce elementu <p>...

Jakieś podpowiedzi? Oczywiście, żeby za łatwo nie było, struktura wewnątrz <p> może być dużo bardziej skomplikowana... a linków może być wiele.

0

Taka myśl - skąd masz te treści, które modyfikujesz? Masz na nie jakiś wpływ, czy dostajesz gotową stronę/treść i musisz na niej działać? Pytam, bo może odwrócenie kolejności by coś dało. Czyli - najpierw przerabiasz elementy typu <P> i wstawiasz tam te swoje linki, a dopiero po zakończeniu przerabiania odpalasz mechanizm przypisujący do nich eventy. Bo z tego co napisałaś to rozumiem, że sytuacja jest taka:
1) ktoś/coś tworzy stronę
2) jakiś mechanizm dopina obsługę zdarzeń
3) Ty grzebiesz w jej strukturze i przez to rozwalasz zdarzenia z pkt.2

0

@cerrato niestety działam na istniejących stronach. Konkretnie piszę rozszerzenie do Chrome.

1

A może zabawa nie outerHTML ale innerHTML pomoże?

https://stackoverflow.com/questions/46941911/javascript-innerhtml-vs-outerhtml:

Use innerHTML as default. This replaces only the content (if using i.e. "=") inside the current element referred to. If you are using outerHTML, then the element referred to will also be replaced.

Zgodnie z w/w to outer podmienia cały element, przez co usuwasz przypisane do niego zdarzenia, a inner jedynie modyfikuje zawartość, ale element jako taki pozostaje w drzewie.

3

Spróbuj wykorzystać Node.childNodes. Zawiera on listę nie tylko pod-elementów HTML (jak children) ale także node'y tekstowe (które interesują Cię najbardziej). Możesz wtedy manipulować dowolnie tekstem w node, wrzucać coś pomiędzy niego, dzielić itd. Bez konieczności nadpisywania inner/outer text/html, (co powoduje przeparsowanie elementów i wyrzucenie handlerów).

<p>Trochę tekstu <a href="#">link</a> i więcej tekstu </p>

<script>
    var p = document.getElementsByTagName('p')[0];
    p.removeChild(p.childNodes[0]); // [0] - tekst przed linkiem, [1] - link, [2] - tekst za linkiem
    var text = document.createTextNode('trochę tekstu wygenerowanego');
    p.insertBefore(text, p.childNodes[0]); // na pozycję [0] przesunął się node linka, więc nowy tekst wrzucamy przed niego
</script>

Jeżeli chodzi o tekst w podelementach danego p to niestety z tym podejściem będziesz musiała przejść samemu całe drzewko (korzystając znowu z childNodes i tym razem nie-tekstowych elementów).

0

Tylko tutaj mam taką sytuację (w tym prostym przykładzie), że oryginalny element <p> ma jedno dziecko (node tekstowy), a zmodyfikowany ma 3 dzieci (text, link, text). Czy sugerujesz usuwać elementy tekstowe, a zostawiać inne? Tzn. coś w tym stylu?

foreach (var chiild in originalP.childNodes) {
    if (child jest node'm tekstowym) {
        //przepnij tekst i linki jeśli są
    }
    else {
        //wejdź głębiej i zrób to samo
    }
}

W sumie to chyba ma sens... Muszę wtedy jeszcze rozkminić jak ustalić, które node'y są do przepięcia...

2

Tak, sugeruję rozbijać węzły tekstowe na 3: Tekst przed(jeżeli jest), link (a) i tekst po(jeżeli jest). Węzeł w postaci

<p>Link do gógla http://www.google.pl podaję</p>

Ma 1 element w childNodes, jest nim węzeł tekstowy. Swoim algorytmem znajdujesz w nim link i rozbijasz go na takie 3 węzły:
[0] 'Link do gógla '
[1] Węzeł a z odpowiednim linkiem i opisem
[2] ' podaję'.
Węzły tekstowe mają ustawiony nodeName: "#text", tak je można rozróżnić.
Jeżeli chodzi o trawersowanie drzewa to już dowolność, można wykorzystać różnicę między Node.children a Node.childNodes (jeden nie ma węzłów tekstowych, a drugi tak), można sprawdzać po nodeName, itd.

2

Trochę rzeźbienia było, ale chyba działa :D Jeszcze będzie sporo testów, ale na dość sporej stronie widzę, że jest OK. Zostawię dla potomnych, bo widziałam w google, że problem dość popularny, a większość rozwiązań opierała się o insertAdjacentHTML albo appendChild, co jest IMHO zbyt ubogie.

function InsertLinksIntoParagraph(original, linked) {
    let j = 0;
    for (let i = 0; i < original.childNodes.length; i++) {
        let child = original.childNodes[i];

        if (child.nodeType !== Node.TEXT_NODE) {
            InsertLinksIntoParagraph(child, linked.childNodes[j]);
        } else {           
            //jeżeli ten lub następny node to a.my-link to zacznij czarowanie
            if (elementIsMyLink(linked.childNodes[j]) || elementIsMyLink(linked.childNodes[j + 1])) {
                let linkedChild = linked.childNodes[j];
                while (typeof linkedChild !== 'undefined'
                    && (linkedChild.nodeType === Node.TEXT_NODE || elementIsMyLink(linkedChild))) {
                    original.insertBefore(linkedChild, child);
                    linkedChild = linked.childNodes[j];
                    i++;
                }
                i--;
                j--;
                original.removeChild(child);    
            }            
        }
        j++;
    }
}

function elementIsMyLink(element) {
    return typeof element !== 'undefined'
        && element.tagName === 'A'
        && element.classList.contains('my-link');
}

Edit: No nie, jednak jeszcze trochę sobie porzeźbię :D Powyższe się wywala dla przypadku:

<p>Coś tam coś tam <a class="my-link" href=#>coś tam <span>coś tam</span></a></p>

Czyli gdy w linku jest jeszcze jakiś element. Pfff =_=

1

No dobra, urodziłam to:

function InsertLinksIntoParagraph(original, linked) {
    let j = 0;
    let linkedLength = linked.childNodes.length; 

    for (let i = 0; i < original.childNodes.length; i++) {
        let child = original.childNodes[i];

        if (child.nodeType !== Node.TEXT_NODE) {
            InsertLinksIntoParagraph(child, linked.childNodes[j]);
        } else {           
            //jeżeli ten lub następny node to a.my-link to zacznij czarowanie
            if (elementIsMyLink(linked.childNodes[j]) || elementIsMyLink(linked.childNodes[j + 1])) {
                let linkedChild = linked.childNodes[j];      

                while (typeof linkedChild !== 'undefined'
                    && (linkedChild.nodeType === Node.TEXT_NODE || elementIsMyLink(linkedChild))) {
                    original.insertBefore(linkedChild, child);
                    linkedChild = linked.childNodes[j];
                    i++;
                }
                //posprzątaj original.childNodes
                original.removeChild(child);    

                while (original.childNodes.length > linkedLength) {
                    original.removeChild(original.childNodes[i]);                    
                }

                i--;
                j--;
            }            
        }
        j++;
    }
}

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