Posts Tagged ‘html’

IE7 Requires type=”submit” for <button> elements

Friday, October 30th, 2009

If you don’t specify type=”submit” for a <button> element, IE7 (and probably IE6, too) will do nothing when that button is clicked (well, unless you have an onclick handler on that element, of course).

The W3C HTML standard states that the default for a <button> element should be “submit”, but if you want it to work with IE7 or earlier, you’ll have to be explicit about it.

I lost some precious time on this fun bug. I was doing some form validation via the great jQuery Validation plugin and for some reason, the form wasn’t validation in any IE earlier than IE 8.

Of course, since it’s such a pain to debug IE, I had a heckuva time figuring out the source of the bug, because I just assumed it was some weird JavaScript quirk, and didn’t even consider that it could be something as simple as a “missing” element attribute.

Ah well. Hopefully this will help somebody else avoid the same problem.

simple textarea auto-resizer

Friday, April 24th, 2009

Today I was having issues with a textarea resizer (a hacked-up version of SmartArea) that I had been using for a while in a work project. It was working fine for textareas of a certain width, but it got less and less useful as the textareas got less wide, not wrapping lines until it already had scrollbars for a word or two.

It seemed to me that it needn’t be as complex as it was, so I decided to try and write my own, and here’s what I came up with:

function growTextArea(e) {
    if (!this.rows || this.rows < 1) this.rows = 1;
    while (this.clientHeight >= this.scrollHeight && this.rows > 1) this.rows -= 1;
    while (this.clientHeight < this.scrollHeight) this.rows += 1;
}

A working example, embedded using jQuery:

$('#example-resizing-textarea')
    .keyup(growTextArea).keyup();

Type some text in here:

Compatibility

This works for me in Firefox, IE6, IE7, Chrome and Chromium, Safari (for Windows, testing in a Windows VM along with the IEs and Chrome), and Opera 9.62. As you may have noticed I’ve avoided using any JS-library or browser-specific code, so this should work equally well with jQuery, Prototype, or with no library at all.

IE actually gives incorrect values for scrollHeight, but that is easily made up for by using “this.clientHeight >= this.scrollHeight” in the first while loop rather than “this.clientHeight == this.scrollHeight”

Minimum and Maximum rows

If you want to set a minimum and maximum height, it takes a little more work:

function sizeTextArea(min, max) {
    return function(e) {
        if (!this.rows || this.rows < min) this.rows = min;
        while ((this.clientHeight >= this.scrollHeight 
                && this.rows > 1 && this.rows <= max) 
               || this.rows > max) this.rows -= 1;
        while ((this.clientHeight < this.scrollHeight 
                || this.rows < min) 
               && this.rows < max) this.rows += 1;
        if (this.rows == max
            && this.clientHeight < this.scrollHeight) this.style.overflow = 'auto';
        else this.style.overflow = 'hidden';
    }
}

Another example, limited to having between 4 and 8 rows:

var sizer48 = sizeTextArea(4, 8);
$('#example-resizing-textarea')
    .keyup(sizer48).keyup();

Type some text in here, too:

Possible modifications could include using pixel sizes instead of changing the “row” attribute and animating the resizing.

This could easily be packaged into a plugin for jQuery or Prototype, and I might just do that, but right now it’s getting late, so I’m going to sleep instead.

First steps to an Erlang OpenID consumer

Wednesday, January 21st, 2009

I’m working on a little project in Erlang and I wanted to use only OpenID for my authentication. It turns out there is currently no Erlang OpenID consumer library (or if there is, I couldn’t find it).

So I’ve started writing my own. So far I’ve got the first necessary step complete: HTML-based discovery.

I’m starting with version 1.1, simply because it is shorter and requires less (I don’t want to implement the XRI or Yadis protocols just yet).

It turns out that mochiweb comes with an HTML parser, so I used that, since I’m using mochiweb for my application. The parsed HTML comes back as a series of nested tuples of the format {<<”tag”>>, Attributes, Children}, where “tag” is the tagname (the root will be <<”html”>>, for example), Attributes is a proplist of that tag’s attributes, and Children is a list of more tuples of the same format and/or binaries with the contents of text nodes. Everything is represented as binaries, so I use those directly rather than converting between strings and binaries.

Here’s the code which finds the link tags with rel=”openid.server” and rel=”openid.delegate” (if it is there):

