Loading HTML content containing inline script via jQuery - asp.net

The Background
I run an ASP.NET site using Graffiti CMS for a local charitable/service organization.
The leaders of the organization want to start integrating a third-party back-end management system that exposes content as full HTML pages.
One of the pages, the officer list, uses inline script to load pictures or placeholders (depending on whether or not there is a picture for the given officer).
I've created a server-side proxy that enables loading the content from these pages using jQuery's .load() AJAX function.
I can display this content fine using an iframe, but that feels really kludgy, and if the size of the content changes, I may need to alter the size of the iframe to ensure it all displays (blech!).
The Problem
If I create a <div> in a Graffiti post, and use $("#divid").load(url) to load the content, the HTML content loads fine, but the inline script is stripped out, so neither the officer images nor the placeholders are displayed.
The Question
Understanding that the reason for the problem is that jQuery is almost certainly trying to protect against potentially bad stuff by removing the inline script before I load it into my DOM, is there a way using jQuery to grab this HTML and load it into my DOM that will preserve the script, but not open major security holes? I do trust the system from which I'm loading the content, if that makes a difference.
Suggestions? I'm looking to keep this as simple as possible...anything too complex, and I'm just as well off to stick with the iframe.
Thanks in advance!
#devhammer

There is an issue when you use document.write. If you have the ability to modify the source pages you can modify them to use the innerHtml technique instead.
To do so you would change something like this:
<div id="testDiv">
<script type="text/javascript">
document.write("<img src='image1.jpg' alt='' />");
</script>
</div>
To this:
<div id="testDiv">
<div>
<script type="text/javascript">
document.getElementByid('testDiv').innerHTML = "<img src='image1.jpg' alt='' />";
</script>

Doesn't work for me...
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title></title>
</head>
<body>
<script src="Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
var dynamic = 'begin <script type="text/javascript">alert("hello");<\/script> end';
$('#test').html(dynamic);
});
</script>
<div id="test"></div>
</body>
</html>
The alert box is showing.. but if you replace it with a document.write, nothing in the document.write appears... you have "begin end"
Hope this helps!

Try setting the HTML manually, like this:
$.get(url, function(htmlText) { $('#divid').html(htmlText); });
I'm pretty sure this will execute the scripts.

Related

Cannot load jquery before other script

