Best html questions in May 2012

Find out if HTML height is set by style or by content

17 votes

I have 2 divs:

<div id="div1"></div>
<div id="div2">div2</div>​

in my css:

#div1{ height:20px}​

Both divs have 20px height, check demo
How can I find out if the div have it's height due to content or have been set in css or inline style?
This helps me find out the dimensions have been set by the developer or just calculated by the browser.

I found a way to achieve it :)

function getRealHeight(element){
    var height=0;
    if (element.children().length>0){
        var temp = $('<div></div>');
        temp.append(element.children());
        height = element.height();
        element.append(temp.children());
    } else {
        var html=element.html();
        element.html('');
        height = element.height();
        element.html(html);
    }
    return height;
}

DEMO

What JavaScript should be included in the <head> and what included in the <body>?

17 votes

I am confused about which JavaScript should be included where?

For instance:

  • Where should one include the jQuery libraries? In the <head> or before the closing </body> element?

  • If the JavaScript is defined at the bottom in the <body>, can it be used inline in the body?

  • If it blocks parallel downloads, then why is it never said to include your CSS at the bottom?

The Place of the <script> Element

The script elements block progressive page downloads.
Browsers download several components at a time, but when they encounter an external script, they stop further downloads until the script file is downloaded, parsed, and executed.
This hurts the overall page time, especially if it happens several times during a page load.
To minimize the blocking effect, you can place the script element toward the end of the page, right before the closing tag.
This way there will be no other resources for the script to block. The rest of the page components will be downloaded and already engaging the user.
The worst antipattern is to use separate files in the head of the document:

<!doctype html>
<html>
<head>
    <title>My App</title>
    <!-- ANTIPATTERN -->
    <script src="jquery.js"></script>
    <script src="jquery.quickselect.js"></script>
    <script src="jquery.lightbox.js"></script>
    <script src="myapp.js"></script>
</head>
<body>
...
</body>
</html>

A better option is to combine all the files:

<!doctype html>
<html>
<head>
    <title>My App</title>
    <script src="all_20100426.js"></script>
</head>
<body>
    ...
</body>
</html>

And the best option is to put the combined script at the very end of the page:

<!doctype html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    ...
    <script src="all_20100426.js"></script>
</body>

