Text Fields
There is a history of great text-centric applications on Palm smartphones. Palm OS Classic included a whole new writing system, Graffiti, to provide simple, effective tools for entering and editing text, and among the Treo's hallmarks were a terrific thumbable keyboard and a system optimized for messaging and email applications. So naturally, HP webOS has a simple, yet powerful text widget to embed text in your applications.
This section will start with the TextField, the base text widget that supports all general text requirements: single or multiline text entry, with common styles for labels, titles, headings, body text, line items and item details. The editing tools include basic entry and deletion, symbol and alternate character sets, cursor movement, selection, cut/copy/paste and auto text correction. Chances are the TextField will address your text needs, but if not, there are three additional specialized widgets:
- PasswordField - handles passwords or other confidential text input
- FilterField - supports type-down filters of a long list or other set of data
- RichTextEdit - a multiline text field that supports simple text styles (bold, italic and underline)
In all of the text widgets, the framework will handle all user interactions with the text field, returning the entered string when the field loses focus. Mojo text fields are smart text fields by default. Auto-capitalization and correction for common typing mistakes is performed on all field unless you disable this feature; see Using Smart Text Features for more details.
Every text field is declared and instantiated following the convention for Mojo widgets. The widget is declared in your scene's view file in a DIV with the x-mojo-element attribute set to the widget's name and a unique id, which is used in your scene controller's setupWidget method.
TextField
The TextField widget provides both single and multiline incarnations, based on an attribute setting. The widget's main goal is to extend the default behavior of the input type="text" HTML element with hint text, focus behavior, truncation, and a host of other additions (see the API guide for more information).
In both incarnations, the widget will generate a Mojo.Event.propertyChange event when it loses focus. The contents of the field will be passed to your event handler in the event.value and as an update to the widget's model.value. The framework will automatically blur a TextField widget when the user taps anywhere else on the scene, even if the location tapped is not focusable. If you want to keep your TextField focused in those instances:
//remember to clean up a document listener in your scene assistant's cleanup function!!!! this.sceneTapped = this.sceneTapped.bind(this); this.controller.listen(this.controller.document, Mojo.Event.tap, this.sceneTapped); this.textFieldWidget = this.controller.get('textfield'); sceneTapped: function(tapEvent) { //if something that is not the textfield widget or a child of //the textfield widget got the tap, call prevent default to //stop the textfield widget from blurring if (tapEvent.target !== this.textFieldWidget && !tapEvent.target.up('div#'+this.textFieldWidget.id)) { tapEvent.preventDefault(); } }
The TextField is another in the set of widgets that will allow you to provide a name (in attribute textFieldName) to make the use of form serialization and data uploading simple. To get the most out of the TextField widget, we recommend you use the styles presented in the user interface guidelines.
Hint Text
The TextField allows you to provide hint text that the user will see until they enter text. The TextField widget will control when to show or hide the hint text, including all cases of cut, copy, and paste and special character entry.
Single-line TextField
The TextField widget defaults to the single-line implementation. The single-line TextField allows the user to scroll back and forth horizontally. When blurred, the TextField value will automatically display only the number of characters that fit in the allowed width, replacing the extra characters with an ellipsis.
To set up a basic TextField for a username that starts out empty:
var attributes = { textFieldName: 'username', hintText: 'Enter Your Username', modelProperty: 'value }; this.model = {}; this.controller.setupWidget('textField', attributes, this.model);
Watch for a property change event to see user updates. Use the original event to ignore property changes caused by tapping elsewhere on the screen.
this.controller.listen('textField', Mojo.Event.propertyChange, this.changed.bind(this)); changed: function(propertyChangeEvent) { var originalEvent = propertyChangeEvent.originalEvent; if (originalEvent.type === 'blur') { //Ignore this event } else { Mojo.Log.info("The user made a property change event. This must be the result of the user pressing the enter key"); } }
Mutiline TextField
If you set multiline to true to in the TextField widget attributes, you will get an editable input field that will automatically grow vertically to fit its contents as keys are typed. To limit the amount the TextField will grow vertically, set limitResize to true in the attributes and set a max-height on the div that instantiates the TextField widget.
The example below creates a multiline TextField that will never take up more than 240px of vertical space in your scene. Once the user enters enough content in the field to make it grow to more than 240px, the content will start to scroll.
HTML:
<div id="multilineTextField" x-mojo-element="TextField" style="overflow: hidden; max-height:240px;"></div>
Scene Assistant:
var attributes = { textFieldName: 'notes', hintText: 'Enter a Note', modelProperty: 'value, multiline: true, limitResize: true }; this.model = {}; this.controller.setupWidget('multilineTextField', attributes, this.model);
PasswordField
If you need a text field to use for passwords or some other type of confidential information, the PasswordField provides many of the TextField widget's features, but masks the display. Any entered text is displayed as a bullet, or "?" character. As with the TextField, the framework handles all of the editing logic within the field and generates a Mojo.Event.propertyChange event when the field has been updated. Unlike the TextField widget, the PasswordField may only have a single line.
Similar to TextField, you specify the location in your scene's view file in a DIV with x-mojo-element="PasswordField" and a unique id, then call your scene controller's setupWidget method with that id. The widget takes a set of attribute properties, all of which are optional, and a model property to hold the text. Other optional attribute properties enable you to specify a name or class for the password field element or change the model property name.
To make a password field:
var attributes = { hintText: 'Enter Password', modelProperty: 'value' }; this.model = {}; this.controller.setupWidget('password', attributes, this.model);
FilterField
If you need a type-down filter for the contents of a list, you can use the FilterField. It can be applied to any case where you want to process the field contents and update some onscreen elements based on the entered string. After setting up the widget, add a listener on the FilterField element for the Mojo.Event.filter* event that best meets your needs.
The FilterField will capture keys typed by the user whenever there is not another element that accepts keyboard input is focused. If you do not always want to filter, for instance when there is no available data to display, you can disable the FilterField widget and it will hide and stop accepting keyboard input.
The FilterField wraps the logic of delaying updating your scene assistant of a filter string until some pause after the user has finished typing a key. The algorithm works like this:
- User types key.
- Framework sets up a filter function to send an event after DELAY miliseconds.
- User types another key.
- Framework cancels first delayed function, and creates a new instance of the delayed function.
- DELAY miliseconds pass without the user entering any new keys.
- The filter function fires and sends an event to your scene assistant.
To create a FilterField that notifies you of the current state of user entered text after every 500ms pause:
var attributes = {delay: 500}; this.controller.setupWidget('filterfield', attributes); //does not require a model this.controller.listen('filterfield', Mojo.Event.filter, this.filter.bind(this)); filter: function(filterEvent) { Mojo.Log.info("The user has typed the following filter query " + filterEvent.filterString); }
If you are going to be using the FilterField to filter contents displayed in a List widget, consider using the FilterList instead. The FilterList combines the functionality of the List widget and FilterField into one widget and provides all the APIs you need for most basic data filtering.
RichTextEdit
There is a simple RichTextEdit widget that behaves exactly like a multiline text field, but in addition supports applying Bold, Italic and Underline styles to arbitrary runs of text within the field. You declare a x-mojo-element="RichTextEdit" DIV in your scene and set it up in your assistant without attributes or a model.
Set up the widget:
this.controller.setupWidget('message', {} , {});
To put editable, formatted contents into the RichTextEdit widget:
this.controller.get('message').innerHTML = "<b>This is some content that starts in the RichTextEdit widget.</b>";
Read the contents of the RichTextEdit field:
var theMessageBody = this.controller.get('message').innerHTML;
To enable the styling, enable the RichTextEditMenu property in the AppMenu (see Menus for information on the App Menu). If you aren't otherwise enabling the App Menu, you can use this line of code:
this.controller.setupWidget(Mojo.Menu.appMenu, {richTextEditMenu: true}, {});
This enables the Bold, Italic and Underline menu options, which when selected will apply that style to the current text selection if it is in a RichTextEdit widget.
Known Issues
- For now, you have to use the blur event and pull the text content from the RichTextEdit's DOM element.
- There is a fairly basic version of this widget in the current SDK and it will likely change substantively before SDK release.