I need to load JQuery before anything else, so I created this code inside _Layout:
<!DOCTYPE html>
<html>
<body class="sidebar-enable" data-keep-enlarged="true">
<div class="wrapper">
#RenderBody()
</div>
<script src="~/js/jquery.min.js"></script>
#RenderSection("DataTableScript", required: false)
</body>
</html>
I have a ViewComponent called ProductsViewComponent, I load it inside a View called Home in this way:
#await Component.InvokeAsync("Products", new { date = "2018-09-05" })
Inside the ViewComponent I need to load the DataTableScript (which requires JQuery for works properly), so I created this logic inside the Default.cshtml (which is the html of ProductsViewComponent):
#{
Layout = "/Views/Shared/_LayoutViewComponent.cshtml";
}
#section DataTableScript{
<script src="~/js/vendor/jquery.dataTables.js"></script>
<script src="~/js/vendor/dataTables.bootstrap4.js"></script>
<script src="~/js/vendor/dataTables.responsive.min.js"></script>
<script src="~/js/vendor/responsive.bootstrap4.min.js"></script>
<script src="~/js/vendor/dataTables.buttons.min.js"></script>
<script src="~/js/vendor/buttons.bootstrap4.min.js"></script>
<script src="~/js/vendor/buttons.html5.min.js"></script>
<script src="~/js/vendor/buttons.print.min.js"></script>
<script src="~/js/vendor/dataTables.keyTable.min.js"></script>
<script src="~/js/vendor/dataTables.select.min.js"></script>
<script src="~/js/dataTable.js"></script>
}
I have specified another Layout because the ViewComponent is not able to render a section (see this question for further information)
inside the _LayoutViewComponent I placed this code:
#RenderBody()
#RenderSection("DataTableScript")
Essentially RenderBody calls _Layout and then the DataTableScript are loaded. But when I start the application I get the DataTableScript loaded before of JQuery and this is really weird because in the _Layout I specified to load the DataTableScript after JQuery.
You can use a partial to render your script tags.
Views/Shared/_DataTableScriptsPartial.cshtml
<script src="~/js/vendor/jquery.dataTables.js"></script>
<script src="~/js/vendor/dataTables.bootstrap4.js"></script>
<script src="~/js/vendor/dataTables.responsive.min.js"></script>
<script src="~/js/vendor/responsive.bootstrap4.min.js"></script>
<script src="~/js/vendor/dataTables.buttons.min.js"></script>
<script src="~/js/vendor/buttons.bootstrap4.min.js"></script>
<script src="~/js/vendor/buttons.html5.min.js"></script>
<script src="~/js/vendor/buttons.print.min.js"></script>
<script src="~/js/vendor/dataTables.keyTable.min.js"></script>
<script src="~/js/vendor/dataTables.select.min.js"></script>
<script src="~/js/dataTable.js"></script>
In your _Layout.cshtml declare a scripts section.
<!DOCTYPE html>
<html>
<head>
#RenderSection("head", required: false)
</head>
<body class="sidebar-enable" data-keep-enlarged="true">
<div class="wrapper">
#RenderBody()
</div>
<script src="~/js/jquery.min.js"></script>
#RenderSection("scripts", required: false)
</body>
</html>
In the page that uses your ViewComponent render the partial in the scripts section.
Products.cshtml
#{
Layout = "_Layout";
}
#await Component.InvokeAsync("Products", new { date = "2018-09-05" })
#section scripts {
#await Html.PartialAsync("_DataTableScriptsPartial")
}
You cannot specify a layout for a view component view. It's essentially a partial view. By the time the view component is processed the main layout is already set in stone. You should use a script loading library to conditionally include your additional scripts, and then externalize the JavaScript that serves your view component and have it run after the associated scripts are finished loading.
There's various different libraries/techniques you can use for this: CommonJS, AMD, RequireJS, etc. You'll need to do some research and figure out which is the best fit for you. However, this is a transformative thing. It will change the entire way you handle scripts with your application and might require some major restructuring of anything existing, as a result.
The easier approach is to simply just include the script in your main layout. If your layout includes this view component, then it's always going to need the scripts anyways, so just go ahead make it static. It doesn't have a the warm fuzzies of a completely self-contained unit of functionality that you're wanting your view component to be, but to get there is going to likely require far more effort that is warranted or reasonable for this one particular scenario.
For what it's worth, you can optimize things a bit by front-loading the scripts using the <link rel="preload" href="..." as="script" /> tag. This would go in your head, and prompt supporting browsers to go ahead and load in the script, without actually running it (which is the part that blocks rendering). Then, by the time you actually include the script before the closing body tag, it's likely already good to go, and the script tag will simply prompt the browser to run it.
UPDATE
One further options is to use a client-side library that supports "components". This would be a replacement for your view component, not something you'd add in addition to. However, the benefit of a client-side component is that you can contain all the JavaScript functionality in that and then the library simply runs over your document at the end and wires everything up. I personally like Vue, but there's other choices like React, Ember, Angular, etc. Consult with the documentation for each to evaluate if you might prefer this approach instead and which particular library you prefer. They all essentially do the same thing, but they each have their own unique ways of getting there.
I like Vue personally because it's light-weight and largely unobtrusive. It doesn't necessarily force you to do things in a certain way, so you can have a bit more freedom in that respect. Libraries like React and Angular tend to be more opinionated, and since they're geared more towards creating single page applications, can sometimes make it difficult to split responsibilities with server-side rendering such as Razor views. Just my opinion though.

one image loads before the rest of the page