“JavaScript Patterns, by Stoyan Stefanov (O’Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750.”

How does inline Javascript (in HTML) work?

13 votes

I know this is bad practice. Don't write code like this if at all possible.

Of course, we'll always find ourselves in situations where a clever snippet of inline Javascript can address an issue quickly.

I am pursuing this query in the interest of fully understanding what happens (and the potential pitfalls) when something like this is written:

<a href="#" onclick="alert('Hi')">Click Me</a>

As far as I can tell this is functionally the same as

<script type="text/javascript">
   $(function(){ // I use jQuery in this example
       document.getElementById('click_me').onclick = 
           function () { alert('Hi'); };
   });
</script>
<a href="#" id="click_me">Click Me</a>

Extrapolating from this it seems that the string assigned to attribute onclick is inserted within an anonymous function which is assigned to the element's click handler. Is this actually the case?

Because I'm starting to do things like this:

<a href="#" onclick="$(this).next().fadeIn(); return false;">Display my next sibling</a> <!-- Return false in handler so as not to scroll to top of page! --> 

Which works. But I don't know how much of a hack this is. It looks suspicious because there is no apparent function that is being returned from!

You might ask, why are you doing this, Steve? Inline JS is bad practice!

Well to be quite honest I'm tired of editing three different sections of code just to modify one section of a page, especially when I'm just prototyping something to see if it will work at all. It is so much easier and sometimes even makes sense for the code specifically related to this HTML element to be defined right within the element: When I decide 2 minutes later that this was a terrible, terrible idea I can nuke the entire div (or whatever) and I don't have a bunch of mysterious JS and CSS cruft hanging around in the rest of the page, slowing down rendering ever so slightly. This is similar to the concept of locality of reference but instead of cache misses we're looking at bugs and code bloat.

You've got it nearly correct, but you haven't accounted for context:

<a href="#" onclick="alert(this)">Click Me</a>

is actually closer to:

<script type="text/javascript">
document.getElementById('click_me').addEventListener("click", function(event) {
    (function(event) {
        alert(this);
    }).call(document.getElementById('click_me'), event);
});
</script>
<a href="#" id="click_me">Click Me</a>

Inline event handlers set this equal to the target of the event.

Is IE The Only Browser (or version) That Does Not Allow Flash Object Manipulation?

12 votes

I've tried multiple ways to edit Flash Objects / Embeds via Javascript and it seems to work in everything but IE, so I'm thinking about just throwing IE out the window for this application unless there are older + used version of other browsers that also do not allow you to edit objects. An example of this would be:

document.getElementById(divID).innerHTML = '<object ...><embed ...><\/embed><\/object>';

or in jquery

var params = '<param name="allowFullScreen" value="true" />' +
             '<param name="allowScriptAccess" value="always" />' +
             '<param name="allowNetworking" value="all" />' +
             '<param name="movie" value="player.swf" />' +
$("#objectPlayer").html(params);

If all the rest of the modern browsers and the most used versions of them do support this kind of editing then I'll just scrap IE. And before I get floods of the SWFObject JS Framework, I'm not going to include a huge framework for a browser that I do not believe is going to contain my demographic.

JSFiddle

Here's a link to a JSFiddle I created. It works in all browsers but IE8

I believe the <param>part of your code is for <object>.

You have to pass the name/value pairs for embed too.

$("#objectPlayer embed").attr({
    "src": "fileName.swf",
    "name": "fileName",
    "allowFullScreen": "true",
    "width": 200,
    "height": 100,
    "type": "application/x-shockwave-flash"

    //and so on...
    });

But I would use SWFObject anyway, it is the industry standard, it's quite robust and it is the best way of embedding flash on the website.

Is there a way to select the first character? :first-letter does not seem to work

12 votes

Example problem: http://jsfiddle.net/6WYXk/

I have some html: <p>% hello world</p>

I want to make the % bold. To do this usually I would write this in CSS:

p:first-letter
{
    font-weight: bold;
}​

However that makes the % and the h bold.

Ideally I'd like a psudeo selector of :first-character

Indeed, that's odd. Doen't work for other symbol chars as well and the same problem has been discussed elsewhere on SO as well.

You should try something like this:

<p>hello world</p>
p:before { content:"%"; font-weight: bold; padding-right: 5px;}

Try it yourself…

Why is it a bad idea to tell your server to parse HTML as PHP?

11 votes

You know you can make a server parse HTML pages as PHP (execute PHP code in a HTML doc) using .htaccess?

Well, some people say it's bad to do so. Why?

Some people also say it opens a security vulnerability in your application. How?

The source code is still removed before the document reaches the browser, so it can't be the case of unauthorized access to source code, right?

Let me start with a little story: back when I was a security contact at a Linux distribution vendor, the PHP security team begged Linux vendors to stop calling interpreter crashes security bugs, even when the PHP interpreter was running inside the web server (say, mod_php on Apache). (At the time, roughly one interpreter crash was being found per week.)

It took a little bit of conversation for them to actually convince us that whoever supplied the running PHP code is completely trusted and any attempt to control what the scripts could do from the interpreter was misguided -- and if someone figured out how to crash the interpreter to walk around the restrictions it tried to impose (such as the entire silly safe mode pile of crap), it was not a security flaw, because the safe execution of scripts was not the goal of the PHP interpreter -- it never was and never would be.

I'm actually pretty happy with the end result of the discussions -- it clearly defined PHP's security goals: You should only ever allow execution of PHP code that you 100% completely trust. If you do not trust it, you do not run it. It's that simple.

Whatever operating system resources are available to the interpreter are all available and fair game, regardless of whether the script exploits a bug in the interpreter or just does something unexpected.

So, please do not allow random code to be executed in the context of your webserver unless that is what you really want.

Please use the principle of least privilege to guide what resources are available to every program.

Consider using a mandatory access control tool such as AppArmor, SELinux, TOMOYO, or SMACK to further confine what your programs can and can't do. I've worked on the AppArmor project since 2001 or so and am fairly confident that with a day's effort most system administrators can enhance their sites security in a meaningful way with AppArmor. Please evaluate several options, as the different tools are designed around different security models -- one or another may be a better fit.

But whatever you do, please don't run your server in a fashion that needlessly opens it up to attack via extra vectors.

Why does a filter gradient on a pseudo element not work in IE8?

9 votes

I want to create buttons like these: pseudo 3d button

In modern browsers the effect is created using inset box-shadow and filters.
For IE8 - pseudo-elements are chosen.
For IE7 - I use special tags wrapped in conditional comments.

Demo: http://jsfiddle.net/8M5Tt/68/embedded/result/

Main Question: Why don't filters work on pseudo elements in IE8?


Update:

I guess that filters do not work on css-generated content, despite the fact that it is not mentioned on this msdn page.

I solved my problem in IE8 by applying filters to conditional elements like I do for IE7.

Final demo: http://jsfiddle.net/matmuchrapna/8M5Tt/73/


Update 2:

I solved my problem, but the main question is still unanswered:

“Why don't filters work on pseudo elements in IE8?”

Started a bounty.

Update 3: I created testcase only for filters(and also -ms-filter) on ie8:

enter image description here

But the filters still don't want to work on pseudo-elements.

Update 4: I think Scotts answer is closest to truth.

The question is "Why don't filters work on pseudo elements in IE8?" The following is as close to a definitive answer as I can muster. It comes from the information on this page.

The gradient filter is a "procedural surface" (along with alphaimageloader). A procedural surface is defined so:

Procedural surfaces are colored surfaces that display between the content of an object and the object's background.

Read that carefully. It is essentially another "layer" you might say between the content of an object and that object's background. Do you see the answer to the question? What is created by :before and :after... Yes! Content. Specifically as MSDN notes:

The ::before and ::after pseudo-elements specify the location of content before and after an element in the document tree. The content attribute, in conjunction with these pseudo-elements, specifies what is inserted.

The generated content interacts with other boxes as if they were real elements inserted just inside their associated element.

Now, if it is content that is generated, then it is not an "object" containing content, but the content itself (which happens to have some behavior similar to an element object that might contain content).

Thus, there is no "object" containing "content" (since it is content) between which the filter can place a procedural surface for content generated by a pseudo-element (i.e. "false element"). A gradient must be applied to the object, and then the procedural surface is placed between it and the content.

How can I create this complicated layout using only CSS?

9 votes

OVERVIEW

I've read a bunch of the "vertical-centering with CSS" tutorials out there:

... but there is another component to my layout that is not represented in any of these methods in addition to the vertical centering.

layout.

There are 2 components to this layout. First, vertically & horizontally centering the content between the header and footer (which is a sticky footer). I have the code in a fiddle to demonstrate but I haven't been able to get this to work in IE (the code is at the bottom of the post).

The second component is where the green arrow is pointing. That represents a hidden element which is meant to expand vertically downwards when clicking on some of the text. However, I DO NOT WANT this expansion to move the content upward as if everything was being centered... I want this element to expand downwards without affecting the position of the content AND pushing the sticky footer down as it expands. In most cases, a browser scrollbar will appear.

So the effect of the hidden element expanding should be like a banner falling off an edge.

This is what the layout should look like after the hidden element has been expanded:

layout2


QUESTION

So how would I achieve this layout using only CSS and have it be cross-browser compatible Please let me know if I need to explain further to clarify confusion.


CODE SO FAR

Note... I have left out some of the boilerplate code that comes with HTML5 BoilerPlate.

CSS

/* --------------------------------------------------------------------------
   General Layout
   -------------------------------------------------------------------------- */
html,body {
    height: 100%;
}

body {
    background-color: #e3e3e3;
    color: #696969;
}

#wrapper {
    min-height: 100%;
    width: 100%;
    min-width: 936px;
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */
header {
    background-color: #232323;
    height: 108px;
    width: 100%;
    margin: auto;
    padding: 24px 0px 8px 0px;
    position: relative;
}

#header-content {
    height: 100%;
    width: 800px;
    margin: auto;
    position: relative;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
footer {
    background-color: #dbdbdb;
    border-top: 1px solid #bababa;
    height: 30px;
    width: 100%;
    min-width: 936px;
    margin-top: -32px;
    position: relative;
}

#footer-content {
    border-top: 1px solid #f8f8f8;
    height: 100%;
    margin: 0px auto;
    position: relative;
}

