Jak wykryć zdarzenie przycisku Wstecz przeglądarki - przeglądarka internetowa


219

Jak ostatecznie wykryć, czy użytkownik nacisnął przycisk Wstecz w przeglądarce?

Jak wymusić użycie przycisku cofania na stronie w aplikacji internetowej na jednej stronie za pomocą #URLsystemu?

Dlaczego, u licha, przyciski powrotu przeglądarki nie uruchamiają własnych wydarzeń !?


2
Chciałbym, aby zdarzenia nawigacyjne (do tyłu / do przodu) zostały dodane. Do tej pory jest to coś w pracy developer.mozilla.org/en-US/docs/Web/API/…
llaaalu

Odpowiedzi:


184

(Uwaga: zgodnie z opinią Sharky, dołączyłem kod do wykrywania backspace)

Tak więc często widziałem te pytania na SO, a ostatnio sam miałem problem z kontrolowaniem funkcji przycisku Wstecz. Po kilku dniach poszukiwania najlepszego rozwiązania dla mojej aplikacji (jednostronicowa z nawigacją mieszającą), opracowałem prosty, bezobsługowy system wykrywania w przeglądarce dla różnych przeglądarek.

Większość osób zaleca używanie:

window.onhashchange = function() {
 //blah blah blah
}

Jednak ta funkcja będzie również wywoływana, gdy użytkownik użyje elementu na stronie, który zmienia skrót lokalizacji. Nie jest to najlepsze doświadczenie użytkownika, gdy użytkownik klika, a strona przewija się do tyłu lub do przodu.

Aby dać ogólny zarys mojego systemu, wypełniam tablicę poprzednimi hashami, gdy mój użytkownik porusza się po interfejsie. Wygląda to mniej więcej tak:

function updateHistory(curr) {
    window.location.lasthash.push(window.location.hash);
    window.location.hash = curr;
}

Całkiem prosto. Robię to, aby zapewnić obsługę wielu przeglądarek, a także obsługę starszych przeglądarek. Po prostu przekaż nowy skrót do funkcji, a on zapisze go dla ciebie, a następnie zmieni skrót (który jest następnie zapisywany w historii przeglądarki).

Korzystam również z przycisku Wstecz na stronie, który przenosi użytkownika między stronami za pomocą lasthashtablicy. To wygląda tak:

function goBack() {
    window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
    //blah blah blah
    window.location.lasthash.pop();
}

Spowoduje to przeniesienie użytkownika z powrotem do ostatniego skrótu i ​​usunięcie tego ostatniego skrótu z tablicy (w tej chwili nie mam przycisku przewijania).

Więc. Jak wykryć, czy użytkownik użył przycisku Wstecz na stronie lub przycisku przeglądarki?

Na początku patrzyłem window.onbeforeunload, ale bezskutecznie - jest to wywoływane tylko wtedy, gdy użytkownik zamierza zmienić strony. Nie dzieje się tak w przypadku aplikacji jednostronicowej korzystającej z funkcji skrótu.

Po dłuższym kopaniu zobaczyłem zalecenia dotyczące próby ustawienia zmiennej flagowej. Problem w tym przypadku polega na tym, że spróbuję to ustawić, ale ponieważ wszystko jest asynchroniczne, nie zawsze będzie ono ustawione na czas na zmianę instrukcji if w haszowaniu. .onMouseDownnie zawsze było wywoływane kliknięciem, a dodanie go do kliknięcia nigdy nie uruchomiłoby go wystarczająco szybko.

To wtedy zacząłem patrzeć na różnicę między document, a window. Moim ostatecznym rozwiązaniem było ustawienie flagi za pomocą document.onmouseoveri wyłączenie jej za pomocą document.onmouseleave.

Co się dzieje, gdy mysz użytkownika znajduje się w obszarze dokumentu (czytaj: renderowana strona, ale z wyłączeniem ramki przeglądarki), moja wartość logiczna jest ustawiona na true. Gdy tylko mysz opuści obszar dokumentu, wartość logiczna zmienia się na false.

W ten sposób mogę zmienić moje window.onhashchangena:

window.onhashchange = function() {
    if (window.innerDocClick) {
        window.innerDocClick = false;
    } else {
        if (window.location.hash != '#undefined') {
            goBack();
        } else {
            history.pushState("", document.title, window.location.pathname);
            location.reload();
        }
    }
}

