Best html questions in September 2011

How do Google+ +1 widgets break out of their iframe?

103 votes

Somehow, hovering over a Google+ plus-one widget can introduce a tooltip-type deal that is clearly larger than the <iframe> element in which it is contained. I’ve inspected the DOM to confirm this.*

screenshot

So:

  1. What? How!?

  2. Is this not a massive opportunity for clickjacking, if used maliciously? (Imagine someone doing a MITM for these social widgets!)

*Update: What I saw was that the tooltip-y message was in a second, dynamically created iframe.

The Google +1 widget is javascript that runs on your website that is building an iframe. This javascript widget is running within the context of your website and therefore is not constrained by the Origin Inheritance Rules for iframes. Therefore this JavaScript widget can set whatever DOM event's it wants on the parent site even though it appears to be just a simple iframe.

Another thing, why is Google using an iframe? Why not just generate a div on the page? Well because the link originates from the iframe, a CSRF token can be embedded in the request and the parent site cannot read this token and forge the request. So the iframe is an anti-csrf measure that relies upon the Origin Inheritance rules to protect itself from a malicious parent.

From an attack perspective this is more like XSS than UI-Redress. You are giving Google access to your website and they could hijack your users Cookie's or perform XHR against your website if they so choose(But then people would sue them for being malicious and wealthy).

In this situation you HAVE to trust Google, but Google doesn't trust you.

Why do browsers still inject <tbody> in HTML5

21 votes

HTML5 doctype example.

Both IE9 and Chrome14 log TBODY as the tagName of the element inside the <table>

The HTML5 spec on <table> clearly states :

followed by either zero or more tbody elements or one or more tr elements

Furthermore. The HTML5 spec on <tr> clearly states :

As a child of a table element, after any caption, colgroup, and thead elements, but only if there are no tbody elements that are children of the table element.

Why are browsers corrupting my DOM and injecting a <tbody> when

  • I did not ask for one
  • It's perfectly valid without one

The answer of "backwards compatiblity" makes absolutely zero sense because I specifically opted in for a HTML5 doctype.

The answer of "backwards compatiblity" makes absolutely zero sense because I specifically opted in for a HTML5 doctype.

However, browsers don't differentiate between versions of HTML. HTML documents with HTML5 doctype and with HTML4 doctype (with the small exception of HTML4 transitional doctype without URL in FPI) are parsed and rendered the same way.

I'll quote the relevant part of HTML5 parser description:

8.2.5.4.9 The "in table" insertion mode

...

A start tag whose tag name is one of: "td", "th", "tr"

Act as if a start tag token with the tag name "tbody" had been

seen, then reprocess the current token.

Why are dashes preferred for CSS selectors / HTML attributes?

20 votes

In the past I've always used underscores for defining class and id attributes in HTML. Over the last few years I changed over to dashes, mostly to align myself with the trend in the community, not necessarily because it made sense to me.

I've always thought dashes have more drawbacks, and I don't see the benefits:

Code completion & Editing

Most editors treat dashes as word separators, so I can't tab through to the symbol I want. Say the class is "featured-product", I have to auto-complete "featured", enter a hyphen, and complete "product".

With underscores "featured_product" is treated as one word, so it can be filled in one step.

The same applies to navigating through the document. Jumping by words or double-clicking on class names is broken by hyphens.