#footer-content > div {
    width: 800px;
    margin: 0px auto;
}


/* --------------------------------------------------------------------------
   DOWNLOADZONE
   -------------------------------------------------------------------------- */
#dl-info {
    width: 400px;
    margin: auto;
    display: table-cell !important;
    vertical-align: middle;
}

#show-hide {
    margin: 8px 0px;
    text-align: center;
}

/* --------------------------------------------------------------------------
   General helper classes
   -------------------------------------------------------------------------- */
.zone {
    background: none;
    border: 0px none;
    height: 100%;
    min-height: 100px;
    width: 100%;
    padding-top: 140px;
    padding-bottom: 31px;
    display: table;
    position: absolute;
    top: 0px;
    bottom: 0px;
    overflow: hidden;
}

.border {
    border: 1px solid #454545;
}

.clear {
    clear: both;
}


/* Hide from both screenreaders and browsers: h5bp.com/u */
.hidden { 
    display: none !important;
    visibility: hidden;
}

/* Hide only visually, but have it available for screenreaders: h5bp.com/v */
.visuallyhidden { 
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
}

/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */
.visuallyhidden.focusable:active, 
.visuallyhidden.focusable:focus { 
    clip: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    position: static;
    width: auto;
}

/* Hide visually and from screenreaders, but maintain layout */
.invisible { visibility: hidden; }

