TextTrackList onchange event not working in IE and Edge - javascript

The TextTrackList.onchange event is not working in IE and Edge. In Chrome and FireFox it works fine.
Is there any alternative I can use? Ive searched through the available events but can't find any.
Or how can I create a workaround? So it works amongst all browsers?
https://www.javascripture.com/TextTrackList
var video = document.getElementById('video');
video.textTracks.addEventListener('change', function () {
console.log("TextTracks change event fired!");
});
video {
max-width: 400px;
max-height: 400px;
}
<video controls id="video">
<source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4" />
<track label="Caption #1" kind="subtitles" srclang="nl" src="path/to/caption1.vtt">
<track label="Caption #2" kind="subtitles" srclang="en" src="path/to/caption2.vtt">
<track label="Caption #3" kind="subtitles" srclang="de" src="path/to/caption3.vtt">
</video>

You might be able to create a kind of polyfill.
First to detect if we support the event or not, we can check for ('onchange' in window.TextTrackList). So we can integrate our unperfect polyfill conditionally and leave the correct implementations unchanged.
Then, we can iterate every x-time over our TextTrackList's TextTracks in order to find which one is the active one, it should be the one with its mode set to "showing".
Now, we just have to store the previous active track and check if the current one is the same. Otherwise, fire the Event.
So a simple implementation could be
// in an outer scope
// textTracks is our TextTrackList object
var active = getActive();
// start polling
poll();
function poll() {
// schedule next check in a frame
requestAnimationFrame(poll);
var current = getActive();
if (current !== active) {
active = current; // update the active one
// dispatchEvent is not supported on TextTrackList in IE...
onchange({
target: textTracks
});
}
}
function getActive() {
for (var i = 0; i < textTracks.length; i++) {
if (textTracks[i].mode === 'showing') {
return textTracks[i];
}
}
}
But to implement a better polyfill, we will want to override the original addEventListener, removeEventListener and onchange properties of the TextTrackList prototype.
Here is a rough implementation, which will not take care of the third param of [add/remove]EventListener.
(function() {
/* Tries to implement an 'change' Event on TextTrackList Objects when not implemented */
if (window.TextTrackList && !('onchange' in window.TextTrackList.prototype)) {
var textTracksLists = [], // we will store all the TextTrackLists instances
polling = false; // and run only one polling loop
var proto = TextTrackList.prototype,
original_addEvent = proto.addEventListener,
original_removeEvent = proto.removeEventListener;
var onchange = {
get: getonchange,
set: setonchange
};
Object.defineProperty(proto, 'onchange', onchange);
Object.defineProperty(proto, 'addEventListener', fnGetter(addListener));
Object.defineProperty(proto, 'removeEventListener', fnGetter(removeListener));
function fnGetter(fn) {
return {
get: function() {
return fn;
}
};
}
/* When we add a new EventListener, we attach a new object on our instance
This object set as '._fakeevent' will hold informations about
the current EventListeners
the current onchange handler
the parent <video> element if any
the current activeTrack
*/
function initFakeEvent(instance) {
// first try to grab the video element from where we were generated
// this is useful to not run useless tests when the video is detached
var vid_elems = document.querySelectorAll('video'),
vid_elem = null;
for (var i = 0; i < vid_elems.length; i++) {
if (vid_elems[i].textTracks === instance) {
vid_elem = vid_elems[i];
break;
}
}
textTracksLists.push(instance);
instance._fakeevent = {
parentElement: vid_elem,
listeners: {
change: []
}
}
if (!polling) { // if we are the first instance being initialised
polling = true;
requestAnimationFrame(poll); // start the checks
}
return instance._fakeevent;
}
function getonchange() {
var fakeevent = this._fakeevent;
if (!fakeevent || typeof fakeevent !== 'object') {
return null;
}
return fakeevent.onchange || null;
}
function setonchange(fn) {
var fakeevent = this._fakeevent;
if (!fakeevent) {
fakeevent = initFakeEvent(this);
}
if (fn === null) fakeevent.onchange = null;
if (typeof fn !== 'function') return fn;
return fakeevent.onchange = fn;
}
function addListener(type, fn, options) {
if (type !== 'change') { // we only handle change for now
return original_addEvent.bind(this)(type, fn, options);
}
if (!fn || typeof fn !== 'object' && typeof fn !== 'function') {
throw new TypeError('Argument 2 of EventTarget.addEventListener is not an object.');
}
var fakeevent = this._fakeevent;
if (!fakeevent) {
fakeevent = initFakeEvent(this);
}
if (typeof fn === 'object') {
if (typeof fn.handleEvent === 'function') {
fn = fn.handleEvent;
} else return;
}
// we don't handle options yet...
if (fakeevent.listeners[type].indexOf(fn) < 0) {
fakeevent.listeners[type].push(fn);
}
}
function removeListener(type, fn, options) {
if (type !== 'change') { // we only handle change for now
return original_removeEvent.call(this, arguments);
}
var fakeevent = this._fakeevent;
if (!fakeevent || !fn || typeof fn !== 'object' && typeof fn !== 'function') {
return
}
if (typeof fn === 'object') {
if (typeof fn.handleEvent === 'function') {
fn = fn.handleEvent;
} else return;
}
// we don't handle options yet...
var index = fakeevent.listeners[type].indexOf(fn);
if (index > -1) {
fakeevent.listeners[type].splice(index, 1);
}
}
function poll() {
requestAnimationFrame(poll);
textTracksLists.forEach(check);
}
function check(instance) {
var fakeevent = instance._fakeevent;
// if the parent vid not in screen, we probably have not changed
if (fakeevent.parentElement && !fakeevent.parentElement.parentElement) {
return;
}
// get the current active track
var current = getActiveTrack(instance);
// has changed
if (current !== fakeevent.active) {
if (instance.onchange) {
try {
instance.onchange({
type: 'change',
target: instance
});
} catch (e) {}
}
fakeevent.listeners.change.forEach(call, this);
}
fakeevent.active = current;
}
function getActiveTrack(textTracks) {
for (var i = 0; i < textTracks.length; i++) {
if (textTracks[i].mode === 'showing') {
return textTracks[i];
}
}
return null;
}
function call(fn) {
fn({
type: 'change',
target: this
});
}
}
})();
var video = document.getElementById('video');
video.textTracks.onchange = function ontrackchange(e) {
console.log('changed');
};
video {
max-width: 400px;
max-height: 400px;
}
<video controls id="video">
<source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4" />
<track label="Caption #1" kind="subtitles" srclang="nl" src="path/to/caption1.vtt">
<track label="Caption #2" kind="subtitles" srclang="en" src="path/to/caption2.vtt">
<track label="Caption #3" kind="subtitles" srclang="de" src="path/to/caption3.vtt">
</video>

