Skip to content

Commit

Permalink
tour/handler: Sync AV player state with tour state #782
Browse files Browse the repository at this point in the history
* When a player is paused (but not ended!), pause the tour
* When a player is resumed, but the tour is paused, resume the tour
* When a tour is paused, pause the video

To achieve the final point, add an observer for the overall tour state
to tourstop_oberver()s. We have to ignore this in UIEvents otherwise we
re-open the mobile view on pausing.
  • Loading branch information
lentinj committed Apr 23, 2024
1 parent 68a76b8 commit 1ea3806
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 31 deletions.
7 changes: 7 additions & 0 deletions OZprivate/rawJS/OZTreeModule/src/tour/Tour.js
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,13 @@ class Tour {
add_fn(this, mutation.target.tourstop, mutation.target);
}
});

// Add observer to tour itself also, to catch pausing
(new window.MutationObserver((mutationList, observer) => {
const el_ts = this.curr_stop().container[0];

if (el_ts.matches(target_sel)) add_fn(this, el_ts.tourstop, el_ts);
})).observe(this.container[0], opts);
} else {
expected_states = new Set(expected_states)
mo = new window.MutationObserver((mutationList, observer) => {
Expand Down
39 changes: 30 additions & 9 deletions OZprivate/rawJS/OZTreeModule/src/tour/handler/HtmlAV.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,31 @@ function handler(tour) {
return Promise.resolve().then(() => {
// Attach events to block progression when playing
return el_avs.forEach((el) => {
el.addEventListener('play', (e) => {
const tourstop = e.target.el_tourstop.tourstop;
el.addEventListener('play', (event) => {
const tourstop = event.target.el_tourstop.tourstop;
const block_name = event.target.src;

if (tourstop.tour.state !== 'tstate-playing') {
tourstop.tour.user_resume();
}

if (tourstop.state === el.autoplay_states.slice(-1)[0]) {
event.target.el_tourstop.tourstop.block_add(block_name);
}
});
el.addEventListener('ended', (e) => {
const tourstop = e.target.el_tourstop.tourstop;
el.addEventListener('pause', (event) => {
const tourstop = event.target.el_tourstop.tourstop;
const block_name = event.target.src;

// If AV is ending (rather than pausing mid-video, do nothing and let the ended event handle things
if (event.target.ended) return;

if (tourstop.state === 'tsstate-active_wait' && tourstop.tour.state === 'tstate-playing') {
tourstop.tour.user_pause();
}
});
el.addEventListener('ended', (event) => {
const tourstop = event.target.el_tourstop.tourstop;
const block_name = event.target.src;

event.target.el_tourstop.tourstop.block_remove(block_name);
Expand All @@ -47,11 +62,17 @@ function handler(tour) {
// Attach observers for any autoplaying AV
tour.tourstop_observer('.contains-httpav', '*', (tour, tourstop, el_ts) => {
el_ts.querySelectorAll(":scope audio,:scope video").forEach((el) => {
if (window.getComputedStyle(el_ts).visibility !== 'visible') {
// Shouldn't ever play whilst invisible
el.pause();
el.currentTime = 0;
} else if (el.autoplay_states.indexOf(tourstop.state) > -1) {

if (!el.paused) {
if (window.getComputedStyle(el_ts).visibility !== 'visible') {
// Shouldn't ever play whilst invisible
el.pause();
el.currentTime = 0;
} else if (tour.state !== 'tstate-playing') {
// Pause when tour is paused
el.pause();
}
} else if (tour.state === 'tstate-playing' && el.autoplay_states.indexOf(tourstop.state) > -1) {
el.play();

// Check to see if final block should be added
Expand Down
2 changes: 1 addition & 1 deletion OZprivate/rawJS/OZTreeModule/src/tour/handler/UIEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ function handler(tour) {
tour.container[0].addEventListener('touchstart', onMouseDown);
tour.tourstop_observer('*', '*', (tour, tourstop, el_ts) => {
// Reset tourstop height after any state change
el_ts.style.height = '';
if (tour.state === 'tstate-playing') el_ts.style.height = '';
});

// Listen to document level visibility (read: inactive tab), translate to tourstop blocks
Expand Down
48 changes: 35 additions & 13 deletions OZprivate/rawJS/OZTreeModule/src/tour/handler/Vimeo.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,27 @@ function handler(tour) {
const tourstop = this.element.el_tourstop.tourstop;
const block_name = this.element.src;

if (tourstop.tour.state !== 'tstate-playing') {
tourstop.tour.user_resume();
}

if (tourstop.state === el_video.autoplay_states.slice(-1)[0]) {
tourstop.block_add(block_name);
}
});
el_video.vimeoplayer.on('pause', function (data) {
const tourstop = this.element.el_tourstop.tourstop;
const block_name = this.element.src;

el_video.vimeoplayer.getEnded().then((ended) => {
// If AV is ending (rather than pausing mid-video, do nothing and let the ended event handle things
if (ended) return;

if (tourstop.state === 'tsstate-active_wait' && tourstop.tour.state === 'tstate-playing') {
tourstop.tour.user_pause();
}
});
});
el_video.vimeoplayer.on('ended', function (data) {
const tourstop = this.element.el_tourstop.tourstop;
const block_name = this.element.src;
Expand All @@ -71,22 +88,27 @@ function handler(tour) {
// Attach observers for any autoplaying video
tour.tourstop_observer('.contains-vimeo', '*', (tour, tourstop, el_ts) => {
el_ts.querySelectorAll(":scope iframe.embed-vimeo").forEach((el) => {
if (window.getComputedStyle(el_ts).visibility !== 'visible') {
// Shouldn't ever play whilst invisible
el.vimeoplayer.pause();
el.vimeoplayer.setCurrentTime(0);
} else if (el.autoplay_states.indexOf(tourstop.state) > -1) {
el.vimeoplayer.play();
el.vimeoplayer.getPaused().then((paused) => {

// Check to see if final block should be added
if (tourstop.state === el.autoplay_states.slice(-1)[0]) {
el.vimeoplayer.getPaused().then((paused) => {
const block_name = el.src;
if (!paused) {
if (window.getComputedStyle(el_ts).visibility !== 'visible') {
// Shouldn't ever play whilst invisible
el.vimeoplayer.pause();
el.vimeoplayer.setCurrentTime(0);
} else if (tour.state != 'tstate-playing') {
// Pause when tour is paused
el.vimeoplayer.pause();
}
} else if (tour.state === 'tstate-playing' && el.autoplay_states.indexOf(tourstop.state) > -1) {
el.vimeoplayer.play();

if (!paused) tourstop.block_add(block_name);
});
// Check to see if final block should be added
if (tourstop.state === el.autoplay_states.slice(-1)[0]) {
if (!paused) tourstop.block_add(el.src);
}
}
}

});
});
});
});
Expand Down
28 changes: 20 additions & 8 deletions OZprivate/rawJS/OZTreeModule/src/tour/handler/Youtube.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ function handler(tour) {
const block_name = iframe.src;
const tourstop = iframe.el_tourstop.tourstop;

// Sync tour state with video state
if (event.data === YT.PlayerState.PLAYING && tourstop.tour.state !== 'tstate-playing') {
tourstop.tour.user_resume();
} else if (event.data === YT.PlayerState.PAUSED && tourstop.state === 'tsstate-active_wait' && tourstop.tour.state === 'tstate-playing') {
tourstop.tour.user_pause();
}

if (event.data == YT.PlayerState.ENDED) {
tourstop.block_remove(block_name);
} else if (event.data == YT.PlayerState.PLAYING && tourstop.state === iframe.autoplay_states.slice(-1)[0]) {
Expand All @@ -67,14 +74,19 @@ function handler(tour) {
el_ts.querySelectorAll(":scope iframe.embed-youtube").forEach((el) => {
const player = window.YT.get(el.id);

if (player.getPlayerState() === YT.PlayerState.PLAYING && window.getComputedStyle(el_ts).visibility !== 'visible') {
// Shouldn't ever play whilst invisible
player.pauseVideo();
// Reset to start
// NB: We can't use stopVideo() to do this, since it will also clear any video clip from the URL
// NB: We also can't do seekTo(0), since seekTo() isn't relative to a clip
if (el.ozStartPos !== undefined) player.seekTo(el.ozStartPos);
} else if (el.autoplay_states.indexOf(tourstop.state) > -1) {
if (player.getPlayerState() === YT.PlayerState.PLAYING) {
if (window.getComputedStyle(el_ts).visibility !== 'visible') {
// Shouldn't ever play whilst invisible
player.pauseVideo();
// Reset to start
// NB: We can't use stopVideo() to do this, since it will also clear any video clip from the URL
// NB: We also can't do seekTo(0), since seekTo() isn't relative to a clip
if (el.ozStartPos !== undefined) player.seekTo(el.ozStartPos);
} else if (tour.state !== 'tstate-playing') {
// Pause when tour is paused
player.pauseVideo();
}
} else if (tour.state === 'tstate-playing' && el.autoplay_states.indexOf(tourstop.state) > -1) {
player.playVideo();

// Check to see if final block should be added
Expand Down

0 comments on commit 1ea3806

Please sign in to comment.