Closed foo123 closed 8 years ago
i managed to make this work as following:
The code listens for script onload
on snoothState onAfter
, when all scripts (if indeed there are any) are loaded, then the jquery.ready
mod exec is run (it needs some corrections from the gist) see below
smoothState
onAfter: function( $container, $newContent ) {
// other page stuff here..
// listen for any extra scripts and wait to load before calling onReeady
var numScripts = 0;
$('script', $newContent).each(function(){
var script = this;
if ( script.src )
{
numScripts++;
script.onload = function( ){
numScripts--;
if ( 0 === numScripts ) onReady( );
};
}
});
if ( 0 === numScripts ) onReady( );
}
onReady
function onReady( fn ) {
setTimeout(function(){
// trigger ready listeners, if any
// using jquery ready method as mod exec
$.readyFn.execute();
$.readyFn.clear();
if ( fn ) fn();
}, 20);
}
jquery.execReady.js
/**
* Replace jQuery's $.fn.ready() function with a mod exec
*
* Sites that make heavy use of the $(document).ready function
* are generally incompatable with asynchrounous content. The
* the $.fn.ready function only runs once. This script replaces
* the ready function with a module execution controller that
* let's us register functions and execute all of the functions
* as we need them. This is useful after HTML gets injected on the
* page and we want to rebind functionally to the new content.
*
* @author Miguel Ángel Pérez reachme@miguel-perez.com
* @note Should be placed directly after jQuery on the page
*
*/
// https://gist.github.com/miguel-perez/476046a42d229251fec3
;(function($){
"use strict";
/** create mod exec controller */
$.readyFn = {
list: [],
register: function(fn) {
$.readyFn.list.push(fn);
},
execute: function(el) {
el = el || document;
for (var i = 0; i < $.readyFn.list.length; i++) {
try {
$.readyFn.list[i].call(el, $);
}
catch (e) {
throw e;
}
};
},
clear: function() {
$.readyFn.list.length = 0;
}
};
/** run all functions */
/*$(document).ready(function(){
$.readyFn.execute();
});*/
/** register function */
$.fn.jqReady = $.fn.ready;
$.fn.ready = function(fn) {
$.readyFn.register(fn);
return this; // this is needed for .ready to work as expected in some cases
};
/** run all functions */
$(document).jqReady(function(){
$.readyFn.execute(this);
$.readyFn.clear();
});
})(jQuery);
another way to write this:
onReady
function onReady( scripts, before, after )
{
var execReady = function( ) {
setTimeout(function(){
if ( before ) before( );
// trigger ready listeners, if any
// using jquery ready method as mpd exec
$.readyFn.execute();
$.readyFn.clear();
if ( after ) after( );
}, 0);
};
var numScripts = 0;
if ( scripts && scripts.length )
{
scripts.each(function( ){
var script = this;
if ( script.src /*&& !script.async*/ && (!script.readyState || ('loaded' !== script.readyState) && ('complete' !== script.readyState)) )
{
numScripts++;
var loader = function loader( ){
if ( !script.readyState ||
('loaded' === script.readyState) ||
('complete' === script.readyState)
)
{
numScripts--;
script.onload = script.onreadystatechange = null;
if ( loader.prev ) loader.prev( );
if ( 0 === numScripts ) execReady( );
}
};
loader.prev = script.onload || null;
script.onload = script.onreadystatechange = loader;
}
});
}
if ( 0 === numScripts ) execReady( );
}
smoothState
onAfter: function( $container, $newContent ) {
// other page stuff here..
// listen for any extra scripts and wait to load before calling onReady
onReady( $('script', $newContent), beforeFunc, afterFunc );
}
NOTE In order to handle more generic cases (not using jquery
, e.g angular
or other) one may need to override or simulate/trigger window.load
events, but you get the idea.
a further refinement (to handle cases where scripts are not async or defer and already loaded and.or cached, ..)
onReady
function onReady( scripts, before, after )
{
var execReady = function( ) {
// trigger ready listeners, if any
// using jquery ready method as mpd exec
setTimeout(function(){
if ( before ) before( );
if ( $.readyFn ) $.readyFn.execute( document, true/* and clear list afterwards*/ );
if ( after ) after( );
}, 0);
};
var numScripts = 0;
if ( scripts && scripts.length )
{
scripts.each(function( ){
var script = this;
if ( script.src && (!script.readyState || ('loaded' !== script.readyState) && ('complete' !== script.readyState)) )
{
numScripts++;
var loader = function loader( ){
if ( !loader.done &&
(!loader.readyState ||
('loaded' === loader.script.readyState) ||
('complete' === loader.script.readyState))
)
{
loader.done = true;
loader.script.onload = loader.script.onreadystatechange = null;
numScripts--;
if ( loader.prev ) loader.prev( );
if ( 0 === numScripts ) execReady( );
}
};
loader.script = script;
loader.done = false;
loader.readyState = script.readyState ? true : false;
loader.prev = script.onload || script.onreadystatechange || null;
script.onerror = script.onload = script.onreadystatechange = loader;
// run it manualy as well, since it may be already loaded and never call onload
setTimeout(loader, 100);
}
});
}
if ( 0 === numScripts ) execReady( );
}
smoothState
onAfter: function( $container, $newContent ) {
// other page stuff here..
// listen for any extra scripts and wait to load before calling onReady
onReady( $('script[src]:not([async]):not([defer])', $newContent), beforeFunc, afterFunc );
}
a gist of the scripts for smoothState - wordpress integration and some more details https://gist.github.com/foo123/c404aeeebbd0a26aceba122ac915aee1
i read all about
smoothState
andWP
(this is what i'm making right now, for smooth page transitions). i even read the part where any new scripts (of the new page) should be inside the content handled by smoothState (done), still the scripts do not seem to be executing at all (my example is a simple contact form script which is only in one page)And yes, i have even patched the
$.fn.ready
method and all tomod exec
style.Thanks
PS Note that loading every possible script that may be needed in all pages although doable IS NOT AN EFFICIENT OPTION. So i'm asking for ways (if this can be done correctly) for any extra page scripts to be executed correctly on page load.