You are correct, it is an issue with IE and Edge.
What you can do is listen to an event on the track load. Just pay attention that the track has got to be on the same domain, otherwise, you will get a silent error (CURS) and the event lister will not list the event.
I have created a code pan so you could try it https://codepen.io/shahar-polak/project/live/AnVpEw/
NOTE: The code will trigger one event in IE and Edge and two events on Chrome and Firefox. Make sure you check for the client browser before using in production.
const video = document.getElementById('video');
const tracks = Array.from(document.querySelectorAll('track'));
video.textTracks.addEventListener('change', function() {
console.log('TextTracks change event fired!');
});
// For IE and Edge
tracks.forEach((track) => {
track.addEventListener("load", function() {
console.log('change track');
}, false);
})
video {
max-width: 400px;
max-height: 400px;
}
<video controls id="video" >
<source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4"/>
<track label="Caption #1" kind="subtitles" srclang="nl" src="./en.vtt">
<track label="Caption #2" kind="subtitles" srclang="en" src="./en.vtt">
<track label="Caption #3" kind="subtitles" srclang="de" src="https://iandevlin.com/html5/dynamic-track/captions/sintel-en.vtt">
</video>

Related

I want to play each button for each video in pure JS

I have a page where I have multiple videos I created one custom button to play video
The problem is I want to write a single JS to achieve this without writing multiple js code for each video
<video id="video"> </video>
<button id="circle-play-b">play</button
<video id="video"> </video>
<button id="circle-play-b">play</button
JS
var video = document.getElementById("video");
var circlePlayButton = document.getElementById("circle-play-b");
console.log(video);
function togglePlay() {
if (video.paused || video.ended) {
video.play();
} else {
video.pause();
}
}
circlePlayButton.addEventListener("click", togglePlay);
video.addEventListener("playing", function () {
circlePlayButton.style.opacity = 0;
});
video.addEventListener("pause", function () {
circlePlayButton.style.opacity = 1;
});
I have an option to add unique id to each video
You have to set seperate listeners for each video elements.And use class names instead of id.
document.getElementByClassName returns array of elements. Iterates over array and set listeners for each elements.
Html
<video class="videos"> </video>
<button class="circle-play-b">play</button>
<video class="videos"> </video>
<button class="circle-play-b">play</button>
Js
var videos = document.getElementsByClassName("videos");
var circlePlayButton = document.getElementsByClassName("circle-play-b");
for (let i = 0; i < circlePlayButton.length; i++) {
let playBtn = circlePlayButton[i];
let video = videos[i];
function togglePlay() {
if (video.paused || video.ended) {
video.play();
} else {
video.pause();
}
}
playBtn.addEventListener('click', togglePlay);
video.addEventListener("playing", function () {
playBtn.style.opacity = 0;
});
video.addEventListener("pause", function () {
playBtn.style.opacity = 1;
});
}
Hope it helps to solve your issue
A valid approach was to treat the video and button structure as a reusable component.
Thus one would provide a generically written (no equally named id attributes) closed html structure ( <video/> and <button/> elements are embedded within a parent or root element).
Then one would implement an initializing function which queries such HTML structures/components and registers every event handler needed.
Of cause any handler and helper function is implemented (and named) in a way that it targets exactly one problem/task a time ( ... which enables code-reuse as shown with the next provided example code) ...
function getToggleControl(elmVideo) {
return elmVideo
.closest('figure')
.querySelector('button');
}
function updateToggleControl(toggleControl, isPaused) {
const { dataset } = toggleControl;
const controlText = isPaused
? dataset.textTogglePlay
: dataset.textTogglePause;
toggleControl.textContent = controlText;
toggleControl.title = controlText;
}
function handleToggleState({ currentTarget: toggleControl }) {
const elmVideo = toggleControl
.closest('figure')
.querySelector('video');
if (elmVideo) {
const isPaused = elmVideo.paused || elmVideo.ended;
if (isPaused) {
elmVideo.play();
} else {
elmVideo.pause();
}
updateToggleControl(toggleControl, !isPaused);
}
}
function handleVideoPlaying({ currentTarget: elmVideo }) {
const toggleControl = getToggleControl(elmVideo);
if (toggleControl) {
toggleControl.style.opacity = .2;
updateToggleControl(toggleControl, false);
}
}
function handleVideoPaused({ currentTarget: elmVideo }) {
const toggleControl = getToggleControl(elmVideo);
if (toggleControl) {
// initially enable the video pause/play button.
toggleControl.disabled && (toggleControl.disabled = false);
toggleControl.style.opacity = 1;
updateToggleControl(toggleControl, true);
}
}
function initVideoPausePlay() {
document
.querySelectorAll('figure[data-video-pause-play] video')
.forEach(elmVideo => {
elmVideo.addEventListener('canplay', handleVideoPaused);
elmVideo.addEventListener('pause', handleVideoPaused);
elmVideo.addEventListener('playing', handleVideoPlaying);
getToggleControl(elmVideo)
?.addEventListener('click', handleToggleState);
});
}
initVideoPausePlay();
* { margin: 0; padding: 0; }
figure { display: inline-block; width: 40%; }
figure video { display: inline-block; width: 100%; }
<figure data-video-pause-play>
<video controls muted>
<source src="https://ia902803.us.archive.org/15/items/nwmbc-Lorem_ipsum_video_-_Dummy_video_for_your_website/Lorem_ipsum_video_-_Dummy_video_for_your_website.mp4" type="video/mp4">
<source src="https://archive.org/embed/nwmbc-Lorem_ipsum_video_-_Dummy_video_for_your_website/Lorem_ipsum_video_-_Dummy_video_for_your_website.HD.mov" type="video/quicktime">
</video>
<button
disabled
class="circle-play-b"
data-text-toggle-play="play"
data-text-toggle-pause="pause">
...
</button>
</figure>
<figure data-video-pause-play>
<video controls muted>
<source src="https://ia902803.us.archive.org/15/items/nwmbc-Lorem_ipsum_video_-_Dummy_video_for_your_website/Lorem_ipsum_video_-_Dummy_video_for_your_website.mp4" type="video/mp4">
<source src="https://archive.org/embed/nwmbc-Lorem_ipsum_video_-_Dummy_video_for_your_website/Lorem_ipsum_video_-_Dummy_video_for_your_website.HD.mov" type="video/quicktime">
</video>
<button
disabled
class="circle-play-b"
data-text-toggle-play="play"
data-text-toggle-pause="pause">
...
</button>
</figure>

