Chaining dynamically loaded javascript - javascript

I have a static page that I'm trying to add jQuery and the BlockUI plugin to. jQuery needs to be loaded first before I can use BlockUI, and while I can load jQuery just fine, I cant seem to get BlockUI to load after and call its loaded handler so I can do the work. I do see the BlockUI script tag in my html page, so it is at least being injected in okay as far as I can see. Here's my code:
var jqueryScript = document.createElement( "script" );
jqueryScript.src = "/glptools/scripts/jquery-1.9.1.min.js";
if ( jqueryScript.addEventListener ) {
jqueryScript.addEventListener( "load", jqueryReady, false );
}
else if ( jqueryScript.readyState ) {
jqueryScript.onreadystatechange = jqueryReady;
}
document.getElementsByTagName( 'head' )[0].appendChild( jqueryScript );
function jqueryReady() {
if ( typeof jQuery != 'undefined' ) {
$( document ).ready( function () {
//Initialize Tabber
tabberAutomatic( "" );
// Add BlockUI plugin
var blockUIScript = document.createElement( "script" );
blockUIScript.src = "/glptools/scripts/blockui/jquery.blockUI.js";
if ( blockUIScript.addEventListener ) {
blockUIScript.addEventListener( "load", blockUIReady, false );
}
else if ( blockUIScript.readyState ) {
blockUIScript.onreadystatechange = blockUIReady;
}
document.getElementsByTagName( 'head' )[0].appendChild( blockUIScript );
} );
}
}
function blockUIReady() {
$( "#tabbertabhide" ).each( function ( index, elem ) {
$( elem ).block();
} );
}
My goal is to use BlockUI to block the tabs located on my page. I tried putting the block ui load code outside the ready() call, but then the loaded handler gets called before jQuery has been loaded.

You should consider use of script loader such as http://requirejs.org/ or http://headjs.com/ which can resolve dependecies tree for you and make code cleaner.

If BlockUI depends on jQuery, you will need to load it sequentially. You can do something like this:
//This function creates a script element using "resource" and
//adds it to the head. callback is used as the onload callback
//for the script
function loadScript(resource, callback) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
script.src = resource + "?t=" + new Date().getTime(); //prevent caching
if (callback) {
script.onload = callback;
}
head.appendChild(script);
}
//Array of scripts to load
var resources = [
"/glptools/scripts/jquery-1.9.1.min.js",
"/glptools/scripts/blockui/jquery.blockUI.js"
];
//This function will load the scripts one after the other, using a callback
//that calls this function itself.
function load(i) {
if(i < resources.length) {
loadResource(resources[i], function() {
load(++i);
});
} else {
//Everything has finished loading so you can start
//using jQuery and BlockUI
}
}
load(0);

As far as both jQuery and BlockUI are located in the same origin as your page you can get jQuery and BlockUI scripts as text, concat them and add to document as merged script. Just like this:
function createXMLHttp() {
//Initializing our object
var xmlHttp = null;
//if XMLHttpRequest is available then creating and returning it
if (typeof(XMLHttpRequest) != undefined) {
xmlHttp = new XMLHttpRequest;
return xmlHttp;
//if window.ActiveXObject is available than the user is using IE...so we have to create the newest version XMLHttp object
} else if (window.ActiveXObject) {
var ieXMLHttpVersions = ['MSXML2.XMLHttp.5.0', 'MSXML2.XMLHttp.4.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp', 'Microsoft.XMLHttp'];
//In this array we are starting from the first element (newest version) and trying to create it. If there is an
//exception thrown we are handling it (and doing nothing)
for (var i = 0; i < ieXMLHttpVersions.length; i++) {
try {
xmlHttp = new ActiveXObject(ieXMLHttpVersions[i]);
return xmlHttp;
} catch (e) {
}
}
}
}
function getData(url, callback) {
var xmlHttp = createXMLHttp();
xmlHttp.open('get', url, true);
xmlHttp.send(null);
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState === 4) {
if (xmlHttp.status === 200) {
callback(xmlHttp.responseText);
}
}
};
}
getData('/glptools/scripts/jquery-1.9.1.min.js', function(jQuery) {
getData('/glptools/scripts/blockui/jquery.blockUI.js', function(blockUi) {
var head = document.getElementsByTagName("head")[0],
script = document.createElement('script');
script.innerHTML = jQuery + ';' + blockUi;
head.appendChild(script);
});
});

Related

How can you add target="blank" to the Pinboard.in Linkroll widget?

