Closed
Bug 150590
Opened 22 years ago
Closed 22 years ago
should be able to type words into <select> - incremental search for item
Categories
(Core :: DOM: UI Events & Focus Handling, enhancement)
Core
DOM: UI Events & Focus Handling
Tracking
()
VERIFIED
FIXED
People
(Reporter: joost, Assigned: yuanyi21)
References
Details
Attachments
(2 files, 2 obsolete files)
22.02 KB,
image/png
|
Details | |
7.62 KB,
patch
|
john
:
review+
bryner
:
superreview+
|
Details | Diff | Splinter Review |
(IE on Macintosh has this behaviour, and it's nice. I think Moz should have it too.) 1. Open any page with an HTML form that has SELECT fields 2. use tab to go to the select field 3. enter a character a-z. input jumps to option starting with character 4. enter words like 'mozilla' in the input. input jumps to options starting with 'm', 'o', 'z' etcetera. Better behaviour would be to jump to the option named 'mozilla' (if any). The delay could be set to 0.5 sec or something.
Comment 1•22 years ago
|
||
-> keyboard navigation
Assignee: rods → aaronl
Status: UNCONFIRMED → NEW
Component: HTML Form Controls → Keyboard Navigation
Ever confirmed: true
QA Contact: tpreston → sairuh
Summary: should be able to type words into input type=select → should be able to type words into <select>
Comment 2•22 years ago
|
||
We already do this! Do you have a testcase where we don't?
Comment 3•22 years ago
|
||
Aaron: check component select box for this bug. When I focus it and write Java, selection is jumping from actual item to Java API for DOM, then to Accessibility APIs, then to Viewer App and finally again to Accessibility APIs.
Component: Keyboard Navigation → Accessibility APIs
Comment 4•22 years ago
|
||
Ok, right. I agree fully. However, I think we might want to do this work on XBLFC based selects only, since the old form controls are going away. CC'ing Sun's brower China accessibility task force, since they did similar work for XUL selects.
Blocks: atfmeta
Summary: should be able to type words into <select> → should be able to type words into <select> - incremental search for item
Yes, I have done that for xul <tree>. It can be ported to XBL <select> easily. Once the XBL form control replaced the old one, I'll bring my patch here.
Assignee: aaronl → kyle.yuan
Comment 6•22 years ago
|
||
Weird. I clicked on a <select> on this page (bugzilla.moz), then right click on the drop down menu, for some reason the popup menu consistantly shows up some distance away from the top-left corner of the content area (away from where the pointer is). I suspect this is a dupe, but couldn't find a bug report for this. Anyone?
You mean the position of popup menu is sometimes wrong? I know that could be a bug of gtk module. I can reproduce that on Solaris when the sidebar opened. Also change the component to keyboard navigation.
Component: Accessibility APIs → Keyboard Navigation
Comment 8•22 years ago
|
||
?irrevelent attachment? moz 2002061908, New Classic 1.1 theme, win98 bug always reproduceable on this end
Comment 9•22 years ago
|
||
Could you create a new bug for comments about the popup menu being in the wrong position, please (or use the existing one?). They aren't relevant to this bug, so it's just spam. :-(
Assignee | ||
Comment 10•22 years ago
|
||
*** Bug 157569 has been marked as a duplicate of this bug. ***
Comment 11•22 years ago
|
||
*** Bug 163532 has been marked as a duplicate of this bug. ***
Comment 12•22 years ago
|
||
*** Bug 167949 has been marked as a duplicate of this bug. ***
Reporter | ||
Comment 13•22 years ago
|
||
Is it possible to borrow code from 'Type Ahead Find'? The functionality is not that dissimilar. And to answer post #2 - no, we don't currently do this.
Comment 14•22 years ago
|
||
Is this a dup of bug 79035
Comment 15•22 years ago
|
||
I would not say that this is a _dup_ of bug 79035 as bug 79035 also suggests that the set of options i restricted to elements that fit the search e.g. if you type 'c' only option beginning with c are displayed. IMHO a nice feature as the drop down lists get more clear with less items.
Comment 16•22 years ago
|
||
We can't borrow any code for typeaheadfind for this. Sorry, they're dealing with completely different data structures. My earlier comment about waiting for XBLFC seems irrelevant now, since it is unclear if we will ever use XBLFC because of performance issues.
Assignee | ||
Comment 17•22 years ago
|
||
I think this wouldn't be a difficult one. If we don't need to wait the XBLFC, I'll try to fix this by this weekend.
Status: NEW → ASSIGNED
Comment 18•22 years ago
|
||
We don't need to wait until XBLFC, no :)
Assignee | ||
Comment 19•22 years ago
|
||
migrate some my previous work for menu/listbox/tree. seeking r=.
Comment 20•22 years ago
|
||
Comment on attachment 99036 [details] [diff] [review] patch to enable incremental typing navigation Good patch, Kyle, even if the review seems long :) >Index: html/forms/src/nsListControlFrame.cpp >=================================================================== >@@ -3300,6 +3300,9 @@ >+ // if we are not doing a incremental finding, the mIncrementalString should be cleared >+ PRBool isIncrementalFinding = PR_FALSE; didIncrementalSearch is a better name I think. And the comment here should read more like: // Whether we did an incremental search or another action Transfer the comment here to the place where you actually clear mIncrementalString. >@@ -3408,29 +3411,50 @@ > ... >+ mIncrementalString.SetLength(mIncrementalString.Length() - 1); Should be mIncrementalString.Truncate(mIncrementalString.Length() - 1) ... SetLength is deprecated. > ... >+ return NS_OK; >+ } >+ >+ static DOMTimeStamp lastKeyTime = 0; Please make this a global variable, and clear it in ComboboxFinish(). Otherwise it will not get cleared when the combobox rolls up and the search could be transferred to a new combobox. I like the idea of making it global, BTW, smart :) There are enough changes in the next set of code that I felt it would be best if I illustrated with some (untested but hopefully working) code. Take the code or make your own if you want, it's just a demonstration :) Make sure you do comments though. The review comments with [changed above] in front of them have been incorporated into this code. EXAMPLE CODE ============ DOMTimeStamp keyTime; aKeyEvent->GetTimeStamp(&keyTime); // Incremental Search: if time elapsed is below INCREMENTAL_SEARCH_KEYPRESS_TIME, // append this keystroke to the search string we will use to find options and start // searching at the current keystroke. Otherwise, // Truncate the string if it's been a long time since our last keypress. if (key - gLastKeyTime > INCREMENTAL_SEARCH_KEYPRESS_TIME) { mIncrementalString.Truncate(); } gLastKeyTime = keyTime; // Determine where we're going to start reading the string // If we have multiple characters to look for, we start looking *at* the // current option. If we have only one character to look for, we start looking // *after* the current option. Exception: if there is no option selected to // start at, we always start *at* 0. PRInt32 startIndex; GetSelectedIndex(&startIndex); if (startIndex == kNothingSelected) { startIndex = 0; } else if (mIncrementalString.IsEmpty()) { startIndex++; } // Append this keystroke to the string. mIncrementalString.Append(PRUnichar((unsigned char)charCode)); ================ >+ nsAutoString pressKey(NS_STATIC_CAST(PRUnichar, charCode)); [changed above] Don't do that. Just Append() the character below, or Truncate() / Append() if necessary. >+ if (keyTime - lastKeyTime > 1000) [changed above] This time should be a constant, maybe #define INCREMENTAL_SEARCH_KEYPRESS_TIME. We need to get someone in here to advise on how long it should be, but we can do that once the rest is ironed out. Is 1 second normal for this kind of thing? >+ mIncrementalString = pressKey; >+ else if (mIncrementalString != pressKey) >+ mIncrementalString += pressKey; [changed above] What happens if the user presses the same key several times in a row on purpose searching for "aaa"? Is this really advisable? I think one should always append the key. >+ lastKeyTime = keyTime; > >+ PRInt32 selectedIndex = -1, start = 1; [changed above] selectedIndex should be named startIndex, and startOffset becomes un-needed at that point. > GetSelectedIndex(&selectedIndex); >- if (selectedIndex == kNothingSelected) { >- selectedIndex = 0; >- } else { >- selectedIndex = (selectedIndex+1) % numOptions; [changed above] The trick of leaving selectedIndex at -1 and setting start to 0 is hard to read :) Should be explicit. Also, it's not selectedIndex in this code anymore, it's startIndex. >+ if (mIncrementalString.Length() > 1) { >+ start = 0; >+ if (selectedIndex < 0) >+ selectedIndex = 0; > } [changed above] It would be slightly more efficient if you did this stuff above ... like if you have to truncate, set startOffset = 0. >+ PRUint32 i, index; >+ for (i = 0; i < numOptions; i++) { >+ index = (i + start + selectedIndex) % numOptions; Nice. I like this improvement. It will have to be modified to "index = (i + startIndex) % numOptions" given the changes above, of course. > ... >+ if (Substring(text, 0, mIncrementalString.Length()) == mIncrementalString) { This should be case-insensitive. Substring(...).Equals(mIncrementalString, nsCaseInsensitiveStringComparator()) should work. You may have to #include "nsUnicharUtils.h" to do that, if it doesn't compile. >+ PRBool wasChanged = PerformSelection(index, > isShift, isControl); Please combine the last two lines into one ... >Index: html/forms/src/nsListControlFrame.h >=================================================================== >@@ -430,6 +430,8 @@ >+ nsString mIncrementalString; // for incremental typing navigation Why not make this global along with lastKeyTime? Or at least make it an nsString* that you initialize the first time you use it, I hear object globals have trouble getting initialized and destroyed properly. There can only be one incremental typing going on at a time anyway, and doing it the way you're doing it here will add 12 bytes per select element. When you do that, don't declare an actual static variable, it's apparently non-portable to create a global object. You can create a static nsAString& nsListControlFrame::GetIncrementalString { static nsString incrementalString; return incrementalString; } and it should do everything you need.
Attachment #99036 -
Flags: needs-work+
Assignee | ||
Comment 21•22 years ago
|
||
jkeiser, thank you very much for the line-by-line review. Here is my comment: > >+ if (keyTime - lastKeyTime > 1000) > > [changed above] This time should be a constant, maybe #define > INCREMENTAL_SEARCH_KEYPRESS_TIME. We need to get someone in here to advise on > how long it should be, but we can do that once the rest is ironed out. Is 1 > second normal for this kind of thing? We do have that constant which is defined in http://lxr.mozilla.org/seamonkey/source/layout/xul/base/src/nsMenuPopupFrame.h#60 I'm not sure where is the best place to share that definition? > >+ mIncrementalString = pressKey; > >+ else if (mIncrementalString != pressKey) > >+ mIncrementalString += pressKey; > > [changed above] What happens if the user presses the same key several times in > a row on purpose searching for "aaa"? Is this really advisable? I think one > should always append the key. This is a trick. In the normal case, when user is typing "aaa", he/she wants to cycle through the all options begin with letter 'a' (otherwise, he/she has to wait for 1-2 seconds to do the same work), rather than locate the option "aaa". This is also the behavior of Windows listbox and mozilla listbox/tree/menu. > > ... > >+ if (Substring(text, 0, mIncrementalString.Length()) == mIncrementalString) { > > This should be case-insensitive. Substring(...).Equals(mIncrementalString, > nsCaseInsensitiveStringComparator()) should work. You may have to #include... I did ToLowerCase for both typing char and option text, so that is already case-insensitive. I'll make a better patch addressing your other comments.
Comment 22•22 years ago
|
||
> We do have that constant which is defined in > http://lxr.mozilla.org/seamonkey/source/layout/xul/base/src/nsMenuPopupFrame.h#60 > I'm not sure where is the best place to share that definition? I guess duplicate it for now. I don't think there really is a good place. What would be really good is, if you could put a comment next to both of them referencing the other one so that if someone changes one they also change the other. > > [changed above] What happens if the user presses the same key several times in > > a row on purpose searching for "aaa"? Is this really advisable? I think one > > should always append the key. > This is a trick. In the normal case, when user is typing "aaa", he/she wants to > cycle through the all options begin with letter 'a' (otherwise, he/she has to > wait for 1-2 seconds to do the same work), rather than locate the option "aaa". > This is also the behavior of Windows listbox and mozilla listbox/tree/menu. All rightey then. It seems like inconsistent UI behavior to me but I'm not a trained UI dude :) > I did ToLowerCase for both typing char and option text, so that is already case-insensitive. Ah yes, I see that. That code is *horrible* ... even though it's not your fault, could you please fix it to not call ToLower() on the string and instead use a comparator? It is completely unnecessary to lowercase the entire string just in order to compare the first one or two characters :)
Assignee | ||
Comment 23•22 years ago
|
||
jkeiser, I believe I've addressed all your comments in comment 20 and comment 22. seeking r=
Attachment #99036 -
Attachment is obsolete: true
Comment 24•22 years ago
|
||
Comment on attachment 99196 [details] [diff] [review] new patch addressing jkeiser's comments r=jkeiser with these changes: > + if (GetIncrementalString().Length() != 1 || > + GetIncrementalString().First() != NS_STATIC_CAST(PRUnichar, charCode)) It would be clearer to invert the if -- if (!(... == 1 && ... == ...) > + if (wasChanged) > UpdateSelection(); // dispatch event, update combobox, etc. > - } Please leave the braces around this if. Same below in if (!didIncrementalSearch). In general, always put braces around ifs. It makes things easier to read, people have to do less parsing in their brains. +#define INCREMENTAL_SEARCH_KEYPRESS_TIME 1000 Why are you changing this to 1s? I think 2.5s is actually better than 1s (maybe 2s is a good compromise). If aaronl is OK with it, though, I'm OK too. Please get his approval for this change.
Assignee | ||
Comment 25•22 years ago
|
||
>Please leave the braces around this if. > >Same below in if (!didIncrementalSearch). In general, always put braces around >ifs. It makes things easier to read, people have to do less parsing in their >brains. Some SRs don't like this style, I was asked to get rid of the braces around the 1-line statement :( But anyway, I would like to keep the present code style in this patch. >Why are you changing this to 1s? I think 2.5s is actually better than 1s >(maybe 2s is a good compromise). If aaronl is OK with it, though, I'm OK too. >Please get his approval for this change. This value is mpt's suggestion in bug 133366 comment 35, and it hasn't got objection from Aaron :)
Attachment #99196 -
Attachment is obsolete: true
Comment 26•22 years ago
|
||
Aaron, are you OK with having only 1 second between keystrokes to indicate that a user is using incremental search? (i.e. "type A, wait .5s, type B" searches for AB but "type A, wait 1s, type B" searches for B) Kyle: I'm OK with the 1s change assuming Aaron is, but not the brace change. The sr is not the point here. Module style reigns for bracing and whitespace, and this is where module style is going (yes, it is currently inconsistent within the module but this is where I want it to go). Please change the bracing style. sr's might have asked you to change it in the past because the main style of the module was to not have braces around one line ifs. That is not so here; we have a coherent direction (even if the code does not yet match it). I feel bad that different module have different styles, but some of us are going in this direction. Forms are one of them. I especially don't want the brace changes to go *backwards* to no braces as this patch is doing. r=jkeiser just with the brace change. Go ahead and ask for super-review with just that change, consider it an automatic review :)
Comment 27•22 years ago
|
||
However we determine what the timeout is for XUL menus -- we should do the same thing here.
Assignee | ||
Comment 28•22 years ago
|
||
jkeiser, in my new patch, (attachment 99235 [details] [diff] [review]), I've already followed your style by adding braces for *every* |if|/|else| statement. aaron, now I unified the all timeout value to 1s, are you okay with that? the reason is bug 133366 comment 35.
Comment 29•22 years ago
|
||
Comment on attachment 99235 [details] [diff] [review] new patch r=jkeiser I apologize, I inferred from your statement that you had not changed the bracing. Sorry for the rant :)
Attachment #99235 -
Flags: review+
Assignee | ||
Comment 30•22 years ago
|
||
sorry for my bad expression in comment 25. When I said "keep the _present_ code style", it meant "keep _your_ code style" :)
Comment 31•22 years ago
|
||
I kind of wish the timeout was globally configurable, but I'm okay with it at 1s for now
Comment 32•22 years ago
|
||
Comment on attachment 99235 [details] [diff] [review] new patch >+nsAString& >+nsListControlFrame::GetIncrementalString() >+{ >+ static nsString incrementalString; >+ return incrementalString; >+} >+ I would just make this a (private) static class variable instead of using a getter, since it's not exposed to any other classes. >+ gLastKeyTime = keyTime; >+ >+ // Append this keystroke to the string. >+ // Exception: if user repeats typing a same key, we'll cycle through the all options >+ // begin with that char, rather than append it. Grammar nit- I think this sounds better: Exception: If the user types the same key repeatedly, we'll cycle through all options beginning with that char, rather than appending it. > } >> } // switch >+ >+ // If we didn't an incremental search, clear the string "didn't do" >--- xul/base/src/nsMenuPopupFrame.h 7 Sep 2002 05:37:39 -0000 1.56 >+++ xul/base/src/nsMenuPopupFrame.h 15 Sep 2002 02:32:32 -0000 >@@ -57,8 +57,12 @@ > > #include "nsITimer.h" > >-#define INC_TYP_INTERVAL 2500 // 2.5s. If the interval of two typings is shorter than this, >+#define INC_TYP_INTERVAL 1000 // 1s. If the interval of two typings is shorter than this, I know you didn't introduce this, but this comment sort of bugs me. Maybe change it to "If the interval between two keypresses is shorter than this, ..." sr=bryner with those changes.
Attachment #99235 -
Flags: superreview+
Assignee | ||
Comment 33•22 years ago
|
||
> I would just make this a (private) static class variable instead of using a > getter, since it's not exposed to any other classes. bryner, in comment 20, jkeiser asked me to use the getter instead of using a class variable so that we can save 12 bytes for each <select>. if you are okay with this, I'll go on to checkin this fix. thanks for correcting my bad english :)
Comment 34•22 years ago
|
||
bryner: also, when I suggested making a static nsAutoString outside a function jag, dmose, alecf, etc. slapped me down and said to use it in a function for cross-platform happiness. Otherwise there are apparently issues with initialization and destruction or something.
Comment 35•22 years ago
|
||
I can imagine such a problem happening with a static |nsCOMPtr|, but I don't see how the order of static constructors and destructors could have an effect for strings. Are the string classes not to be used before XPCOM is initialized or after it's shut down?
Comment 36•22 years ago
|
||
Perhaps it's because the initializer for the AutoString won't run at all. Really not sure. jag, alecf, dmose, jst, any comment on the use of "static nsAutoString gMyString;"? One of you told me not to do this but I can't remember who, the discussion was long and involuted :)
Comment 37•22 years ago
|
||
its not complicated: constructors dont always run when a DLL is loaded dynamically... the simple solution is to have something like static nsAutoString* gString; nsAString& getGlobalFoo() { if (!gString) gString = new nsAutoString("blah"); return *gString; } and you could do something similar for setting the string. Then you can access it like CallSomething(getGlobalFoo()) or pos = getGlobalFoo().Find(...);
Assignee | ||
Comment 38•22 years ago
|
||
alec, now the problem is: what do you think about the following code? I use a private static class member as a "getter". +class nsListControlFrame { + ... + static nsAString& GetIncrementalString (); +}; +nsAString& +nsListControlFrame::GetIncrementalString() +{ + static nsString incrementalString; + return incrementalString; +} + or as alternative, does this global variable also work? +static nsAutoString gIncrementalString;
Comment 39•22 years ago
|
||
Just so this doesn't get lost. If you do what alecf suggested you'll need to make sure the global heap allocated ns(*)String is deleted on shutdown.
Comment 40•22 years ago
|
||
kyle: I think that might work, actually. I don't know why I didn't think of it :)
Comment 41•22 years ago
|
||
OK, so it seems like our simplest solution is the one already in the patch :)
Assignee | ||
Comment 42•22 years ago
|
||
checked in!
Status: ASSIGNED → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
Comment 43•22 years ago
|
||
where is the UI for this feature documented? I didn't see anything on http://www.mozilla.org/projects/ui/accessibility/ In particular, I'm wondering if there is a means of finding the next occurance. If a menu contains something like a_word_1 b_word_1 c_word_1 d_word_1 e_word_1 f_word_1 z_really_long_word_goes_here_1 a_word_2 b_word_2 c_word_2 d_word_2 e_word_2 f_word_2 z_really_long_word_goes_here_2 a_word_3 b_word_3 c_word_3 d_word_3 e_word_3 f_word_3 z_really_long_word_goes_here_3 ... it would be nice to type 'z' and then maybe Accel-G a couple of times to get to the third occurance without having to completely spell out z_really_long_word_goes_here_3 Could Accel-G be "stolen" for this purpose while focus is within a select? If not, is there some other means of quickly getting to that third z option? -matt
Comment 44•22 years ago
|
||
The last posting brings back a nice idea into my mind that somebody told me: If it is possible to jump to b_word_x by typing 'b', some people would really like it if all not-b_word_x would be faded out: Like I type 'c' and the list looks like that: c_word_1 c_word_2 c_word_3 Indeed, I understand that some people don't want other option-values to be omitted. That's why the fade-out-feature should be optional. Summarising, for me (from a simple user's perspective), the feature should show the following behaviour: c --> all not-c_words are faded out wait c again --> jumps to the next occurance of c wait c again --> jumps to the next occurance inst del --> complete list a --> first occurance of a b --> first occurance of ab The problem is the 'wait'. When is the 'b' supposed tu follwow the 'a' and when is it supported to replace it? Furthermore, people would like to quickly jump to the next occurance rather than having to wait. Perhaps, we have to forget about jumping to the next occurance by re-typing the same letter and trigger this feature by the enter-key or F3 or cursor-down or some other key that is not supposed to be value of any option-tag. This allows to type words into select-fields and quickly navigate through them. René PS: I hope my discussion isn't off topic, but I have to admit I have not understood all the recent code-postings. PPC: What is Accel-G?
Comment 45•22 years ago
|
||
Accel-G means "accelerator key and G"... On a PC, that's Ctrl-G. On a Mac, that's Command-G. Etc. "Accel" is a platform-neutral way of saying "normal keyboard shortcut character". I like the "remove options" option. Is there a bug filed for that feature request? Regarding the timeout question, there is an existing timelimit in the similar Bug 30088 which could be re-used here. Then the behavior would be consistent. -matt
Comment 46•22 years ago
|
||
Thanks for the explanation. Concerning the time limit, please consider, that if there are long lists, and people want to jump down 20 items, they type ttttttttttttt rather than t-t-t-t-t-t-t-t-t-t-t-t-t-t ('-' indicates a small wait time). If you trigger the jump to the next occurance by F3 or enter, you can spare the wait time. on the other hand, think about your mother in law :-) She looks for e.g. a_word and she types a (look for the next key) _ (look for the next key) w ... What I want to say: It might be difficult for some people not to exceed the time limit when typing words. Please cosider that. René
Assignee | ||
Comment 47•22 years ago
|
||
Re: comment 44, please see comment 21. You can go to the 3rd z_.... just by typing 'z' three times. Re: comment 45, the fade-out feature is good, but it may not be suitable for every situation, for example, if there are some options like: ja jb ... jz ka then someone may want to go jz by pressing 'k' then 'up arrow'. Your new feature will let us lose this 'shortcut'. If you really like this feature, you can file a new bug instead of discussing it in a fixed bug :)
Comment 48•22 years ago
|
||
typing z three times fails to go to the third z_ if there is a 'zzz' in the select. Is there a method which doesn't break in situations like that? -matt
Assignee | ||
Comment 49•22 years ago
|
||
I don't think there is any method can deal with the all situations. But we must guarantee that this feature is suitable for the most common usage.
Comment 50•22 years ago
|
||
http://www.mozilla.org/projects/ui/accessibility/typeaheadfind.html that feature has the same problem, and provides a solution (Accel-G to find again). I think borrowing Accel-G within the menu search would be an ideal solution. If not that, then it at least shows that a solution is possible, and some other method could be used. Not providing a solution just leaves a user wondering "why did they solve this problem in that context, and then ignore it here... it's the same problem". Broken UI is worst when it is only broken in some contexts. At least if it is broken everywhere, you can learn to expect it not to work. -matt
Comment 51•22 years ago
|
||
there's a problem with our current implementation: see bug 144303 We will need an option in drop-down XUL for overriding the default fade-out wait period, e.g. set it to zero.
Comment 52•22 years ago
|
||
vrfy'd fixed with 2002.10.15.08 comm trunk builds.
Status: RESOLVED → VERIFIED
Updated•5 years ago
|
Component: Keyboard: Navigation → User events and focus handling
You need to log in
before you can comment on or make changes to this bug.
Description
•