getScript or eval in specific location? - javascript

I was wondering if eval (or some variant of jQuery's getScript) can be used to position external javascript in places other than the end of the DOM or at the head. I've tried:
var head = document.getElementById("fig");
instead of
var head = document.getElementsById("head")[0];
with
var script = document.createElement("script");
script.text = $(".code").val();
head.appendChild(script);
But I can't seem to get it to work regardless. (The code does work, but Firebug shows the code being replaced both at #fig and at the end of the page, right before the </body> tag.
Basically the JavaScript toolkit I'm using renders things based on where the script tag is located, and I'm trying to dynamically modify the javascript based on user input (hence I can't really refer to a new external JS file - I'd rather run an eval, which isn't ideal).
I guess the worst case scenario would be to save the user input into a "new" file using PHP or something and use getScript pointing to that new PHP file, but it seems exceedingly hacky.
Thank you once again!

Does the "JavaScript toolkit" you refer to use document.write or document.writeln to insert output into the page? If so, you could override that function to append the script output into the correct location:
document.write = function(s) {
$('#fig').append(s);
};
document.writeln = function(s) {
$('#fig').append(s + '\n');
};
and then load and execute the script using $.getScript.
Edit: A more robust way of doing it, depending on how the code is added:
var output = '';
document.write = function(s) {
output += s;
};
document.writeln = function(s) {
output += s + '\n';
};
$.getScript('URL of script here', function() {
$('#fig').append(output);
});

Related

Set Script Source from the same file instead of a different one?

I create an iframe in a file and insert a <script> tag as its content. The Script src is loaded from a different file called test.js. Here is how it is done:
var scriptElement = document.querySelector("#your-widget");
var iframe = document.createElement("iframe");
scriptElement.parentNode.insertBefore(iframe, scriptElement.nextSibling);
var script = document.createElement("script");
iframe.contentWindow.document.appendChild(script);
script.src = "http://www.example.com/test.js";
Instead of loading the content of the script from http://www.example.com/test.js I want to take it from the same file where the above code is. This would like this:
var scriptElement = document.querySelector("#your-widget");
var iframe = document.createElement("iframe");
scriptElement.parentNode.insertBefore(iframe, scriptElement.nextSibling);
var script = document.createElement("script");
iframe.contentWindow.document.appendChild(script);
script.src = // ????
// the following JavaScript code should be placed inside the script
function mywidget() {
// some code
return true;
}
mywidget.succeeded = mywidget();
How can I set the Script Source from the same file instead of a different one?
If you literally just want to place that exact snippet in a script tag, you can just do so using .innerText.
script.innerText = 'function mywidget() { ...';
Then it will execute as is when it's inserted into the DOM. If you want to dynamically find and inject that code, read on.
There are exactly two ways to load a script on a page.
Add a <script> with the src attribute pointing to a file.
Create a <script> tag then set the contents to whatever you want to execute.
var script = document.createElement('script');
script.innerText = 'console.log("Hello, World!")';
document.body.appendChild(script);
If you want to extract part of a script and use those contents then the best you can do is load the contents via ajax and inject it using method 2.
Assuming you have jQuery (for easy AJAX work):
$.ajax({
url: 'path/to/script.js',
dataType: 'text', // make sure it doesn't get eval'd
success: function(contentsOfScript) {
// Refer to method 2
}
});
Now you can go about extracting the contents of that snippet in one of two ways:
Know exactly which line it begins on.
var lines = contentsOfScript.split('\n');
var snippet = lines.slice(lineNumber + 1); // adjust for 0 indexing
Generate a regular expression to identify where your code begins. This is rather tricky and very error prone if your snippet isn't easily distinguished from other code.
var snippet = contentsOfScript.match(/function mywidget.+/)[0];
Neither of these methods will work if you perform any minification on your code.

Can JavaScript access it's own source url?

Suppose I'm embedding a javascript in HTML page:
<script type="text/javascript" src="www.mydomain.com/script.js?var1=abc&var2=def"></script>
Is there a way I can get the src url inside the script and extract the params?
Given that you are using a regular script element in the HTML source, you can just get the last script element in the document. Since script elements are (in the absence of attributes that you aren't using in your example) blocking, no more will be added to the document until this one has been executed.
var scripts = document.getElementsByTagName('script');
var last_script = scripts[scripts.length - 1];
var url = script.src;
This won't work if you dynamically add a script element before the last script using DOM.
this little hack uses error handling to find the location of external scripts from within:
(function(){ // script filename setter, leaves window.__filename set with active script URL.
if(self.attachEvent){
function fn(e,u){self.__filename=u;}
attachEvent("onerror",fn);
setTimeout(function(){detachEvent("onerror", fn)},20);
eval("gehjkrgh3489c()");
}else{
Object.defineProperty( window, "__filename", { configurable: true, get:function __filename(){
try{document.s0m3741ng()}catch(y){
return "http://" +
String(y.fileName || y.file || y.stack || y + '')
.split(/:\d+:\d+/)[0].split("http://")[1];
}
}})//end __filename
}//end if old IE?
}());
it sets a global "__filename" property when run, so atop an external script, the __filename is in effect for the execution of the whole script.
i strongly prefer to sniff url parts from scr attributes, but this works in most browsers and without knowing the URL ahead of time.
I don't think there is a property already inside the script that points to this url.
From the script, you can read the DOM. So you can lookup the script tag and inspect its src attribute, but if you got multiple scripts (or the DOM was modified), you cannot really know for sure which one it is.
I assume it is for checking input. So to solve this, you can eiter:
Render the script through a server side script (PHP), and let it output variables. Disadvantage: eats more server resources and makes caching a bitch.
Just get parameter from all the scripts loading from your domain. Maybe it doesn't matter much, or you have only one script anyway. Disadvantage: In this case this is possible, but not very reliable and resistant to changes.
My preferred: Add the variables to the script tag (actually, to another script tag) to make them available directly in Javascript, rather than parsing the script url.
Like this:
<script type="text/javascript">
var1 = 'abc';
var2 = 'def';
</script>
<script type="text/javascript" src="www.mydomain.com/script.js"></script>
Here are two other solutions that will work no matter how the script is loaded (even if they are loaded dynamically or with async or defer attributes):
Put an id on the script tag.
<script id="myscript" type="text/javascript" src="www.mydomain.com/script.js?var1=abc&var2=def"></script>
Then, you can find it with the id:
$("#myscript").attr("src")
Or second, if you know the filename, you can search for any script tag that contains that filename:
function findScriptTagByFilename(fname) {
$("script").each(function() {
if (this.src.indexOf(fname) !== -1) {
return this.src;
}
});
}
var url = findScriptTagByFilename("/script.js");

Append <script> when preparing a html code for iframe: without executing

I am preparing an HTML code on memory for an Iframe, when I use append it executes the code.
html = $(parser.parseFromString($("#EHtml").val(), "text/html"));
js = '<script>' + $("#EJs").val() + '</script>';
html.find('body').append(js);
$("#EHtml").val() contains HTML code
and the append function does its job but also executes the code.
Any thoughts here?
You need to just store a reference to the string of code and do 1 of two things: either do the append interaction only when you want to run the code later, or run eval(jsString) when you want to run it.
Script tags won't execute if their [type] attribute is set to anything wacky.
<script type="wacky/non-executing">
console.log("This will not execute! You will not see this!");
</script>
Its Obvious to run script when you insert it, between script tags,Because your DOM already complete loads.
And it will run twice because you put it inside the body So when you body content canges the script ran again!
So you have to set your Script tag on head of an iframe to it will run Only when you insert it or reload,and not again an again !
I am not suggesting you to use eval() because it is dangerous to use for script evaluation,eval() is basically used for another purpose !
Use <script></script> tags to run your script and place it on head if you don't want to ran it twice .
var script = document.createElement('script');
script.innerHTML = $("#EJs").val();
iframe.contentWindow.document.head.appendChild(script);
May be this will help you..
Try using entities, like
var encodeHtmlEntity = function(str) {
var buf = [];
for (var i=str.length-1;i>=0;i--) {
buf.unshift(['&#', str[i].charCodeAt(), ';'].join(''));
}
return buf.join('');
};
html.find('body').append(encodeHtmlEntity(js));
to append and
var decodeHtmlEntity = function(str) {
return str.replace(/&#(\d+);/g, function(match, dec) {
return String.fromCharCode(dec);
});
};
decodeHtmlEntity(html.find('body').val());
to read.
Got it in the way I need.
I was trying to add the script tag without using ways around the problem - I mean I just wanted to add the tag as it is. Thanks every body for the inputs - I got the solution from your advises...
in the end I could append to the Iframe but it was executing in the main page context. What was causing the problem was using JQuery to do the appending... so here it is:
frame = document.getElementById("frame");
out = (frame.contentWindow) ? frame.contentWindow : (frame.contentDocument.document) ? frame.contentDocument.document : frame.contentDocument;
out.document.open();
out.document.write(html.find('html')[0].outerHTML);//HTML added here
//JS appended here
js=out.document.createElement('script');
js.innerHTML = 'js code here';
out.document.getElementsByTagName("body")[0].appendChild(js);
out.document.close();
I hope its useful for someone...

Is there a way to refresh just the javascript include while doing development?

While doing development on a .js file I'd like to just refresh that file instead of the entire page to save time. Anyone know of any techniques for this?
Here is a function to create a new script element. It appends an incremented integer to make the URL of the script unique (as Kon suggested) in order to force a download.
var index = 0;
function refreshScript (src) {
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.src = src + '?' + index++;
document.getElementsByTagName('head')[0].appendChild(scriptElement);
}
Then in the Firebug console, you can call it as:
refreshScript('my_script.js');
You'll need to make sure that the index itself is not part of the script being reloaded!
The Firebug Net panel will help you see whether the script is being downloaded. The response status should be "200 OK" and not "304 Not Modified. Also, you should see the index appended in the query string.
The Firebug HTML panel will help you see whether the script element was appended to the head element.
UPDATE:
Here is a version that uses a timestamp instead of an index variable. As #davyM suggests, it is a more flexible approach:
function refreshScript (src) {
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.src = src + '?' + (new Date).getTime();
document.getElementsByTagName('head')[0].appendChild(scriptElement);
}
Alexei's points are also well-stated.
I suggest you to use Firebug for this purpose.
See this video, it helped me a lot.
http://encosia.com/2009/09/21/updated-see-how-i-used-firebug-to-learn-jquery/
If you're talking about the unfortunate case of client-side/browser caching of your .js file, then you can simply version your .js file. You can:
Rename the .js file itself (not preferred)
Update the include line to reference yourfile.js?1, yourfile.js?2, etc.. Thus forcing the browser to request the latest version from the server. (preferred)
Unfortunately, you have to refresh the web page to see edits to your JavaScript take place. There is no way that I know of to edit JavaScript in "real-time" and see those edits effect without a refresh.
You can use Firebug to insert new JavaScript, and make real-time changes to DOM objects; but you cannot edit JavaScript that has already been run.
If you just fed up refilling the forms while developing just use form recover extensions like this one https://addons.mozilla.org/ru/firefox/addon/lazarus-form-recovery/

An other way to load a js file in js code

I opened a javaScript file in a javaScript time....
document.write("<script src='newnote.js' type='text/javascript'></script>");
is there an other way to load the js in js code..?
(this file is for loading a popup menu js code , which is loaded after delay by clock js code ... so i want an othe way to loaded it)
When opening a JS file, its code is executed at once - functions are created, code is run, events are set. The only way to 'unload' a Javascript file is to manually undo all the code that has been run as a result of loading the unwanted file: setting all new functions, variables and prototype aditions to undefined (e.g. window.badFunction = undefined, unset all events, remove all new DOM elements..
If you wanted to unload another JS file every time when opening a page, it could in theory be done, but not very easily and if the loaded JS file should change, you would have to update your invalidating file.
What you did isn't like opening a local file in a programming language like C++ or Java. You don't need to close anything.
Is it possible that the script that you are adding to the page (in this case newnote.js) is causing the error you are experiencing?
Instead of the line you used starting with document.write use this instead:
var newnote = document.createElement('script');
newnote.src = "newnote.js";
newnote.type = "text/javascript";
document.documentElement.firstChild.appendChild( newnote );
If you still get your quotes error, then the code inside of newnote.js is messed up.
Don't think this was really what you were asking, but if you used the code I listed above you could then remove this file from your page by calling this:
document.documentElement.firstChild.removeChild( newnote );
One more thought:
If your path to newnote.js is not correct (because it is not in the same directory as the calling page) then the server would return a 404 error page instead of the file. If your browser tried to execute it like javascript, it could throw an error. Try supplying the full URL: http://yoursite.com/js/newnote.js or a root relative one: /js/newnote.js
you are not opening a javascript file, in fact you cannot open any file from local file system, so there is no question of closing. You are inserting a script tag replacing all contents of the document. This would result in fetching newnote.js using the current url with newnote.js replacing anything after last slash.
To include a script you could try this:
var s = document.createElement('script');
s.src = 'newnote.js';
s.type = 'text/javascript';
var head = document.getElementsByTagName('head')[0]
head.appendChild(s);
or like that:
document.write("<script type='text/javascript' src='newnote.js'><\/sc" + "ript>");

Categories

Resources