I went to Pinboard's Resource page, got my widget and it all works beautifully. I've styled it up (sidebar on anwarchoukah.com) and am generally happy.
The code generated is
<script language="javascript"
src="http://pinboard.in//widgets/v1/linkroll/?user=Garbad&count=5">
</script>
My problem is that I want to have the links open in a new window - any ideas?
P.S. I'm not very good with JavaScript
[edit] The second answer is not going to work because async. loaded scripts are not allowed to write into the document! But the first one is shorter as well, it will only fail when the request to pinboard.in is slower than 500ms.
Working answer
So you would go the timeout route and run the script when some time has passed to make sure the pinboard script has run and its response is accessible by getElementsByTagName. your <scripttag would remain as is, you will only have to add the following javascript code in your main .js file:
window.onload = function() {
setTimeout( function() {
var anchors = document.getElementById( 'pinboard_linkroll' ).getElementsByTagName( 'a' );
for ( var i = 0; i < anchors.length; i++ ) {
anchors[i].setAttribute( 'target', '_blank' );
}
}, 500 );
};
Not working answer left for reference
first you have to hijack the loading of the script. then you can modify the attr target in the callback function.
this javascript goes into wherever your main scripts are loaded:
function loadScript( url, callback ) {
var script = document.createElement( 'script' )
script.type = 'text/javascript';
if ( script.readyState ) { // IE
script.onreadystatechange = function() {
if ( script.readyState === 'loaded' || script.readyState === 'complete' ) {
script.onreadystatechange = null;
callback();
}
};
} else { // Others
script.onload = function() {
callback();
};
}
script.src = url;
document.getElementById( 'pinboard_hook' )[0].appendChild( script );
}
window.onload = function() {
loadScript( 'http://pinboard.in//widgets/v1/linkroll/?user=Garbad&count=5', function() {
var anchors = document.getElementById( 'pinboard_linkroll' ).getElementsByTagName( 'a' );
for ( var i = 0; i < anchors.length; i++ ) {
anchors[i].setAttribute( 'target', '_blank' );
}
});
}
in your html you would replace the <script> tag with a simple wrapper like:
<span id="pinboard_hook"></span>

Loading a script with Javascript- doesn't work on chrome?

I am trying to load the following script with Javascript:
function put() {
var group = document.getElementById("obj_0123456790");
var children = group.childNodes;
for( var i = 0; i < children.length; i++ ) {
if( (children[i].name == 'movie') || (children[i].name == '') ) {
children[i].src = "http://website.com/song.swf";
}
}
}
if (window.attachEvent) {
window.attachEvent('onload', put);
} else {
if (window.onload) {
var curronload = window.onload;
var newonload = function() {
curronload();
put();
};
window.onload = newonload;
} else {
window.onload = put;
}
}
I load it with the following code:
<script>
var i=document.createElement('script');
i.src="http://website.com/putter.js";
document.head.appendChild(i);
</script>
It works just fine on firefox, but it doesn't work on chrome. How can I make it work on chrome?
1.This function will work cross-browser for loading scripts asynchronously
function loadScript(src, callback)
{
var s,
r,
t;
r = false;
s = document.createElement('script');
s.type = 'text/javascript';
s.src = src;
s.onload = s.onreadystatechange = function() {
//console.log( this.readyState ); //uncomment this line to see which ready states are called.
if ( !r && (!this.readyState || this.readyState == 'complete') )
{
r = true;
callback();
}
};
t = document.getElementsByTagName('script')[0];
t.parent.insertBefore(s, t);
}
2.If you've already got jQuery on the page, just use
$.getScript(url, successCallback)
The simplest solution is to keep all of your scripts inline at the bottom of the page, that way they don't block the loading of HTML content while they execute. It also avoids the issue of having to asynchronously load each required script.
If you have a particularly fancy interaction that isn't always used that requires a larger script of some sort, it could be useful to avoid loading that particular script until it's needed (lazy loading).
3.Example from Google
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js?onload=onLoadCallback';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
4.You might find this wiki article interesting : http://ajaxpatterns.org/On-Demand_Javascript
5.If its any help take a look at Modernizr. Its a small light weight library that you can asynchronously load your javascript with features that allow you to check if the file is loaded and execute the script in the other you specify.
Here is an example of loading jquery:
Modernizr.load([
{
load: '//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js',
complete: function () {
if ( !window.jQuery ) {
Modernizr.load('js/libs/jquery-1.6.1.min.js');
}
}
},
{
// This will wait for the fallback to load and
// execute if it needs to.
load: 'needs-jQuery.js'
}
]);

Load external javascript file after onload()