Zauważysz czek na #undefined. Wynika to z faktu, że jeśli w mojej tablicy nie ma dostępnej historii, funkcja zwraca wartość undefined. Używam tego, aby zapytać użytkownika, czy chce odejść za pomocą window.onbeforeunloadzdarzenia.

Krótko mówiąc, dla osób, które niekoniecznie używają przycisku Wstecz na stronie lub tablicy do przechowywania historii:

document.onmouseover = function() {
    //User's mouse is inside the page.
    window.innerDocClick = true;
}

document.onmouseleave = function() {
    //User's mouse has left the page.
    window.innerDocClick = false;
}

window.onhashchange = function() {
    if (window.innerDocClick) {
        //Your own in-page mechanism triggered the hash change
    } else {
        //Browser back button was clicked
    }
}

I masz to. prosty, trzyczęściowy sposób wykrywania użycia przycisku Wstecz w porównaniu z elementami na stronie w odniesieniu do nawigacji hash.

EDYTOWAĆ:

Aby mieć pewność, że użytkownik nie użyje backspace, aby wywołać zdarzenie back, możesz również dołączyć następujące (Dzięki @thetoolman na to pytanie ):

$(function(){
    /*
     * this swallows backspace keys on any non-input element.
     * stops backspace -> back
     */
    var rx = /INPUT|SELECT|TEXTAREA/i;

    $(document).bind("keydown keypress", function(e){
        if( e.which == 8 ){ // 8 == backspace
            if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                e.preventDefault();
            }
        }
    });
});

5
+1 fajny pomysł, ale myślę, że to się nie powiedzie, jeśli użytkownik użyje dowolnego skrótu klawiaturowego do „wstecz” (klawisz Backspace w Firefox), gdy jego mysz znajduje się w oknie przeglądarki
Sharky

3
Zrobię - i tak jestem teraz w biurze :) (EDYCJA: Gotowe teraz)
Xarus

7
Co z telefonem komórkowym (np. Ipad)
basarat

5
Co z wydarzeniami przeciągania z gładzika na MAC. Czy to też można uchwycić?
Sriganesh Navaneethakrishnan

6
Jak rozróżnić przyciski do przodu i do tyłu?
Mr_Perfect,

79

Możesz wypróbować popstatemoduł obsługi zdarzeń, np .:

window.addEventListener('popstate', function(event) {
    // The popstate event is fired each time when the current history entry changes.

    var r = confirm("You pressed a Back button! Are you sure?!");

    if (r == true) {
        // Call Back button programmatically as per user confirmation.
        history.back();
        // Uncomment below line to redirect to the previous page instead.
        // window.location = document.referrer // Note: IE11 is not supporting this.
    } else {
        // Stay on the current page.
        history.pushState(null, null, window.location.pathname);
    }

    history.pushState(null, null, window.location.pathname);

}, false);

Uwaga: Aby uzyskać najlepsze wyniki, należy ładować ten kod tylko na określonych stronach, na których chcesz zaimplementować logikę, aby uniknąć innych nieoczekiwanych problemów.

Zdarzenie popstate jest uruchamiane za każdym razem, gdy zmienia się bieżący wpis historii (użytkownik przechodzi do nowego stanu). Że dzieje się, gdy użytkownik kliknie na przyciski Wstecz / Forward przeglądarce lub kiedy history.back(), history.forward(), history.go()metody są programowo nazywa.

Właściwość event.stateis zdarzenia jest równa obiektowi stanu historii.

Aby uzyskać składnię jQuery, zawiń ją (aby dodać nawet słuchacza, gdy dokument będzie gotowy):

(function($) {
  // Above code here.
})(jQuery);

Zobacz także: window.onpopstate przy ładowaniu strony


Zobacz także przykłady dotyczące aplikacji jednostronicowych i strony pushState HTML5 :

<script>
// jQuery
$(window).on('popstate', function (e) {
    var state = e.originalEvent.state;
    if (state !== null) {
        //load content with ajax
    }
});

// Vanilla javascript
window.addEventListener('popstate', function (e) {
    var state = e.state;
    if (state !== null) {
        //load content with ajax
    }
});
</script>

