6

For better accessibility we needed a second alternative set of play/pause controls and (with the help of user Kento Nishi) we successfully moved from DEMO A (with only 1 audio playback control) to DEMO B (with duplicated audio playback controls).

PROBLEM1 The time duration (far right number) is broken in DEMO B.

PROBLEM2 Every webpage has its own folder. Some pages have a spoken audio file ready made, *.mp3 but some pages dont. Would it be possible to hide all audio controls html if the spoken.mp3 (same file name for all pages) is absent in the page's own filder? So in summary: if the *.mp3 file exists on the server in the current web page folder <source src="*.mp3" type="audio/mpeg"> then display the html for the audio controls. Otherwise hide the audio html controls via CSS.

The old DEMO A, with only 1 set of controls:

var play = document.getElementsByTagName('play')[0];
var pause = document.getElementsByTagName('pause')[0];

The new DEMO B, with multiple set of controls:

document.getElementsByTagName("playpause")[0].addEventListener("click", playpause);
document.getElementsByTagName("playpause")[1].addEventListener("click", playpause);

Here JS Lint shows errors: unexpected for and unexpected var, but I doubt wether these the reason behind the broken audio time duration.

BEAUTY The good part about both demos A & B are that the audio file is loaded not until (and only after) a user clicks play. That way not wasting any bandwith untill user clicks play! This functionality is important and should remain intact, as well as the duplicated set of controls layout-wise and the html parts should remain as much as possible intact.

BOUNTY:200 The new demo works except the duration/audio length is broken and when audio file is not existing the controlls are shown. The bounty is a little token of appreciation for a solution to either problems (or both) in a working jsfiddle demo. Thanks for any and all help.

Sam
  • 15,156
  • 23
  • 85
  • 134

2 Answers2

2

If I understand correctly, you use JSLint to lint your code. The reason why it says the for is unexpected is because of the configuration of JSLint which by default doesn't accept a for-loop. On the JSLint website, you can take a look at the bottom of the page to change that:

enter image description here

Basically, some consider that every loop should be done in functional programming style (with a .forEach for instance). To know why, I suggest you take a look online to get multiple opinions but you can have one here.

As for your "bonus question", I can conclude that the problem lies with using the source tag to specify your audio source. Try using the src attribute of the audio tag and it should work. I could not find why, so we'll have to wait for someone else to answer that.

Jeahel
  • 620
  • 1
  • 8
  • 24
  • 1
    Well the remaining question is "why using a `source` tag inside an `audio` tag prevents the `loadeddata` event from firing". I think you should edit you question (especially the title) to reflect that. As I said, I don't understand why but someone else may have the answer, provided that the question is understandable ;) – Jeahel Jul 14 '18 at 14:00
  • Thanks @Jeahel changed the title according to your suggestion, improved the question and updated both JSFIDDLE demos. – Sam Jul 16 '18 at 08:46
2

This is a new answer based on the changing requirements and due to a bug that I missed causing the audio to auto load on page load.

https://jsfiddle.net/3aof2jnL/

This fiddle I have rebuilt from the ground up for your requirements.

This uses one time only functions as event binding that are then unbound once the system is set up.

it also does not have the <audio> tags in the HTML to prevent preloading before it's needed. and create the audio when the play button is triggered.

To understand it all the code in this fiddle has been commented so for more details on how I did it please read the comments in the fiddle.

As for problem 2 you are better off using server-side code E.G use PHP

<?php
$page_name = $_SERVER['REQUEST_URI'];
str_replace($page_name, ".php", ".mp3");
if(file_exists("audio/{$pageName}")){
 // page has an mp3 audio
}
?>

Oh and one last thing before I go you need to get all your audio's and converted them to OGG and have both an OGG Vorbis format and an MP3 format, not all browser support mp3 and the ones that don't do support OGG. then with my javascript, you will see

audioSources["audio/mpeg"] = "http://www.hochmuth.com/mp3/Bloch_Prayer.mp3";

you should add an OGG path for example.

audioSources["audio/ogg"] = "http://www.hochmuth.com/ogg/Bloch_Prayer.ogg";

------ old answer fixed the original problem only -----

Here you go working, https://jsfiddle.net/y61bjk5e/1/

