0

Meta: A similar question about locally stored A/V files can be found here: Clickable "positioning" hyperlinks to A/V (locally stored on your website and “hidden” behind a poster image).


Dear people from the Stackoverflow community,

The application

I am having an iframe <iframe name="video"... which is named video, and which is to be seen as the "main player" of a certain video.

Since I haven't been able to get interactive transcript on this video yet, I call different playing/starting positions in the video using: <a href="//www.youtube.com/embed/...&start=60" target="video">1:00</a>, e.g. for second 60.

This is working fine when the <iframe name="video".. is already "active": then the link shifts the video's playing position inside the iframe. This is great!

However it is not working fine, when the <iframe name="video".. isn't "active" yet, which is the case: then the link then opens in a different browser tab, instead of inside the iframe (or where the iframe is supposed to show up).

What I mean by hidden

What I mean with the iframe not being "active" is the following: it is "hidden" behind a "poster image" via the following code:

<div onclick="play();" id="vid" style="...; background: ... url('...poster.image.url...') no-repeat center;-webkit-background-size: cover; ...;overflow:hidden"></div>

<script type="text/javascript">function play(){document.getElementById('vid').innerHTML = '<iframe name="video" ... src="//www.youtube.com/embed/...?&...start=0"></iframe>';}</script>


In other words: i specifically don't want "<a target="_blank""-behaviour. I guess the target="video" is not working properly now, since the iframe is "hidden" behind the poster image.