Powinno to być zgodne z Chrome 5+, Firefox 4+, IE 10+, Safari 6+, Opera 11.5+ i podobne.


2
Kenorb, masz rację, że popstate działa na tę zmianę, ale nie rozróżnia programowo wywoływania zdarzenia od momentu kliknięcia przez użytkownika przycisków przeglądarki.
Xarus,

1
Świetny post na temat aplikacji jednostronicowych i pushState HTML5 . Idealny do nowoczesnych „układów jednej strony” lub „aplikacji jednostronicowych”. Dziękuję za link i odpowiedź!
lowtechsun

1
e. stan wydaje się zawsze niezdefiniowany we współczesnych przeglądarkach
FAjir

Sugeruję umieszczenie kodu we fragmencie, aby można go było uruchomić bezpośrednio tutaj.
FourCinnamon0

16

Od dłuższego czasu zmagałem się z tym wymogiem i wdrożyłem niektóre z powyższych rozwiązań. Natknąłem się jednak na obserwację i wydaje się, że działa ona w przeglądarkach Chrome, Firefox i Safari + Android i iPhone

Ładowanie strony:

window.history.pushState({page: 1}, "", "");

window.onpopstate = function(event) {

  // "event" object seems to contain value only when the back button is clicked
  // and if the pop state event fires due to clicks on a button
  // or a link it comes up as "undefined" 

  if(event){
    // Code to handle back button or prevent from navigation
  }
  else{
    // Continue user action through link or button
  }
}

Daj mi znać, jeśli to pomoże. Jeśli czegoś brakuje, chętnie to zrozumiem.


1
Nie prawda. eventma wartość nawet dla przycisku przewijania
Daniel Birowsky Popeski

14

W javascript typ nawigacji 2oznacza kliknięcie przycisku Wstecz lub Dalej przeglądarki, a przeglądarka faktycznie pobiera zawartość z pamięci podręcznej.

if(performance.navigation.type == 2)
{
    //Do your code here
}

1
To nie działa w przypadku aplikacji na pojedynczej stronie, wynik zawsze wynosi 1 (co oznacza przeładowanie). Co więcej, nie robi różnicy między przyciskiem Wstecz i Dalej, co jest bardzo niefortunne.
papillon

„Co więcej, nie robi to różnicy między przyciskiem Wstecz i Dalej, co jest bardzo niefortunne.” Tak, ponieważ za każdym razem, gdy dane są pobierane z pamięci podręcznej, tym razem performance.navigation.type wynosi 2
Hasan Badshah

Nie gwarantuje się, że będzie działać we wszystkich przeglądarkach! więc powinieneś napisać coś takiego: if (window.performance) {// kod związany z wydajnością} również lepiej jest użyć TYPE_BACK_FORWARD zamiast 2 dla większej czytelności.
blank94

7

To na pewno zadziała (do wykrywania kliknięcia przycisku Wstecz)

$(window).on('popstate', function(event) {
 alert("pop");
});

6

Zobacz:

history.pushState(null, null, location.href);
    window.onpopstate = function () {
        history.go(1);
    };

to działa dobrze...


Nie działa w Chrome 78.0.3904.70 (oficjalna wersja) (64-bit)
Jeffz

Potwierdzono pracę nad Brave v1.3.118 >> Chromium: 80.0.3987.116 (Official Build) (64-bit)
ZeroThe2nd

Nie działa, jeśli trafiłeś na stronę z zewnętrznej strony.
Milan Vlach

5
if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
  alert('hello world');
}

To jedyne rozwiązanie, które działało dla mnie (nie jest to strona internetowa). Działa z Chrome, Firefox i Safari.


1
Window.performance.navigation zostało wycofane. Oto dokumentacja developer.mozilla.org/en-US/docs/Web/API/Performance/navigation
llaaalu 18.06.19

To działało dla mnie na mojej stronie .cshtml. Z powodzeniem działał na Chrome i IE. Dzięki
Justjyde,

5

Prawidłowa odpowiedź jest już dostępna, aby odpowiedzieć na pytanie. Chcę wspomnieć o nowym JavaScript API PerformanceNavigationTiming , który zastępuje przestarzałe performance.navigation .