/* Contain floats: h5bp.com/q */
.clearfix:before, 
.clearfix:after { 
    content: "";
    display: table;
}

.clearfix:after { clear: both; }

.clearfix { *zoom: 1; }

​ HTML

<!doctype html>
<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
<!-- misteroneill.com/improved-internet-explorer-targeting-through-body-classes/ -->
<!--[if lt IE 7]> <html class="no-js ie ie6 lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie ie7 lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie ie8 lt-ie9 lt-ie8" lang="en"> <![endif]-->
<!--[if IE 9]> <html class="no-js ie ie9 lt-ie9" lang="en"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]>
<!-->
<html class="no-js" lang="en">
<!--<![endif]-->
<head>
    <title>Layout</title>
</head>

<body class="select-none">

    <div id="wrapper">

        <header>
            <div id="header-content">
            </div><!-- end #header-content -->
        </header><!-- end header -->

        <div id="downloadzone" class="zone clearfix">

            <div id="dl-info">
                <div class="border">
                    <div id="dl-button">Icon Here</div>
                    <div id="dl-extras">
                        <div id="dl-filename">text text text</div>
                        <div id="show-hide">CLICK TO SHOW/HIDE HIDDEN ELEMENT</div>
                    </div>
                </div>
            </div>

        </div><!-- end #downloadzone -->

    </div><!-- end #wrapper -->

    <footer>
        <div id="footer-content">
            <div class="border-highlight">
            </div><!-- end .border-highlight -->
        </div><!-- end #footer-content -->
    </footer><!-- end footer -->

</body>
</html>
​

