Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

NaturalTextBox class #191

Open
pyjsorg opened this Issue · 16 comments

1 participant

@pyjsorg
Owner

A new class to provide natural number data entry.
A modified kitchensink file (Text.py) to provide an example of use.

Useful for quantity fields. Offers min/max validation and sets maximum length based on maximum natural possible.

Original issue: http://code.google.com/p/pyjamas/issues/detail?id=528 (December 07, 2010 15:28:07)

@pyjsorg
Owner

From m...@carlroach.com on December 07, 2010 15:53:54:
Has anyone got OS X and a keyboard with numpad I've not tested with this set-up.

@pyjsorg
Owner

From cornelis...@gmail.com on December 07, 2010 17:46:53:
I wonder if you made it a bit to complex for what you want. Why not just catch the change with getText() and fix it on key-up or change. Something like in the attached RestrictedTextBox. Then you don't have figure out how stuff gets into the text box.

Possible invocations:

import re

def testFloat(text):
    try:
        f = float(text)
    except:
        return False
    return text.upper()

text1 = RestrictedTextBox('01234567890')
text2 = RestrictedTextBox(testFloat)
text3 = RestrictedTextBox(re.compile('^[a-h]?[0-9]*[A-Z]*$'))
@pyjsorg
Owner

From m...@carlroach.com on December 07, 2010 18:07:45:
I've tried to make it no more complex than what I need :)

My initial requirements were that no unrestricted characters were to appear at any point - like the HTML5 control.

RestrictedTextBox has that one quirk... that 'bad' characters are displayed for a brief moment. However, it doesn't have additional issues with clipboard pasting or AltGr+6.

I can imagine 'some' feeling that RestrictedTextBox is clunky. And equally, that it is elegant! :) (arguing with those brief appearances being positive ui behaviour)

NaturalTextBox isn't a complete solution because 'bad' chars can get through so I'm inclined to mould your RestrictedTextBox for my app. If in doubt... choose the lesser of two code implementations :)

@pyjsorg
Owner

From m...@carlroach.com on December 07, 2010 18:27:39:
Further testing of RestrictedTextBox...

Due to the use of setText the cursor position in the textbox is lost as after calling setText() the cursor is moved to the end of any text.

Secondly, if I type a 'good' char followed by a 'bad' char, realise and hit backspace then RestrictedText move the bad char and the user removes the good!

Both edge cases but that's where control design bites one!

@pyjsorg
Owner

From m...@carlroach.com on December 07, 2010 18:41:20:
And further...

paste 'bad' chars in using a menu rather than keyboard short-cut and the contents, of course, appear and remain.

Annoyingly I may have to merge the approaches used for event catching to get somewhere. Or abandon it and ask everyone to move to HTML5 browsers :)

@pyjsorg
Owner

From cornelis...@gmail.com on December 07, 2010 21:10:41:
Maybe I can fix the cursor position problem, but for the other problems I don't see a solution (short appearance, backspace, paste from menu). I think that the latter two also are valid for NaturalTextBox (or am I wrong). The paste from menu is only handled when the focus is lost or another key is hit :-(

If you want me to look into the cursor position problem, let me know. I don't have use for this class myself at the moment :-)

@pyjsorg
Owner

From m...@carlroach.com on December 07, 2010 22:23:25:
thanks - I can sort the cursor position out with get/setCursorPos() - provided browsers support it.

you'll be glad to know that handling onInput() will get fired when the contents change and not simply when the control loses focus. Using this I've managed to remove 'bad' chars when they are pasted in. happens fast too.

I'll finish up tomorrow and post what I get done.

@pyjsorg
Owner

From atsep...@gmail.com on December 08, 2010 01:52:52:
Carl,

I'm attaching my NumericTextBox (which I've updated to handle Ctrl+V) as well. It works very similar to yours but accepts all floating numbers. Additionally it allows to specify a function to call upon update (I added this to allow auto-preview in my web app). I figured the functionality was similar enough to post it under the same "issue", pyjamas could benefit from having both classes in it. I'd rather not merge the two to avoid overhead.

@pyjsorg
Owner

From cornelis...@gmail.com on December 08, 2010 06:53:13:
Thanks Alexander.

BTW. Carl/Alexander, after a nights sleep, I even would prefer to see the stuff I type/paste for a short while. It gives me the feedback that I've been corrected and not the feeling that my keyboard is stuck.