I have created a Wordpress theme but am having a problem with the page loading.
When I move between pages there is one table (with 2 images) in the header that stays behind on the page when all the other elements have been unloaded.
Any ideas how can I fix this so that this image only shows with the rest of the page?
see http://thetaonline.co.za/newWeb/ and click on each of the menu items to see the image that remains (loads before the rest of the page).
Your HTML code is messed up. Its opening a <table> before the <html> and closing after the </html>. This stuff should go inside the <body>...</body> area.
Thats basically the reason why its being shown before the page completes to load, because the external resources being called with <script src=... or <link href=... will hang the page rendering at this point until they are loaded. Thats the reason why this stuff is usually called before everything, inside the <head>...</head> block where there is (or should be) still nothing defined for display.
Sinse you are doing it wrong, it will show what is ready for rendering -- basically just that image -- until the rest is loaded.
As of putting the external resource calls inside the <head> block, it seems to be correct, so basically you only have to bring that table to the right place to make the page display properly.
I see there are also some typos that may cause issues, like <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" missing the > in the end etc. You should review your code.
try to use jquery and do something like this:
$(function() {
$.preload(["image1.png", "image2.png"]);
}
edit: You should rather take a look at Havenard's answer!
I don't know, if this is a good idea (I guess it is not!), but you could actually hide those images first and then show them with jquery after the page is loaded completely:
<table width="35" border="0" cellspacing="0" cellpadding="0" style="display:none" id="specialimages">
<!-- your 2 images in here -->
</table>
<script type="text/javascript">
$(document).ready(function() {
$('#specialimages').show();
});
</script>

How do I validate noscript+meta refresh tag in xHTML?

For visitors that don't support JavaScript, I'm redirecting them to a certain page - "js.html".
For this, I have the following in all my files:
<noscript>
<meta http-equiv="Refresh" content="0;URL=js.html" />
</noscript>
Of course, this doesn't validate in XHTML as noscript must be placed in <body>.
But when I place that code in the body of my document, I get another error, because meta tags can only be used in the <head> section, so I'm kind of stuck in an infinite loop here.
Is there a way to make this validate? It works fine in all browsers so it's not a big deal, I just would like to validate my app.
Here is what you could do:
Insert the meta into your head but with a refresh of let's say 2 seconds. And very next to that place a SCRIPT tag that removes that meta refresh. So any JS user will not be redirected:
<meta id="refresh" http-equiv="Refresh" content="10;URL=js.html" />
<script type="text/javascript">
$('refresh').remove();
</script>
The browser might hav already "mentioned" the meta refresh. So you could just use JavaScript to write an opening and closing HTML comment (inlcude an opening script tag to close the script tag of the second document.write) around it:
<script type="text/javascript">
document.write("<!-- ");
</script>
<meta http-equiv="Refresh" content="2;URL=js.html" />
<script type="text/javascript">
document.write(' --><script type="text/javascript">');
</script>
I could successfully tested this one.
Just a hint on how I handle non-js users. I have a css class called "js" which I add to any element that should only be visible for javascript users. Through javascript I add a css file containing a rule for the class "js" that shows every element with the "js" class. All links (functions) are alo designed, that they can be used without javascript or in a new tab clicking a link while holding down CTRL.
I've tried all the suggestions I could find for this, including the answers to this question, but none worked. Kau-Boy's answer to this question didn't work for me (as it comments out both the meta tag and most of the second code script block, then js breaks on '); which it tries to interpret after the comment is closed i.e. this happens:
<script type="text/javascript">
document.write("<!-- ");
</script>
<!-- <meta http-equiv="Refresh" content="2;URL=js.html" /><script type="text/javascript"> document.write(' -->
<script type="text/javascript">
');
</script>
I took inspiration though from what it did do, and put together the following which seems to work:
<script type="text/javascript">
document.write('\x3Cscript type="text/javascript">/*');
</script>
<meta http-equiv="Refresh" content="0;URL=js.html" />
<script type="text/javascript">/**/</script>
Essentially, if javascript is enabled, we get 3 script elements, one of which is the meta tag tricked inside a javascript comment, so it doesn't redirect. If javascript is disabled, all it sees is two script elements which it ignores, and the unmolested meta element, so it redirects.
Note: if you serve up your page with application/xhtml+xml content type (which you probably should be doing, I suppose, if the document is xhtml), this will break js in the browser, since the write method will usually be disabled.
As you've discovered, this problem cannot be resolved in HTML4. In HTML5 currently, however, noscript is valid in head, so you could use HTML5 for validation purposes. (The HTML5 validator is much better than the HTML4 one anyway).
One caveat though: HTML5 has an outstanding issue (ISSUE-117) which calls for deprecation of noscript, so it's possible that by the time HTML5 reaches last call, noscript will no longer be valid in HTML5.

Like pageflakes (Incremental Page Display OR Lazy Load)?

I need to know how to load user control after the page is completely loaded
Incremental Page Display OR Lazy Load concept
typically like Pageflakes ?
This is called Ajax: http://www.w3schools.com/Ajax/ajax_intro.asp
To address your comment below, here is a (VERY SIMPLE) example of such a thing, using the jQuery library. http://jquery.com/
<html>
<head>
<script src="jquery.js"></script>
<script>
$(document).ready(function(){
$("#content").load("/myajaxpage.htm");
});
</script>
</head>
<body>
<div id="content"></div>
</body>
</html>
This would download the myajaxpage.htm page after loading, and put the contents into the div with the id "content".

How send parameters with javascript tag?

How can I send parameters (with QueryString) within a javascript tag as the source attribute to a ASP.NET page?
Example: <script language="javascript" src="myDomain/myPage.aspx?id=123&no=43"></script>
And what I have to do in "myPage.aspx"?
For example I want to send a picture to the script tag according to it's src querystring.
The script tag is used to include javascript code in the page. If you want to show an image on the page, even one generated dynamically, you want to use an img tag, not a script tag.
<img src="myDomain/myPage.aspx?id=123&no=43" alt="some text" />
Normally, you'd use an HttpHandler for this (ashx instead of aspx) and it would simply need to construct the image (or read it from a file) and then send the data down in the response with the correct MIME-type, length, etc.
See this reference on how to retrieve images from a DB using an HttpHandler.
It's not clear what you intend to do in your myPage.aspx. Since it is a script tag, it should be generating javascript code. But I don't see any reason why you'd need to dynamically generate your javascript code. Javascript variables basically have global scope, so define the image in a variable before including the script tag.
So in your html page you would do something like this in your header:
<script type="text/javascript">
var imageURL = 'http://www.google.com/intl/en_ALL/images/logo.gif';
</script>
<script src="myScript.js" type="text/javascript"></script>
And then in myScript.js:
alert("The image URL is: " + imageURL);
//do whatever processing with the image that you need to do...
Google Analytics used to work like this (before they went to a more object-oriented approach).
Why would you send a picture to a script tag? Basically what you have will work client side. In MYPage.aspx you need to output what you want to send.
I'd recommend using an HttpHandler which is a great to dynamically provide things like CSS, Javascript or images
Asp.net System.Web.HttpContext.Current.Session null in global.asax
What's the best way to display an image from a sql server database in asp.net?
All you have to do is give your <SCRIPT> tag a SRC attribute pointing to an ASPX page, just like you wanted. The only trick is that you have to have the ASPX page that returns javascript set the contentType to text/javascript. (Make sure it sends back only valid javascript.)
Here are two files to prove that it works:
JavascriptLibraryTester.aspx
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="JavascriptLibraryTest.js.aspx?Color=red" type="text/javascript" charset="utf-8">
</script>
</head>
<body>
show Server Generated Javascript
</body>
JavascriptLibraryTest.js.aspx
<%# Page Language="C#" %>
<%
Response.ContentType = "text/javascript";
string color = Request["Color"];
string now = DateTime.Now.ToString();
%>
function showServerGeneratedJavascript(){
alert('<%=now %>\n<%=color %>');
}

Resources