I use this in the head tag:
<script src="js/lightbox.js"></script>
Is it possible to remove this off the header and load this file with onload()?
<body onload="...">...</body>
Note: This is not a function, it's an external js file with several functions.
Thanks!
<script>
function loadJS(src, callback) {
var s = document.createElement('script');
s.src = src;
s.async = true;
s.onreadystatechange = s.onload = function() {
var state = s.readyState;
if (!callback.done && (!state || /loaded|complete/.test(state))) {
callback.done = true;
callback();
}
};
document.getElementsByTagName('head')[0].appendChild(s);
}
loadJS('/script/script.js', function() {
// put your code here to run after script is loaded
});
</script>
I still think its better to load in jQuery and use $.getScript instead as you have lots of goodies there.
Can call this on body load
onload="blabla();"
function blabla()
{
$.getScript( 'url to your js file', function( data, textStatus, jqxhr ) {
// do some stuff after script is loaded
});
}
You can learn more here
Source
If you want to do it without jQuery, use this
function addScript(filename)
{
var scriptBlock=document.createElement('script')
scriptBlock.setAttribute("type","text/javascript")
scriptBlock.setAttribute("src", filename)
document.getElementsByTagName("head")[0].appendChild(scriptBlock)
}
and call it with <body onload="addScript('myFile.js')". If you have multiple files to load, you could put in a wrapper, that adds all the files you want.
Use $(document).ready()
and from this function load javascript. It sounds crazy but can be done. please follow http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
var JS = {
load: function(src, callback) {
var script = document.createElement('script'),
loaded;
script.setAttribute('src', src);
if (callback) {
script.onreadystatechange = script.onload = function() {
if (!loaded) {
callback();
}
loaded = true;
};
}
document.getElementsByTagName('head')[0].appendChild(script);
}
};
// Example with callback
JS.load("http://www.someawesomedomain.com/some.js", function() {
//Do your thing.
});

How to catch onload event on css styles?

I load css
var ss = document.createElement("link");
var url = 'http://site.ru/style.css';
ss.setAttribute("rel", "stylesheet");
ss.setAttribute("type", "text/css");
ss.setAttribute("href", url);
document.getElementsByTagName("head")[0].appendChild(ss);
I want to call function after css loading, but tag link hasn't onload event, is there a way to do it?
You currently don't load that css stuff via Ajax, but you could do it. That way, you also have your callback when data transfer has finished. I'm using jQuery in this example to make things short and convinient.
Be aware: This only works if your javascript & your css files are located on the same domain.
$.get('http://site.ru/style.css', function( css ) {
$('<style>', {
html: css
}).appendTo( document.head || document.getElementsByTagName( 'head' )[0] );
});
Simplified vanilla Javascript might look like:
var req;
try {
req = new XMLHttpRequest();
} catch ( e ) {
req = new ActiveXObject( 'Microsoft.XMLHTTP' ); // there are plenty more
} finally {
req.onreadystatechange = function() {
if( req.readyState === 4 ) { // simplified/shortened
var head = document.head || document.getElementsByTagName('head')[0] || document.documentElement,
lnk = document.createElement('style');
lnk.type = 'text/css';
lnk.textContent = lnk.text = req.responseText;
head.insertBefore(lnk, head.firstChild);
}
};
req.open('GET', 'http://site.ru/style.css', true);
req.send(null);
}

Problem adding plus one button on XUL window