Carl, good find (get/setCursorPos() and onInput()). I've played with the idea of setting the focus to the text box if the text is corrected and focus was lost, but I'm not sure about that. Maybe an method onRestriction to be called when the input has been corrected. That method could do nothing or set the focus and can be overridden to do the opposite. That holds also for onInput and onKeyUp, which, if overridden with a do-nothing, make the text box only check on leaving the box. Which is maybe something that other would want. (There's nothing to be changed to facilitate this behaviour).

@pyjsorg
Owner

From m...@carlroach.com on December 08, 2010 11:11:42:
Good points.
I'd looked at IE9Preview, Opera 10, Chrome 8 & Firefox 3.6 to see how they implemented . Note the feature hasn't yet been ratified.

IE9Preview & firefox don't.
Opera & Chrome do.

Opera: displays all characters; if any characters are non-digit they are removed when user clicks spin-up and min or max is displayed (sometime min, sometimes max; a bug?). Opera implements Form validation and catches numbers outside of range on form submission (without some quite clunky language)

Chrome: stops all characters from displaying except for [0-9.+-e] it also filters out pasting of 'bad' chars too in any clipboard pasting. Pasting maintains a sensible cursor position. It does allow multiple '.' & 'e'. In this case, pressing a spin button will correct the content to the nearest value.

It's a shame that this feature hasn't been ratified and ie9 has "had a go" - MS generally design very polished control UIs - as I'd like to see what approach MS take.

It is Chrome's behaviour I am aiming at for Natural numbers. imho it's a clean design with little overhead (e.g. error messages and UI flab).

Having slept on it I was tempted to take Opera's approach... let it all in and deal with it on form submit. Or a half-way... deal with it on lose focus. but the user's attention may well no longer be on the input field. So I'll give it a little more for a Chrome-like solution.

I still think your preference for 'show user where they went wrong and auto-correct it' is a good argument. but it can get difficult to implement - catching onInput() changes the content so quickly one can miss the 'appearance'. and surely it should take the same length of time as for removing a typed char? Fussy yes, but that's UI for you :)

One thought: the approach all browsers take for implementing maxlength is to stop users typing. it's not gameover but it helps (me at least) to see another related area where user input is stopped in its tracks.

On with the coding.

@pyjsorg
Owner

From atsep...@gmail.com on December 09, 2010 00:02:49:
I agree with Carl, it seems cleaner to me when a character does not appear at all rather than flashing shortly, especially since I remember most Desktop applications implementing this the same way.

@pyjsorg
Owner

From m...@carlroach.com on December 09, 2010 00:06:55:
I'll update NumberBox tomorrow

@pyjsorg
Owner

From m...@carlroach.com on December 09, 2010 08:29:35:
I've focused on base10 numbers rather than a general filter for text entry.
NumberBox handles Naturals, Integers and Reals

The control only filters out text using onInput() which dramatically simplifies character matching code. Benefit: it blocks clipboard pasting of non-number characters and AltGr+6 prefixed input. Only one downside: hold down a key that will be blocked and you'll see it flickering in the control. I think, though, that the benefits of this simplified approach outside this one downside.

For those who need such functionality or have time... please take a look. I've modified Text.py from kitchensink for ease of access.

@pyjsorg
Owner

From atsep...@gmail.com on December 09, 2010 20:30:11:
Carl, I can't run your code right now to test it. From the source, however, it looks like your allowable keys logic only sensors on per-character basis and would allow erroneous entries such as these (unless I'm missing something):
12.3.32.432
--5
5--
7-4-
.--.
I see that you later run valueAsNumber to correct this, but that resets the entire string which can be annoying to the user.

@pyjsorg
Owner

From m...@carlroach.com on December 09, 2010 23:57:46:
yes, Atsepkov, you read my code correctly.

I purposely allow users to enter incorrect syntax. This is my reasoning...
1. I wanted the user to feel in control. If they want to place a 2nd decimal point before removing the first they are able to. I followed Google Chrome here that restricts the digits but then leaves it to the user to enter a number (in whatever order they want to).

  1. Even if I want to enforce all restrictions it's not technically possible. min/max can't be done as users type for example.

  2. Reinforcing #1 I haven't seen tighter control than this anywhere. I'm following that convention.

Regarding char by char checking...
1. I can't see a way to otherwise maintain the cursor's position after pastes. For a number box I need nothing more (see above)

Regarding clearing contents
1. I have no strong opinion here. I didn't want valueAsNumber() to return None if the contents were a syntax error (or NaN). I didn't want to complicate form processing.

  1. There is a weakness of doing anything at the onChange() stage as users' attention can be elsewhere so they do not see that the control has a) blank b) been set to a min/max

The third area raises question: a) should the control offer min/max? b) should the control blank the content on lose of focus if contents are NaN or outside a min/max range?

@pyjsorg
Owner

From m...@carlroach.com on December 14, 2010 18:38:04:
Chrome 8.0.555/Safari 5.02 have the autofocus attribute on its own and it works but has the side effect of not displaying some table rows.

Opera 10.63 gets autofocus="true", displays the table rows but doesn't set the focus on the input control nor placeholder text. Opera does display placeholder text if I remove AutoFocus=True from my Python code.

A few web pages refer to odd behaviour with autofocus in browsers.

I'm going to take Luke's advice about shipping something. I'll remove autofocus and required and send an update with the other attributes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.