How to loop a video 3 times only?

I want to loop a video three times only. Rendering it in a for loop doesn't seem to work properly.
I am wondering how to do this with an HTML video.
I have this HTML video.
<div id="video" class="Adform-video"></div>
And this JS
(function() {
Floating.setup({
clicktag: dhtml.getVar('clickTAG', 'http://example.com'),
target: dhtml.getVar('landingPageTarget', '_blank'),
video: {
sources: dhtml.getVar('videoSources'),
poster: dhtml.getAsset(3),
clicktag: dhtml.getVar('clickTAG')
}
});
Floating.init();
})();
var Floating = (function() {
var videoPlayer;
var banner = dhtml.byId('banner'),
closeButton = dhtml.byId('closeButton'),
video = dhtml.byId('video'),
clickArea = dhtml.byId('click-area'),
lib = Adform.RMB.lib;
function setup(settings) {
for (var prop in settings) {
if (_settings[prop] instanceof Object) {
for (var prop2 in settings[prop]) {
_settings[prop][prop2] = settings[prop][prop2];
}
} else {
_settings[prop] = settings[prop];
}
}
}
var _settings = {
clicktag: null,
target: null,
video: null
};
function init() {
createVideoPlayer();
}
closeButton.onclick = function (event) {
dhtml.external.close && dhtml.external.close();
};
clickArea.onclick = function() {
stopVideo();
window.open(_settings.clicktag, _settings.target);
};
function createVideoPlayer() {
var videoSettings = _settings.video;
videoPlayer = Adform.Component.VideoPlayer.create({
sources: videoSettings.sources,
clicktag: videoSettings.clicktag,
loop: videoSettings.loop,
muted: videoSettings.muted,
poster: videoSettings.poster,
theme: 'v2'
});
if (videoPlayer) {
videoPlayer.removeClass('adform-video-container');
videoPlayer.addClass('video-container');
videoPlayer.appendTo(video);
}
function landPoster() {
if(!lib.isWinPhone) {
videoPlayer.video.stop();
}
}
videoPlayer.poster.node().onclick = landPoster;
if (lib.isAndroid && lib.isFF) {
lib.addEvent(video, 'click', function(){}, false);
}
}
function stopVideo() {
if (videoPlayer.video.state === 'playing') videoPlayer.video.pause();
}
return {
setup: setup,
init: init
};
})();
The video will be used as an ad, and therefore I will only loop through it trice.
I have looked at these posts but they didn't seem to work:
Loop HTML5 video
Prop video loop
How can I do that?
Check out the standard HTML5 video element's onended event handler. Set up a simple JS event function with a integer counter and use the pause feature of video element when counter reaches 3. This link should help!
https://www.w3schools.com/TAGS/av_event_ended.asp
Also, I'm curious to know why exactly you want a video to loop only thrice...
Anyway, if the functionality is somewhat similar to a small animation(of a small video) which should be played 3 times, consider making a GIF animation with three hard-coded repetitions!
PROBLEM SOLVED
<!DOCTYPE html>
<html>
<body>
<video id="myVideo" width="320" height="176" autoplay controls>
<source src="mov_bbb.mp4" type="video/mp4">
<source src="mov_bbb.ogg" type="video/ogg">
Your browser does not support the audio element.
</video>
<script>
var aud = document.getElementById("myVideo");
var a=0;
aud.onended = function() {
a=a+1;
if(a!=3)
{
aud.play();
}
};
</script>
</body>
</html>

