Make podcast-playback to be controllable via keyboard (#14139)
* Make podcast-playback to be controllable via keyboard * Add improved state handling for the play/pause controller * Fix business logic + Improve HTML semantics * Remove manual tabIndex addition (not required now) * Refactor redudant event-listener * Keep aria-pressed label in sync in all cases * Code refactor * Add seed data to create a test podcast * Add a static file and use that as example podcast episode (#1) Rather than relying at test time on external media, and requiring the podcast episode import flow to run during e2e testing, just insert a canned episode that shows. Confirmed in cypress this does show after visit('/pod') in the togglePodcastPlayback.spec.js * Add cypress test * Move cypress tests * Update cypress/integration/seededFlows/podcastFlows/togglePodcastPlayback.spec.js Co-authored-by: Suzanne Aitchison <suzanne@forem.com> * fix button name in test Co-authored-by: Daniel Uber <djuber@gmail.com> Co-authored-by: rhymes <github@rhymes.dev> Co-authored-by: Suzanne Aitchison <suzanne@forem.com>
This commit is contained in:
parent
0479d61d02
commit
4280434aed
6 changed files with 77 additions and 7 deletions
|
|
@ -82,14 +82,18 @@ function initializePodcastPlayback() {
|
|||
|
||||
function spinPodcastRecord(customMessage) {
|
||||
if (audioExistAndIsPlaying() && recordExist()) {
|
||||
getById(`record-${window.activeEpisode}`).classList.add('playing');
|
||||
var podcastPlaybackButton = getById(`record-${window.activeEpisode}`);
|
||||
podcastPlaybackButton.classList.add('playing');
|
||||
podcastPlaybackButton.setAttribute('aria-pressed', 'true');
|
||||
changeStatusMessage(customMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function stopRotatingActivePodcastIfExist() {
|
||||
if (window.activeEpisode && getById(`record-${window.activeEpisode}`)) {
|
||||
getById(`record-${window.activeEpisode}`).classList.remove('playing');
|
||||
var podcastPlaybackButton = getById(`record-${window.activeEpisode}`);
|
||||
podcastPlaybackButton.classList.remove('playing');
|
||||
podcastPlaybackButton.setAttribute('aria-pressed', 'false');
|
||||
window.activeEpisode = undefined;
|
||||
}
|
||||
}
|
||||
|
|
@ -183,7 +187,8 @@ function initializePodcastPlayback() {
|
|||
Array.prototype.forEach.call(records, function (record) {
|
||||
var episodeSlug = record.getAttribute('data-episode');
|
||||
var podcastSlug = record.getAttribute('data-podcast');
|
||||
record.onclick = function () {
|
||||
|
||||
var togglePodcastState = function (e) {
|
||||
if (podcastBarAlreadyExistAndPlayingTargetEpisode(episodeSlug)) {
|
||||
var audio = getById('audio');
|
||||
if (audio) {
|
||||
|
|
@ -194,6 +199,7 @@ function initializePodcastPlayback() {
|
|||
loadAndPlayNewPodcast(episodeSlug);
|
||||
}
|
||||
};
|
||||
record.addEventListener('click', togglePodcastState);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.record-wrapper {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.playing {
|
||||
.record {
|
||||
.main-image {
|
||||
|
|
|
|||
|
|
@ -49,18 +49,18 @@
|
|||
</time>
|
||||
<% end %>
|
||||
</div>
|
||||
<div id="record-<%= @episode.slug %>" class="record-wrapper" data-podcast="<%= @podcast.slug %>" data-episode="<%= @episode.slug %>">
|
||||
<button id="record-<%= @episode.slug %>" class="record-wrapper" data-podcast="<%= @podcast.slug %>" data-episode="<%= @episode.slug %>" aria-pressed="false">
|
||||
<div class="record" id="record">
|
||||
<%= optimized_image_tag(@podcast.image_url,
|
||||
optimizer_options: { width: 420, height: 420, crop: "fill" },
|
||||
image_options: { class: "main-image", alt: @podcast.title }) %>
|
||||
<img alt="Play Button" class="butt play-butt" src="<%= image_path("playbutt.png") %>" />
|
||||
<img alt="Pause Button" class="butt pause-butt" src="<%= image_path("pausebutt.png") %>" />
|
||||
<img alt="Play podcast" class="butt play-butt" src="<%= image_path("playbutt.png") %>" />
|
||||
<img alt="Play podcast" class="butt pause-butt" src="<%= image_path("pausebutt.png") %>" />
|
||||
<div class="status-message" id="status-message-<%= @episode.slug %>">
|
||||
play
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<%# checking both podcast_episode and podcast status for now %>
|
||||
<% unless @episode.https? %>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
describe('Toggle Podcast playback', () => {
|
||||
beforeEach(() => {
|
||||
cy.testSetup();
|
||||
});
|
||||
|
||||
it('should toggle podcast playback', () => {
|
||||
cy.visit('/pod');
|
||||
cy.contains('div', 'Example media | crow call').click();
|
||||
|
||||
cy.findByRole('button', { name: 'Developer on Fire Play podcast' }).as(
|
||||
'toggleButton',
|
||||
);
|
||||
|
||||
cy.get('@toggleButton')
|
||||
.invoke('attr', 'aria-pressed')
|
||||
.should('eq', 'false');
|
||||
cy.get('@toggleButton').click();
|
||||
cy.get('@toggleButton').invoke('attr', 'aria-pressed').should('eq', 'true');
|
||||
});
|
||||
});
|
||||
BIN
public/media/crow-call.mp3
Normal file
BIN
public/media/crow-call.mp3
Normal file
Binary file not shown.
|
|
@ -549,6 +549,45 @@ end
|
|||
|
||||
##############################################################################
|
||||
|
||||
seeder.create_if_doesnt_exist(Podcast, "title", "Test podcast") do
|
||||
podcast_attributes = {
|
||||
title: "Developer on Fire",
|
||||
description: "",
|
||||
feed_url: "http://developeronfire.com/rss.xml",
|
||||
itunes_url: "https://itunes.apple.com/us/podcast/developer-on-fire/id1006105326",
|
||||
slug: "developeronfire",
|
||||
twitter_username: "raelyard",
|
||||
website_url: "http://developeronfire.com",
|
||||
main_color_hex: "343d46",
|
||||
overcast_url: "https://overcast.fm/itunes1006105326/developer-on-fire",
|
||||
android_url: "http://subscribeonandroid.com/developeronfire.com/rss.xml",
|
||||
image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
published: true
|
||||
}
|
||||
podcast = Podcast.create!(podcast_attributes)
|
||||
|
||||
podcast_episode_attributes = {
|
||||
body: "<p>A real good crow call</p>",
|
||||
guid: "<guid isPermaLink=\"true\">/media/crow-call.mp3</guid>",
|
||||
https: false,
|
||||
itunes_url: nil,
|
||||
image: nil,
|
||||
media_url: "/media/crow-call.mp3",
|
||||
processed_html: "<p>A real good crow call</p>",
|
||||
published_at: Date.new(2021,1,1),
|
||||
slug: "crow-call",
|
||||
subtitle: "Example media: Crow Call",
|
||||
summary: "<p>6 seconds of bird song</p>",
|
||||
title: "Example media | crow call",
|
||||
website_url: "https://github.com/forem/",
|
||||
tag_list: nil,
|
||||
podcast_id: podcast.id
|
||||
}
|
||||
PodcastEpisode.create!(podcast_episode_attributes)
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
|
||||
seeder.create_if_none(Reaction) do
|
||||
user = User.find_by(username: "trusted_user_1")
|
||||
admin_user.reactions.create!(category: :vomit, reactable: user)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue