In an effort to reduce the front-endd page load time, I have been experimenting with loading the mp3player via AJAX. I have 3-4 mp3players on each node and it was slowing down page load by about 2 seconds (4 x HTTP requests saved, each with a payload of 10KB)

I made a module to do the dirty work (see below) of getting the player.swf to AJAX load.

Now I am taking it to the next level and trying to also load audio-player.js on click as well. The problem I have found is that because mp3player stores some variables in CDATA (<!--//--><![CDATA[//><!-- AudioPlayer.setup("/sites/vibe-wired.com/modules/mp3player/mp3player/player.swf", {width:290}); //--><!]]>), it causes an error when it cannot find the JS file.

So I stripped the CDATA and audio-player.js out of the page on theme load, and am experimenting to see if I can get it to load on click as well.

So I think the order of injection would be something like:

1) audio-player.js
2) CDATA
3) player.swf

I tried to also inject the CDATA into the DOM after loading audio-player.js but I couldn't get it to work (it shows the It look's like you don't have Adobe Flash Player installed. warning). I'm not 100% I was injecting it into the DOM in the right way - anyone know the correct jQuery way of doing this?

I guess this is more of an AJAX question but I was hoping someone knew of a way of doing this.

The module code:

drupal_add_js(drupal_get_path('module', 'custom') .'/js/custom.js');

/**
* Implementation of hook_menu().
*/
function custom_menu() {
  $items = array();

  $items['ajax/mp3player_handler'] = array(
    'page callback' => 'custom_ajax_mp3player_handler',
    'type' => MENU_CALLBACK,
    'access arguments' => array('access content'),
  );
  return $items;
}

function custom_ajax_mp3player_handler() {

  $mp3player = theme('mp3player', 'Default', file_create_url(arg(3)), NULL, NULL, NULL);

  // Hack to insert a custom markup ID for each player. If not, all ID's are: "mp3player_1"
  $rootID = 'mp3player_';
  $currentDelta = strpos($mp3player, $rootID);
  $currentID = $rootID . substr($mp3player, $currentDelta + strlen($rootID), 1);
  $newID = $rootID . arg(2);  // arg(2) comes from the URL - which was originally the 'title' of the clicked DIV
  $mp3ID = str_replace ($currentID, $newID, $mp3player);

  print $mp3ID;
  exit;
}

Then in my custom.js file:

Drupal.behaviors.custom = function(context) {
  $("div.lesson-audio-reading").hide().end();	// Hide the DIVs to animate
  var toggleCount = [];		// Array to store TRUE when a DIV is clicked, to avoid AJAX reloads

  $('div.lesson-audio-title', context).bind('click', function(){
		// Variables for DIV ID's
        var toggleId = "#" + $(this).attr("id").replace("title", "player");		// ID of the DIV to animate and add mp3player to
        var toggleNum = $(this).attr("id").substring($(this).attr("id").length-1);	// Integer to identify DIV (in case of multiple mp3players)
        var toggleLoading = 'div#audio-loading-' + toggleNum;		// ID for loading throbber

        if(!toggleCount[toggleNum]) {	// First time DIV has been clicked? Avoids AJAX reloads
		
				// Display throbber for AJAX loading
                $(this).ajaxStart(function() {
                        $(toggleLoading).addClass('audio-loading');
                        }).ajaxComplete(function() {
                                $(toggleLoading).removeClass('audio-loading');
                });
				
                $(toggleId).load('/ajax/mp3player_handler/' + encodeURI($(toggleId).attr('title')));	// Add mp3player markup to the DIV
                toggleCount[toggleNum] = true;		// The DIV has been clicked
        }

		// Animate DIV
        if (!$(toggleId).is(':animated')) {
                $(toggleId).slideToggle(1200);
        }

        return false;
  });
}

And my markup for the DIVs is like:

<div id="audio-title-0" class="lesson-audio-title">
	<div id="audio-loading-0"></div>
</div>
<div id="audio-player-0" class="lesson-audio-reading" title="0/01-lesson-audio.mp3"></div>

Comments

jdelaune’s picture

I've found the best way is to start off with a div wrapping round the mp3 player with a css style show set to none. Then an onclick javascript event set to make that div show works well. Means the flash doesn't get loaded until the show is run. Might save you a lot of work fiddling with modules.

andrewsuth’s picture

In my experience, hiding the DIV will still load the SWF into the broswer. It just doesn't display it to the user.

Do you have an example where you've got it working like that?

jdelaune’s picture

http://stpetersbrighton.org/sunday-talks

Checked in safari and the .swf and .mp3 aren't loaded until you click on the listen button.

andrewsuth’s picture

I got the same results as you when using IE7 but when inspecting the components using FireBug on FF shows it as loading on page view (loads player.swf only once). I guess broswers handle it differently.

My main problem was that I was injecting the player at the theme layer and it was causing FF and IE7 to load player.swf multiple times, which was causing a 1-2 second delay in some cases. I managed to get around it with the AJAX loading module above.

I hope in the future that all browsers handle hidden elements like Safari and IE7 does...

mwoodwar’s picture

Is this a 'view' of a content type? I love the way the player shows up right under the passage selected. I'm going to play with this some...thanks for the inspiration (and of course the module...I'm going to rip out all of the swf tools stuff...lots of overhead.

Mark