How do I get embedded JavaScript to run in a .innerHTML write? - javascript

I previously had this problem with an external file not running.
I fixed this by loading the file dynamically instead...i.e. creating the element in JavaScript and linking to it via the .src attribute ( did this instead of using a scrip tag in the html ). Do I need to do something similar here?
Here is the embedded JavaScript I need to run that is inserted via .innerHTML of the body. Currently it is just "dead code" in my page. Note the json I'm passing in as the second variable to the set function. This is PHP composed and passed to the client via ajax POST.
<script type='text/javascript'>new Arc.Shared().set( 'tweet_data', [{"id":"1","0":"1","picture":"0","1":"0","name":"Test Account","2":"Test Account","tweet":"Hi","3":"Hi","time":"1338559048","4":"1338559048"},{"id":"1","0":"1","picture":"0","1":"0","name":"Test Account","2":"Test Account","tweet":"hi","3":"hi","time":"1338558809","4":"1338558809"},{"id":"1","0":"1","picture":"0","1":"0","name":"Test Account","2":"Test Account","tweet":"<a class=\"bookmark_tweet\" target=\"_blank\" href=\"http:\/\/ebay.com\">ebay <\/a>","3":"<a class=\"bookmark_tweet\" target=\"_blank\" href=\"http:\/\/ebay.com\">ebay <\/a>","time":"1338504456","4":"1338504456"},{"id":"1","0":"1","picture":"0","1":"0","name":"Test Account","2":"Test Account","tweet":"foo","3":"foo","time":"1338504225","4":"1338504225"},{"id":"1","0":"1","picture":"0","1":"0","name":"Test Account","2":"Test Account","tweet":"foo","3":"foo","time":"1338504222","4":"1338504222"},{"id":"1","0":"1","picture":"0","1":"0","name":"Test Account","2":"Test Account","tweet":"foo","3":"foo","time":"1338504220","4":"1338504220"},{"id":"1","0":"1","picture":"0","1":"0","name":"Test Account","2":"Test Account","tweet":"foo","3":"foo","time":"1338504217","4":"1338504217"}] );</script>
Notes:
Alternative to Eval Snippet:
var myCode = 'alert("Howdy?");';
var myFucn = new Function(myCode);
myFucn();

If you want to run AJAX injected JS, you should call "eval()" on it (for security reasons). Another possibility is to load it via a <script src='[url to your JS]'></script> tag.

Another way per Why doesn't embedded JavaScript execute when inserted in response to an ajax call?
Here is the append child method...that take ajax responseText and appends it into the DOM.
function onSuccess() {
src = document.createElement('script');
src.innerHTML = this.responseText;
document.body.appendChild(src);
}
Third way is to have an external element trigger it per here:
Executing <script> elements inserted with .innerHTML

Related

Writing to file on github pages using javascript

Is there any way of writing to a file on github pages using javascript? I want to save some info that i wanna use elsewhere to a json file (preferably, but txt would also work), and was wondering if it was possible.
Step-by-step guide
If you are less of a JavaScript maven, then you might want to follow use step-by-step.
Embedded JavaScript
In the first example we create a Markdown file called js.md In that Markdown file we put an HTML div element with an id "text". Later in that file we add a script tag and inside we write some simple JavaScript code. This code will locate the element that has the id "text", or div element, and inside the element it will put the text that appears on the right-hand side of the assignment.
The main thing you need to remember here is that the JavaScript code must come at the end so by the time it is executed the DOM is ready. Otherwise the JavaScript code will not find the HTML element.
examples/github/js.md
<div id="text"></div>
<script>
document.getElementById("text").innerHTML = "Text added by JavaScript code";
</script>
jQuery loaded from external file
Our next step is to use jQuery instead of vanilla JavaScript. For this we only need to load jQuery from its CDN. If we are already loading an external JavaScript file, I though we can also move our code to an external file. So I created the demo.js file loaded it using another script tag.
This time we can put the script tags anywhere we like as the jQuery callback function will be only executed when the DOM is ready. The only limitation is that we need to load our code after we have loaded jQuery itself.
examples/github/jquery.md
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="/demo.js"></script>
<div id="text"></div>
In our jQuery code we have an anonymous callback function that will be called when the HTML was loaded and the DOM is ready. That's what $().ready does. Inside the function we use the $("#text") expression to locate the element with id "text" and then we use the html method to set the content of the element. (It is the same as innerHTML in vanilla JavaScript.)
examples/github/demo.js
$().ready(function() {
$("#text").html("Text added by jQuery code.");
});
Loading JSON data from server
Finally, we would like to get some data from the server. As we cannot run anything on the server we cannot get dynamic data, but we can store the data in JSON files and load them using the Ajax methods provided by jQuery.
In this example the Markup file is effectively the same as in our previous examples.
examples/github/json.md
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="/json.js"></script>
<div id="text"></div>
In the jQuery code we use the getJSON method to fetch the data.json file from the server. This means, first the HTML file that was generated from the Markdown file will be loaded. Then the browser will load jQuery followed by our code. Then, once everything is ready, our code runs and loads the JSON file from the server.
The first parameter of getJSON is the URL of the JSON file we would like to load. The second parameter is an anonymous callback function that will be executed when we get the response from the server. Then the jQuery will call our anonymous function and it will pass the content of the JSON file after it was converted to a JavaScript object.
console.log(data); was only added for debugging.
In the last JQuery code, in $("#text").html(data["text"]); the first part $("#text") will locate the element with the id "text". The html method will set the content of the element to the value we pass to it which in our case is data["text"], the value of the "text" key that arrived from the JSON file.
examples/github/json.js
$().ready(function(){
$.getJSON( "/data.json", function( data ) {
console.log(data);
$("#text").html(data["text"]);
});
});
This is the data.json
examples/github/data.json
{
"text" : "Text supplied in the JSON file"
}
Hope this helped!