How can I detect whether my audio stream is: playing, paused or finished?

I'm working on an online radio website and am trying to detect what state the audio player is currently in for the user.
The current setup I've got is often wrong in knowing this and if I'm on iOS and I pause from the lock screen player instead, it will still think it's playing because I never clicked the html pause button.
Finally how is it possible to detect when my stream has fully ended. I've tried: onstalled="", onwaiting="", onerror="", onended="". But none of them work 100% of the time. The closest one to work would be: onstalled="", but even that only had a 60% success rate or so (occasionally when I'm loading the site it would tell me it has ended).
HTML:
<audio autoplay="" id="player" title="" oncanplay="radioLoaded()">
<source src="...">
</audio>
Javascript:
function radioLoaded() {
if (player.paused) {
document.getElementById('radioplaypause').innerHTML = varRadioResume;
} else if (player.play) {
document.getElementById('radioplaypause').innerHTML = varRadioPause;
} else {
document.getElementById('radioplaypause').innerHTML = varRadioLoading;
}
window.player = document.getElementById('player');
document.getElementById('radioplaypause').onclick = function () {
if (player.paused) {
player.play();
this.innerHTML = varRadioPause;
} else {
player.pause();
this.innerHTML = varRadioResume;
}
}
};
function radioEnded() {
document.getElementById('radiolivetext').innerHTML = 'OFFLINE';
document.getElementById('radioplayer').style.display = 'none';
document.getElementById('radioinformation').style.display = 'none';
};
Try this, with some corrections/notes to the code in general:
function radioLoaded() {
// move this line to the top
window.player = document.getElementById('player'); // !!! <-- name too generic, possibility of global collisions
var playPauseButton = document.getElementById('radioplaypause');
if (player.paused) {
playPauseButton.innerHTML = varRadioResume;
} else if (player.play) {
playPauseButton.innerHTML = varRadioPause;
} else {
playPauseButton.innerHTML = varRadioLoading;
}
playPauseButton.onclick = function () {
if (player.paused) {
player.play();
this.innerHTML = varRadioPause;
} else {
player.pause();
this.innerHTML = varRadioResume;
}
};
player.onended = function () {
console.log('ended');
};
// other helpful events
player.onpause = function () {
console.log('paused...');
}
player.onplay = function () {
console.log('playing...');
}
player.onprogress = function (e) {
console.log(e.loaded + ' of ' + e.total + ' loaded');
}
};

