Form.focusFirstElement

0 views
Skip to first unread message

Matt Raible

unread,
Jan 23, 2007, 2:02:24 AM1/23/07
to Ruby on Rails: Spinoffs
It seems like there's a bug with Form.focusFirstElement. If I have a
submit button at the top of my form, it's selected first, rather than
an input field. Should prototype.js be changed from:

findFirstElement: function(form) {
return $(form).getElements().find(function(element) {
return element.type != 'hidden' && !element.disabled &&
['input', 'select',
'textarea'].include(element.tagName.toLowerCase());
});
},

to:

findFirstElement: function(form) {
return $(form).getElements().find(function(element) {
return element.type != 'hidden' && element.type != 'submit' &&
element.type != 'button' && element.type != 'reset' &&
!element.disabled &&
['input', 'select',
'textarea'].include(element.tagName.toLowerCase());
});
},

?

Thanks,

Matt

Christophe Porteneuve

unread,
Jan 23, 2007, 3:20:24 AM1/23/07
to rubyonrail...@googlegroups.com
Actually I'm not sure it should. We can envision forms with just a
submit button (e.g. confirmation forms of some kind), which would
benefit from focusFirstElement encompassing submits.

On the other hand, I believe it would make a lot of sense to have
findFirstElement rely on tabindex attributes when they exist, which
would provide spec consistency and maximum flexibility for page developers.

This may be better discussed on the Core list.

--
Christophe Porteneuve a.k.a. TDD
"[They] did not know it was impossible, so they did it." --Mark Twain
Email: t...@tddsworld.com

Martin Bialasinski

unread,
Jan 23, 2007, 5:12:31 AM1/23/07
to rubyonrail...@googlegroups.com
On 1/23/07, Christophe Porteneuve <t...@tddsworld.com> wrote:

> On the other hand, I believe it would make a lot of sense to have
> findFirstElement rely on tabindex attributes when they exist, which
> would provide spec consistency and maximum flexibility for page developers.

This is an excellent idea.

RobG

unread,
Jan 23, 2007, 7:31:43 AM1/23/07
to Ruby on Rails: Spinoffs

If you mean consistency with the HTML spec in regard to navigation of
elements within forms, that will likely require that the
form.getElements method is re-written to return elements in the right
order.


>
> This is an excellent idea.

Maybe, but difficult to implement in Prototype.

The findFirstElement method is unreliable because it is dependent on
the results of form.getElements(), which, as pointed out in another
thread, does not return results in the order they are coded in the
document unless the elements in the form are organised (probably by
chance) in the same order as that used in Form.Element.Serializers.

One solution is to use the form's elements collection, but since that
is unreliable in IE with dynamic forms, it may be better to walk down
the DOM tree to find the elements in the correct order.

It also seems reasonable that if you are going to go to the length of
getting all the tabindexes and finding the lowest one, as well as
keeping all the elements in the right order, that you will also check
if the elements are visible by looking at their (possibly inherited)
CSS visibility and display property values, and finally ignoring those
that are readonly.

And should elements that can't be successful (e.g. those with no name
attribute) be ignored?

All that seems an amazing amount of work, and will likely still not
identify the "right" element in some cases. The element in the page
that should get focus (if it needs to be set programatically) must be
known at the time the page is generated or updated. In that case, it
is much simpler to use something like:

$('elementID').focus();

or

$('form').elements[0].focus();

--
Rob

Martin Bialasinski

unread,
Jan 23, 2007, 8:36:14 AM1/23/07
to rubyonrail...@googlegroups.com
On 1/23/07, RobG <rg...@iinet.net.au> wrote:

> The findFirstElement method is unreliable because it is dependent on
> the results of form.getElements(), which, as pointed out in another
> thread, does not return results in the order they are coded in the
> document

32 return $A($(form).getElementsByTagName('*')).inject([],
33 function(elements, child) {
34 if (Form.Element.Serializers[child.tagName.toLowerCase()])
35 elements.push(Element.extend(child));
36 return elements;
37 }

That looks like it returns them in order.

> One solution is to use the form's elements collection, but since that
> is unreliable in IE with dynamic forms,

It is? Interesting. Do you have a reference for this?

> that you will also check
> if the elements are visible by looking at their (possibly inherited)
> CSS visibility and display property values,

I don't know, that looks like overkill. How far should that go? As a
real-live case, a container with a label and the input whould be made
hidden, not the input alone, so you would have to check for this as
well.

> and finally ignoring those that are readonly.

There is a "!element.disabled" condition present.

> And should elements that can't be successful (e.g. those with no name
> attribute) be ignored?

