my problem is as follow.
I have a multiple script blocks that contain javascript code type of text/plain.
So my question is is there any script that i can dynamically convert them from text/plain to text/javascript type and execute its content ? The problem i'm having is the place of execution, because scripts contain document.write so the output is appended in the end of the html not on the location of the script itself.
eg: let's say something like this
<script type="text/plain">alert('hello world');</script>
<script type="text/javascript">
$(document).ready(function(){
$("script[type*=plain]").each(function() {
$(this).attr('type','text/javascript');
});
});
</script>
thnx
Modifying a script element in place doesn't cause it to be executed. You need to create a new script element with the appropriate content. Another option is to eval() the contents of the old element:
$(document).ready(function(){
$("script[type*=plain]").each(function() {
eval($(this).text());
});
});
You can go with some nasty approach, of selecting the tag with type=plain and then accessing its innerText attribute, assigning it to eval method.
var el = $("script[type*=plain]")[0];
eval(el.innerText);
But I'd try to avoid using eval
If there's a different approach I'm not aware of it, and for this I am sorry.
You can not make document.write to place it's output in place of <script> element if you change script's type, because entire page's javascript code woudn't re-run every time you add new <script> or evaluating existing one.
If you want to replace <script type="text/plain"> with the result of script execution, you can return some string from that script instead of using document.write and then insert this string in place of <script type="text/plain"> element:
<script type="text/plain">
var result = "line1<br>";
result += "line2";
alert('hello world');
result
</script>
<script type="text/javascript">
$(document).ready(function(){
$("script[type*=plain]").each(function() {
$(this).replaceWith(eval($(this).text()));
});
});
</script>
Related
I have an ASP.NET MVC view model that I need to pass to a JavaScript function when the page loads, and I'm currently doing that like so:
<script type="text/javascript">
$(window).on("load", function () {
myFunction(#Html.Raw(JsonConvert.SerializeObject(Model)));
});
</script>
In other words, I'm using JSON.NET to serialize the model to JSON, and inserting that (un-encoded) into my <script> block.
When rendered, the script block ends up looking something like:
<script type="text/javascript">
$(window).on("load", function () {
myFunction({"myProperty": "the property value"});
});
</script>
That works, up to a point. But when my model contains a string property that whose text includes HTML tags *, these confuse the browser into thinking that the <script> block has ended, and the browser starts rendering the tags embedded in the view model.
Edit: per the comments, this only happens if there's a </script> tag.
For example:
<script type="text/javascript">
$(window).on("load", function () {
myFunction({"myProperty": "<script>...</script>"});
});
</script>
How can I solve this?
This is a know problem. PHP's json_encode function encodes / as \/ to avoid exactly this problem.
A straightforward solution is to write your own JSON encode wrapper-function that replaces </script> by <\/script> after JSON encoding.
Maybe there is a better solution though, I'm not familiar with asp.net.
Is it possible to assign a value of <script src="http://domain.com/external.php"></script> directly to another variable, like the following (not using JQuery, but simple Javascript):
<script>
document.getElementById('ID').innerHTML=<script src="http://domain.com/external.php"></script>;
</script>
maybe doing something like this is better
script=document.createElement('script');
script.src='http://whatever.js';
document.getElementsByTagName('head')[0].appendChild(script);
If you're trying to append the script inside the DOM as a string, you have to do something like this :
var script = '<script src="http://domain.com/external.php"></scr'+'ipt>';
document.getElementById('ID').innerHTML = script;
the closing script tag will cause issues in parsing when inserted as a string because it closes the current script, concatenation will solve that.
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('');
I have an external javascript file that I want to, upon include, write some HTML to the end of the web page.
Upon doing so though I get the error Missing } in XML expression on the line that uses dropdownhtml.
Here is my code
var dropdownhtml = '<div id="dropdown"></div>';
$(document).ready(function(){
//$(document).append(dropdownhtml);
alert(dropdownhtml);
});
The XHTML webpage that includes this file does so like this:
<script type="text/javascript" src="/web/resources/js/dropdownmenu.js"></script>
Doing either append or alert throws up the same error, what is going wrong?
I got this error because I called an external JavaScript within an existing JavaScript, so ended up with:
<script type="text/javascript">
<script type="text/javascript">
code
</script>
code
</script>
Edit Your update changes the question a bit. :-)
There's nothing wrong with your quoted Javascript or with the script tag that includes it, the problem must lie elsewhere on the page.
The old answer:
If you're including Javascript inside an XML document, you must wrap it up in a CDATA section, or you'll run into trouble like this because the XML parser neither knows nor cares about your Javascript quotes, and instead seems markup (your <div>s in the string).
E.g.:
<foo>
<bar><![CDATA[
var dropdownhtml = '<div id="dropdown"></div>';
$(document).ready(function(){
//$(document).append(dropdownhtml);
alert(dropdownhtml);
});
]]></bar>
</foo>
Naturally you need to ensure that the ]]> sequence never appears in a string (or comment, etc.) your script, but that's quite easy to do (for instance: "Be sure to interrupt the end sequence with a harmless backslash like this: ]]\>; that escape just resolves to > anyway.")
There's definitely a missing ); at the end of your code sample. Don't get where there may be a missing } though.
I have empty script on my page
<script src=""></script>
And this leads to such error
I see so many things like this:
S = "<scr" + "ipt language=\"JavaScript1.2\">\n<!--\n";
Why do they do this, is there an application/browser that messes up if you just use straight "<script>"?
Have a look at this question:
Javascript external script loading strangeness.
Taken from bobince's answer:
To see the problem, look at that top
line in its script element:
<script type="text/javascript">
document.write('<script src="set1.aspx?v=1234"
type="text/javascript"></script>');
</script>
So an HTML parser comes along and sees
the opening <script> tag. Inside
<script>, normal <tag> parsing
is disabled (in SGML terms, the
element has CDATA content). To find
where the script block ends, the HTML
parser looks for the matching
close-tag </script>.
The first one it finds is the one
inside the string literal. An HTML
parser can't know that it's inside a
string literal, because HTML parsers
don't know anything about JavaScript
syntax, they only know about CDATA. So
what you are actually saying is:
<script type="text/javascript">
document.write('<script src="set1.aspx?v=1234"
type="text/javascript">
</script>
That is, an unclosed string literal
and an unfinished function call. These
result in JavaScript errors and the
desired script tag is never written.
A common attempt to solve the problem
is:
document.write('...</scr' + 'ipt>');
This wouldn't explain why it's done in the start tag though.
The more appropriate way to append scripts is to use the DOM.
Create an element of type <script>. See documentation for document.createElement.
Set its attributes (src, type etc.)
Use body.appendChild to add this to the DOM.
This is a much cleaner approach.