how to resume the timer from where it was paused using jquery

My Problem is when i press PAUSE btn & after few seconds again if i press the play button then then timer is starting from the beginning .` The timer should continue from the current pause time,if user clicks play button followed by pause button.
Please help me for this, i am trying to solve this issue since last 2 days. But still its not solved as per my app requirement.
function myApp() {
this.paused = false;
this.paused = true // set pause to true (stop)
this.isactive = false; // countdown is active
return this.observer(); // call and return the "observer" method of the "myApp" class
}
myApp.prototype.observer = function() { // observer method
var self = this; // set this to self (this is the current instance of this class)
$('#btn_start').on('click', function(event){ // where an user click on "btn_start"
event.preventDefault();
self.play('mp3'); // call the play method and store the state in a public var
self.countdown(30, self.onEnd); // 30 is the audio duration - second parameter is the callback when the audio is finished
self.isactive = true;
});
return this; // return this instance
};
myApp.prototype.play = function() { // play method
var song = document.getElementById('audiosource');
if (this.paused === true)
{
console.log('play song');
song.play();
this.paused = false;
}
else
{
console.log('pause song');
song.pause();
this.paused = true;
}
return this;
};
myApp.prototype.countdown = function(duration, callback) { // countdown method
var self = this, // class instance
countdown = null, // countdown
ctx = null; // setIntervall clearer
timer = duration; // timer
if (this.isactive === true) // if this method yet called
{
return false;
}
countdown = function() {
console.log('start countdown:' + self.paused);
if (timer === 0)
{
clearInterval(ctx);
callback.call(this);
return false;
}
if (self.paused === false) // if not in pause
{
timer -= 1;
console.log(timer);
$('#timer > span').html(timer);
}
};
ctx = setInterval(countdown, 1000);
};
myApp.prototype.onEnd = function() {
// when the audio is finish..
alert ('end of the song');
};
; $(function() {
new myApp();
});
I would structure your app differently
<div id="app">
<div id="timer">click play</div>
PLAY
</div>
<audio id="audiosource">
<source src="http://www.virtuagym.com/audio/en/get_ready.mp3" type="audio/mpeg" />
<source src="http://www.soundjay.com/button/button-1.wav" type="audio/wav" />
</audio>
<audio id="a_1" >
<source src="http://www.virtuagym.com/audio/en/1.ogg" type="audio/ogg" />
<source src="http://www.virtuagym.com/audio/en/1.mp3" type="audio/mp3" />
</audio>
<audio id="a_2" >
<source src="http://www.virtuagym.com/audio/audio/en/2.ogg" type="audio/ogg" />
<source src="http://www.virtuagym.com/audio/audio/en/2.mp3" type="audio/mp3" />
</audio>
<audio id="a_3" >
<source src="http://www.virtuagym.com/audio/audio/en/3.ogg" type="audio/ogg" />
<source src="http://www.virtuagym.com/audio/audio/en/3.mp3" type="audio/mp3" />
</audio>
<audio id="a_4" >
<source src="http://www.virtuagym.com/audio/audio/en/4.ogg" type="audio/ogg" />
<source src="http://www.virtuagym.com/audio/audio/en/4.mp3" type="audio/mp3" />
</audio>
<audio id="a_5" >
<source src="http://www.virtuagym.com/audio/audio/en/5.ogg" type="audio/ogg" />
<source src="http://www.virtuagym.com/audio/en/5.mp3" type="audio/mp3" />
</audio>
JS:
(function ($) {
// function to play sounds, calls `done` when sounds are finished to play
// here you should adjust timings for your audio
var playGetReady = function (done) {
var ids = ['audiosource', 'a_5', 'a_4', 'a_3', 'a_2', 'a_1'],
playNext = function () {
var id = ids.shift();
document.getElementById(id).play();
if (ids.length) {
setTimeout(playNext, 1000);
} else {
done();
}
};
playNext();
};
// constructor
function App($el, startFrom) {
this.$el = $el; // root element
this.$timer = this.$('#timer'); // find element to render countdown to
this.$button = this.$('#btn_start'); // play/pause button
// $.proxy(fn, ctx); makes `ctx` to be referenced by `this` inside `fn`
// sets handler on button
this.$button.click($.proxy(this.buttonHandler, this));
// sets value to start countdown
this.set(startFrom);
// we're not running yet
this.intervalHandle = null;
};
// look for elements inside of root element
App.prototype.$ = function () {
return this.$el.find.apply(this.$el, arguments);
};
// called on play/pause button click
App.prototype.buttonHandler = function (e) {
e.preventDefault(); // prevent anchor default action
this.toggle(); // toggle play/pause
};
App.prototype.start = function () {
var self = this;
playGetReady(function () { // play get ready sound
// start countdown
self.intervalHandle = setInterval($.proxy(self.tick, self), 1000);
// change button text to PAUSE
self.$button.text('PAUSE');
});
};
App.prototype.stop = function () {
// stop countdown
clearInterval(this.intervalHandle);
// set `intervalHandle` to null to be able to check whether
// countdown is running or not
this.intervalHandle = null;
// change button text to PLAY
this.$button.text('PLAY');
};
App.prototype.toggle = function () {
// if running
if (this.intervalHandle) {
// then stop
this.stop();
// if not
} else {
// then start
this.start();
}
};
// sets new value for countdown
App.prototype.set = function (timeLeft) {
this.counter = timeLeft;
};
// called every second to update counter, rerender, call `end` callback
// and play sound
App.prototype.tick = function () {
// update countdown
this.counter -= 1;
// push new countdown to page
this.render();
if (this.counter === 0) { // if countdown is finished
this.stop(); // stop decreasing it
this.end(); // end callback, ask for new value or terminate
}
};
// pushed countdown to page
App.prototype.render = function () {
this.$timer.text(this.counter);
};
// on end callback
App.prototype.end = function () {
// ask for new countdown
var text = prompt('end of the first exercise, NOw lets play the second exercise for your with another by loading its time');
if (text) { // if user entered any
var next = Number(text); // convert it to number
this.set(next); // set new countdown value
this.render(); // push changes to page
this.start(); // start countdown
} else { // if user entered nothing
// do nothing
this.$timer.text('You\'re done'); // tell user he finished
}
};
$(function () {
var app = new App($('#app'), 5); // create app
});
})(jQuery);
Note, you should adjust timings in playGetReady according to your sounds. Also, only a_5 and a_1 are loading.
Hope it'll help. I'd also recommend you reading tutorial or book on JavaScript.
jsFiddle
You must store the timeleft somewhere and when you press play again, you resume from timeleft.
I just added the timeleft var.
function myApp() {
this.timeleft = 30;
this.paused = false;
this.paused = true; // set pause to true (stop)
this.isactive = false; // countdown is active
return this.observer(); // call and return the "observer" method of the "myApp" class
}
myApp.prototype.observer = function() { // observer method
var self = this; // set this to self (this is the current instance of this class)
$('#btn_start').on('click', function(event){ // where an user click on "btn_start"
event.preventDefault();
self.play('mp3'); // call the play method and store the state in a public var
self.countdown( self.timeleft, self.onEnd); // 30 is the audio duration - second parameter is the callback when the audio is finished
self.isactive = true;
});
return this; // return this instance
};
myApp.prototype.play = function() { // play method
var song = document.getElementById('audiosource');
if (this.paused === true)
{
console.log('play song');
song.play();
this.paused = false;
}
else
{
console.log('pause song');
song.pause();
this.paused = true;
}
return this;
};
myApp.prototype.countdown = function(duration, callback) { // countdown method
var self = this, // class instance
countdown = null, // countdown
ctx = null; // setIntervall clearer
timer = duration; // timer
if (this.isactive === true) // if this method yet called
{
return false;
}
countdown = function() {
console.log('start countdown:' + self.paused);
if (timer === 0)
{
clearInterval(ctx);
callback.call(this);
return false;
}
if (self.paused === false) // if not in pause
{
timer -= 1;
console.log(timer);
self.timeleft = timer;
$('#timer > span').html(timer);
}
};
ctx = setInterval(countdown, 1000);
};
myApp.prototype.onEnd = function() {
// when the audio is finish..
alert ('end of the song');
};
;$(function() {
new myApp();
});

Why this won't be fired?

I tried to make a button to start playing video on player.
Player is showing up and works fine if I press "Playing" on control bar.
But My a href link to start playing won't work.
play() won't be fired. why?
<script>
function onYouTubePlayerReady(playerId) {
ytplayer = document.getElementById("myytplayer");
}
function play() {
if (ytplayer) {
ytplayer.playVideo();
}
}
</script>
<script type="text/javascript" src="swfobject.js"></script>
<div id="ytapiplayer">
You need Flash player 8+ and JavaScript enabled to view this video.
</div>
<script type="text/javascript">
var params = { allowScriptAccess: "always" };
var atts = { id: "myytplayer" };
swfobject.embedSWF("http://www.youtube.com/v/P5_GlAOCHyE?enablejsapi=1&playerapiid=ytplayer",
"ytapiplayer", "425", "356", "8", null, null, params, atts);
</script>
Play
Talking to Flash objects can be difficult. Here's the code I use to send messages:
function runFlashFunction( flashName, funcName ) {
var
od = document[flashName],
ow = window[flashName];
// flash isn't happy with o=func;o(); syntax
try {
if( od && !!(od[funcName]) ) {
return document[flashName][funcName]( );
}
if( ow && !!(ow[funcName]) ) {
return window[flashName][funcName]( );
}
if( ow && ow.length && !!(ow[0]) && !!(ow[0][funcName]) ) {
return window[flashName][0][funcName]( );
}
return void 0;
} catch( ex ) {
return void 0;
}
}
Why all that? because some browsers use different ways to access the flash content. The last one probably isn't needed, but I include it to be sure.
Also your link uses a style which isn't recommended. This is better:
Play
Or even better: assign the callback in the JavaScript, not the HTML:
$(function(){
$('#playLink').click(function(){ // name the link playLink (or whatever)
play();
return false;
});
});
Try not to use a global variable
var ytplayer = null;
function onYouTubePlayerReady(playerId) {
ytplayer = document.getElementById("myytplayer");
}
function play() {
if (ytplayer) {
ytplayer.playVideo();
}
}

Categories

Resources