6

I noticed that YouTube doesn't actually reload when you click a link/video on their website. If you define a variable in the console you'll see it will persist.

But neither popstate nor beforeunload get fired. So how is Youtube accomplishing that? And how can I detect that URL change without making a timer constantly check the URL bar.

window.onpopstate = function(event) {
  console.log('popstate test!')
  return "test"
}

window.onbeforeunload = function(event) {
  console.log('beforeunload test!')
  return "test"
}

I'm not just looking for a YouTube-solution, I'm looking for a general solution that covers the technology YouTube is using.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Forivin
  • 14,780
  • 27
  • 106
  • 199
  • when they use ajax there is no entry in history or an beforeunload-event. – Blauharley Jan 20 '17 at 22:32
  • Ajax to change the URL of the address bar?? – Forivin Jan 20 '17 at 22:32
  • are they really change the url completely? as far as I saw is that they change the query-flag(?v=6z-DCbOLYzc) at the end: https://www.youtube.com/watch?v=6z-DCbOLYzc – Blauharley Jan 20 '17 at 22:37
  • First of all, what difference would it make? I mean it's not an achor. And secondly, if you visit a channel or or homepage, it definitely changes more than the querystring. – Forivin Jan 20 '17 at 22:40
  • Yeah, I know what you mean but youtube is nothing special there must be a regular method to accomplish that. I'm not quite sure whether a iframe is used to track history because a history-iframe does also exist on a regulary youtube site(id#history-iframe). Very interesting topic! – Blauharley Jan 20 '17 at 23:00

2 Answers2

2

They're using onpopstate. Paste your JavaScript into the JavaScript console, click on a video, and then click the Back button. You should now see "popstate test!" in the console.

The real problem here is that there's no onpushstate event, but this person seems to have implemented it. There was also a previous StackOverflow question about it. However, this don't seem to work for YouTube, perhaps because they are trying to edit the pushState property of history, but YouTube actually stored history.pushState in a separate variable and is thus unaffected by this code.

However, this transitionend event on the #progress element just for YouTube seems to work.

Noble Mushtak
  • 1,784
  • 10
  • 22
  • 1
    @Forivin None of it works? For me, the `onpopstate` test definitely works, but the `onpushstate` stuff does not. – Noble Mushtak Jan 20 '17 at 23:16
  • Well, as onpopstate wouldn't be of much use, I haven't really tried it again. I mean want an event that gets fired when I navigate to a new url, not when I pres the back button. – Forivin Jan 20 '17 at 23:28
  • @Forivin I am also having trouble finding a `onpushstate` event library that works for me (even though it works when I call `history.pushState`, it does not work when I go to a new URL), but at least this shows that they are using history states somehow since `onpopstate` works. – Noble Mushtak Jan 20 '17 at 23:38
  • @Forivin Someone asked this question before and there is an ad hoc solution for YouTube: https://stackoverflow.com/questions/24297929/javascript-to-listen-for-url-changes-in-youtube-html5-player?rq=1 However, this is also not working for me. – Noble Mushtak Jan 20 '17 at 23:45
  • @Forivin I have found a solution that seems to work and it comes from the list of ad hoc solutions linked above. Please see the edited answer for more info. – Noble Mushtak Jan 23 '17 at 20:57
  • Well, YouTube was just an example. I'm looking for a way to detect URL changes on any website that utilizes the technology YouTube is using. Also, next time YouTube changes an id or something this would break again. There has to be a more sophisticated lower-level way of doing this. – Forivin Jan 23 '17 at 21:04
-2

This can actually be implemented in a really simple way. Suppose you have a link in your webpage

<a id="mylink" href="/new-url">My link</a>

You can override its behavior by returning false from an event handler:

document.getElementById("mylink").onclick = function (event) {
    window.history.pushState({urlPath:'/new-url'}, "", "/new-url");
    // use ajax to reload parts of the page here
    return false;
}

Using this technique you can make only part of the page reload when clicking the link.

Edit

I believe youtube does not listen in any way for location changes. This is because if you actually call

window.location = '/watch?v=notrelevant'

The webpage is still refreshed.

Niebieski
  • 125
  • 6