Reloading a dynamically loaded script - javascript

I am loading the mathJax javascript library over their CDN dynamically their CDN dynamically. This is so I can apply it to a html partial page I am loading at the same time.
As it stands, the scripts will load once but not reload when the html partial page changes. I have tried using a timestamp on the CDN URL and removing the scripts from the DOM, among other things. I have been trying to solve this all afternoon with no success. There are no errors appearing.
So, is there anything else I can try to get the scripts to reload with each new html snippet? Thanks a ton for any suggestions. Here is my code:
$scope.getLesson = function (x)
{
$scope.lessonMenu = false;
$scope.hiddenMenuLink = true;
x = x.replace(/[\s]/g, '');
$scope.parse = $parse(x)($scope);
var i = 0;
$.get("Lessons/" + x + ".html", function (data) {
// send the current html to view
$scope.currentLessonHTML = data.toString();
// destroy mathjax if existing
if (i > 1 && script1.parentNode != null) {
script1.parentNode.removeChild(script1);
script2.parentNode.removeChild(script2);
i = 0;
}
// loading the MathJax dynamically
var head = document.getElementsByTagName("head")[0];
var script1 = document.createElement("script");
var script2 = document.createElement("script");
var responsibleSibling = document.createElement("script");
var mathJax = "http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" + "?nocache=" + new Date().getTime();
var mathJaxConfig = 'MathJax.Hub.Config({extensions: ["tex2jax.js"], jax: ["input/TeX", "output/HTML-CSS"],tex2jax: {inlineMath: [ ["$","$"], ["\\\\(","\\\\)"] ],displayMath: [ ["$$","$$"], ["\\[","\\]"] ],processEscapes: true},"HTML-CSS": { availableFonts: ["TeX"] }});';
script1.type = "text/x-mathjax-config";
script1[(window.opera ? "innerHTML" : "text")] = mathJaxConfig;
head.appendChild(script1);
script2.type = "text/javascript";
script2.src = mathJax;
head.appendChild(script2);
i++;
// apply new lesson
$scope.showLesson = true;
$scope.$apply();
});
}

I finally figured this out. The script was being reloaded, but it was not applying the typeset specific to the Mathjax library. The solution is a built-in function to queue the typeset to async operations, like such:
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
http://docs.mathjax.org/en/latest/typeset.html
Thanks for feedback.

Related

Load map from myshiptracking after page load