Sometimes you want this, sometimes you don't.

> All that seems an amazing amount of work, and will likely still not
> identify the "right" element in some cases.

I believe, it does not have to work in all imaginable cases. 80/20 rule.

> The element in the page
> that should get focus (if it needs to be set programatically) must be
> known at the time the page is generated or updated.

I guess in most cases you know it and the simple solutions will work.

But you also have real world cases like mine. I have a object
hierarchy with a showForm() method in the root class that calls the
_getForm() method implemented by each class. Then, in showForm(), I
insert the returned structure into the DOM, focus the first form
control etc.

Of cause, I could change this so I know the ID of the first element,
but I like the current separation of duties.

Speaking of real world usage: now that I think about it, when would
tab-index be used?

- As the original poster requests, to focus a button at the top of the
form. ("creative use" of z-index instead of a introducing a "include
submits" option to focusFirstElement() )

- To focus a submit button at the bottom of a form that got filled out
with reasonable defaults. Think a delivery address pre-filled with
data from a previous transaction. The user has to just press return to
submit.

The tab-index would basically be used as a override for cases where
focusFirstElement() does not do the right thing.

I think it is not a bad idea. Adds flexibility.

Bye,
Martin

RobG

unread,
Jan 23, 2007, 11:43:12 AM1/23/07
to Ruby on Rails: Spinoffs
Martin Bialasinski wrote:
> On 1/23/07, RobG <rg...@iinet.net.au> wrote:
>
> > The findFirstElement method is unreliable because it is dependent on
> > the results of form.getElements(), which, as pointed out in another
> > thread, does not return results in the order they are coded in the
> > document
>
> 32 return $A($(form).getElementsByTagName('*')).inject([],
> 33 function(elements, child) {
> 34 if (Form.Element.Serializers[child.tagName.toLowerCase()])
> 35 elements.push(Element.extend(child));
> 36 return elements;
> 37 }
>
> That looks like it returns them in order.


The function I looked at was:

getElements: function(form) {
form = $(form);
var elements = new Array();

for (var tagName in Form.Element.Serializers) {
var tagElements = form.getElementsByTagName(tagName);
for (var j = 0; j < tagElements.length; j++)
elements.push(tagElements[j]);
}
return elements;
},

in Prototype 1.5 rc1 which doesn't return them in the correct order -
it seems to have been fixed in 1.5.0. Why does Prototype use its
lengthy and (to me) very clumsy method rather than the elements
collection?


> > One solution is to use the form's elements collection, but since that
> > is unreliable in IE with dynamic forms,
>
> It is? Interesting. Do you have a reference for this?

When using DOM methods to add form controls, IE doesn't properly add
the name attribute so you can't use it to reference them with the
elements collection.

>
> > that you will also check
> > if the elements are visible by looking at their (possibly inherited)
> > CSS visibility and display property values,
>
> I don't know, that looks like overkill. How far should that go? As a
> real-live case, a container with a label and the input whould be made
> hidden, not the input alone, so you would have to check for this as
> well.

No, you need to check the computed/current style of the element. And
just how far you go is exacly my point.


>
> > and finally ignoring those that are readonly.
>
> There is a "!element.disabled" condition present.

readonly != disabled.

>
> > And should elements that can't be successful (e.g. those with no name
> > attribute) be ignored?
>
> Sometimes you want this, sometimes you don't.

Precisely, so how does findFirstElement handle that?

>
> > All that seems an amazing amount of work, and will likely still not
> > identify the "right" element in some cases.
>
> I believe, it does not have to work in all imaginable cases. 80/20 rule.

So how about a comment somewhere that explains its limits? There are
proably good reasons to not skip disabled or hidden elements - if you
use it to disable the first element in the form, it will subsequently
skip that element if you try to use it to re-enable the element.

>
> > The element in the page
> > that should get focus (if it needs to be set programatically) must be
> > known at the time the page is generated or updated.
>
> I guess in most cases you know it and the simple solutions will work.
>

[...]


> Speaking of real world usage: now that I think about it, when would
> tab-index be used?

Rarely, I didn't suggest it.

>
> - As the original poster requests, to focus a button at the top of the
> form. ("creative use" of z-index instead of a introducing a "include
> submits" option to focusFirstElement() )

No, the request was to focus on the first text input and skip the
button. The fastest way to do that is to loop over the elements
collection until the first input type text is found
(getElementsByTagName might be faster if there are lots of non-input
elements at the start of the collection). I don't think any general
function is going to provide such fine control without a large number
of paramters and good documentation.

>
> - To focus a submit button at the bottom of a form that got filled out
> with reasonable defaults. Think a delivery address pre-filled with
> data from a previous transaction. The user has to just press return to
> submit.

So the user fills in the first input, hits tab and goes straight to the
submit button. But that has nothing to do with whether
findFirstElement is useful for the OP.

>
> The tab-index would basically be used as a override for cases where
> focusFirstElement() does not do the right thing.

But how does anyone know what "the right thing" is? The function is
called "findFirstElement", it seems to return the first non-disabled,
non-hidden element - which may not be the first element in a good
percentage of cases.


--
Rob

Martin Bialasinski

unread,
Jan 23, 2007, 6:19:19 PM1/23/07
to rubyonrail...@googlegroups.com
On 1/23/07, RobG <rg...@iinet.net.au> wrote:

> Why does Prototype use its
> lengthy and (to me) very clumsy method rather than the elements
> collection?

Beats me.

> > > One solution is to use the form's elements collection, but since that
> > > is unreliable in IE with dynamic forms,
> >
> > It is? Interesting. Do you have a reference for this?
>
> When using DOM methods to add form controls, IE doesn't properly add
> the name attribute so you can't use it to reference them with the
> elements collection.

Well, anyone not using builder.js or some other lib should know to use
the createNode(string) IE-method.

But: The form control does not need a name attribute to be part of
elements, if I read my sources correctly. Or is this another IE bug?

> > I don't know, that looks like overkill. How far should that go? As a
> > real-live case, a container with a label and the input whould be made
> > hidden, not the input alone, so you would have to check for this as
> > well.
>
> No, you need to check the computed/current style of the element.

And how would you do this without walking the DOM?
document.defaultView.getComputedStyle() will tell you if the element
is visible according to its own style declaration. But it will not
tell you that the element is not visible becaue one of its parents is
not visible. At least according to my quick tests.

> > > and finally ignoring those that are readonly.
> >
> > There is a "!element.disabled" condition present.
>
> readonly != disabled.

Oh yes, my bad. Should be checked as well.

> There are
> proably good reasons to not skip disabled or hidden elements - if you
> use it to disable the first element in the form, it will subsequently
> skip that element if you try to use it to re-enable the element.

You are speaking about findFirstElement(), right? Yes, the way the
function is described currently this is the case. It is a function
that is very specific in its scope.

There is no design documentation describing the intention behind the
function, so it is rather difficult to tell right from wrong. "Return
the first input where the user can enter some data" or something.
findFirstElement() by the letter of the name would be
form.elements[0].

And I wonder if anyone actually uses findFirstElement() somewhere and
to what purpose (why one wants a reference to the first form control?
And without a iterator like findNextElement?). Real life usage, not
hypothetical cases. IIRC, it was introduced during a refactoring of
focusFirstElement() and looks designed specifically for
focusFirstElement().

> > - As the original poster requests, to focus a button at the top of the
> > form. ("creative use" of z-index instead of a introducing a "include
> > submits" option to focusFirstElement() )
>
> No, the request was to focus on the first text input and skip the
> button.

I mixed that up. Well, then it would be a substitute for a "do not
include submit/reset/button" option.

> I don't think any general
> function is going to provide such fine control without a large number
> of paramters and good documentation.

Agreed.

> > The tab-index would basically be used as a override for cases where
> > focusFirstElement() does not do the right thing.
>
> But how does anyone know what "the right thing" is?

Documentation. Once the default case is specified, addressing
readonly, disabled, input type, etc.

Reply all
Reply to author
Forward
0 new messages