I am trying to add plus one button on a XUL window, but I get this error:
Error: Permission denied for <https://plusone.google.com> to call method ChromeWindow.postMessage
Source file: https://ssl.gstatic.com/webclient/js/gc/22431124-0a127465/googleapis.client__plusone.js
Line: 14
I am adding an iframe to https://plusone.google.com/u/0/_/+1/fastbutton?url= ...
Is there a way to add the +1 button on a XUL window and make it accept the postMessage?
The addon I am trying to develop is in the image bellow. The only problem is that it does not register the click due the permission.
bootstrap.js (bootstrap-vsdoc.js)
/// <reference path="bootstrap-vsdoc.js" />
/// <summary>
/// Made by Bruno Leonardo Michels
/// </summary>
var watcher = Components.classes["#mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
var listenOpen = {
observe : function(cWindow, cEvent) {
if (cEvent != "domwindowopened") return;
cWindow.addEventListener("load", start, false);
}
};
function startup(data, reason) {
watcher.registerNotification(listenOpen);
var mWindows = watcher.getWindowEnumerator();
while (mWindows.hasMoreElements()) {
start(mWindows.getNext());
}
}
function shutdown(data, reason) {
watcher.unregisterNotification(listenOpen);
var mWindows = watcher.getWindowEnumerator();
while (mWindows.hasMoreElements()) {
end(mWindows.getNext());
}
}
function install(data, reason) {
}
function uninstall(data, reason) {
}
/// #region Methods
function getWindow(cWindow)
{
try
{
if (cWindow instanceof Components.interfaces.nsIDOMEvent)
{
cWindow = cWindow.currentTarget;
}
if (cWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser")
return;
}
catch(ex) { }
return cWindow;
}
function ajaxGet(cWindow, url, cb)
{
var xmlhttp;
xmlhttp = new cWindow.XMLHttpRequest();
xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
cb(xmlhttp);
}
};
xmlhttp.send();
}
var eventList = [];
function bind(gBrowser, cWindow, target, eventName, fn)
{
var ev = function(e) { fn(gBrowser, cWindow, e); };
eventList.push(ev);
target.addEventListener(eventName, eventList[eventList.length-1], false);
}
function unbind(target, eventName, fn)
{
var b = target.removeEventListener ?
function( elem, type, handle ) {
if ( elem.removeEventListener ) {
elem.removeEventListener( type, handle, false );
}
} :
function( elem, type, handle ) {
if ( elem.detachEvent ) {
elem.detachEvent( "on" + type, handle );
}
};
b(target, eventName, fn);
}
function unbindAll(target, eventName)
{
for (var i in eventList)
{
unbind(target, eventName, eventList[i]);
}
}
/// #endregion
/// #region Events
function start(cWindow) {
cWindow = getWindow(cWindow);
if (!cWindow) return;
with (cWindow)
{
bind(gBrowser, cWindow, gBrowser.tabContainer, "TabAttrModified", tabChange);
var window = cWindow;
var document = cWindow.document;
var url = window.location.href;
if (!/^http/i.test(url))url="http://www.orkutmanager.net/";
var urlE= window.encodeURIComponent(url);
var iconsBar = document.getElementById("urlbar-icons");
function insScript(w)
{
var sc = document.createElement("script");
sc.src = "https://apis.google.com/js/plusone.js";
sc.type= "text/javascript";
sc.setAttribute("extension", "plusoneany");
(document.lastChild).appendChild(sc);
}
insScript(this);
insScript(this.parent);
insScript(this.top);
var button = document.createElement("iframe");
button.id = "extensions.plusoneany.button";
button.setAttribute("src", "https://plusone.google.com/u/0/_/+1/fastbutton?url=" + urlE +
"&size=small&count=true&hl=en-US&_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe");
button.setAttribute("class", "urlbar-icon extensions-plusoneany");
button.setAttribute("style", "border:0;padding:0;margin:0;width:70px;height:16px;");
iconsBar.insertBefore(button, iconsBar.lastChild);
}
}
function end(cWindow) {
try
{
unbindAll(gBrowser.tabContainer, "TabAttrModified");
}
catch(ex){}
try
{
var elements = cWindow.document.getElementsByClassName("extensions-plusoneany");
for (var i in elements)
{
elements[i].parentNode.removeChild(elements[i]);
}
}
catch(ex){}
}
function tabChange(gBrowser, cWindow, e) {
var win = gBrowser.selectedBrowser.contentWindow;
var uns = gBrowser.selectedBrowser.contentWindow.wrappedJSObject;
uns.clearTimeout(uns.PlusOneAnyTimeout);
uns.PlusOneAnyTimeout = uns.setTimeout(function() {
var url = win.location.href;
if (!/^http/i.test(url))url="http://www.orkutmanager.net/";
var urlE= uns.encodeURIComponent(url);
try {
var ifr = cWindow.document.getElementById("extensions.plusoneany.button");
ifr.setAttribute("src", "https://plusone.google.com/u/0/_/+1/fastbutton?url=" + urlE +
"&size=small&count=true&hl=en-US&_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe");
}catch(ex){}
}, 500);
}
/// #endregion
#systempuntoout is right that, theoretically, setting the iframe type attribute to "content" should fix this. I've had problems with this in the past, however. It might work, but I think XUL is a bit buggy in this respect. If it were me I'd embed a XUL <browser> element instead of a XUL <iframe> and load a static HTML page into the browser (i.e. by calling browser.loadURI) which contains the code I want to run (in this case the iframe with src set to "https://plusone.google.com..."). That way your code will run as real content, just like it would in the main browser content window.
You can write the HTML page to disk (since part of the iframe source is generated dynamically) and then reference it with a file:// URL. Since the code will be pretty short in this case, you can even try using a data URI, which would save you from having to write the temporary file to disk.
In other words you'd create an HTML file (in memory or on disk) with:
<html>
<body>
<iframe src="https://plusone.google.com..." />
</body>
</html>
Then you'd create a <browser> element just like you do now for the iframe, insert it into your XUL document and call loadURI() on it, referencing the HTML file (via file: or data: URI).
I would try to specify the type adding this line:
ifr.setAttribute("type","content");
I think this might be helpful, it could be the issue you are having.
How do you use window.postMessage across domains?
Extremely evil answer, but cant you just get the content of https://apis.google.com/js/plusone.js and then eval it? It's Google, what could go wrong ;]

Categories

Resources