How to load all scripts, stylesheets, and markup from one js file? - javascript

The following small snippet of code cannot be changed once deployed (it's in an RIA) so everything must be loaded via a bootstrapper.js file:
<div id="someDivID"></div>
<script type="text/javascript" src="bootstrapper.js"></script>
What's the best way to load up all the js, css, and markup? Is there a better (cleaner, faster, crisper) way than the following?:
function createDivs() {
var jsDiv = document.createElement('div');
jsDiv.id = 'allJavascriptHere';
var contentDiv = document.createElement('div');
contentDiv.id = 'allContentHere';
document.getElementById("someDivID").appendChild(jsDiv);
document.getElementById("someDivID").appendChild(contentDiv);
function importScript(url){
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.getElementById("jsDiv").appendChild(script);
}
importScript("http://example.com/jquery-1.4.2.min.js");
importScript("http://example.com/anotherScript.js");
}
window.onload = function(){
$.get("http://example.com/someHTML.html", function(data) {
$('#contentDiv').html(data);
setTimeout("javaScript.init()", 200);
});
}
with stylesheets in the someHTML.html file as so:
<style type="text/css">
#import url("example.com/styleSheet.css");
</style>
(note: I don't know why I need the setTimeout but for some reason I do. Maybe your answer won't require it.)

You can use jQuery's $.getScript() to import scripts.
I recently wrote a function to import CSS.
var getCss = function(file, callback) {
if (typeof callback !== 'function') {
throw 'Not a valid callback';
};
$.get(file, function(css) {
var top = $('head > link[rel=stylesheet]').length ? $('head > link[rel=stylesheet]:last') : $('head > *:last');
top.after('<link rel="stylesheet" type="text/css" href="' + file + '">');
callback();
});
};

If your css is also in that js file, you can simply add css code to the documents style tag. It can be useful in some situations, where using different css file is not allowed etc.

If you're looking to load CSS asynchronously in an easy fashion similar to $.getScript check out loadCSS, a standalone library for loading CSS without a dependency on jQuery.

Related

Run JavaScript inside <script src="..."></script> Tags?

I've a JavaScript file that processes tab switches. Here is the source:
var tCount = 0;
function SwitchToTab(id) {
if (id < 0 || id > tCount) { id = 0; }
for (var i = 0; i < tCount; i++) { document.getElementById("tab" + i).className = ""; }
document.getElementById("tab" + id).className = "active";
for (var i = 0; i < tCount; i++) { document.getElementById("area" + i).style.display = "none"; }
document.getElementById("area" + id).style.display = "";
}
function InitializeTabs(initialTabId, tabsCount) {
tCount = tabsCount;
SwitchToTab(initialTabId);
}
I'm trying to make it as short as possible like this:
<script src="Resources/Tabs.js">InitializeTabs(0, 4);</script>
It doesn't works but it works if I separate them like this:
<script src="Resources/Tabs.js"></script>
<script>InitializeTabs(0, 4);</script>
So, is there any way to run JavaScript inside <script src="..."></script> tags? What I am missing?
No, this is not possible. The html spec dictates that a <script> tag does one or the other.
<script>Tag Html Spec, emphasis mine.
The script may be defined within the contents of the SCRIPT element or in an external file. If the src attribute is not set, user agents must interpret the contents of the element as the script. If the src has a URI value, user agents must ignore the element's contents and retrieve the script via the URI.
You are suppose to do it the second way. in <script src="Resources/Tabs.js">InitializeTabs(0, 4);</script> you are referencing an external javascript file, your inline code should go into a second script block.
You can either use src, or put JavaScript inside the tag.
But not both at once. There's no downside to using two tags anyway (apart from larger file size).
When you include <script src="Resources/Tabs.js"></script>, you are mentioning that you want to use the Javascript which is included inside the Tabs.js file so that the compiler knows where to look for InitializeTabs function, when it is trying to execute the function.
Now if you want to include some Javascript inline, that is inside the HTML, hen you use the <script>... JAVASCRIPT HERE .... </script>
You need to do it like this
<script src="Resources/Tabs.js"></script>
<script>InitializeTabs(0, 4);</script>
You can't put javascript inside of <script src="... tags, but you could run a JavaScript file which parses the HTML, looking for <script src tags, which converts it into two tags.
For example,
<script src="Resources/Tabs.js">InitializeTabs(0, 4);</script>
would have to be converted into
<script src="Resources/Tabs.js"></script>
<script>InitializeTabs(0, 4);</script>
Here's the code I tried:
var tags = document.querySelectorAll("script[src]");
[].forEach.call(tags, function(elem){
var text = elem.innerText;
var src = elem.src;
var parent = elem.parentNode;
parent.removeChild(elem);
var newTag = document.createElement('script');
newTag.setAttribute('src', src);
parent.appendChild(newTag);
var newTag = document.createElement('script');
var t = document.createTextNode(text);
newTag.appendChild(t);
parent.appendChild(newTag);
});
in a JSFiddle

Call to window.print firing before documents style is applied

I have a form with a print function. Inside the function I open a window, build the document, add the head with style sheets, add the form HTML and make the call to print the last part of the body. The problem is the initial print preview/print doesn't reflect the style. If I cancel the print and attempt to print manually, the style shows up.
I've tried quite a few ways of doing this with no luck. It seems like a timing issue. Any ideas?
Browser is Chrome. Below is the JS function. (This is injected with a faces context).
function printForm(windowTitle, path){
var printWindow = window.open();
var printDocument = printWindow.document;
var headHtml = "<link href='" + path + "/css/style.css' rel='stylesheet' type='text/css'/>";
printDocument.getElementsByTagName('head')[0].innerHTML = headHtml;
var printDiv = printDocument.createElement("DIV");
var formDiv = document.getElementById("formDiv");
printDiv.innerHTML = formDiv.innerHTML // Styling here is the issue
printDocument.body.appendChild(printDiv);
var scriptTag = printDocument.createElement("script");
var script = printDocument.createTextNode("print();");
scriptTag.appendChild(script);
printDocument.body.appendChild(scriptTag);
}
I think you need a setTimeout to delay printing for a second or two so the style can be applied. You'll need to tinker to find the right length.
Instead of trying to guessing with a timer, it might be more precise to use the load event on the <link ...> to know exactly when it has completed loading.
Below is a function I use which illustrates this technique. It uses an off-screen <iframe> to print a portion of a page. It's jQuery based, but the principles are the same in vanilla JS. Note the setting of the <link>'s onload function with an anonymous function which invokes print() on the <iframe>'s window object.
/*
* expects:
* <tag id="whatever">...goop...</tag>
* <input type="button" class="printit" data-target="whatever" value="Print">
*/
$(function() {
$( '.printit' ).click(function() {
var goop = $( '#' + this.dataset.target ).prop('outerHTML');
var ifr = $('<iframe>');
var bas = $('<base href="' + document.baseURI + '">');
var lnk = $('<link rel="stylesheet" href="/css/print.css">');
lnk.on('load', function() { /* CSS is ready! */
ifr[0].contentWindow.print();
});
ifr.css( { position: 'absolute', top: '-10000px' } )
.appendTo('body')
.contents().find('body').append(goop);
ifr.contents().find('head').append(bas).append(lnk);
return false;
});
});

Calling a function in one external file from a function in another external file

I keep reading that it is possible to load javascript files, and then use those functions in other files. Unfortunately I can't get this to work. Here is my current path:
<script src="js/bootstrap.min.js"></script>
<script src="js/twitter_crypt.js"></script>
<script src="js/scripts.js"></script>
<script src="http://platform.twitter.com/widgets.js"></script>
<script src="js/interactive.js"></script>
I am using functions from the twitter_crypt.js file in my interactive.js file (last in path).
When I console.log(nameOfFunction) in interactive.js which is in twitter_crypt.jsit tells me that function is not defined.
I ran into this posts but I am not looking to use something like require.js .
I am just trying to call functions from the other files. I assume the must be available since I am using jquery, bootstra.min.js and other files that are being loaded.
I believe I have everything in order as well which is what this post talks about.
//Twitter_Crypt JS file:
function decoder(key, encodedMessage){
var coded = "";
var ch;
var index;
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(var i = 0; i < encodedMessage.length; i++){
ch = encodedMessage.charAt(i);
index = key.indexOf(ch);
if(index === -1){
coded = coded + ch;
} else {
coded = coded + alphabet.charAt(index);
}
}
return coded;
}
InteractivJS File:
$('#decodeSubmit').on("click", function(ev){
if($("#encryptText").val() === ""){
alert("Please Enter a Decrypted Tweet");
} else {
ev.preventDefault();
var decodedTweet = decoder("zipsunxmogdkfabrhcylvqewtj", $("#encryptText").val());
$("#decode_form").fadeOut("fast");
$("#decode").fadeIn("fast");
$('#decode_progress').progressbar({
display_text: 'center',
use_percentage: false,
refresh_speed: 10,
done: function($this) {
$(".modal-body").append(decodedTweet).css('color', 'black');
$("#decodeNewTweet").fadeIn("slow");
$(".modal").modal("show");
}
});
}
});
When I put the function decoder inside the interactiveJS file it works fine. When it is in the twitter_crypt.js file I keep getting a decoder is not defined.
Originally I had both scripts wrapped in a document ready, which helped but didn't solve everything. Why isn't my decoder function in global scope though? It isn't wrapped in any other functions?
Do I have to do something like window.decoder =function(){}

How to force a script reload and re-execute?

I have a page that is loading a script from a third party (news feed). The src url for the script is assigned dynamically on load up (per third party code).
<div id="div1287">
<!-- dynamically-generated elements will go here. -->
</div>
<script id="script0348710783" type="javascript/text">
</script>
<script type="javascript/text">
document.getElementById('script0348710783').src='http://oneBigHairyURL';
</script>
The script loaded from http://oneBigHairyURL then creates and loads elements with the various stuff from the news feed, with pretty formatting, etc. into div1287 (the Id "div1287" is passed in http://oneBigHairyURL so the script knows where to load the content).
The only problem is, it only loads it once. I'd like it to reload (and thus display new content) every n seconds.
So, I thought I'd try this:
<div id="div1287">
<!-- dynamically-generated elements will go here. -->
</div>
<script id="script0348710783" type="javascript/text">
</script>
<script type="javascript/text">
loadItUp=function() {
alert('loading...');
var divElement = document.getElementById('div1287');
var scrElement = document.getElementById('script0348710783');
divElement.innerHTML='';
scrElement.innerHTML='';
scrElement.src='';
scrElement.src='http://oneBigHairyURL';
setTimeout(loadItUp, 10000);
};
loadItUp();
</script>
I get the alert, the div clears, but no dynamically-generated HTML is reloaded to it.
Any idea what I'm doing wrong?
How about adding a new script tag to <head> with the script to (re)load? Something like below:
<script>
function load_js()
{
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.src= 'source_file.js';
head.appendChild(script);
}
load_js();
</script>
The main point is inserting a new script tag -- you can remove the old one without consequence. You may need to add a timestamp to the query string if you have caching issues.
Here's a method which is similar to Kelly's but will remove any pre-existing script with the same source, and uses jQuery.
<script>
function reload_js(src) {
$('script[src="' + src + '"]').remove();
$('<script>').attr('src', src).appendTo('head');
}
reload_js('source_file.js');
</script>
Note that the 'type' attribute is no longer needed for scripts as of HTML5. (http://www.w3.org/html/wg/drafts/html/master/scripting-1.html#the-script-element)
Creating a new script tag and copying the contents of the existing script tag, and then adding it, works well.
var scriptTag = document.createElement('script');
scriptTag.innerText = "document.body.innerHTML += 'Here again ---<BR>';";
var head = document.getElementsByTagName('head')[0];
head.appendChild(scriptTag);
setInterval(function() {
head.removeChild(scriptTag);
var newScriptTag = document.createElement('script');
newScriptTag.innerText = scriptTag.innerText;
head.appendChild(newScriptTag);
scriptTag = newScriptTag;
}, 1000);
This won't work if you expect the script to change every time, which I believe is your case. You should follow Kelly's suggestion, just remove the old script tag (just to keep the DOM slim, it won't affect the outcome) and reinsert a new script tag with the same src, plus a cachebuster.
Small tweak to Luke's answer,
function reloadJs(src) {
src = $('script[src$="' + src + '"]').attr("src");
$('script[src$="' + src + '"]').remove();
$('<script/>').attr('src', src).appendTo('head');
}
and call it like,
reloadJs("myFile.js");
This will not have any path related issues.
Use this function to find all script elements containing some word and refresh them.
function forceReloadJS(srcUrlContains) {
$.each($('script:empty[src*="' + srcUrlContains + '"]'), function(index, el) {
var oldSrc = $(el).attr('src');
var t = +new Date();
var newSrc = oldSrc + '?' + t;
console.log(oldSrc, ' to ', newSrc);
$(el).remove();
$('<script/>').attr('src', newSrc).appendTo('head');
});
}
forceReloadJS('/libs/');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
I know that is to late, but I want to share my answer.
What I did it's save de script's tags in a HTML file,
locking up the scripts on my Index file in a div with an id, something like this.
<div id="ScriptsReload"><script src="js/script.js"></script></div>
and when I wanted to refresh I just used.
$("#ScriptsReload").load("html_with_scripts_tags.html", "", function(
response,
status,
request
) {
});

Changing innerHTML of script tags in IE for loading google plusone button explicitly

To add Google's plusone button on your website the following script tag is to be inserted (for explicit load).
<script type="text/javascript" src="https://apis.google.com/js/plusone.js">
{"parsetags": "explicit"}
</script>
It looks pretty straight forward in HTML. However I wan't to insert the script using a JS file. So I use the following code:
var e = document.createElement('script');
e.src = "https://apis.google.com/js/plusone.js";
e.id = "googplusonescript";
e.innerHTML = '{"parsetags": "explicit"}';
document.getElementsByTagName("head")[0].appendChild(e);
It works pretty awesome in all the browsers except IE because IE doesn't allow us to write the innerHTML of script tags. Anywork arounds anyone ? (I have jquery inserted in the page. So can use jquery too.)
Came across the same issue.
Under IE you should use
script.text = '{"parsetags": "explicit"}';
instead of script.innerHTML
try creating a textNode and appending it to your script tags:
var myText = document.createTextNode('{"parsetags": "explicit"}');
myScriptTag.appendChild(myText);
Try the following:
window['___gcfg'] = { parsetags: 'explicit' };
var ispoloaded;
function showpo() {
var pohd = document.getElementsByTagName('head')[0];
var poscr = document.createElement('script');
poscr.type ='text/javascript';
poscr.async = true;
poscr.text ='{"parsetags": "explicit"}'; //works on IE too
poscr.src = "http://apis.google.com/js/plusone.js";
pohd.appendChild(poscr);
ispoloaded = setInterval(function () {
//check if plusone.js is loaded
if(typeof gapi == 'object') {
//break the checking interval if loaded
clearInterval(ispoloaded);
//render the button, if passed id does not exists it renders all plus one buttons on page
gapi.plusone.go("idthatexists");
}
}, 100); //checks every 0.1 second
}

Categories

Resources