I know for sure this behavior isn't occuring when the iframe wouldn't be hidden at all. I tested this multiple times. Further more, with the current "hidden" poster feature, this behavior is also not occuring when the poster image is clicked FIRST (before clicking on a <a href="...></a>).

If you would to see this behaviour for yourself, you can see it on my site. The best is to look/CTRL-F for "stef", and open the ▾̲ ̲u̲n̲d̲e̲r̲l̲i̲n̲e̲d̲ ̲t̲o̲g̲g̲l̲e̲, which you will find there.

So how to sucessfully "target" the "hidden" iframe without opening a new browser window/tab?

Any help would be greatly appreciated. Many thanks, Vincent Verheyen.

Community
  • 1
  • 1
O0123
  • 481
  • 9
  • 28
  • So, what do you mean by a that? Do you want that `data-time = "end"` to make the video go to an end or do you wanna specify a `data-time-end=80` to order the video to stop there? – undefined Jan 22 '15 at 02:01
  • I meant just to order the **linked** `...href...data-time=...` video **fragment** to pause there, I didn't mean to trim the **complete** video **file/stream**. – O0123 Jan 22 '15 at 05:43
  • Well I used the `&end` native youtube api, so here is the [**fiddle**](http://jsfiddle.net/yhmo9j1a/7/). Again, check it out, feel free to criticise, and if it's all good I'll elaborate on the answer (and maybe polish it up a bit, it's pretty rough-looking). – undefined Jan 22 '15 at 06:10
  • Thanks, the stop time displays fine as a bracket **]** in the progress bar, but it doesn't seem to really stop there yet. --- In Chrome and Safari I can, but in Firefox, I can't play the video. --- I guess what's also unavoidable, is that when you mouse-click/scroll through the video at the progress bar, then the `&end` would stop being "active"? But I guess there's no easy work-around. --- Thanks for the help, however I was actually referring to *different* `&end`'s, specific for every `...href...data-time=...`. Do you think that's possible, instead of only 1 `&end` for the *whole* file? – O0123 Jan 22 '15 at 06:52
  • You mean that you want a data-end for each jumper? [**here**](http://jsfiddle.net/yhmo9j1a/11/). About the other issues, that's a youtube-browser problem, not very much we can do, unfortunately there is no way to pause the video, since it's not natively supported by youtube. – undefined Jan 22 '15 at 07:15
  • Thanks a bunch, @Rou! You were truly a star in the dark. --- As for the end-times, which you implemented perfectly: perhaps it is better to leave this feature altogether out of the final answer then, since Firefox is a much-used browser, and this feature causes the video to be completely unplayable in there. – O0123 Jan 22 '15 at 08:04
  • Perhaps 1 final "P.S."-question: I have an audio file I want to play (also behind an image facade, and with clickable position links), but stored locally, e.g. at `www.site.dom/audio.ext`. I noticed your code still works then, by changing `iframe.src = "http://www.youtube.com/embed/" + video + "?&...&..." + start;` to `iframe.src = "" + video + start;` and by creating a `
    `. ... ↓
    – O0123 Jan 22 '15 at 08:49
  • ... ↑ However, the start-position links can then no longer be used, since the Youtube syntax is no longer applicable. I have been reading things on the net about `function(){something.currentTime=...;});`, but I have not been able to implement this. --- So my final question would be this: what if you have the audio or video file just stored locally, instead of on Youtube, how would you go about repositioning by hyperlinks then? --- Many thanks in advance. – O0123 Jan 22 '15 at 09:04
  • Hmm, what version of firefox are you in? I can play the video just fine, in fact I made the fiddle in firefox. About the other question, I think it would be proper to ask another question or update this one, I can do it though. – undefined Jan 22 '15 at 17:00
  • Well firefox works just fine for me, maybe you shouldn't worry about it! I'll make the answer then. – undefined Jan 22 '15 at 17:20
  • **Remark on my stupidity**: The firefox issue was my fault. Although I don't know what went wrong: a good old clearing of the browser's history made me normal again. – O0123 Jan 22 '15 at 19:46
  • It's settled then! I'll owrk in your other question as soon as I can! – undefined Jan 22 '15 at 23:48

1 Answers1

1

Well here we are! The fiddle.

HTML

Your html will contain both facades and jumpers to accomplish what you asked.

    What's a facade?

facade: "the principal front of a building, that faces on to a street or open space."

This will be the image shown before you play the video or click on any jumpers, it's html will look like this:

<div class="videoFacade" data-name="video1" data-video="ByJFdTFEwF4" data-start="8">
    <img src="http://i.imgur.com/xeUiWGn.png" />
</div>

    What's a jumper?

A jumper is an anchor that will update the iframe's url to the desired time in the video, it will look like this:

JavaScript

window.addEventListener("load", initVideoFacade);

function initVideoFacade() {
    var allFacades = document.querySelectorAll(".videoFacade");
    for (var i = 0; i < allFacades.length; i++) {
        var facade = allFacades[i];
        setUpFacade(facade);
    }

    var allJumpers = document.querySelectorAll(".videoJumper");
    for (var i = 0; i < allJumpers.length; i++) {
        var jumper = allJumpers[i];
        setUpJumper(jumper);
    }
}

function setUpJumper(jumper) {
    jumper.addEventListener("click", function (e) {
        e.preventDefault();
        jumpTo(jumper);
        var video = jumper.dataset.video;
        var facade = getFacadeByVideo(video);
        if (facade) playVideo(facade);
        return false;
    });
}

function setUpFacade(facade) {
    facade.addEventListener("click", function () {
        playVideo(facade);
    });
}

function getFacadeByVideo(video) {
    return document.querySelector(".videoFacade[data-name=" + video + "]");
}

function getIframeByVideo(video) {
    return document.querySelector(".videoIframe[data-name=" + video + "]");
}

function updateVideoSource(iframe, start, end) {
    var iframeSrc = iframe.src.replace(/start=[0-9]+/i, "start=" + start);
    var hasEnd = iframeSrc.indexOf("end") != -1;
    if (hasEnd) iframeSrc = iframeSrc.replace(/end=[0-9]+/i, "end=" + end);
    else iframeSrc += "&end=" + end;
    return iframeSrc;
}

function updateFacadeData(facade, start, end) {
    facade.setAttribute("data-start", start);
    facade.setAttribute("data-end", end);
}

function jumpTo(jumper) {
    var start = jumper.dataset.start;
    var end = jumper.dataset.end;
    var video = jumper.dataset.video;
    var iframe = getIframeByVideo(video);
    if (iframe) {
        var iframeSrc = updateVideoSource(iframe, start, end);
        iframe.src = iframeSrc;
    } else {
        var facade = getFacadeByVideo(video);
        updateFacadeData(facade, start, end);
    }
}

function playVideo(facade) {
    var start = facade.dataset.start || 0;
    var end = facade.dataset.end;
    var name = facade.dataset.name;
    var video = facade.dataset.video;
    var iframe = document.createElement("iframe");
    iframe.dataset.name = name;
    iframe.className = "videoIframe";
    var iframeSrc = "http://www.youtube.com/embed/" + video + "?&cc_load_policy=1&modestbranding=1&autoplay=1&rel=0&showinfo=0&theme=light&start=" + start;
    if (end) iframeSrc += "&end=" + end;
    iframe.src = iframeSrc;
    iframe.frameBorder = 0;
    replaceNode(facade, iframe);
}

function replaceNode(node1, node2) {
    var parent = node1.parentNode;
    var next = node1.nextSibling;
    parent.insertBefore(node2, next);
    parent.removeChild(node1);
}

Here is a timeline:

  • We add the initVideoFacade() method to the load event in the page, this will make sure all our facades and jumpers are up and running before doing anything.

  • The initVideoFacade() method will find all jumpers and facades and set them up using the setUpFacade() and setUpJumper() methods.

  • The setUpJumper() method will add a click event on the jumper and tell it to jump to a determined time in the video, specified in the jumper. Also, if the video is not yet playing, it will do so now.

  • The jumpTo() method will update the iframe's src (or the facade initial data if the video is not playing) using a couple of regular expressions to replace the &start= and &end= parts of the iframe src.

  • The setUpFacade() method will simply play the video, removing the facade and inserting the iframe.

  • The playVideo() method will create a new iframe from a facade, replacing it and assigning it's source, start and end time to the video.

CSS

This just handles the styling of the facade and iframe :)

.videoFacade, .videoIframe {
    position: relative;
    width: 360px;
    height: 202.5px;
    margin:5px;
}
.videoFacade {
    cursor: pointer;
    border:1px solid black;
}
.videoFacade img {
    position: absolute;
    width: 50px;
    height: 50px;
    left: 50%;
    top: 50%;
    margin: -25px 0 0 -25px;
}

Hope it helped!

undefined
  • 3,949
  • 4
  • 26
  • 38
  • The answer and the act of answering are prettier than any diamond. I am sure you are hiding some jewels for us on your profile page and would be curious to see your work. – O0123 Jan 22 '15 at 19:08