Adding javascript to onDocumentReady issue

I have a div on my page defined as follows:
<div id="scripts">
</div>
I want to dynamically change the contents of the div and load in some scripts using jQuery. I am doing it like this:
$('#scripts').html('<script language="JavaScript">pn = "landing page"; '+
'cms_1 = "content"; '+
'cms_2 = "promotional "; '+
'cms_3 = "campaign"; '+
'cms_s = "blk:us:dc"; '+
'cms_env = "dev"; '+
'cms_country = "USA"; '+
'<\/script>');
This is in the document.Ready function. However, when I view the source after the page is loaded, the div appears empty and I do not see the script tags. I thought that the script wasn't getting added but when I add alert("done"); to the script. I get the alert which tells me that the code is executed.
Why can't I see the changes made when I view the source? Is the Source html rendered before the document.ready function?
The html function from jquery internally uses the innerHTML property of the browser when available. In general, script blocks inserted via innerHTML don't get executed almost in any browser.
Try creating a script tag with the content and appending it to the document instead, e.g.
var script=document.createElement('script');
script.type='text/javascript';
script.html(...);
$("#scripts").append(script);
After seeing your motivation in the comment, I have to add : although you can later physically remove a script tag from the site, this won't have the effect of unloading its content (e.g. functions defined in the script). The only way to achieve that without refreshing the page is to encapsulate the objects defined in it and delete them manually. This is of course only possible if the content of the script was designed upfront in such a way.

Running the javascript code present on another html page through jquery

It might be a noob questions but I have just started using jquery.
My basic requirement to extract the link which is there in the javascript code present in another html (code is embedded in the html page and not in a seperate file).
The link is also present as a href attribute of <a> tag inside a tag, just to add if it is easier to extract it from there (I am using chrome so I think it considers there are no child nodes of <noscript> tag)
After this I tried doing an ajax request to the html page (using $.ajax) thinking it will run the scripts on the page but got the html code of the page in return :S . I have also heard of something called evalscripts:true but not sure if that will work here or how to use it?
I have also tried to search for the link in html code returned by my html page by using the "contains" operation of jquery.
I am doing all this to create a greasemonkey script. Please suggest
Example Code:
This is a function present inside the html of that page:
function fun() {
obj = new pollingObj('argument', "a link I want to extract comes here");
}
I want to extract the link: "a link I want to extract comes here" and then open it.on my page where I am running my jquery script
This link is also present like this on the html page:
<noscript>
blabla
</noscript>
Also is it possible to run the javascripts present on that page if the link extraction is not possible?
If you're able to get the html code of the page successfully via .ajax, and the data you want is in the HTML code, it's not worth the effort to bother with trying to run the scripts. Just access the URL through the DOM:
// ajax success function
success: function(html) {
var anchorCode = $(html)
// this assumes that noscript is a top-level element
// otherwise, use .find('noscript')
.filter('noscript')
.text(); // get the code for the anchor tag, as a string
var myLink = $(anchorCode).attr('href');
// do something with myLink
}
Edit: It turns out that jQuery is a little funny in the way it deals with noscript tags - inner tags don't appear to be considered part of the DOM, so you need to grab the text content of the tag and then use jQuery to DOM-ify it. See updated code above.

How do I get the original innerHTML source without the Javascript generated contents?

