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
Comment #1
jdelaune CreditAttribution: jdelaune commentedI'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.
Comment #2
andrewsuth CreditAttribution: andrewsuth commentedIn 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?
Comment #3
jdelaune CreditAttribution: jdelaune commentedhttp://stpetersbrighton.org/sunday-talks
Checked in safari and the .swf and .mp3 aren't loaded until you click on the listen button.
Comment #4
andrewsuth CreditAttribution: andrewsuth commentedI 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...
Comment #5
mwoodwar CreditAttribution: mwoodwar commentedIs 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