If I understand you correctly (my apologies if I'm answering the wrong question here), you want an element of unknown height to be horizontally and vertically centered, with a possible other element beneath it that shouldn't affect the position when it's displayed?

How about using overflow? Here's a demo. I'll put the code here soon.

Compatibility warning: the vertical centering method used will not work in Internet Explorer 7 or lower.

Layout with fixed header and footer, fixed width sidebar and flexible content

9 votes

I'm trying set up a layout that will look like this: enter image description here

I want to use twitter bootstrap for the project, but I understand it may not be the best way to go for the basic layout that looks like this. I know how to setup the header and footer to be fixed at the top and bottom, but I have a hard time having my sidebar constant width and independently scrollable.

My current implementation is here: http://jsfiddle.net/Mwkrw/3/.

I tried setting up the fixed sidebar using Fixed sidebar naviagion in fluid twitter bootstrap 2.0 and a couple of other similar answers on stack overflow, but they all break when the sidebar is longer than the content and as far as I know there is no way to give it an independent scroll.

I would ideally like to do this with pure css - no javascript. I'm sure it's possible and it's my lack of skill and knowledge that prevents me form doing it properly, so there may be no point in unnecessarily adding javascript code. (I'm still adding a javascript tag in case it's not possible)

Thanks for all the help!

EDIT: So my header clearly did not need to be position fixed. Here is the new and improved version: http://jsfiddle.net/Mwkrw/4/ I'm still struggling with the two scrollable divs though.

The magic is in box-sizing:border-box;. For compatibility with Firefox, chrome<10, and safari<5.1, add the -webkit- and -moz- prefixes. IE supports it as of 8.0.

<!doctype html>
<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <title>very structured layout</title>
        <style type='text/css'>
            *      {margin:0; padding:0;}
            body   {background:#fff; position:absolute; width:100%; height:100%;}
            #main  {background:#888; height:100%; padding:60px 0 40px; box-sizing:border-box;}
            #head  {background:#f8f; position:absolute; width:100%; height:60px;}
            #left  {background:#ff8; float:left; width:250px; height:100%; overflow:scroll;}
            #right {background:#8f8; height:100%; overflow:scroll;}
            #foot  {background:#f88; position:absolute; bottom:0; width:100%; height:40px;}​
        </style>
    </head>
    <body>
        <div id='head'>header: width = 100%, height = 40px</div>
        <div id='main'>
            <div id='left'>left: width = 250px, height = 100%</div>
            <div id='right'>right: width = 100% - 250px, height = 100%</div>
        </div>
        <div id='foot'>foot: width = 100%, height = 60px</div>​
    </body>
</html>

fiddle

edit: after Andres' solution made me realize I could achieve greater compatibility, I messed around a bit and came up with an alternate solution, which I think is more intuitive as well. It doesn't work in IE7, but it does work in IE8.

The page is the same as the above, with the only change being that the CSS is replaced with this:

*      {margin:0; padding:0;}
body   {background:#fff;}
#main  {background:#888; position:absolute; top:40px; bottom:60px; width:100%;}
#head  {background:#f8f; position:absolute; width:100%; height:40px;}
#left  {background:#ff8; position:absolute; width:250px; height:100%; overflow:scroll;}
#right {background:#8f8; margin-left:250px; height:100%; overflow:scroll;}
#foot  {background:#f88; position:absolute; bottom:0; width:100%; height:60px;}

fiddle

Note that, for both versions, #head and #foot need to have an overflow property other than visible if their content would otherwise extend off the page.

Table or list: what should I use here?

9 votes

I would like to know which tags I should use for layout like this. Semantically is both a table and a list to me. How I can achieve those underlines and keep the markup right?

enter image description here

I would personally use an ordered list to achieve this, the sub list under Suma skladki means it isn't really tabular data.

This link should give you EXACTLY what you need:

http://thepcspy.com/read/css_table_of_contents/

Dynamic float layout with CSS

8 votes

Let me try and explain what I want to achieve. I want X boxes with a specific width (250 px) set but dynamic height to be placed in the body. But I want them to be as compact as possible, no unnecessary empty space between them.

Now If all boxes had same width and height, this would be easy. I could for example just put float:left; on them. But the when the boxes height is dynamic, and all boxes have random height I end up with spaces between the boxes.

Let me show two examples:

This is what I want:

This is what I want

This is what I end up with:

This is what I end up with

This is my CSS:

<style type="text/css">
<!--
body {
    background:#CCCCCC;
}
.flowBox {
    background:#FFFFFF;
    margin:10px;
    float:left;
    padding:10px;
    width:250px;
    border:#999999 1px solid;
}
.clear {
    clear:both;
}
-->
</style>

HTML example for a box:

<div class="flowBox">
   <h1>Header 0</h1>
   Erat volutpat. Sed rutr...
</div>

Full source code: http://pastebin.com/UL1Nqyvm

Is there a way to achieve this with CSS? Thanks for any help or directions!

From what I've seen before, what you want to achieve is hardly possible if not impossible with CSS only. What you want, basically, is a layout similar to Pinterest, you can check their website for a reference if you aren't sure what I am talking about.

From here, you can research a bit more into how Pinterest layout was done and if there are any alternatives - CSS Frameworks, jQuery Plugins and so on.

What I found for you from a short search with having the above in mind:

Additionally, here is a short explanation by Evan Sharp who wrote the code for Pinterest layout:

I wrote the Pinterest script. Here's the base of how it works:

Beforehand: Absolutely position the pin containers Determine column width Determine margin between columns (the gutter)

Setup an array: Get the width of the parent container; calculate the # of columns that will fit Create an empty array, with a length equaling the # of columns. Use this array to store the height of each column as you build the layout, e.g. the height of column 1 is stored as array[0]

Loop through each pin: Put each pin in the shortest column at the moment it is added "left:" === the column # (index array) times the column width + margin "top:" === The value in the array (height) for the shortest column at that time Finally, add the height of the pin to the column height (array value)

The result is lightweight. In Chrome, laying out a full page of 50+ pins takes <10ms>

You can go from here by either researching into the topic even further with the slight guidance I have provided or if you are into coding, you could even make your own implementation of the above explanation.

It would be much easier to use the jQuery Plugins though, but if they suit your case that's only for you to decide.

How to find which element breaks HTTPS on a webpage?

8 votes

Is there a simple way, maybe through a firefox plugin or something, to be able to tell which element on a webpage is breaking the HTTPS connection?

I've searched the source for any "http" and did not find any. I am thinking the root of the problem lies in a javascript file somewhere, but I was hoping to narrow it down easier than going line by line through all the javascript files.

Any simple solution or suggestions?

I don't know about firefox, but Google Chrome shows all insecure content sources in console.

For example:

The page at https://mail.google.com/mail/u/0/?shva=1#inbox displayed insecure content from http://example.com.

Etc.

What is the relationship between XHTML and HTML5 (and on)?

8 votes

Is there any reason to consider XHTML related details for web development for someone who works with HTML4 and plans to work with HTML5?

Or was XHTML a "side" development in web technology which is not related to the current mainstream of web development (which I guess is HTML5)?


Rationale for asking

The reason I'm asking is that a StackOverflow answer I previously posted was recently commented on to the effect that "You should NOT use upper case HTML tags". When I asked "why" the commenter pointed me to a couple of articles, both of which gave the reasoning for lowercase-only tag names as "Upper case tag names are not allowed in XHTML" as the main reason.

Since I don't currently do web development in XHTML (pure HTML4.0) and only plan to use HTML5 as the next step, I'm interested in whether XHTML should be a factor in assorted decisions I make as far as web development

Please note that this question is NOT asking whether one should use upper or lower case tag names in pure HTML - merely whether the upper-case-tag prohibition in XHTML should be a factor in my decision making, or I should ignore XHTML related rules.

Most of the info you will find on XHTML fails to mention that the whole purpose of XHTML is to be used by both humans and computers for data exchange. XHTML was created so that computers could talk to each other, but in the same time remain readable by humans. The most crazy thing is that various code monks became obsessed with XHTML compliance, without any intend of using the XHTML for data exchange and without understanding what XHTML actually is.

Edit: A good example of XHTML use is an airline company publishing its flights. The company can utilize XHTML to produce a single list of flights that will be both consumable be humans visiting online and by services that will read the data for their needs.

On the other hand if you own a hair-salon, there is no need for your site to validate against XHTML standards.

c# - Winform App - Webpage Interaction

7 votes

Windows Form Application – Manipulating input-elements in WinForm WebBrowser

Although I am familiar with HttpWebResponse/HttpWebRequest to login to a website, I was trying it now via using the mshtml library and found some weird behavior and I would like to see if someone else might be able to help me out here..

I have an HTML login page with a java backend with a Username field, a Password field and a Button.

The logic is very basic, I have a built a winform app with a built in webbrowser. At the Document_Completed event I use the following code to enter my settings and to click the button.

private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (webBrowser.Url.ToString() == @"MyWebPage/signin")            
    {
        HTMLDocument hdc = new HTMLDocumentClass();
        hdc = (HTMLDocument)webBrowser.Document.DomDocument;

        IHTMLElement elb = hdc.getElementById("login_button");
        IHTMLInputElement elu = (IHTMLInputElement)hdc.getElementById("username");
        IHTMLInputElement elp = (IHTMLInputElement)hdc.getElementById("password");

        try
        {
            elu.value = "MyID";
            elp.value = "MyPwd";
            elb.click();
        }
        catch { }
    }
}

Apart for this code being very quick and without error handling, it should do the trick and it does, partially..

There are two scenario's:

  • I launch the tool, it loads the webpage.

    • The tool populates the UserID field and the Password field correctly
    • The tool fails to click the button
  • I click the button manually, I am logged in, I click logout, I am back at login page

    • I immediatly logged in again, the tool enters the information
    • The tool immediatly clicks the button as well.

Is there anyone who might be able to explain me why this happens and how I could get around this with the current setup (hence not using HttpWebRequest). I don't see the difference between loading the page at startup or being redirected after logout, but apparently there is a difference in there or I am doing something wrong.

Any feedback on this matter is very much appreciated.

Thanks, Kevin

EDIT:

I added a Button to my Windows Form that bas the same backend Code as below in order to click the button on the webpage, this works perfectly.

I triggered clicking this button in the webBrowser_Completed event but it doesn't work. For some reason, everything I add to the webBrowser_DocumentCompleted event does not allow me to trigger the click event for the button in my WebBrowser control. Once that entire event has completed, if I then try to trigger it it works but I would like to automate this.. Any advice?

This might be a long shot and not the most elegant workaround but how about letting a backgroundworker run for a second in your DocumentCompleted event that then triggers the button that you clicked from it's seperate thread. This might just get this automated. As this will run from a different thread, keep in mind that you might have to invoke certain controls so this might be another downside to this workaround..

If this doesn't work then, as Regfor previously suggested, Watin.org can help you out.

How to compare two HTML elements

7 votes

How can we compare two HTML elements whether they are identical or not ?

I tried this thing but no luck

<div class="a"> Hi this is sachin tendulkar </div>
<div class="a"> Hi this is sachin tendulkar </div>

And then on button click, I call a function check()

var divs = $(".a");
alert(divs.length);    // Shows 2 here which is correct
if (divs.get(0) == divs.get(1)) alert("Same");

But this is not working. Everything is same in two divs. Apart from this How can we compare whether two HTML elements are completely idential or not. Including their innerHTML, className, Id, and their attributes.

Is this doable ?

Actually, I have two HTML documents and I want to remove the identical content from both of them So two elements can have same id.

PS: Updating after Crowder's valuable comments. If we compare two elements as strings, we would not get a match as their order of attributes may vary So the only option is to iterate through each child attribute and match. I still have to figure out completely working implementation strategy.

(See below for a complete, largely-untested, and certainly un-refactored off-the-cuff solution. But first, the bits and pieces of it.)

Comparing their innerHTML is easy:

if (divs[0].innerHTML === divs[1].innerHTML)
// or if you prefer using jQuery
if (divs.html() === $(divs[1]).html()) // The first one will just be the HTML from div 0

...although you have to ask yourself whether these two elements are equivalent according to your criteria:

<div><span class="foo" data-x="bar">x</span></div>
<div><span data-x="bar" class="foo">x</span></div>

...because their innerHTML will be different (at least on Chrome, and I suspect on most if not all browsers). (More on that below.)

Then you need to compare all of their attributes. As far as I know, jQuery doesn't give you a means of enumerating the attributes, but the DOM does:

function getAttributeNames(node) {
  var index, rv, attrs;

  rv = [];
  attrs = node.attributes;
  for (index = 0; index < attrs.length; ++index) {
    rv.push(attrs[index].nodeName);
  }
  rv.sort();
  return rv;
}

Then

var names = [getAttributeNames(div[0]), getAttributeNames(div[1])];
if (names[0].length === names[1].length) {
    // Same number, loop through and compare names and values
    ...
}

Note that by sorting the arrays above, I'm assuming the order of their attributes is not significant in your definition of "equivalent." I hope that's the case, because it doesn't seem to be preserved, as I get different results from different browsers when running this test. That being the case, we have to come back to the innerHTML question, because if the order of attributes on the elements themselves is not significant, then presumably the order of attributes on descendant elements shouldn't be significant. If that's the case, you'll need a recursive function that checks the descendants according to your definition of equivalent, and not use innerHTML at all.

But you should be able to put something together from the pieces above to compare two elements according to your criteria.

More to explore:


The question interested me strangely, so I kicked around at it for a while, and came up with the following. It's mostly untested, could use some refactoring, etc., but it should get you most of the way there. I do, again, assume the order of attributes is not significant. The below assumes even the slightest difference in the text is significant.

function getAttributeNames(node) {
  var index, rv, attrs;

  rv = [];
  attrs = node.attributes;
  for (index = 0; index < attrs.length; ++index) {
    rv.push(attrs[index].nodeName);
  }
  rv.sort();
  return rv;
}

function equivElms(elm1, elm2) {
  var attrs1, attrs2, name, node1, node2;

  // Compare attributes without order sensitivity
  attrs1 = getAttributeNames(elm1);
  attrs2 = getAttributeNames(elm2);
  if (attrs1.join(",") !== attrs2.join(",")) {
    display("Found nodes with different sets of attributes; not equiv");
    return false;
  }

  // ...and values
  // unless you want to compare DOM0 event handlers
  // (onclick="...")
  for (index = 0; index < attrs1.length; ++index) {
    name = attrs1[index];
    if (elm1.getAttribute(name) !== elm2.getAttribute(name)) {
      display("Found nodes with mis-matched values for attribute '" + name + "'; not equiv");
      return false;
    }
  }

  // Walk the children
  for (node1 = elm1.firstChild, node2 = elm2.firstChild;
       node1 && node2;
       node1 = node1.nextSibling, node2 = node2.nextSibling) {
     if (node1.nodeType !== node2.nodeType) {
       display("Found nodes of different types; not equiv");
       return false;
     }
     if (node1.nodeType === 1) { // Element
       if (!equivElms(node1, node2)) {
         return false;
       }
     }
     else if (node1.nodeValue !== node2.nodeValue) {
       display("Found nodes with mis-matched nodeValues; not equiv");
       return false;
     }
  }
  if (node1 || node2) {
    // One of the elements had more nodes than the other
    display("Found more children of one element than the other; not equivalent");
    return false;
  }

  // Seem the same
  return true;
}

Live examples: