best way to load scripts dynamically - javascript

I'm working on a project where I've had to greatly widgetize my code. As such, I'm loading 5 pages of JS dynamically into the DOM. The problem I'm having though is that I don't have a way to check and wait for these scripts to be loaded. If it takes them a second to get pushed up into the DOM, then my script tries to run, but fails when it calls on them.
Here's an example of how I'm embedding my scripts.
var script_tag2 = document.createElement('script');
script_tag2.setAttribute("type","text/javascript");
script_tag2.setAttribute("src","http://www.freeptools.com/mapster/js/three.min.js");
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag2);
This inserts it into the DOM, but I dont' have a way to pause my code until it's done. Has anyone run into this before? I'm trying to come up with a best practices for this, but coming up short.

Use jQuery.getScript
jQuery.getScript("http://www.freeptools.com/mapster/js/three.min.js")
.done(function() {
/* yay, all good, do something */
})
.fail(function() {
/* boo, fall back to something else */
});

Related

WebBrowser.Navigate with JavaScript

I am using the WebBrowser Component in System.Windows.Forms. The code loads content from a website and returns it properly. There is a JavaScript which is executed and loading some of the DOMs after the page has loaded completely.
The JavaScript is not finished loading by the time the .Navigate method finished execution. If I set a Breakpoint on the .Navigate in Debug mode, It will, clearly because .Navigate is asynchronous, run through the process of loading the page including the scripts.
void LoadPageWithScripts() {
Browser.Navigate("mypagewithscriptsurl");
// whatever comes next prevents the DOM generated by the script from beeing loaded
// ... e.g.:
Console.WriteLine("whatever");
// use Browser.Document later
}
I know, this question is similar to the one provided here: JavaScript only works...
Unfortunately, I have no Influence on the page which is loaded, so the approaches I have seen there, are not suitable for my needs.
I have tried to simply work with Thread.Sleep, as suggested by many forums. But even this won't work. As soon as the code continues to run past the .Navigate method, the JavaScript is lost. Only setting a break point on it will work currently.
Browser.Navigate("pageUrl");
Browser.Navigate("pageurl");
// Very bad solution
Thread.Sleep(2000);
while (true)
{
if (Browser.ReadyState == WebBrowserReadyState.Complete)
{
// do something
break;
}
else
{
Application.DoEvents();
}
}
Using the DocumentCompleted Event will not work, since the Script is not loaded before the document is in completed state.
Browser.Navigate("pageUrl");
Browser.DocumentCompleted += (o, e) =>
{
var text = Browser.DocumentText;
Console.WriteLine(text);
};
Hope to find some help.

Qt function runJavaScript() does not execute JavaScript code

I am trying to implement the displaying of a web page in Qt. I chose to use the Qt WebEngine to achieve my task. Here's what I did :
Wrote a sample web page consisting of a empty form.
Wrote a JS file with just an API to create a radio button inside the form.
In my code, it looks like this :
View = new QWebEngineView(this);
// read the js file using qfile
file.open("path to jsFile");
myJsApi = file.Readall();
View->page()->runjavascript (myjsapi);
View->page()->runjavascript ("createRadioButton(\"button1\");");
I find that the runJavaScript() function has no effect on the web page. I can see the web page in the output window, but the radio button I expected is not present. What am I doing wrong?
I think you will have to connect the signal loadFinished(bool) of your page() to a slot, then execute runJavaScript() in this slot.
void yourClass::mainFunction()
{
View = new QWebEngineView(this);
connect( View->page(), SIGNAL(loadFinished(bool)), this, SLOT(slotForRunJS(bool)));
}
void yourClass::slotForRunJS(bool ok)
{
// read the js file using qfile
file.open("path to jsFile");
myJsApi = file.Readall();
View->page()->runJavaScript(myjsapi);
View->page()->runJavaScript("createRadioButton(\"button1\");");
}
I had this problem, runJavascript didn't have any effect. I had to put some html content into the view (with page().setHtml("") before running it.
Check the application output, it might contain JavaScript errors. Even if your JS code is valid, you might encounter the situation where the script is run before DOMContentLoaded event, that is document.readyState == 'loading'. Therefore, the DOM might not be available yet, as well as variables or functions provided by other scripts. If you depend on them for your code to run, when you detect this readyState, either wait for the event or try calling the function later, after a timeout. The second approach with timeout might be needed if you need to get the result of the code execution, as this can be done only synchronously.

Include a javascript file only once in Joomla

now, this question has been asked and answered successfully many times, yet none of the things i try work.
I have tried head.js & require.js libraries
I have also tried
if (!window.unique_name) {
unique_name = true;
//code here..
}
none of which I can get to work (the global variable is always undefined)
the script I am trying to include runs something like this:
//clock.js
clockyTick = function() {
//my code here
}
setInterval(clockyTick, 1000);
the apps that call this script, standalone, work fine.
only when both apps are included on the same page (via calls to PHP require()) they break.
Here is the cause of the problems (I think):
I am building custom web apps on a (Joomla) site and have the requirement of displaying two of my apps on the same page.
Both apps need the same .js file to operate correctly, which works fine when they run standalone, but as soon as both apps are running on the same page (in the admin section) the scripts conflict and stop each other from working
(the script in question is a dynamic clock script that grabs the specialised contents of a div and modifies it to something else)
I think the reason I cannot get aforementioned libraries to work, is the fact that they also are being included twice on the admin page.
is there any way around this, or do I have to bite the bullet and integrate a library into the main Joomla template? (meaning the library is uselessly loaded on every single page, yet only used on 3 of hundreds)
jQuery is also required, separately, on each app..but thankfully I am able to use noConflict to avoid problems there (not ideal)
The joomla way would be to instantiate the document inside your module and unset only the conflicting script as described in this question here just before you load the module's script:
1) get an instance if the document object and remove the js files (you
could do that in a plugin) :
<?php
//get the array containing all the script declarations
$document = JFactory::getDocument();
$headData = $document->getHeadData();
$scripts = $headData['scripts'];
//remove your script, i.e. mootools
unset($scripts['/media/system/js/mootools-core.js']);
unset($scripts['/media/system/js/mootools-more.js']);
$headData['scripts'] = $scripts;
$document->setHeadData($headData);
?>
Or in your case, I think you could try the dirty solution below inside your js files:
//1st module script
var unique_name;
if (unique_name == false || unique_name == null) {
unique_name = true;
//code here..
alert("Included 1st script");
}else{
//do nothing
alert("Not included 1st script")
}
//2nd module script
var unique_name;
if (unique_name == false || unique_name == null) {
unique_name = true;
//code here..
alert("Included 2nd script");
}else{
//do nothing
alert("Not included 2nd script")
}
Here is a DEMO
If you are having conflicts with PHP require(), you can try require_once(). However, as mentioned, that’s not the Joomla way of doing things.

How to only wait for document.readyState in IE and fire instantly for all other browsers?

I have written a CSS and Javascript lazyloader to dynamically load resources for seperate pagelets (in the way that Facebook renders a page with it's BigPipe technology).
In short an HTML frame is rendered first, then separate parts of the page are all generated asynchronously by the server. When each pagelet arrives the pagelets css is loaded first, then its innerHTML is set, then finally we load any required javascript for this pagelet and initialise it.
Everything works perfectly and perceived load time is pretty much instantaneous for any given page.
However in IE, I occasional I get Method does not support method or property when initialising the scripts.
I have solved this by checking for document.readyState before loading the scripts.
Now this isn't a huge issue but it adds on average 170ms to a pageload in chrome or firefox. Which is not needed.
function loadScripts(init){
// ensure document readystate is complete before loading scripts
if( doc.readyState !== 'complete'){
setTimeout(function(){
loadScripts(init);
}, 1 );
}
else{
complete++;
if(complete == instance.length){
var scripts = checkJS(javascript);
if(scripts.length) {
LazyLoad.js(scripts, function(){
runPageletScript();
for (var i = 0; i < scripts.length; ++i) {
TC.loadedJS.push(scripts[i]);
}
});
}
else{
runPageletScript();
}
}
}
}
What I am looking for is a modification to this script which will only implement the 'wait' in IE, if it is any other browser it will just fire straight away. I cannot use a jQuery utility like $.Browser and need it to be the tiniest possible method. I hate to use any form of browser detection but it appears as though its my only solution. That said if anyone can come up with another way, that would be fantastic.
Any suggestions would be gratefully received.
You could use JScript conditional compilation, which is only available in IE browsers (up to IE10).
Because it's a comment, it's best to place it inside new Function as minifiers might remove it, changing your code. Though in general you should avoid using new Function, in this case there's not really any other way to prevent minifiers from removing it.
Example:
var isIE = !(new Function('return 1//#cc_on &0')());
However, it seems that your main issue is that the DOM hasn't loaded yet -- make sure that it has loaded before running any loader using the DOMContentLoaded event (IE9+):
document.addEventListener('DOMContentLoaded', function () {
// perform logic here
});
Here is just another solution as the solution from Qantas might not always work. For instance on UMTS connections it could happen that providers remove comments to save bandwith (maybe they preserve conditional comments):
if(navigator.appName == 'Microsoft Internet Explorer'
&& doc.readyState !== 'complete'){
...
}

Intercepting DOM and JS engine calls

I want to intercept DOM object read and write queries fired by JS while getting loaded by the browser. After intercepting these calls, i wish to screen them. I have written the logic for screening but am not able to block the calls.
Is there any way other than modifying source code of the browser to achieve this? If so pls help me.
You mean like this?
(for some reason fails in Fx with illegal operation)
<script>
var oldGet = document.getElementById;
document.getElementById=function(id) {
return confirm('Someone wants to know about '+id+', is that ok?')?oldGet(id):null;
}
window.onload=function() {
alert(document.getElementById('div1').innerHTML);
}
</script>
<div id="div1">Hello</div>

Categories

Resources