Poniższy kod zaloguje się do konsoli „back_forward”, jeśli użytkownik wylądował na Twojej stronie za pomocą przycisku Wstecz lub Dalej. Spójrz na tabelę zgodności przed użyciem jej w swoim projekcie.

var perfEntries = performance.getEntriesByType("navigation");
for (var i = 0; i < perfEntries.length; i++) {
    console.log(perfEntries[i].type);
}

To nie jest sposób na stwierdzenie, czy kliknięto przycisk Wstecz na tej stronie . Informuje, czy został kliknięty na ostatniej stronie .
Seph Reed

Ale okazało się, że jest to rzeczywista odpowiedź, której szukałem, ponieważ problem pojawia się po tym, jak nacisnąłem przycisk Wstecz, a nie wcześniej, co oznacza, że ​​mogę wbudować kod odpowiedzi, który zatrzymuje problemy z duplikacjami żądań. Dzięki.
Andrew

1
To może nie odpowiedzieć na pytanie, ale dokładnie to, czego potrzebowałem! Fajny - nie wiedziałem o tym ...
Hogsmill

4

Przeglądarka: https://jsfiddle.net/Limitlessisa/axt1Lqoz/

Do sterowania mobilnego: https://jsfiddle.net/Limitlessisa/axt1Lqoz/show/

$(document).ready(function() {
  $('body').on('click touch', '#share', function(e) {
    $('.share').fadeIn();
  });
});

// geri butonunu yakalama
window.onhashchange = function(e) {
  var oldURL = e.oldURL.split('#')[1];
  var newURL = e.newURL.split('#')[1];

  if (oldURL == 'share') {
    $('.share').fadeOut();
    e.preventDefault();
    return false;
  }
  //console.log('old:'+oldURL+' new:'+newURL);
}
.share{position:fixed; display:none; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,.8); color:white; padding:20px;
<!DOCTYPE html>
<html>

<head>
    <title>Back Button Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

</head>

<body style="text-align:center; padding:0;">
    <a href="#share" id="share">Share</a>
    <div class="share" style="">
        <h1>Test Page</h1>
        <p> Back button press please for control.</p>
    </div>
</body>

</html>


To nie odpowiada na zadane pytanie. Pytanie dotyczy wykrycia użycia przycisku Wstecz na stronie w porównaniu z natywnym przyciskiem Wstecz przeglądarki.
Xarus,

2
Pytanie jest oznaczone javascript, a nie jquery.
skwny

3

Oto moje zdanie na ten temat. Zakłada się, że gdy adres URL zmienia się, ale nie wykryto kliknięcia w documentwykrytym urządzeniu, jest to przeglądarka wstecz (tak lub dalej). Kliknięcie użytkownika jest resetowane po 2 sekundach, aby działało na stronach, które ładują zawartość przez Ajax:

(function(window, $) {
  var anyClick, consoleLog, debug, delay;
  delay = function(sec, func) {
    return setTimeout(func, sec * 1000);
  };
  debug = true;
  anyClick = false;
  consoleLog = function(type, message) {
    if (debug) {
      return console[type](message);
    }
  };
  $(window.document).click(function() {
    anyClick = true;
    consoleLog("info", "clicked");
    return delay(2, function() {
      consoleLog("info", "reset click state");
      return anyClick = false;
    });
  });
  return window.addEventListener("popstate", function(e) {
    if (anyClick !== true) {
      consoleLog("info", "Back clicked");
      return window.dataLayer.push({
        event: 'analyticsEvent',
        eventCategory: 'test',
        eventAction: 'test'
      });
    }
  });
})(window, jQuery);

2

Byłem w stanie użyć niektórych odpowiedzi w tym wątku i innych, aby uruchomić go w IE i Chrome / Edge. history.pushState dla mnie nie był obsługiwany w IE11.

if (history.pushState) {
    //Chrome and modern browsers
    history.pushState(null, document.title, location.href);
    window.addEventListener('popstate', function (event) {
        history.pushState(null, document.title, location.href);
    });
}
else {
    //IE
    history.forward();
}

Właśnie wypróbowałem to na Chrome 78.0.3904.70 (oficjalna wersja) (64-bit) i nie działało.
Jeffz

2