In addition to this topic execute a javascript after page load is complete I noticed the solution didn't work for loading a map. I do have a similar use case. However, if I follow the script the script needed doesn't load.
I want to load a map after the loading of the page is finished, however I do see the script in the page source, but no script is executed.
The source is:
var mst_width = "96%";
var mst_height = "350vh";
var mst_border = "0";
var mst_map_style = "simple";
var mst_mmsi = "244770624";
var mst_show_track = "true";
var mst_show_info = "true";
var mst_fleet = "";
var mst_lat = "";
var mst_lng = "";
var mst_zoom = "";
var mst_show_names = "0";
var mst_scroll_wheel = "true";
var mst_show_menu = "true";
window.onload = function () {
var element = document.createElement("script");
element.src = "http://www.myshiptracking.com/js/widgetApi.js";
document.getElementsByTagName("head")[0].appendChild(element);
}
In the page source I see:
var mst_width = "96%";
var mst_height = "350vh";
var mst_border = "0";
var mst_map_style = "simple";
var mst_mmsi = "244770624";
var mst_show_track = "true";
var mst_show_info = "true";
var mst_fleet = "";
var mst_lat = "";
var mst_lng = "";
var mst_zoom = "";
var mst_show_names = "0";
var mst_scroll_wheel = "true";
var mst_show_menu = "true";
window.onload = function () {
var element = document.createElement("script");
element.src = "http://www.myshiptracking.com/js/widgetApi.js";
document.getElementsByTagName("head")[0].appendChild(element);
}
Can someone please point me in the direction on how to get the script executed? I also assumed that the script should be appended to the 'body' instead of the 'head'm but I'm not sure about it.
Thanks!
Edit based change of head to body:
<script>
var mst_width="96%";var mst_height="350vh";var mst_border="0";var mst_map_style="simple";var mst_mmsi="244770624";var mst_show_track="true";var mst_show_info="true";var mst_fleet="";var mst_lat="";var mst_lng="";var mst_zoom="";var mst_show_names="0";var mst_scroll_wheel="true";var mst_show_menu="true";
window.onload = function() {
var element = document.createElement("script");
element.src = "http://www.myshiptracking.com/js/widgetApi.js";
document.getElementsByTagName("body")[0].appendChild(element );
}
</script>
So, finally I managed to solve the problem and got the desired map in my browser... using the following HTML+JS code (which you can run with the button below):
<html lang="en-US" prefix="og: http://ogp.me/ns#">
<head>
<script>
var mst_width="100%";var mst_height="450px";var mst_border="0";var mst_map_style="terrain";var mst_mmsi="";var mst_show_track="";var mst_show_info="";var mst_fleet="";var mst_lat="";var mst_lng="";var mst_zoom="";var mst_show_names="0";var mst_scroll_wheel="true";var mst_show_menu="true";
function loadMap() {
var element = document.createElement("script");
element.setAttribute("id", "myshiptrackingscript");
element.setAttribute("async", "");
element.setAttribute("defer", "");
element.src = "http://www.myshiptracking.com/js/widgetApi.js";
document.getElementById("mapContent").appendChild(element );
}
window.onload = loadMap
console.log('Registered onload')
</script>
</head><body>
<div id="mapContent" />
</body></html>
Two points of attention:
you should add the created script tag as child of a tag belonging to the body ot the page (I used <div id="mapContent"/> and getElementById to access it)
you should load the HTML page through a http:// URL, not through a a file:// one: with the latter you get an error with message like "Browser does not support embedded objects"
I hope this can help you to solve the problem in you real case!
There are many ways to invoke your function when the page has loaded.
My vanilla's js tool of choice most of the time is:
window.addEventListener('DOMContentLoaded', function(){
//your bindings and functions
}
That way of proceeding is preferred to your onload method as otherwise, you won't be able to attach multiple events when the DOM loads completely.
Try this:
window.onload=function(){
document.write('<script src="http://www.myshiptracking.com/js/widgetApi.js>
</script>');
}
wrap your javascript code with this:
if(document.readyState === 'complete') {
// good to go! Put your code here.}

Loading Inline Javascript through an AJAX load through jQuery

I have a similar problem to this question.
Loading Javascript through an AJAX load through jQuery?
I want to load an HTML page into a div container using Ajax and JQuery's .load() . The html page has javascript on it that loads a weather widget from http://www.showmyweather.com/
This is the script:
<script type="text/javascript" src="http://www.showmyweather.com/weather_widget.php? int=0&type=js&country=ca&state=Ontario&city=Hamilton&smallicon=1&current=1&forecast=1&background_color=ffffff&color=000000&width=175&padding=10&border_width=1&border_color=000000&font_size=11&font_family=Verdana&showicons=1&measure=C&d=2013-11-11"></script>
I don't know how to include the widget in the DOM other than placing the script inline the html page. If there is a way to use this script and add it in using $.getscript(); that would be nice, but I can't figure it out.
var element = document.createElement("iframe");
document.body.appendChild(element);
var frame = window.frames[windows.frames.length - 1];
frame.document.write('<scr' + 'ipt type="text/javascript" src="http://www.showmyweather.com/weather_widget.php?int=0&type=js&country=ca&state=Ontario&city=Hamilton&smallicon=1&current=1&forecast=1&background_color=ffffff&color=000000&width=175&padding=10&border_width=1&border_color=000000&font_size=11&font_family=Verdana&showicons=1&measure=C&d=2013-11-11"></sc'+ 'ript>');
This is the way it's done with mootools in Asset.javascript:
var loadScript = function (source, properties) {
properties || (properties = {});
var script = document.createElement('script');
script.async = true;
script.src = source;
script.type = 'text/javascript';
var doc = properties.document || document, load = properties.onload || properties.onLoad;
return delete properties.onload, delete properties.onLoad, delete properties.document,
load && (script.addEventListener ? script.addEventListener("load", load) : script.attachEvent("readystatechange", function() {
[ "loaded", "complete" ].indexOf(this.readyState) >= 0 && load.call(this);
}))
doc.getElementsByClassName("head")[0].appendChild(script);
}
Now you can call loadScript("script url", {document: window.frames[0].document}) and it will load the script in the window. Just need to pass it an external document in options and a script.

Get file path of currently executing JavaScript code for dynamically loaded cross domain JavaScript file

I need to load cross-domain JavaScript
files dynamically for bookmarklets in my site http://jsbookmarklets.com/
The solution should satisfy:
Fetch the path of current file
The domain of current web-page and JS file in execution are different
The solution should be cross-browser
Multiple scripts might be loaded at once asynchronously (that's why the related questions mentioned below are not a fit)
I want to get the file path of currently executing JavaScript code for dynamically loading few more resources (more CSS files and JS files like custom code and jQuery, jQuery UI and Ext JS libraries) which are stored in the same/relative folder as the JavaScript Bookmarklet.
The following approach does not fit my problem:
var scripts = document.getElementsByTagName("script");
var src = scripts[scripts.length-1].src;
alert("THIS IS: "+src);
Related questions which do not fit my problem:
Get the url of currently executing js file when dynamically loaded
Get script path
The current solution that I'm using, which works, but is very lengthy:
var fnFullFilePathToFileParentPath = function(JSFullFilePath){
var JSFileParentPath = '';
if(JSFullFilePath) {
JSFileParentPath = JSFullFilePath.substring(0,JSFullFilePath.lastIndexOf('/')+1);
} else {
JSFileParentPath = null;
}
return JSFileParentPath;
};
var fnExceptionToFullFilePath = function(e){
var JSFullFilePath = '';
if(e.fileName) { // firefox
JSFullFilePath = e.fileName;
} else if (e.stacktrace) { // opera
var tempStackTrace = e.stacktrace;
tempStackTrace = tempStackTrace.substr(tempStackTrace.indexOf('http'));
tempStackTrace = tempStackTrace.substr(0,tempStackTrace.indexOf('Dummy Exception'));
tempStackTrace = tempStackTrace.substr(0,tempStackTrace.lastIndexOf(':'));
JSFullFilePath = tempStackTrace;
} else if (e.stack) { // firefox, opera, chrome
(function(){
var str = e.stack;
var tempStr = str;
var strProtocolSeparator = '://';
var idxProtocolSeparator = tempStr.indexOf(strProtocolSeparator)+strProtocolSeparator.length;
var tempStr = tempStr.substr(idxProtocolSeparator);
if(tempStr.charAt(0)=='/') {
tempStr = tempStr.substr(1);
idxProtocolSeparator++;
}
var idxHostSeparator = tempStr.indexOf('/');
tempStr = tempStr.substr(tempStr.indexOf('/'));
var idxFileNameEndSeparator = tempStr.indexOf(':');
var finalStr = (str.substr(0,idxProtocolSeparator + idxHostSeparator + idxFileNameEndSeparator));
finalStr = finalStr.substr(finalStr.indexOf('http'));
JSFullFilePath = finalStr;
}());
} else { // internet explorer
JSFullFilePath = null;
}
return JSFullFilePath;
};
var fnExceptionToFileParentPath = function(e){
return fnFullFilePathToFileParentPath(fnExceptionToFullFilePath(e));
};
var fnGetJSFileParentPath = function() {
try {
throw new Error('Dummy Exception');
} catch (e) {
return fnExceptionToFileParentPath(e);
}
};
var JSFileParentPath = fnGetJSFileParentPath();
alert('File parent path: ' + JSFileParentPath);
var s = document.createElement('script');
s.setAttribute('src', 'code.js');
document.body.appendChild(s);
Can you not simply do this?
var myScriptDir = 'http://somesite.tld/path-to-stuff/';
var s = document.createElement('script');
s.setAttribute('src', myScriptDir + 'code.js');
document.body.appendChild(s);
// code inside http://somesite.tld/path-to-stuff/code.js will use myScriptDir to load futher resources from the same directory.
If you don't want to have code inside the script to be responsible for loading further resources you can use the onload attribute of the script tag, like s.onload=function(){...}. For cross browser compatibility you might first load jQuery and then use the getScript function. Relevant links are http://www.learningjquery.com/2009/04/better-stronger-safer-jquerify-bookmarklet and http://api.jquery.com/jQuery.getScript/
Some of the comments have already mentioned this, but I'll try to elaborate a bit more.
The simplest, most cross-browser, cross-domain way of figuring out the path of the current script is to hard-code the script's path into the script itself.
In general, you may be loading third-party script files, so this would not be possible. But in your case, all the script files are under your control. You're already adding code to load resources (CSS, JS, etc.), you might as well include the script path as well.

Serve alternate external Javascript file depending on if elements are defined or not in the page

Ok, here goes my first question on here.
Setup: We use a javascript based tool to A/B test our landing page designs. I need version A (control) to link to one external javascript file, and version B (variation) to link to an alternate javascript file.
Goal: to have an internal js script at the bottom of the control that looks to see if the tool is in fact serving A or B, and if true, which one was served. The result indicates which external script should be linked.
Issue: regardless of if the tool is in fact serving A or B, the original script is linked first, then if the tool is detected, the appropriate script is linked after that.
Here is my code (I apologize in advance for any newbie mistakes):
//script at bottom of original or tool-served control html page template
<script type="text/javascript">
valForTool = function () {
var variationId = _tool_exp[_tool_exp_ids[0]].combination_chosen;
if (variationId == 1) {
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = 'js/scripts.js';
document.body.appendChild(newScript);
};
}
originalValidation = function () {
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = 'js/scripts.js';
document.body.appendChild(newScript);
}
$(function(){
if (typeof _tool_exp_ids !== 'undefined' && typeof _tool_exp_ids[0] !== 'undefined') {
valForTool();
} else {
originalValidation();
};
});
</script>
//end script on control or original template
//script on tool-served variation html template - will run after the above script
<script type="text/javascript">
$(function() {
$('#project_info input[type=submit]').removeAttr('disabled');
$('#project_info').unbind();
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = 'js/scripts2.js';
document.body.appendChild(newScript);
$('.input_text').parent().addClass('contact_field');
});
</script>
// end script on variation template
Any ideas as to what I'm doing wrong? Did I provide enough information? Thanks! I love this site as a reference for my questions, but this is my first time actually posting one.
Shortening it down a bit, it seems like your just doing this:
<script type="text/javascript">
$(function(){
if (typeof _tool_exp_ids !== 'undefined' && typeof _tool_exp_ids[0] !== 'undefined') {
var variationId = _tool_exp[_tool_exp_ids[0]].combination_chosen;
if (variationId == 1) {
$.getScript('js/scripts.js', function() {runSecond();});
}
}else{
$.getScript('js/scripts.js', function() {runSecond();});
}
function runSecond() {
$('#project_info input[type=submit]').removeAttr('disabled').unbind();
$.getScript('js/scripts2.js');
$('.input_text').parent().addClass('contact_field');
}
});
</script>
Now looking at that, it's obvious that both scripts are running no matter what conditions are met in those if/else statements, and I don't really get what it is your trying to do, but the first thing i would do, is to add some console.logs to see if those if/else statements are working like they are supposed to, and then figure what scripts should be loaded under which conditions etc ?

innerHTML to insert script in body (for ZeroClipboard) not working

I'm building <div> elements using AJAX, and I want to add ZeroClipboard functionality. Firebug shows the code is building correctly, and when I copy it into a raw HTML test page it works too. The builds are not happening at onload, but down the track.
The code is as follows, calling some functions that create the new elements:
dom_append_child_with_onclick ("img",export_id,"icon_active",report_heading_id, "event.cancelBubble = true;");
dom_append_child ("div",export_script_id,"",report_heading_id);
text = "<script language='JavaScript'>var clip" +rnum +"=new ZeroClipboard.Client();clip"+rnum+".setText('');clip"+rnum+".addEventListener('mouseDown',function(client){alert('firing');clip"+rnum+".setText(document.getElementById('SL40').value);});clip"+rnum+".glue('XR"+rnum+"','RH"+rnum+"');</script>";
document.getElementById(export_script_id).innerHTML=text;
My question: when you insert a script into the <body>, do you have to do something to get it to fire? The script appears not to be doing its thing, and I can't get the alert 'firing' to display.
Note: the cancelBubble is to stop the onClick function of the underlying element. It may be unnecessary if I can get the flash working.
Thanks.
You can just inject your script into the page as a DOM object, but this does not work in all browsers:
var s = document.createElement("script");
s.type = "text/javascript";
s.innerText = "var clip" +rnum +"=new ZeroClipboard.Client();clip"+rnum+".setText('');clip"+rnum+".addEventListener('mouseDown',function(client){alert('firing');clip"+rnum+".setText(document.getElementById('SL40').value);});clip"+rnum+".glue('XR"+rnum+"','RH"+rnum+"');";
document.getElementsByTagName("head")[0].appendChild(s);
Or, for better compatibility, you probably want to just declare a function which sets this up in your page, and then just call the function with the rnum as the parameter.
e.g.
function useZeroClipboard(rnum) {
window["clip" + rnum] = new ZeroClipboard.Client();
cwindow["clip" + rnum].setText('');
window["clip" + rnum].addEventListener('mouseDown', function(client){
alert('firing');
window["clip" + rnum].setText(document.getElementById('SL40').value);
});
window["clip" + rnum].glue('XR"+rnum+"','RH"+rnum+"');
}
Then you can just call that in your code:
useZeroClipboard(rnum);
Instead of writing the script block.
Here is a method that recursively replaces all scripts with executable ones:
function replaceScriptsRecurse(node) {
if ( nodeScriptIs(node) ) {
var script = document.createElement("script");
script.text = node.innerHTML;
node.parentNode.replaceChild(script, node);
}
else {
var i = 0;
var children = node.childNodes;
while ( i < children.length) {
replaceScriptsRecurse( children[i] );
i++;
}
}
return node;
}
function nodeScriptIs(node) {
return node.getAttribute && node.getAttribute("type") == "text/javascript";
}

Categories