I'm trying to use the HTMLUnit testing framework with a web application using the KnockoutJS javascript binding library. KnockoutJS is dependent on a custom HTML attribute named 'data-bind'. My HTMLUnit tests are not passing -- it appears that knockout is not running at all, and my current best-guess as to why is that HTMLUnit does not support custom attributes.
Does anyone have any experience in this area, or have a working test for a knockout-based solution using htmlunit?
For custom attributes to work on HtmlUnit, construct the WebClient object using BrowserVersion.FIREFOX_3_6 as browserVersion.
Check the WebClient class documentation: http://htmlunit.sourceforge.net/apidocs/com/gargoylesoftware/htmlunit/WebClient.html
By default, WebClient is constructed using BrowserVersion.INTERNET_EXPLORER_7, which deletes all custom attributes set by Javascript.
Related
As a web developer I feel too much of my time is spent on CSS. I am trying to come up with a solution where I can write re-usable CSS i.e. classes and reference these classes in the HTML without additional code in ASPX or ASCX files etc. or code-behind files. I want an intermediary which links up HTML elements with CSS classes.
What I want to achieve:
Modify HTML immediately before transmission
Select elements in the HTML
Based on rules defined elsewhere (e.g. in a text file relating to
the page currently being processed):
Add a CSS class reference to multiple HTML elements
Add multiple CSS class references to a single HTML element
How I envisage this working:
Extend ASP.NET functions which generate final HTML
Grab all the HTML as a string
Pass the string into a contructor for an object with querying (e.g. XPATH) methods
Go through list of global rules e.g. for child ul of first div then class = "navigation"
Go through list of page specific rules e.g. for child ul of first div then class &= " home"
Get processed HTML from object e.g. obj.ToString
ASP.NET to resume page generation using processed HTML
So what I need to know is:
Where / how can I extend ASP.NET page generation functions (to get all HTML of page)
What classes have element / node querying methods and access to attributes
Thanks for your help in advance.
P.S. I am developing ASP.NET web forms websites with VB.net code-behinds running on ISS 7
Check out my CsQuery project: https://github.com/jamietre/csquery or on nuget as "CsQuery".
This is a C# (.NET 4) port of jQuery. In basic performance tests (included in the project test suite) selectors are about 100 times faster than HTML Agility Pack + Fizzler (a css selector add-on for HAP); it's plenty fast for manipulating the output stream in real time on a typical web site. If you are amazon.com or something, of course, YMMV.
My initial purpose in developing this was to manipulate HTML from a content management system. Once I had it up and running, I found that using CSS selectors and the jQuery API is a whole lot more fun than using web controls and started using it as a primary HTML manipulation tool for server-rendered pages, and built it out to cover pretty much all of CSS, jQuery and the browser DOM. I haven't touched a web control since.
To intercept HTML in webforms with CsQuery you do this in the page codebehind:
using CsQuery;
using CsQuery.Web;
protected override void Render(HtmlTextWriter writer)
{
var csqContext = WebForms.CreateFromRender(Page, base.Render, writer);
// CQ object is like a jQuery object. The "Dom" property of the context
// returned above represents the output of this page.
CQ doc = csqContext.Dom;
doc["li > a"].AddClass("foo");
// write it
csqContext.Render();
}
To do the same thing in ASP.NET MVC please see this blog post describing that.
There is basic documentation for CsQuery on GitHub. Apart from getting HTML in and out, it works pretty much like jQuery. The WebForms object above is just to help you handle interacting with the HtmlTextWriter object and the Render method. The general-purpose usage is very simple:
var doc = CQ.Create(htmlString);
// or (useful for scraping and testing)
var doc = CQ.CreateFromUrl(url);
// do stuff with doc, a CQ object that acts like a jQuery object
doc["table tr:first"].Append("<td>A new cell</td>");
Additonally, pretty much the entire browser DOM is available using the same methods you use
in a browser. The indexer [0] returns the first element in the selection set like jquery; if you are used to write javascript to manipulate HTML it should be very familiar.
// "Select" method is the same as the property indexer [] we used above.
// I go back and forth between them to emphasise their interchangeability.
var element = dom.Select("div > input[type=checkbox]:first-child")[0];
a.Checked=true;
Of course in C# you have a wealth of other general-purpose tools like LINQ at your disposal. Alternatively:
var element = dom["div > input[type=checkbox]:first-child"].Single();
a.Checked=true;
When you're done manipulating the document, you'll probably want to get the HTML out:
string html = doc.Render();
That's all there is to it. There are a vast number of methods on the CQ object, covering all the jQuery DOM manipulation techniques. There are also utility methods for handling JSON, and it has extensive support for dynamic and anonymous types to make passing data structures (e.g. a set of CSS classes) as easy as possible -- much like jQuery.
Some More Advanced Stuff
I don't recommend doing this unless you are familiar with lower-level tinkering with asp.net's http workflow. There's nothing at all undoable but there will be a learning curve if you've never heard of an HttpHandler.
If you want to skip the WebForms engine altogether, you can create an IHttpHandler that automatically parses HTML files. This would definitely perform better than overlaying on a the ASPX engine -- who knows, maybe even faster than doing a similar amount of server-side processing with web controls. You can then then register your handler using web.config for specific extensions (like htm and html).
Yet another way to automatically intercept is with routing. You can use the MVC routing library in a webforms app with no trouble, here's one description of how to do this. Then you can create a route that matches whatever pattern you want (again, perhaps *.html) and pass handling off to a custom IHttpHandler or class. In this case, you're doing everything: you will need to look at the path, load the file from the file system, parse it with CsQuery, and stream the response.
Using either mechanism, you'll need a way to tell your project what code to run for each page, of course. That is, just because you've created a nifty HTML parser, how do you then tell it to run the correct "code behind" for that page?
MVC does this by just locating a controller with the name of "PageNameController.cs" and calling a method that matches the name of the parameter. You could do whatever you want; e.g. you could add an element:
<script type="controller" src="MyPageController"></script>
Your generic handler code could look for such an element, and then use reflection to locate the correct named class & method to call. This is pretty involved, and beyond the scope of this answer; but if you're looking to build a whole new framework or something this is how you would go about it.
Intercepting the content of the page prior to it being sent is rather simple. I did this a while back on a project that compressed content on the fly: http://optimizerprime.codeplex.com/ (It's ugly, but it did its job and you might be able to salvage some of the code). Anyway, what you want to do is the following:
1) Create a Stream object that saves the content of the page until Flush is called. For instance I used this in my compression project: http://optimizerprime.codeplex.com/SourceControl/changeset/view/83171#1795869 Like I said before, it's not pretty. But my point being you'll need to create your own Stream class that will do what you want (in this case give you the string output of the page, parse/modify the string, and then output it to the user).
2) Assign the page's filter object to it. (Page.Response.Filter) Note that you need to do it rather early on so you can catch all of the content. I did this with a HTTP Module that ran on the PreRequestHandlerExecute event. But if you did something like this:
protected override void OnPreInit(EventArgs e)
{
this.Response.Filter = new MyStream();
base.OnPreInit(e);
}
That would also most likely work.
3) You should be able to use something like Html Agility Pack to parse the HTML and modify it from there.
That to me seems like the easiest approach.
I inherited a legacy app that is a mix of technologies from the last 10 yrs. It is not architected well so please don't berate me on why i need to do this, i just need to do it and get it done...
i have an important variable that is available client side in vbscript
i have an asp.net itemtemplate that lives inside a datagrid
i need to modify the style of a column in the grid based on the client variable
i cannot access the .net stuff in the vbscript to mess with it
i am trying to dynamically add a hidden field via vbscript to the page with the variable that i need, then find that in the .net code maybe using Page.FindControl so I can set the style dynamically using the variable that was given to me client side
any thoughts on the fastest way to do this?
Write the variable to a text file, read the text file into your .Net app.
problem solved, i sent the value in a query string and pulled it out using response.querystring on the .net side
the html tag itself has a .net function embedded in the class tag which will return the right style based on the value. the style hides the field
I'm trying to look for good (in-depth) explanation on what happens when you use MVC ajax helpers. What events and css classes get added. I can find sprinkle of info here and there but no overall explanation of how this ajax framework works. Is there a good explanation out there?
The Ajax Helper methods render Html to your page.
The best way to see exactly what an Ajax Helper method adds is by viewing the source when it renders in your browser at runtime.
You can even see the unobtrusive stuff rendered in the source if you remove your reference to the jquery.unobtrusive-ajax.js.
You can also write your own Ajax (and Html) Helper methods in the form of Extension Methods.
MVC3 Ajax helpers simply add some css class names and data on the form element.
You have to include jquery.unobtrusive-ajax.js in your project.
When the dom is ready, this script searches form elements with the above css class names. When the form is submitted, the script catch the event, serialize the form values, use $.ajax to call the target url, and can put the response into a given element id, or give it to your custom js method depending on the options you used.
input-validation-error and input-validation-valid classes are used for unobtrusive validation, which is not the same as unobtrusive ajax (they only share the word unobtrusive). It needs jquery.validate.unobtrusive.js and transform microsoft script validation into jquery validate validation.
See http://rocketsquared.com/wiki/Plugins/Validation for details about jquery validate validation.
I have a custom class library that performs validation. I want to open up this class for use within Javascript. I understand that I can easily achieve this by utilizing WebServices/WCF or by creating a function on my page with the WebMethod attribute, but it'd be nice not to have to set all that up for every project.
Ideally I'd like to just add the WebMethod attribute to my class library methods and then call them using Javascript.
Unfortunately, you will have to expose an endpoint that your Javascript function can see. In ASP.NET this is most easily done with the web method attribute that you have encountered. However, this method requires two parts the endpoint and the actual code. If you think about it, it makes sense. Javascript has no way of talking directly to a compiled .NET assembly. It must go through a type agnostic interface. One thing that you can do, and you may be doing this, is generate the .asmx file with the web method and then have that call your class library method. This will not prevent you from having the .asmx endpoint, but will prevent any duplication of the actual code. I don't have a lot of experience with WCF, but I believe that you will still need an endpoint of some sort to interface between Javascript and C#.
The WebMethod attribute has to be used from a page level method. It's not too much of a hassle though if you set your library up correctly. A WebMethod is just a static method, but if you plan to use it in multiple pages, then you most definately want to make it a WCF service. Neither of these should be difficult and the overhead is minimal.
Alternatively you could use a base Page class that all your other pages inherit from and define your WebMethod there. This class could live in class library somewhere and be used across multiple projects.
Does anyone know if it is possible to leverage the power of JQuery on the .Net serverside?
For example I have some HTML as a String in some code behind. Is there a way to execute JQuery on it?
I'm currently doing this...
Assume this is the String...
<input id='AddressSettings_txtFirstName' name='txtFirstName'
value='#firstNameValue#' size='25' type='text' class='val_required'/>
My C# does this
strHTML = strHTML.Replace("#firstNameValue#", customerInfo.FirstName);
And this is how I bind my data to my HTML.
Now what I would like to do is instead of having to add the #firstNameValue# as a place holder and replacing it I would like to somehow execute a line of JQuery on the HTML string in my C# code.
strHTML = strHTML.ExecuteJQuery("$('#AddressSettings_txtFirstName').text('"
+ customerInfo.FirstName + "')");
What are my options here?
For all intents and purposes, the answer is "no" (while there might be some obscure way of handling this, it's not the most optimal way).
It appears you are looking for a way to manipulate the HTML that is being produced on the server-side, which is a very legitimate desire, it's just that the approach on the server side using .NET (or other) technologies is radically different than how you would approach it on the client-side.
Because the content is already rendered on the client, the way you would apprach modifying it is different. On the server, the page is built of from various parts which ultimately render the HTML to the client, using data that the client doesn't necessarily have access to (as well as resources and libraries).
It's for that reason you want to use what's available on the server to accomplish what you are doing.
Whether you are using the WebForms model or MVC model of ASP.NET, there are mechanisms that allow you to bind to data without having to write out the tag yourself.
For example, in the WebForm model, you have the TextBox class which you can set the Text property on.
In ASP.NET MVC, there is the TextBox extension method on the InputExtensions class which allows you to pass the content of the textbox and the method will render the tag for you.
May be what you want is the HTML agility pack. You can't execute JavaScript, but you can do some DOM manipulation. Give it a try http://htmlagilitypack.codeplex.com/.
Use jQuery with jsdom for Node.js. Easiest way to manipulate DOM elements using javascript on the server-side.
The DOM is a browser specific entity. Thus, not directly available as you seek. However, you can determine just what you want to manipulate, and use either .live() or calling your jQuery code to add behavioral stuff as elements get added. As for change:
<input id='AddressSettings_txtFirstName' name='txtFirstName'
value='#firstNameValue#' size='25' type='text' class='val_required'/>
$('#AddressSettings_txtFirstName').change(function(){
// do stuff here
});
will fire when it changes for instance.
EDIT: One other option is to have the client pull the data using ajax and JSON - but that is a small shift in your method of working at present.
Well this is the answer for Java.Here and Here
Provided by some guy named John Resig. (Not sure he knows what hes talking about when it comes to JQuery...wink wink)
Now what about .Net?
This technology, ItsNat, is very similar to your desires, the bad news... is Java based.