get_openid_server(Identifier) ->
    NormalizedIdentifier = normalize_identifier(Identifier),
    case http:request(NormalizedIdentifier) of
        {ok, {_Status, _Headers, Body}} ->
            HtmlTokens = mochiweb_html:parse(Body),
            find_openid_tags(HtmlTokens);
        _ ->
            {error, http_error}
    end.
 
normalize_identifier(Ident = "http://" ++ _Rest) ->
    Ident;
normalize_identifier(Ident) ->
    "http://" ++ Ident.
 
find_openid_tags(HtmlTokens) ->
    case find_tag(<<"head">>, [HtmlTokens]) of
        {<<"head">>, _Attrs, Children, _Rest} ->
            case find_tag_with_attr(<<"link">>, {<<"rel">>, <<"openid.server">>}, Children) of
                not_found ->
                    {error, openid_server_not_found};
                ServerAttrs ->
                    Server = proplists:get_value(<<"href">>, ServerAttrs),
                    case find_tag_with_attr(<<"link">>, {<<"rel">>, <<"openid.delegate">>}, Children) of
                        not_found ->
                            [{server, Server}];
                        DelegateAttrs ->
                            Delegate = proplists:get_value(<<"href">>, DelegateAttrs),
                            [{server, Server}, {delegate, Delegate}]
                    end
            end;
        not_found ->
            {error, no_head_tag}
    end.
 
find_tag(_TagName, []) ->
    not_found;
find_tag(TagName, [{TagName, Attributes, Children} | Rest]) ->
    {TagName, Attributes, Children, Rest};
find_tag(TagName, [{_OtherTag, _Attributes, Children} | Rest]) ->
    find_tag(TagName, Children ++ Rest);
find_tag(TagName, [_Other | Rest]) ->
    find_tag(TagName, Rest).
 
find_tag_with_attr(_TagName, {_AttrKey, _AttrVal}, []) ->
    not_found;
find_tag_with_attr(TagName, Attr = {AttrKey, AttrVal}, Tags) ->
    case find_tag(TagName, Tags) of
        not_found ->
            not_found;
        {TagName, Attributes, Children, Rest} ->
            case proplists:get_value(AttrKey, Attributes) of
                AttrVal ->
                    Attributes;
                _ -> 
                    find_tag_with_attr(TagName, Attr, Children ++ Rest) 
            end
    end.

(the <PIPE>s above should be “|”s and the <SEMI>s should be “;”s. Not sure why the syntax highlighter is doing that to them…

Assuming the above code is put into a module called “openid”, you get the following:

1> openid:get_openid_server("blog.paulbonser.com")
[{server,<<"http://www.livejournal.com/openid/server.bml">>},
 {delegate,<<"http://misterpib.livejournal.com/">>}]
2>

As I said, this is the first step. Hopefully I’ll have some time very soon to get on with the next couple of steps, and then I’ll be done.

Python HTML Layout Engine Progress

Saturday, September 13th, 2008

I’ve made some progress on my Python web browser. It’s nothing earth-shattering at the moment, but it does take all the text from a web page and render it.

It currently treats each element (including the ones in the head, actually, I need to fix that) as an inline text element. It doesn’t quite do proper whitespace compression between elements, either, leading to some multiple spaces in certain places. What it does do nicely is the splitting on lines in reasonable places.

The part I’m working on next is the application of CSS rules to the document. I’m considering a couple of different possibilities for methods of walking the DOM tree and cascading the rules into each element. Either way it ends up boiling down to walking the tree and matching CSS selectors against each element, and applying rules for those elements which match, of course taking into account the specificity of the matching selector to make sure the proper rule ends up taking precidence.

I haven’t sat down and figured the bit O of them yet, but I think it’s going to be a memory vs. speed decision.

Once I have styles applying to elements, I’ll probably work on getting all the standard HTML4 CSS rules rendering properly. After that, it will be on the more thorough block element handling, replaced elements (images, form elements), and probably psuedo-classes and psuedo-selectors.

After that, I dunno… Acid2?

Anyway, that’s me getting ahead of myself. I mean, it doesn’t even render block elements yet (since it has no way of setting an elment to be a block element, due to the whole no CSS being applied yet thing).

If you are curious, you can check it out from my public git repo.

I warn you, the code is not really commented too much (except for in the layout section, there’s a whole outline of how that’s all supposed to work in there). If you want to see the magic of how it renders now, go ahead and run getgoogle.py (which, ironically, doesn’t even get Google at this point, since Google has some JavaScript which it wants to render as text…). You’ll need pygame installed to run it.

I’ll save you some time, though. It looks like this:

But hopefully not for long :)