(More generally, I think of classes and ids as tokens, so it doesn't make sense to me that a token should be so easily splittable on hyphens.)

Ambiguity with arithmetic operator

Using dashes breaks object-property access to form elements in JavaScript. This is only possible with underscores:

form.first_name.value='Stormageddon';

(Admittedly I don't access form elements this way myself, but when deciding on dashes vs underscores as a universal rule, consider that someone might.)

Languages like Sass (especially throughout the Compass framework) have settled on dashes as a standard, even for variable names. They originally used underscores in the beginning too. The fact that this is parsed differently strikes me as odd:

$list-item-10
$list-item - 10

Inconsistency with variable naming across languages

Back in the day, I used to write underscored_names for variables in PHP, ruby, HTML/CSS, and JavaScript. This was convenient and consistent, but again in order to "fit in" I now use:

  • dash-case in HTML/CSS
  • camelCase in JavaScript
  • underscore_case in PHP and ruby

This doesn't really bother me too much, but I wonder why these became so misaligned, seemingly on purpose. At least with underscores it was possible to maintain consistency:

var featured_product = $('#featured_product'); // instead of
var featuredProduct = $('#featured-product');

The differences create situations where we have to translate strings unnecessarily, along with the potential for bugs.

So I ask: Why did the community almost universally settle on dashes, and are there any reasons that outweigh underscores?

There is a related question from back around the time this started, but I'm of the opinion that it's not (or shouldn't have been) just a matter of taste. I'd like to understand why we all settled on this convention if it really was just a matter of taste.

Code completion

Whether dash is interpreted as punctuation or as an opaque identifier depends on the editor of choice, I guess. However, as a personal preference, I favor being able to tab between each word in a CSS file and would find it annoying if they were separated with underscore and there were no stops.

Also, using hyphens allows you to take advantage of the |= attribute selector, which selects any element containing the text, optionally followed by a dash:

span[class|="em"] { font-style: italic; }

This would make the following HTML elements have italic font-style:

<span class="em">I'm italic</span>
<span class="em-strong">I'm italic too</span>

Ambiguity with arithmetic operator

I'd say that access to HTML elements via dot notation in JavaScript is a bug rather than a feature. It's a terrible construct from the early days of terrible JavaScript implementations and isn't really a great practice. For most of the stuff you do with JavaScript these days, you'd want to use CSS Selectors for fetching elements from the DOM anyway, which makes the whole dot notation rather useless. Which one would you prefer?

var firstName = $('#first-name');
var firstName = document.querySelector('#first-name');
var firstName = document.forms[0].first_name;

I find the two first options much more preferable, especially since '#first-name' can be replaced with a JavaScript variable and built dynamically. I also find them more pleasant on the eyes.

The fact that Sass enables arithmetic in its extensions to CSS doesn't really apply to CSS itself, but I do understand (and embrace) the fact that Sass follows the language style of CSS (except for the $ prefix of variables, which of course should have been @). If Sass documents are to look and feel like CSS documents, they need to follow the same style as CSS, which uses dash as a delimiter. In CSS3, arithmetic is limited to the calc function, which goes to show that in CSS itself, this isn't an issue.

Inconsistency with variable naming across languages

All languages, being markup languages, programming languages, styling languages or scripting languages, have their own style. You will find this within sub-languages of language groups like XML, where e.g. XSLT uses lower-case with hyphen delimiters and XML Schema uses camel-casing.

In general, you will find that adopting the style that feels and looks most "native" to the language you're writing in is better than trying to shoe-horn your own style into every different language. Since you can't avoid having to use native libraries and language constructs, your style will be "polluted" by the native style whether you like it or not, so it's pretty much futile to even try.

My advice is to not find a favorite style across languages, but instead make yourself at home within each language and learn to love all of its quirks. One of CSS' quirks is that keywords and identifiers are written in lowercase and separated by hyphens. Personally, I find this very visually appealing and think it fits in with the all-lowercase (although no-hyphen) HTML.

Can I load an entire HTML document into a document fragment in Internet Explorer?

15 votes

Here's something I've been having a little bit of difficulty with. I have a local client-side script that needs to allow a user to fetch a remote web page and search that resulting page for forms. In order to do this (without regex), I need to parse the document into a fully traversable DOM object.

Some limitations I'd like to stress:

  • I don't want to use libraries (like jQuery). There's too much bloat for what I need to do here.
  • Under no circumstances should script from the remote page be executed (for security reasons).
  • DOM APIs, such as getElementsByTagName, need to be available.
  • It only needs to work in Internet Explorer, but in 7 at the very least.
  • Let's pretend I don't have access to a server. I do, but I can't use it for this.

What I've tried

Assuming I have a complete HTML document string (including DOCTYPE declaration) in the variable html, here's what I've tried so far:

var frag = document.createDocumentFragment(),
    div  = frag.appendChild(document.createElement("div"));

div.outerHTML = html;
//-> results in an empty fragment

div.insertAdjacentHTML("afterEnd", html);
//-> HTML is not added to the fragment

div.innerHTML = html;
//-> Error (expected, but I tried it anyway)

var doc = new ActiveXObject("htmlfile");
doc.write(html);
doc.close();
//-> JavaScript executes

I've also tried extracting the <head> and <body>nodes from the HTML and adding them to a <HTML> element inside the fragment, still no luck.

Does anyone have any ideas?

Fiddle: http://jsfiddle.net/JFSKe/6/

DocumentFragment doesn't implement DOM methods. Using document.createElement in conjunction with innerHTML removes the <head> and <body> tags (even when the created element is a root element, <html>). Therefore, the solution should be sought elsewhere. I have created a cross-browser string-to-DOM function, which makes use of an invisible inline-frame.

All external resources and scripts will be disabled. See Explanation of the code for more information.

Code

/*
 @param String html    The string with HTML which has be converted to a DOM object
 @param func callback  (optional) Callback(HTMLDocument doc, function destroy)
 @returns              undefined if callback exists, else: Object
                        HTMLDocument doc  DOM fetched from Parameter:html
                        function destroy  Removes HTMLDocument doc.         */
function string2dom(html, callback){
    /* Sanitise the string */
    html = sanitiseHTML(html); /*Defined at the bottom of the answer*/

    /* Create an IFrame */
    var iframe = document.createElement("iframe");
    iframe.style.display = "none";
    document.body.appendChild(iframe);

    var doc = iframe.contentDocument || iframe.contentWindow.document;
    doc.open();
    doc.write(html);
    doc.close();

    function destroy(){
        iframe.parentNode.removeChild(iframe);
    }
    if(callback) callback(doc, destroy);
    else return {"doc": doc, "destroy": destroy};
}

/* @name sanitiseHTML
   @param String html  A string representing HTML code
   @return String      A new string, fully stripped of external resources.
                       All "external" attributes (href, src) are prefixed by data- */

function sanitiseHTML(html){
    /* Adds a <!-\"'--> before every matched tag, so that unterminated quotes
        aren't preventing the browser from splitting a tag. Test case:
       '<input style="foo;b:url(0);><input onclick="<input type=button onclick="too() href=;>">' */
    var prefix = "<!--\"'-->";
    /*Attributes should not be prefixed by these characters. This list is not
     complete, but will be sufficient for this function.
      (see http://www.w3.org/TR/REC-xml/#NT-NameChar) */
    var att = "[^-a-z0-9:._]";
    var tag = "<[a-z]";
    var any = "(?:[^<>\"']*(?:\"[^\"]*\"|'[^']*'))*?[^<>]*";
    var etag = "(?:>|(?=<))";

    /*
      @name ae
      @description          Converts a given string in a sequence of the
                             original input and the HTML entity
      @param String string  String to convert
      */
    var entityEnd = "(?:;|(?!\\d))";
    var ents = {" ":"(?:\\s|&nbsp;?|&#0*32"+entityEnd+"|&#x0*20"+entityEnd+")",
                "(":"(?:\\(|&#0*40"+entityEnd+"|&#x0*28"+entityEnd+")",
                ")":"(?:\\)|&#0*41"+entityEnd+"|&#x0*29"+entityEnd+")",
                ".":"(?:\\.|&#0*46"+entityEnd+"|&#x0*2e"+entityEnd+")"};
                /*Placeholder to avoid tricky filter-circumventing methods*/
    var charMap = {};
    var s = ents[" "]+"*"; /* Short-hand space */
    /* Important: Must be pre- and postfixed by < and >. RE matches a whole tag! */
    function ae(string){
        var all_chars_lowercase = string.toLowerCase();
        if(ents[string]) return ents[string];
        var all_chars_uppercase = string.toUpperCase();
        var RE_res = "";
        for(var i=0; i<string.length; i++){
            var char_lowercase = all_chars_lowercase.charAt(i);
            if(charMap[char_lowercase]){
                RE_res += charMap[char_lowercase];
                continue;
            }
            var char_uppercase = all_chars_uppercase.charAt(i);
            var RE_sub = [char_lowercase];
            RE_sub.push("&#0*" + char_lowercase.charCodeAt(0) + entityEnd);
            RE_sub.push("&#x0*" + char_lowercase.charCodeAt(0).toString(16) + entityEnd);
            if(char_lowercase != char_uppercase){
                RE_sub.push("&#0*" + char_uppercase.charCodeAt(0) + entityEnd);   
                RE_sub.push("&#x0*" + char_uppercase.charCodeAt(0).toString(16) + entityEnd);
            }
            RE_sub = "(?:" + RE_sub.join("|") + ")";
            RE_res += (charMap[char_lowercase] = RE_sub);
        }
        return(ents[string] = RE_res);
    }
    /*
      @name by
      @description  second argument for the replace function.
      */
    function by(match, group1, group2){
        /* Adds a data-prefix before every external pointer */
        return group1 + "data-" + group2 
    }
    /*
      @name cr
      @description            Selects a HTML element and performs a
                                  search-and-replace on attributes
      @param String selector  HTML substring to match
      @param String attribute RegExp-escaped; HTML element attribute to match
      @param String marker    Optional RegExp-escaped; marks the prefix
      @param String delimiter Optional RegExp escaped; non-quote delimiters
      @param String end       Optional RegExp-escaped; forces the match to
                                  end before an occurence of <end> when 
                                  quotes are missing
     */
    function cr(selector, attribute, marker, delimiter, end){
        if(typeof selector == "string") selector = new RegExp(selector, "gi");
        marker = typeof marker == "string" ? marker : "\\s*=";
        delimiter = typeof delimiter == "string" ? delimiter : "";
        end = typeof end == "string" ? end : "";
        var is_end = end && "?";
        var re1 = new RegExp("("+att+")("+attribute+marker+"(?:\\s*\"[^\""+delimiter+"]*\"|\\s*'[^'"+delimiter+"]*'|[^\\s"+delimiter+"]+"+is_end+")"+end+")", "gi");
        html = html.replace(selector, function(match){
            return prefix + match.replace(re1, by);
        });
    }
    /* 
      @name cri
      @description            Selects an attribute of a HTML element, and
                               performs a search-and-replace on certain values
      @param String selector  HTML element to match
      @param String attribute RegExp-escaped; HTML element attribute to match
      @param String front     RegExp-escaped; attribute value, prefix to match
      @param String flags     Optional RegExp flags, default "gi"
      @param String delimiter Optional RegExp-escaped; non-quote delimiters
      @param String end       Optional RegExp-escaped; forces the match to
                                  end before an occurence of <end> when 
                                  quotes are missing
     */
    function cri(selector, attribute, front, flags, delimiter, end){
        if(typeof selector == "string") selector = new RegExp(selector, "gi");
        flags = typeof flags == "string" ? flags : "gi";
         var re1 = new RegExp("("+att+attribute+"\\s*=)((?:\\s*\"[^\"]*\"|\\s*'[^']*'|[^\\s>]+))", "gi");

        end = typeof end == "string" ? end + ")" : ")";
        var at1 = new RegExp('(")('+front+'[^"]+")', flags);
        var at2 = new RegExp("(')("+front+"[^']+')", flags);
        var at3 = new RegExp("()("+front+'(?:"[^"]+"|\'[^\']+\'|(?:(?!'+delimiter+').)+)'+end, flags);

        var handleAttr = function(match, g1, g2){
            if(g2.charAt(0) == '"') return g1+g2.replace(at1, by);
            if(g2.charAt(0) == "'") return g1+g2.replace(at2, by);
            return g1+g2.replace(at3, by);
        };
        html = html.replace(selector, function(match){
             return prefix + match.replace(re1, handleAttr);
        });
    }

    /* <meta http-equiv=refresh content="  ; url= " > */
    html = html.replace(new RegExp("<meta"+any+att+"http-equiv\\s*=\\s*(?:\""+ae("refresh")+"\""+any+etag+"|'"+ae("refresh")+"'"+any+etag+"|"+ae("refresh")+"(?:"+ae(" ")+any+etag+"|"+etag+"))", "gi"), "<!-- meta http-equiv=refresh stripped-->");

    /* Stripping all scripts */
    html = html.replace(new RegExp("<script"+any+">\\s*//\\s*<\\[CDATA\\[[\\S\\s]*?]]>\\s*</script[^>]*>", "gi"), "<!--CDATA script-->");
    html = html.replace(/<script[\S\s]+?<\/script\s*>/gi, "<!--Non-CDATA script-->");
    cr(tag+any+att+"on[-a-z0-9:_.]+="+any+etag, "on[-a-z0-9:_.]+"); /* Event listeners */

    cr(tag+any+att+"href\\s*="+any+etag, "href"); /* Linked elements */
    cr(tag+any+att+"src\\s*="+any+etag, "src"); /* Embedded elements */

    cr("<object"+any+att+"data\\s*="+any+etag, "data"); /* <object data= > */
    cr("<applet"+any+att+"codebase\\s*="+any+etag, "codebase"); /* <applet codebase= > */

    /* <param name=movie value= >*/
    cr("<param"+any+att+"name\\s*=\\s*(?:\""+ae("movie")+"\""+any+etag+"|'"+ae("movie")+"'"+any+etag+"|"+ae("movie")+"(?:"+ae(" ")+any+etag+"|"+etag+"))", "value");

    /* <style> and < style=  > url()*/
    cr(/<style[^>]*>(?:[^"']*(?:"[^"]*"|'[^']*'))*?[^'"]*(?:<\/style|$)/gi, "url", "\\s*\\(\\s*", "", "\\s*\\)");
    cri(tag+any+att+"style\\s*="+any+etag, "style", ae("url")+s+ae("(")+s, 0, s+ae(")"), ae(")"));

    /* IE7- CSS expression() */
    cr(/<style[^>]*>(?:[^"']*(?:"[^"]*"|'[^']*'))*?[^'"]*(?:<\/style|$)/gi, "expression", "\\s*\\(\\s*", "", "\\s*\\)");
    cri(tag+any+att+"style\\s*="+any+etag, "style", ae("expression")+s+ae("(")+s, 0, s+ae(")"), ae(")"));
    return html.replace(new RegExp("(?:"+prefix+")+", "g"), prefix);
}

Explanation of the code

The sanitiseHTML function is based on my replace_all_rel_by_abs function (see this answer). The sanitiseHTML function is completely rewritten though, in order to achieve maximum efficiency and reliability.

Additionally, a new set of RegExps are added to remove all scripts and event handlers (including CSS expression(), IE7-). To make sure that all tags are parsed as expected, the adjusted tags are prefixed by <!--'"-->. This prefix is necessary to correctly parse nested "event handlers" in conjunction with unterminated quotes: <a id="><input onclick="<div onmousemove=evil()>">.

These RegExps are dynamically created using an internal function cr/cri (Create Replace [Inline]). These functions accept a list of arguments, and create and execute an advanced RE replacement. To make sure that HTML entities aren't breaking a RegExp (refresh in <meta http-equiv=refresh> could be written in various ways), the dynamically created RegExps are partially constructed by function ae (Any Entity).
The actual replacements are done by function by (replace by). In this implementation, by adds data- before all matched attributes.

  1. All <script>//<[CDATA[ .. //]]></script> occurrences are striped. This step is necessary, because CDATA sections allow </script> strings inside the code. After this replacement has been executed, it's safe to go to the next replacement:
  2. The remaining <script>...</script> tags are removed.
  3. The <meta http-equiv=refresh .. > tag is removed
  4. All event listeners and external pointers/attributes (href, src, url()) are prefixed by data-, as described previously.

  5. An IFrame object is created. IFrames are less likely to leak memory (contrary to the htmlfile ActiveXObject). The IFrame becomes invisible, and is appended to the document, so that the DOM can be accessed. document.write() are used to write HTML to the IFrame. document.open() and document.close() are used to empty the previous contents of the document, so that the generated document is an exact copy of the given html string.

  6. If a callback function has been specified, the function will be called with two arguments. The first argument is a reference to the generated document object. The second argument is a function, which destroys the generated DOM tree when called. This function should be called when you don't need the tree any more.
    If the callback function isn't specified, the function returns an object consisting of two properties (doc and destroy), which behave the same as the previously mentioned arguments.

Additional notes

  • Setting the designMode property to "On" will stop a frame from executing scripts (not supported in Chrome). If you have to preserve the <script> tags for a specific reason, you can use iframe.designMode = "On" instead of the script stripping feature.
  • I wasn't able to find a reliable source for the htmlfile activeXObject. According to this source, htmlfile is slower than IFrames, and more susceptible to memory leaks.

  • All affected attributes (href, src, ...) are prefixed by data-. An example of getting/changing these attributes is shown for data-href:
    elem.getAttribute("data-href") and elem.setAttribute("data-href", "...")
    elem.dataset.href and elem.dataset.href = "...".
  • External resources have been disabled. As a result, the page may look completely different:
    <link rel="stylesheet" href="main.css" /> No external styles
    <script>document.body.bgColor="red";</script> No scripted styles
    <img src="128x128.png" /> No images: the size of the element may be completely different.

Examples

sanitiseHTML(html)
Paste this bookmarklet in the location's bar. It will offer an option to inject a textarea, showing the sanitised HTML string.

javascript:void(function(){var s=document.createElement("script");s.src="http://rob.lekensteyn.nl/html-sanitizer.js";document.body.appendChild(s)})();

Code examples - string2dom(html):

string2dom("<html><head><title>Test</title></head></html>", function(doc, destroy){
    alert(doc.title); /* Alert: "Test" */
    destroy();
});

var test = string2dom("<div id='secret'></div>");
alert(test.doc.getElementById("secret").tagName); /* Alert: "DIV" */
test.destroy();

Notable references

Invert/change logo on scroll

12 votes

An article over on askthecssguy.com shows how to change/invert an image on scroll using fixed backgrounds: http://askthecssguy.com/articles/mike-asks-the-css-guy-about-a-scrolling-trick-with-background-images/

My goal takes this concept further by having the image float over other elements (in this case images).

You can see the result here: http://playground.iamkeir.com/invert-logo/v2/

However, my implementation uses superfluous elements and, so, I was wondering if anyone had any ideas/suggestions of another way to achieve this?

Javascript is certainly an option but I worry it would not be lean/elegant. Someone also suggested using Canvas.

Any ideas welcomed! Thank you.

You can avoid extra markup by using :after CSS pseudo element. Thus, your final markup will look like:

<ul>
        <li class="light">
            <img src="http://farm3.static.flickr.com/2802/4253151258_7d12da9e1c_z.jpg" />
        </li>
        <li class="dark">
            <img src="http://farm1.static.flickr.com/31/66005536_d1c5afca29_z.jpg?zz=1" />
        </li>
        <li class="light">
            <img src="http://farm4.static.flickr.com/3574/3646151231_0c68f4f974_z.jpg" />
        </li>
        <li class="dark">
            <img src="http://farm4.static.flickr.com/3432/3310214210_813d13c899_z.jpg" />
        </li>
    </ul>

And the altered CSS will be:

.dark:after,
.light:after,
.dark .after,
.light .after {
    position: absolute;
    display: block;
    content: '';
    top: 0; left: 0;
    height: 100%;
    width: 76px;
    background: transparent url(logo-white.png) no-repeat fixed 0 0;
    z-index: 5;
}

.dark:after,
.dark .after {
    background-image: url(logo-black.png);
}

Notice that there is .after class there. This is to make it work in IE<8, which, sadly, requires to use an expression:

.dark,
.light {
    behavior: expression( !this.before ? this.before = this.innerHTML = '<div class="after"></div>' + this.innerHTML : '' );
}

While using expressions is generally discouraged, this one shouldn't affect the performance too much, since it is fully evaluated only once, and when the element is created, the condition returns false.

There is one pitfall, though. If IE8 works in IE8/IE8 mode, the pseudo-elements will be under the images, unless you set negative z-index for the latter, which isn't always acceptable.

You can look at working example here.

CSS Selector "(A or B) and C"?

10 votes

This should be simple, but I'm having trouble finding the search terms for it.
Let's say I have this:

<div class="a c">Foo</div>
<div class="b c">Bar</div>

In CSS, how can I create a selector that matches something that matches "(.a or .b) and .c"?

I know I could do this:

.a.c,.b.c {
  /* CSS stuff */
}

But, assuming I'm going to have to do this sort of logic a lot, with a variety of logical combinations, is there a better syntax?

is there a better syntax?

No. CSS' or operator (,) does not permit groupings. It's essentially the lowest-precedence logical operator in selectors, so you must use .a.c,.b.c.

Why should y.innerHTML = x.innerHTML; be avoided?

9 votes

Let's say that we have a DIV x on the page and we want to duplicate ("copy-paste") the contents of that DIV into another DIV y. We could do this like so:

y.innerHTML = x.innerHTML;

or with jQuery:

$(y).html( $(x).html() );

However, it appears that this method is not a good idea, and that it should be avoided.

(1) Why should this method be avoided?

(2) How should this be done instead?


Update:
For the sake of this question let's assume that there are no elements with ID's inside the DIV x.
(Sorry I forgot to cover this case in my original question.)

Conclusion:
I have posted my own answer to this question below (as I originally intended). Now, I also planed to accept my own answer :P, but lonesomeday's answer is so amazing that I have to accept it instead.

This method of "copying" HTML elements from one place to another is the result of a misapprehension of what a browser does. Browsers don't keep an HTML document in memory somewhere and repeatedly modify the HTML based on commands from Javascript.

When a browser first loads a page, it parses the HTML document and turns it into a DOM structure. This is a relationship of objects following a W3C standard (well, mostly...). The original HTML is from then on completely redundant. The browser doesn't care what the original HTML structure was; its understanding of the web page is the DOM structure that was created from it. If your HTML markup was incorrect/invalid, it will be corrected in some way by the web browser; the DOM structure will not contain the invalid code in any way.

Basically, HTML should be treated as a way of serialising a DOM structure to be passed over the internet or stored in a file locally.

It should not, therefore, be used for modifying an existing web page. The DOM (Document Object Model) has a system for changing the content of a page. This is based on the relationship of nodes, not on the HTML serialisation. So when you add an li to a ul, you have these two options (assuming ul is the list element):

// option 1: innerHTML
ul.innerHTML += '<li>foobar</li>';

// option 2: DOM manipulation
var li = document.createElement('li');
li.appendChild(document.createTextNode('foobar');
ul.appendChild(li);

Now, the first option looks a lot simpler, but this is only because the browser has abstracted a lot away for you: internally, the browser has to convert the element's children to a string, then append some content, then convert the string back to a DOM structure. The second option corresponds to the browser's native understanding of what's going on.

The second major consideration is to think about the limitations of HTML. When you think about a webpage, not everything relevant to the element can be serialised to HTML. For instance, event handlers bound with x.onclick = function(); or x.addEventListener(...) won't be replicated in innerHTML, so they won't be copied across. So the new elements in y won't have the event listeners. This probably isn't what you want.

So the way around this is to work with the native DOM methods:

for (var i = 0; i < x.childNodes.length; i++) {
    y.appendChild(x.childNodes[i].cloneNode(true);
}

Reading the MDN documentation will probably help to understand this way of doing things:

Now the problem with this (as with option 2 in the code example above) is that it is very verbose, far longer than the innerHTML option would be. This is when you appreciate having a Javascript library that does this kind of thing for you. For example, in jQuery:

$('#y').empty().append($('#x').clone(true).contents());

This is a lot more explicit about what you want to happen. As well as having various performance benefits and preserving event handlers, for example, it also helps you to understand what your code is doing. This is good for your soul as a Javascript programmer and makes bizarre errors significantly less likely!

How can I achieve a slot machine spinning effect with CSS3 & jQuery?

9 votes

I am creating a demo application that randomly selects a venue when a button is clicked. Once the button is clicked I want to have the venues scroll through with a slot machine spinning animation using CSS3 and jQuery before a venue is selected.

I thought about using -webkit-keyframes and changing the background position, but it's not the ideal animation I would like.

@-webkit-keyframes spin{  
  0% {  
        background-position: 0, 0 0;
        -webkit-transform: rotateX(0deg);
     }
  100% { 
        background-position: 0, 0 -640px;
        -webkit-transform: rotateX(360deg);
     }
}

.rotating{
    -webkit-animation: spin .5s infinite linear;
    -webkit-transition: background-position .7s;
}

Can anyone give any insight on how this can be achieved? Here is what I have so far. Any help is appreciated.

Thank You

After much research plagiarising I've come up with this. Hopefully it helps in some shape or form.

http://jsfiddle.net/DnTX6/

How to post an array of files in ASP.NET MVC 3?

9 votes

I would like to be able to post multiple files in one form. I would like to pass these files as an array of files. For example I would like to do this.

<input type="file" name="files[0]" />
<input type="file" name="files[1]" />
<input type="file" name="files[2]" />

Then I would like to be able to receive these files as an array in the Controller. I've tried this.

public ActionResult AddPart(HttpPostedFileBase[] files)

But that doesn't work. I've googled it but all I can find is examples on uploading one file. Does anyone know how to do this using MVC3 C#.

If you want to upload not only one file, you need to use enctype="multipart/form-data" in your form.

@using (Html.BeginForm("", "Client", FormMethod.Post, new {enctype="multipart/form-data"}))

And controller:

[HttpPost]
public ActionResult AddPart(IEnumerable<HttpPostedFileBase> files) 

All other parts is ok.

Ellipsis for overflow text in dropdown boxes

8 votes

I'm fixing the width of one of my dropdown boxes (yes I know there are cross-browser issues with doing this).

Is there a non-js way to cut off overflowing text and append ellipses? text-overflow:ellipsis doesn't work for <select> elements (at least in Chrome).

Example here: http://jsfiddle.net/t5eUe/

HTML is very limited in what it specifies for form controls. That leaves room for operating system and browser makers to do what they think is appropriate (like the iPhone’s modal select which, when open, looks totally different from the traditional pop-up menu).

It looks like most operating systems cut the selected option off without an elipsis. If you were able to change how the text gets cut off, it would look strange since that’s not how select boxes work in the rest of the operating system.

If it bugs you, you can use a customizable replacement, like Chosen, which looks distinct from the native select.

Or, file a bug against a major operating system or browser! For all we know, the way text is cut off in selects might be the result of a years-old oversight that everyone copied, and it might be time for a change.

Can I rely on the implicit creation of the `tbody` tag?

8 votes
<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
    <script type="text/javascript">
        $( document ).ready( function(){
            $( "table > tr > td > input[id]" ).each( function( i, element ){ 
                alert( $( element ).attr( 'id' ) ) 
            });
        });
    </script>
</head>
<body>
<form>
    <table>
        <tr><td>City:</td><td><input type="text" id="city" name="city" /></td></tr>
        <tr><td>state:</td><td><input type="text" id="state" name="state" /></td></tr>
    </table><br />
    <input type="submit" value="OK"/>
</form>
</body>
</html>

When I write it this way it doesn't work because my browser create automatically a tbody tag so I have to write

    $( "table tr > td > input[id]" ).each( function( i, element ){ 
        alert( $( element ).attr( 'id' ) ) 
    });

or

    $( "table > tbody > tr > td > input[id]" ).each( function( i, element ){ 
        alert( $( element ).attr( 'id' ) ) 
    });

Can I rely on the implicit creation of the tbody tag or should I not count on that?


Added to explain my comment to Tim Down's answer:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js"></script>
<script type="text/javascript">
    $( document ).ready( function() {
        var ids = [];
        var form = document.forms[0];
        var formEls = form.elements;
        var f_len = formEls.length;
        for ( var i = 0; i < f_len; ++i ) {
            ids.push( formEls[i].id );
        }
        var data = [ [ 'one', 'two', 'thre' ], [ 'four', 'five', 'six' ] ];
        var ids_len = ids.length;
        for ( i = 0; i < ids_len; i++ ){
            $( "#" + ids[i] ).autocomplete({
                source: data[i]
            });
        }
    });
</script>
</head>
<body>
<form>
    <table>
        <tr><td>A:</td><td><input type="text" id="a" name="a" /></td></tr>
        <tr><td>B:</td><td><input type="text" id="b" name="b" /></td></tr>
    </table><br />
    <input type="submit" value="OK"/>
</form>
</body>
</html>

When I run this, the Webconsole shows me a warning something like this:
Empty string to getElementById () is passed.
One string form the strings returned by form.elements is empty.

It's not a question on relying on it being automatically created or not.

The question is if it's mandatory or not.

According to the HTML5 draft:

A tbody element's start tag may be omitted if the first thing inside the tbody element is a tr element, and if the element is not immediately preceded by a tbody thead, or tfoot element whose end tag has been omitted.

A tbody element’s end tag may be omitted if the tbody element is immediately followed by a tbody or tfoot element, or if there is no more content in the parent element.

So you can actually omit it if your code met the above conditions, otherwise it is needed.

As other people pointed out, even if it is needed, and the html parser won't find it because you didn't write it, it will be inserted into the DOM for you, as stated in the html5 specs.

This said, as a rule of thumb, never rely on anyone creating something automatically for you! (see below)

So even if the browser will create it for you, this doesn't mean newer browsers or new version of the same browser will follow the same way, and your code may become broken then.


Also, your JS could be optimized.

$( document ).ready( function(){
    $( "td > input[id]" ).each( function( i, element ){ 
        alert( element.id );
    });
});
  1. Always write semicolons at the end of statements. Don't rely on the JS engine write them for you!!! (see above).

  2. No need to call the jQuery function and create a jQuery object out of element just to call the attr() method to get the id. JavaScript already has the id() method to retrieve the id.

  3. If your actual markup is like the one you posted in your answer, you could write the jQuery selector like this: table input[id]. Or, if you have nested tables td > input[id] like gilly3 suggested.

How to properly use h1 in HTML5

8 votes

Which of the following is the correct way to structure a page:

1) h1 only in header

<header>
    <h1>Site title</h1>
    <nav>...</nav>
</header>
<section>
    <h2>Page title</h2>
</section>

If I use h1 exclusively inside header as the site's title, every page will have the same content for the h1 tag. That doesn't seem very informative.


2) h1 in header and section, for both site and page title

<header>
    <h1>Site title</h1>
    <nav>...</nav>
</header>
<section>
    <h1>Page title</h1>
</section>

I've also seen examples of using h1 more than once, in both header and section tags. However, isn't it wrong to have two titles for the same page? This example shows multiple header and h1 tags http://orderedlist.com/resources/html-css/structural-tags-in-html5/


3) h1 only in section, emphasizing the page title

<header>
    <p>Site title</p>
    <nav>...</nav>
</header>
<section>
    <h1>Page title</h1>
</section>

Lastly, W3 seems to recommend using h1 within the main section element, does that mean I shouldn't use it in the header element?

Sections may contain headings of any rank, but authors are strongly encouraged to either use only h1 elements, or to use elements of the appropriate rank for the section's nesting level.

As I state in my comment and you quote in the W3C, h1 is a heading and not a title. Each sectioning element can have its own heading element(s). You cannot think of h1 as being the title of a page only but as the heading of that particular section of the page. Just like the front page of a newspaper, each article can have its own heading (or title).

Here is a good article on this.

Put CSS and JavaScript in files or main HTML?

8 votes

Although it is always recommended to put JavaScript and CSS code into appropriate files (as .js and .css), most of major websites (like Amazon, facebook, etc.) put a significant part of their JavaScript and CSS code directly within the main HTML page.

Where is the best choice?

http://developer.yahoo.com/performance/rules.html#external

Yahoo (even though they have many inline styles and scripts), recommends making them external. I believe google page speed used to (or still does?) do the same as well.

It's really a logical thing to have them separate. There are so many benefits to keeping CSS and JS separate to the HTML. Things like logical code management, caching of those pages, lower page size (would you rather a ~200ms request for a 400kb cached resource, or a 4000ms delay from having to download that data on every page?), SEO options (less crap for google to look through when scripts/styles are external), easier to minify external scripts (online tools etc), can load them synchronously from different servers....

That should be your primary objective in any website. All styles that make up your whole website should be in the one file (or files for each page, then merged and minified when updated), the same for javascript.

In the real world (not doing a project for yourself, doing one for a client or stakeholder that wants results), the only time where it doesn't make sense to load in another javascript resource or another stylesheet (and thus use inline styles/javascript) is if there's some kind of dynamic information that is on a kind of per-user, per-session or per-time-period that can't be accomplished as simply any other way. Example: when my website has a promotion, we dump a script tag with a small JSON object of information. Because we don't minify and merge multiple files, it makes more sense to just include it in the page. Sure there are other ways to do this, but it costs $20 to do that, whereas it could cost > $100 to do it another way.

Perhaps Amazon/Facebook/Google etc use so much inline code is so their servers aren't taxed so much. I'm not too sure on the benchmarking between requesting a 1MB file in one hit or requesting 10 100KB files (presuming 1MB/10 = 100KB for examples' sake), but what would be faster? Potentially the 1MB file, BUT smaller requests can be loaded synchronously, meaning each one of those 10 requests could come from a separate server/domain potentially, thus reducing overall load time.

Further, google homepages for example seem to dump a JSON array of information for the widgets, presumably because it compiles all that information from various sources, minifies it, caches it, then puts in on the page, then the javascript functions build the layout (client side processing power rather than server-side).

Detect which word has been clicked on within a text

8 votes

I am building a JS script which at some point is able to, on a given page, allow the user to click on any word and store this word in a variable.

I have one solution which is pretty ugly and involves class-parsing using jQuery: I first parse the entire html, split everything on each space " ", and re-append everything wrapped in a <span class="word">word</span>, and then I add an event with jQ to detect clicks on such a class, and using $(this).innerHTML I get the clicked word.

This is slow and ugly in so many ways and I was hoping that someone knows of another way to achieve this.

PS: I might consider running it as a browser extension, so if it doesn't sound possible with mere JS, and if you know a browser API that would allow that, feel free to mention it !

A possible owrkaround would be to get the user to highlight the word instead of clicking it, but I would really love to be able to achieve the same thing with only a click !

The only cross-browser (IE < 8) way that I know of is wrapping in span elements. It's ugly but not really that slow.

This example is straight from the jQuery .css() function documentation, but with a huge block of text to pre-process:

http://jsfiddle.net/kMvYy/

Here's another way of doing it (given here: jquery capture the word value ) on the same block of text that doesn't require wrapping in span. http://jsfiddle.net/Vap7C/1

Add to innerHTML without destroying form contents

5 votes

I have a form that is generated via ajax based of a multi-file uploader (swfupload). It adds more form elements to a given dom element upon the completion of each file uploaded. This thus gives me a problem. If i selected 5 files to upload, the first file will generate a form which I will start entering data in, however, when the 2nd file is completed uploading, it clears the previous entered data in the form elements and also appends the 2nd form elements.

I think this is because im using:

document.getElementById('test').innerHTML = document.getElementById('test').innerHTML + newformelements;

I think doing the above doesn't keep any entered data in the forms, just the HTML itself.

So, how can I append to this element without destroying what has been put into form fields already? The number of possible children is dynamic based of the multi-uploader.

Are you open to use jquery? If yes then You can easily do something like this

$("#divid").append("html you want to append");

CSS alignment problem

5 votes

How can I make my registration fields like this

enter image description here

How can I achieve this via CSS? I mean, that my textboxes should be aligned from label's end to the page's end...

EDIT

Here is my view part

<div id="member-search">

<h5>Last Name:</h5>
@Html.TextBox("member-last-name")
</div>
<div>
<h5>Pass:</h5>
@Html.TextBox("member-pass")
</div>

<input type="submit" value="Search" class="button"/>
</div>

In CSS I tried a lot, but with no success. width:auto doesn't help and I don't find solution for this. Thanks for help.

With changes to your view you can achieve this. My answer is based on the following answer: How to make text input box to occupy all the remaining width within parent block?

You can look at the modified version of the answer at http://jsfiddle.net/626B2/63/

HTML:

<div id="parent">
    <div id="inner">
        <label>UserName</label><span><input id="text" type="text" /></span>
    </div>
    <div id="inner">
        <label>pass</label><span><input id="text" type="text" /></span>
    </div>
    <input id="submit" type="button" value="Submit" />
</div>

CSS:

#inner {
    display: table;
    width: 100%;
}
label {
    display: table-cell;
    white-space:nowrap;

}
span {
    display: table-cell;
    width: 100%;
    padding: 0px 10px;
}
#text {
    width: 100%;
}