Is it possible to get in some way the original HTML source without the changes made by the processed Javascript? For example, if I do:
<div id="test">
<script type="text/javascript">document.write("hello");</script>
</div>
If I do:
alert(document.getElementById('test').innerHTML);
it shows:
<script type="text/javascript">document.write("hello");</script>hello
In simple terms, I would like the alert to show only:
<script type="text/javascript">document.write("hello");</script>
without the final hello (the result of the processed script).
I don't think there's a simple solution to just "grab original source" as it'll have to be something that's supplied by the browser. But, if you are only interested in doing this for a section of the page, then I have a workaround for you.
You can wrap the section of interest inside a "frozen" script:
<script id="frozen" type="text/x-frozen-html">
The type attribute I just made up, but it will force the browser to ignore everything inside it. You then add another script tag (proper javascript this time) immediately after this one - the "thawing" script. This thawing script will get the frozen script by ID, grab the text inside it, and do a document.write to add the actual contents to the page. Whenever you need the original source, it's still captured as text inside the frozen script.
And there you have it. The downside is that I wouldn't use this for the whole page... (SEO, syntax highlighting, performance...) but it's quite acceptable if you have a special requirement on part of a page.
Edit: Here is some sample code. Also, as #FlashXSFX correctly pointed out, any script tags within the frozen script will need to be escaped. So in this simple example, I'll make up a <x-script> tag for this purpose.
<script id="frozen" type="text/x-frozen-html">
<div id="test">
<x-script type="text/javascript">document.write("hello");</x-script>
</div>
</script>
<script type="text/javascript">
// Grab contents of frozen script and replace `x-script` with `script`
function getSource() {
return document.getElementById("frozen")
.innerHTML.replace(/x-script/gi, "script");
}
// Write it to the document so it actually executes
document.write(getSource());
</script>
Now whenever you need the source:
alert(getSource());
See the demo: http://jsbin.com/uyica3/edit
A simple way is to fetch it form the server again. It will be in the cache most probably. Here is my solution using jQuery.get(). It takes the original uri of the page and loads the data with an ajax call:
$.get(document.location.href, function(data,status,jq) {console.log(data);})
This will print the original code without any javascript. It does not do any error handling!
If don't want to use jQuery to fetch the source, consult the answer to this question: How to make an ajax call without jquery?
Could you send an Ajax request to the same page you're currently on and use the result as your original HTML? This is foolproof given the right conditions, since you are literally getting the original HTML document. However, this won't work if the page changes on every request (with dynamic content), or if, for whatever reason, you cannot make a request to that specific page.
Brute force approach
var orig = document.getElementById("test").innerHTML;
alert(orig.replace(/<\/script>[.\n\r]*.*/i,"</script>"));
EDIT:
This could be better
var orig = document.getElementById("test").innerHTML + "<<>>";
alert(orig.replace( /<\/script>[^(<<>>)]+<<>>/i, "<\/script>"));
If you override document.write to add some identifiers at the beginning and end of everything written to the document by the script, you will be able to remove those writes with a regular expression.
Here's what I came up with:
<script type="text/javascript" language="javascript">
var docWrite = document.write;
document.write = myDocWrite;
function myDocWrite(wrt) {
docWrite.apply(document, ['<!--docwrite-->' + wrt + '<!--/docwrite-->']);
}
</script>
Added your example somewhere in the page after the initial script:
<div id="test">
<script type="text/javascript"> document.write("hello");</script>
</div>
Then I used this to alert what was inside:
var regEx = /<!--docwrite-->(.*?)<!--\/docwrite-->/gm;
alert(document.getElementById('test').innerHTML.replace(regEx, ''));
If you want the pristine document, you'll need to fetch it again. There's no way around that. If it weren't for the document.write() (or similar code that would run during the load process) you could load the original document's innerHTML into memory on load/domready, before you modify it.
I can't think of a solution that would work the way you're asking. The only code that Javascript has access to is via the DOM, which only contains the result after the page has been processed.
The closest I can think of to achieve what you want is to use Ajax to download a fresh copy of the raw HTML for your page into a Javascript string, at which point since it's a string you can do whatever you like with it, including displaying it in an alert box.
A tricky way is using <style> tag for template. So that you do not need rename x-script any more.
console.log(document.getElementById('test').innerHTML);
<style id="test" type="text/html+template">
<script type="text/javascript">document.write("hello");</script>
</style>
But I do not like this ugly solution.
I think you want to traverse the DOM nodes:
var childNodes = document.getElementById('test').childNodes, i, output = [];
for (i = 0; i < childNodes.length; i++)
if (childNodes[i].nodeName == "SCRIPT")
output.push(childNodes[i].innerHTML);
return output.join('');

Getting content of a script file using Javascript