The reason for this is your we're binding events after they had fired because they were inside the playpause function

Also, your play variable was not set so that is now set to a collection that it loops through.

Barkermn01
  • 6,295
  • 30
  • 71
  • Thanks! But as already written in the question the audio file (plus its time duration) *must be loaded in **after** (and not before)* a user clicks play. The demo in your answer loads the complete audio file right at page load while the majority of webusers are not visually impaired. Compare these two waterwafalls: https://gtmetrix.com/reports/jsfiddle.net/X0zIQyxE `(630 KB, 16 requests)` and https://gtmetrix.com/reports/jsfiddle.net/mE5qt0AL `(1220 KB, 19 requests)`. The latter proves audio is loaded at page load, which would be a downgrade from the DEMOs in the question. – Sam Jul 18 '18 at 13:47
  • Imagine read out loud spoken audio mp3 of 8 mb. When requested on demand for the visually impared its not a problem! But when loaded in by 95% of visitors who are not visually impared and who are never going to press play its a tremmendous waste of bandwhith! That is why the provided demo's dont load the audio file unless play is pressed. This functionality must be kept alive as stated in the question. – Sam Jul 18 '18 at 13:56
  • 1
    But I did not change that in any way... I moved event's out of the play pause function the only change I made was to use the metadata event for the audio. however, this code goes about what you're trying to do very very bad I will author you a version that works correctly. Like for starters if you are not wanting a preloaded system don to use HTML to load anything as HTML is preloaded by the browser before the DOM is ready. – Barkermn01 Jul 19 '18 at 08:38
  • Loading in the metadata loads (apparently) the entire audio file in unfortunately (in my case can be up to 8mb of clear high quality recorded spoken stories/contents/written texts). – Sam Jul 19 '18 at 10:08
  • Oh my god that strikes me on a fantastic idea... Upvoted also. Would it be possible to first see IF the file `` exist? if YESS only then display the whole html for the audio controls. Otherwise hide the html via CSS. Please see updated question and problem split, either of the two worth 200 Bounty points. – Sam Jul 19 '18 at 10:28
  • 1
    But I don't configure it to load I just use the events when they are fired that was the point this code way just loads it from the start. at no point do Javascript set the audio source and that's what I was meaning by it's been authored wrong. – Barkermn01 Jul 19 '18 at 10:50
  • 1
    Okies I have updated the answer and re-authored all the code to work better and keep it secure out of global scope variables. – Barkermn01 Jul 19 '18 at 11:52
  • Thank you very much! Awesome and tremmendous work! Does make things more complicated (no other way) as the audio source has now moved from the html into the javascript.... Now before I accept this answer and happily give out the bounty to this answer, can you finally please take one last look at your previous answer which solved problem 1 and try to make that version in such a way sothat it does not LOAD in the audio file at page start (DEMO A also did not load in the file). Just a final touch and im going to accept this as the answer (no matter what others post here as alternative). – Sam Jul 19 '18 at 16:34
  • 1
    Sorry, I'm slightly confused by what you are saying? It does not load the audio on page load anymore. line 59-66 make sure that the load is not done until the play button is clicked. the only thing that prevents preload is the `preload="none"` that you could put on the audio source. – Barkermn01 Jul 19 '18 at 16:43
  • 1
    I have updated both versions to use the `preload="none"` even though for the new one it won't make a difference as line 59-66 make sure it could not load because it did not know what to load until it was needed. – Barkermn01 Jul 19 '18 at 16:51
  • Thanks! The new version is flawless :) Award given! In order to understand you in the version before that, a final question: I cant seem to find the 'preload="none' in the demo https://jsfiddle.net/y61bjk5e/ and thus this demo still loads the entire audio file at page load. Any way this could be easily avoided through Javascript without changing anything of the html? Thanks! – Sam Jul 19 '18 at 21:26
  • You would have to use whats in the new version as even with `preload="none"` it still auto loads the audio I'm not sure how your DEMO B did not. as there was nothing in Javascript that stopped it preloading and only the `preload="none"` in the HTML. Javascript you would need to set the source when the play button is triggered and not before E.G `document.getElementsByTagName("audio")[0].addEventListener("click", function(){ this.insertAdjacentHTML("") })` – Barkermn01 Jul 20 '18 at 13:45