I have HTML5 video in one of the pages with autoplay enabled. That video keeps playing from beginning when I browse other pages after visiting the page with the video.
To reproduce the issue, just add this code in one of the .erb file:
<video controls autoplay>
<source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
Then navigate to that page and then to other pages. Tested in Chrome, Firefox and Safari in Mac.
hi all, i meet this issue too. Any update for this?
It's funny this bug :smile:
:D i just paused video
This is sort of less a bug than fundamentally how TL5 works by design.
Unlike TL3's "partial replacement", TL5 _removes all elements in the body from the DOM_, no matter what. If an element has a data-turbolinks-permanent attribute, it is still removed from the old page's body and moved into the new one, which is what's causing the behavior you're seeing.
Unfortunately, I think probably the only way this will be fixed is with some kind of dom-diffing plugin so that elements which persist between pages are not removed and re-inserted.
A solution mentioned in #157 which may work here is to create an HTMLVideoElement without an associated tag.
Any idea how to actually solve this?
Here's how I managed it.
document.addEventListener("turbolinks:request-end", function() {
if ($('video').length > 0) {
$('video').remove()
}
});
I'm also encountering this issue.
The only workaround I've found is to opt out of Turbolinks cache completely.
<meta name="turbolinks-cache-control" content="no-cache">
This is what I am using to get around the issue.
Dynamically add the video element on load then remove before it gets cached. In this snippet, content_player_div is the parent element of the video element.
<script>
$(document).one("turbolinks:before-cache", function(event) {
$("video[id=content_player_video]").remove();
});
$(document).one("turbolinks:load", function(event) {
if( $("#content_player_video").length == 0 ) {
$("#content_player_div").append(
$("<video controls autoplay/>")
.attr("id", "content_player_video")
.attr("oncontextmenu", "return false;")
.attr("controlList", "nodownload")
.append($("<source/>")
.attr("src", "<%= source_url %>")
.attr("type", "video/mp4")
)
)
}
});
</script>
As has been hinted at, this is due to Turbolinks caching. Even though the autoplay-video is not visible, it is stored in the cache, and therefore will still play automatically.
I think Turbolinks could handle this by default, but in the meantime, and as an alternative to disabling the cache, or re-constructing the video element manually, you may find the following script useful. Similar to Persisting Elements Across Page Loads, this solution requires that autoplay elements have a unique ID…
;(function () {
var each = Array.prototype.forEach
var autoplayIds = []
document.addEventListener('turbolinks:before-cache', function () {
var autoplayElements = document.querySelectorAll('[autoplay]')
each.call(autoplayElements, function (element) {
if (!element.id) throw 'autoplay elements need an ID attribute'
autoplayIds.push(element.id)
element.removeAttribute('autoplay')
})
})
document.addEventListener('turbolinks:before-render', function (event) {
autoplayIds = autoplayIds.reduce(function (ids, id) {
var autoplay = event.data.newBody.querySelector('#' + id)
if (autoplay) autoplay.setAttribute('autoplay', true)
else ids.push(id)
return ids
}, [])
})
})()
This script gets all the autoplay elements before the page is cached, stores each ID in autoplayIds, then removes the autoplay attribute. When a page is about to be rendered, it iterates over the stored IDs, and checks if the new body contains an element with a matching ID. If it does, then it re-adds the autoplay attribute, otherwise it pushes the ID to the new autoplayIds array. This ensures that autoplayIds only includes IDs that have not been re-rendered.
(This solution was also posted on my StackOverflow answer.)
Hope that helps.
Tried your solution @domchristie , however i'm getting errors. My set up is two different videos each on different pages. Copied and pasted your code. Each video has a unique id.
Uncaught TypeError: Cannot read property 'push' of undefined
Could be a problem with your reducer... haven't had a chance to play. Tested on latest Chrome and Safari... same problem.
@jaybloke Thanks for testing this out. I noticed that the reducer wasn't returning anything. The script above has now been fixed. Thanks again
Works like a charm @domchristie !
Most helpful comment
Here's how I managed it.