I have the following script element in my web page:
<script src="default.js" type="text/javascript"></script>
Using JavaScript, I want to be able to retrieve the content of the script file. I know I could use an ajax request to get the data but then I am getting something from the server that I already have locally.
So what I would prefer to do is retrieve the content from the DOM (if that's possible) or something that has the same result.
Cheers
Anthony
UPDATE
I was trying to simplify the question, maybe a bad a idea, I thought this way would cause less questions.
The real situation I have is as follows, I actually have
<script type="text/html" class="jq-ItemTemplate_Approval">
...
html template that is going to be consumed by jQuery and jTemplate
...
</script>
Now this works fine but it means each time the page loads I have to send down the template as part of the HTML of the main page. So my plan was to do the following:
<script src="template.html" type="text/html"></script>
This would mean that the browser would cache the content of template.html and I would not have to send it down each time. But to do this I need to be able to get the content from the file.
Also in this case, as far as I know, requesting the content via ajax isn't going to help all that much because it has to go back to the server to get the content anyway.
If I understand you correctly, you don't want to use Ajax to load an html template text, but rather have it loaded with the rest of the page. If you control the server side, you can always include the template text in an invisible div tag that you then reference from Javascript:
<div id="template" style="display:none;">
...template text...
</div>
<script>
// pops up the template text.
alert(document.getElementById("template").innerHTML);
</script>
If you are just looking for to load the template so that you can have it cached, you can put the contents in a variable like this:
<script>
var template = "template text..";
</script>
or you can load it using ajax and store the template in a variable so it is accessible. It's pretty trivial in jquery:
var template;
$.get("template.html", function(data){
template = data;
});
unless you load a script as literal text in the page, it does not exist as text. It is interpreted by the browser and melded into the runtime, with any other scripts.
If you want the source you have to fetch it again,if with Ajax get the responseText.
It will come from the browser cache, and doesn't have to be downloaded again.
I think what you want to do is to assign a variable inside template.js. Then you have the variable available for use wherever you want in jquery. Something like:
var tpl = "<div> ... </div>"
Wouldn't this be a simpler solution to your problem? We do this in Ext JS. I think this will work for you in jQuery.
You could get the attribute of the src of the script and then use XHR to get the contents of the JS file. It's a much cleaner way of doing it IMO. e.g.:-
if(window.XMLHttpRequest) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.status == 200 && xhr.readyState == 4) {
var sourceCode = xhr.responseText;
alert('The source code is:-\n'+sourceCode);
}
}
xhr.open("GET",document.getElementById('scriptID').src,true);
xhr.send(null);
}
Using an iFrame & HTML5 Local Storage
Save the templates for rendering later...
not stoked about the iFrame, but it seems to be working pretty good (haven't ran performance tests yet)
Put the iFrame on the page you want the template on (index.html)
<html>
<head>
<iframe src="mustache.Users.html" onload="this.remove();" class="hidden" id="users_template"></iframe>
</head>
</html>
Make sure the src attribute is set
hide the element until you can get rid of it after it loads
Put this body wrapper around your template (mustache.Users.html)
(don't worry it won't show up in the template)
<body onload="localStorage.setItem('users_template',this.document.body.innerHTML);">
<ul class="list-group" id="users" >
{{#users}}<li>{{name}}</li>{{/users}}
</ul>
</body>
replace 'users_template' with whatever name for your variable
the 'onload' attribute saves the template into localStorage during load
Now You can access your templates from anywhere
localStorage.getItem('users_template')
OR
window.localStorage.getItem('users_template')
What is in the JavaScript file? If it's actual code, you can run functions and reference variables in there just like you had cut and paste them into the webpage. You'll want to put the include line above any script blocks that reference it.
Is this what your looking to accomplish?
Why not use Ajax (well Ajah because its html :-))?
when the server is set up correctly and no no-cache or past expires headers are sent, the browser will cache it.
The way that most JavaScript import files work is they include a script, that immediately calls a function with a parameter of certain text, or of another function. To better illustrate, say you have your main index.html file, set it up like this:
<html>
<head>
</head>
<body>
<script>
let modules = {};
function started(moduleName, srcTxt) {
modules[moduleName] = (srcTxt) //or something similar
}
</script>
<!--now you can include other script tags, and any script tags that will be included, their source can be gotten (if set up right, see later)-->
<script src="someOtherFile.js"></script>
</body>
</html>
now make that other file, someOtherFile.js, and right away when its loaded, simply call that "started" function which should already be declared in the scope, and when thats done, then whatever text is passed, from the file, is stored in the main index.html file. You can even stringify an entire function and put it in, for example:
started("superModule", (function() {
/*
<?myCustomTemplateLanguage
<div>
{something}Entire Javascript / html template file goes here!!{/something}
</div>
?>
*/
}).toString());
now you can access the inner content of the function, and get all the text in between the comments, or better yet, then do other parsing etc, or make some other kind of parsing identifiers at the beginning and end of the comments, as shown above, and get all text in between those

Categories

Resources