Pełnoprawny komponent można wdrożyć tylko wtedy, gdy ponownie zdefiniujesz API (zmienisz metody „historii” obiektu). Podzielę się właśnie zapisaną klasą. Testowane na Chrome i Mozilli Obsługują tylko HTML5 i ECMAScript5-6

class HistoryNavigation {
    static init()
    {
        if(HistoryNavigation.is_init===true){
            return;
        }
        HistoryNavigation.is_init=true;

        let history_stack=[];
        let n=0;
        let  current_state={timestamp:Date.now()+n};
        n++;
        let init_HNState;
        if(history.state!==null){
            current_state=history.state.HNState;
            history_stack=history.state.HNState.history_stack;
            init_HNState=history.state.HNState;
        } else {
            init_HNState={timestamp:current_state.timestamp,history_stack};
        }
        let listenerPushState=function(params){
            params=Object.assign({state:null},params);
            params.state=params.state!==null?Object.assign({},params.state):{};
            let h_state={ timestamp:Date.now()+n};
            n++;
            let key = history_stack.indexOf(current_state.timestamp);
            key=key+1;
            history_stack.splice(key);
            history_stack.push(h_state.timestamp);
            h_state.history_stack=history_stack;
            params.state.HNState=h_state;
            current_state=h_state;
            return params;
        };
        let listenerReplaceState=function(params){
            params=Object.assign({state:null},params);
            params.state=params.state!==null?Object.assign({},params.state):null;
            let h_state=Object.assign({},current_state);
            h_state.history_stack=history_stack;
            params.state.HNState=h_state;
            return params;
        };
        let desc=Object.getOwnPropertyDescriptors(History.prototype);
        delete desc.constructor;
        Object.defineProperties(History.prototype,{

            replaceState:Object.assign({},desc.replaceState,{
                value:function(state,title,url){
                    let params={state,title,url};
                    HistoryNavigation.dispatchEvent('history.state.replace',params);
                    params=Object.assign({state,title,url},params);
                    params=listenerReplaceState(params);
                    desc.replaceState.value.call(this,params.state,params.title,params.url);
                }
            }),
            pushState:Object.assign({},desc.pushState,{
                value:function(state,title,url){
                    let params={state,title,url};
                    HistoryNavigation.dispatchEvent('history.state.push',params);
                    params=Object.assign({state,title,url},params);
                    params=listenerPushState(params);
                    return desc.pushState.value.call(this, params.state, params.title, params.url);
                }
            })
        });
        HistoryNavigation.addEventListener('popstate',function(event){
            let HNState;
            if(event.state==null){
                HNState=init_HNState;
            } else {
                HNState=event.state.HNState;
            }
            let key_prev=history_stack.indexOf(current_state.timestamp);
            let key_state=history_stack.indexOf(HNState.timestamp);
            let delta=key_state-key_prev;
            let params={delta,event,state:Object.assign({},event.state)};
            delete params.state.HNState;
            HNState.history_stack=history_stack;
            if(event.state!==null){
                event.state.HNState=HNState;
            }
            current_state=HNState;
            HistoryNavigation.dispatchEvent('history.go',params);
        });

    }
    static addEventListener(...arg)
    {
        window.addEventListener(...arg);
    }
    static removeEventListener(...arg)
    {
        window.removeEventListener(...arg);
    }
    static dispatchEvent(event,params)
    {
        if(!(event instanceof Event)){
            event=new Event(event,{cancelable:true});
        }
        event.params=params;
        window.dispatchEvent(event);
    };
}
HistoryNavigation.init();

// exemple

HistoryNavigation.addEventListener('popstate',function(event){
    console.log('Will not start because they blocked the work');
});
HistoryNavigation.addEventListener('history.go',function(event){
    event.params.event.stopImmediatePropagation();// blocked popstate listeners
    console.log(event.params);
    // back or forward - see event.params.delta

});
HistoryNavigation.addEventListener('history.state.push',function(event){
    console.log(event);
});
HistoryNavigation.addEventListener('history.state.replace',function(event){
    console.log(event);
});
history.pushState({h:'hello'},'','');
history.pushState({h:'hello2'},'','');
history.pushState({h:'hello3'},'','');
history.back();

    ```

Niezłe podejście! Dzięki za dodanie tego (wciąż wydaje mi się niesamowite, że po tylu latach jest rozmowa na ten temat)
Xarus,

To wydaje się być sprytnym mechanizmem śledzenia historii. Jednak kod nie jest komentowany, więc jego przestrzeganie jest dość trudne. Jeśli ktoś opuści bieżącą stronę, kod nie wykryje tego naciśnięcia przycisku, co nie odpowiada pierwotnemu pytaniu: „Jak ostatecznie wykryć, czy użytkownik nacisnął przycisk Wstecz w przeglądarce?”. Naciskanie przycisków i śledzenie historii to dwie różne rzeczy, nawet jeśli jedna może wywołać drugą. Fakt, że wciąż trwa rozmowa, wskazuje na poważną wadę w projektowaniu przeglądarki internetowej.
CubicleSoft

1

Document.mouseover nie działa dla IE i FireFox. Jednak próbowałem tego:

$(document).ready(function () {
  setInterval(function () {
    var $sample = $("body");
    if ($sample.is(":hover")) {
      window.innerDocClick = true;
    } else {
      window.innerDocClick = false;
    }
  });

});

window.onhashchange = function () {
  if (window.innerDocClick) {
    //Your own in-page mechanism triggered the hash change
  } else {
    //Browser back or forward button was pressed
  }
};

Działa to w przypadku Chrome i IE, a nie FireFox. Nadal pracuję nad poprawą działania FireFox. Każdy prosty sposób na wykrycie kliknięcia przycisku Wstecz / Dalej przeglądarki jest mile widziany, szczególnie w JQuery, ale także w AngularJS lub zwykłym JavaScript.


1
 <input style="display:none" id="__pageLoaded" value=""/>


 $(document).ready(function () {
        if ($("#__pageLoaded").val() != 1) {

            $("#__pageLoaded").val(1);


        } else {
            shared.isBackLoad = true;
            $("#__pageLoaded").val(1);  

            // Call any function that handles your back event

        }
    });

Powyższy kod działał dla mnie. W przeglądarkach mobilnych, gdy użytkownik kliknął przycisk Wstecz, chcieliśmy przywrócić stan strony zgodnie z jego poprzednią wizytą.


Powyższy kod działał dla mnie w przeglądarkach mobilnych, kiedy użytkownicy kliknęli przycisk Wstecz, chcieliśmy przywrócić stan strony zgodnie z jego poprzednią wizytą
Ashwin

0

Rozwiązałem go, śledząc oryginalne zdarzenie, które wywołało hashchange(machnięcie, kliknięcie lub koło), aby zdarzenie nie mogło zostać pomylone z prostym lądowaniem na stronie, oraz użycie dodatkowej flagi w każde z moich powiązań zdarzeń. Przeglądarka nie ustawia flagi ponownie falsepo naciśnięciu przycisku Wstecz:

var evt = null,
canGoBackToThePast = true;

$('#next-slide').on('click touch', function(e) {
    evt = e;
    canGobackToThePast = false;
    // your logic (remember to set the 'canGoBackToThePast' flag back to 'true' at the end of it)
}

-21

Próbowałem powyższych opcji, ale żadna z nich nie działa dla mnie. Oto rozwiązanie

if(window.event)
   {
        if(window.event.clientX < 40 && window.event.clientY < 0)
        {
            alert("Browser back button is clicked...");
        }
        else
        {
            alert("Browser refresh button is clicked...");
        }
    }

Patrz link http://www.codeproject.com/Articles/696526/Solution-to-Browser-Back-Button-Click-Event-Handli więcej szczegółów


8
@MunamYousuf To dość oczywiste, dlaczego ten fragment kodu tak naprawdę nie działa. Śledzi przycisk Wstecz przeglądarki, ale przycisk znajduje się poza oknem ekranu, dlatego współrzędne clientX i clientY nie powinny być dostępne. Zakładając, że to działa, co powiesz na iOS? Przycisk Wstecz znajduje się na dole ... Również sposób, w jaki jest napisany, jest bardzo nieefektywny, jest to warunek każdego wywołanego zdarzenia ... Boże, jest tak źle, że dam mu głos w dół.
James Wong - Przywróć Monikę

To jest przerażające! dlaczego miałbyś to robić? : / i to nawet nie zadziała, jak powiedział James.
msqar
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.