Chapter 3—JavaScript Components

The Component Store contains over 30 ready-made components for use in Remote Forms and the JavaScript Client. The components are displayed under the JavaScript Components tab in the Component Store when a remote form is open in design mode (assuming the $client property in the remote form is set to kClientJavaScript, which is the default for all new remote forms). In addition, there are a number of alternative controls available under the JavaScript Native Components tab.

You can create your own custom JavaScript components, defined using JSON, which will appear under the JSON Components tab in the Component Store: these are described in the JSON Components chapter.

Example Apps and Code

The JavaScript Apps Gallery on the Omnis website showcases many of the JavaScript Components and provides a sample app which you can download and run in the latest version of Omnis Studio. View the gallery here:

https://www.omnis.net/platform/#jsgallery

or you can use the shortcut: tinyurl.com/jsgallery10

Many of the example apps in the gallery are featured in the example code in this chapter, and many of them also appear under the Samples section in the Hub in the Studio Browser.

In addition, the Applets option under the Hub in the Studio Browser has several sample web apps that use many of the JavaScript Components, including a Contacts manager for recording information about colleagues or friends, a Holidays app for managing annual leave requests, and a Webshop app which has a product catalog and shopping cart. You can examine the remote forms and components in these example apps, and look at the code behind each component: you can double-click on a JavaScript component in design mode to see its code methods in the method editor.

Creating JavaScript Components

To create or add a JavaScript Component to a remote form, you need to open the remote form in design mode and open the Component Store: the latter should open automatically, but you can open it, or bring it to the top, from the main Omnis toolbar (CStore button), or by pressing F3. The JavaScript Components tab (group button) should be selected by default, showing the standard JavaScript Components; there is a number of “native” controls under the JavaScript Native Components tab.

image1

You can Right-click/Cmnd-click on the background of the Component Store and select Large/Small Icons and/or Text to alter the display of the component store, and you can Save the window setup from the same menu to store the layout and positioning of the Component Store.

Before adding any JavaScript components to your remote form, you may want to change the current breakpoint or add a new one. A new remote form has two breakpoints 320 and 768 pixels; you are advised to add components to the larger breakpoint first and then rearrange or resize the components on the smaller breakpoint. You can Right-click on the background of a remote form and choose Copy Layout From Breakpoint to copy the position and size of components from one breakpoint to the current breakpoint.

To create a JavaScript component, you can:

  1. Drag a component icon from the Component Store and drop onto a JavaScript remote form; the component is added at the default size

  2. Double-click on a component icon in the Component Store to add it to a form; the component is added at the default size

  3. Select the component icon in the Component Store and press Return to add it (same effect as double-clicking)

  4. Select the component icon in the Component Store, then in the remote form click and drag the cursor to draw the component the size you want; note some components have a standard size, or the size of some elements are fixed, e.g. the button icon for radio buttons.

Once you have placed the component on the remote form you can resize or re-position it, and set its properties using the Property Manager (if the Property Manager is hidden, press F6 to open it or bring it to the top). The following screen shot shows the Pie Chart example app (available in the Hub under Samples), with the JavaScript Pie Chart component selected; the Property Manager (on the right) shows the properties of the current selected object, under different tabs such as General or Appearance, which could be a class, or in this case, a specific component.

image2

Copying Components

In design mode, you can use the standard Copy/Paste menu options in the Edit menu or Ctrl-C and Ctrl-V keyboard options to copy and paste a component on the same form, or onto a different form. Alternatively, you can hold down the Ctrl key and click and drag a component to make a copy of the component. You can also drag a component from one remote form and drop it onto another remote form to make a copy of a component (for forms with the old kLayoutTypeScreen layout type, the forms must be set to the same value of $screensize to copy objects in this way).

JavaScript Components

The following components are available for JavaScript remote forms under the “JavaScript Components” tab (group button), plus there are a number of “native” components under the “JavaScript Native Components” tab (List, Slider & Switch), also listed here.

Component Description
Activity Control Animated image to display during a long process or Omnis Server activity
Background Control Object you can set to Rectangle, Line, Triangle, or Image
BarChart Control Displays a bar chart based on a list of values
Button Control Standard pushbutton which reacts to clicks
Checkbox Control Check box for on/off values
ComboBox Field combining entry box and droplist
Complex Grid Grid which can display all types of data and formatting
Data grid Control Simple grid for text and numerical data display
Date Picker Control Data picker with touch selection
Device Control Allows access to hardware and services on mobile device
Droplist List that drops down when clicked
Edit Control Standard edit field for data entry or display
File Control Allows end users to upload or download files
HTML Object Object to display HTML content
Hyperlink Control List containing hyperlink style options
Label Object Basic label object
List Control Standard list field for displaying list variable data
Map Control Displays a Google map for specified location(s)
Native List List control with platform dependent appearance
Native Slider Slider control with platform dependent appearance
Native Switch Switch control with platform dependent appearance
Navigation Bar Control Navigation with touch selection
Navigation Menu Object Dropdown menu with hierarchical options
Page Control Allows selection of page pane using touch
Paged Pane Can contain fields on multiple panes
Picture Control Standard field for displaying images
PieChart Control Displays a pie chart based on a list of values
Popup Menu Control A menu that pops up when clicked
Progress Bar Control Shows progress of server process or calculation
RadioGroup Control Displays a group of radio buttons for exclusive selection
Rich Text Editor Control Rich text editor allowing end users to edit and format text
Segmented Control Navigation control with different buttons or “segments”
Slider Control Slider component for setting values
Split Button A button with a droplist of alternative options
Subform Allows you to insert another remote form class as a subform
Switch Control Allows on/off selection; you specify an icon for on/off state
Tab Control Multiple tabs to control selection of page pane
Timer Control Timer object triggers an event at a specified interval
Toolbar Control Toolbar with custom buttons (icons and text), auto overflow and optional side menu
TransButton Control Interactive button with alternate hover image
Tree Control List for displaying hierarchical data or list of options
Video Control Plays a YouTube or other hosted video

Native JavaScript Components

The “JavaScript Native Components” group contains components that have a more familiar or “native” appearance when they are displayed on different mobile platforms – their appearance is rendered in the JavaScript Client using CSS customized for each platform. The different appearance for each platform is handled by Omnis automatically, therefore you only need to setup the component once in design mode. The Native components currently include the Native List, Native Slider, and Native Switch.

When running on a supported device, these controls will render and work in a manner close to a device’s native versions. For example, a native Switch control will look like an iOS switch on an iOS device, an Android switch on an Android device, and so on, while using a single control and set of methods in design mode in your remote form.

JavaScript Remote forms have an Appearance property called $defaultappearance which determines both how a native control is displayed in the design window, and how it would render on non-supported clients (e.g. Desktop browsers). The property is either kAppearanceiOS or kAppearanceAndroid (kAppearanceBlackberry is no longer supported).

The $defaultappearance property can also be switched using the ‘Native Components Display As’ context menu option of a JavaScript Remote Form (right-click on the form to open the context menu). You can also cycle through the values using the keyboard shortcut Ctrl-Shift-N on Windows or Cmd-Shift-N on macOS when the remote form is the top window.

It is recommended that you set $disablesystemfocus property to kTrue for any native controls you have used, to prevent the focus ring being drawn around a controls when it is selected – otherwise the focus ring may interfere with the native appearance.

JavaScript Component Properties

All JavaScript components have their own set of properties which you can view and set in the Property Manager (F6).

$dataname for JavaScript Controls

The variable specified in the $dataname property of a JavaScript component must be an instance variable, or in some cases a column in a row instance variable in the form VarName.ColumnName. The Property Manager will display an error message when you try to assign an invalid $dataname property. (This applies to $dataname as well as other similar properties such as $listname which require a variable.)

Naming JavaScript Controls

When you create a component in your remote form, a name is generated automatically and assigned to the $name property of the component. This is usually in the format <remoteformname>_<component-type>_<number>, such as ‘rftest_edit_1001’ for an edit control on a remote form called rftest. However, you can enter your own name for a component which may better describe the object within the context of your form; for example, an edit field to allow the end user to enter their first name could be named Firstname. You can change $name of a component in the Property Manager.

The name you assign to an object does not have to conform to any convention other than any conventions you may like to use in your forms or the application to identify different objects. However, the name of a component (specifically the value in $name) is used in the Omnis notation and throughout your library to refer to the object. Therefore, you should not use spaces and try to use alphanumeric characters only for object names to avoid any possible conflicts in your code. For example, an object name should not include the dollar sign ($) since this would cause a conflict when you reference the object using the Omnis notation which prefixes property and method names with the dollar sign.

Component Resizing and using $edgefloat

The “floating edge” ($edgefloat) capabilities for JavaScript components allow the components to be resized automatically, when the end user resizes their web browser window or when the layout changes on a breakpoint. The $edgefloat property can be set to one of the kEF… constants which determines which edges of the component, if any, will “float” or resize when the browser window is resized. The possible values for $edgefloat are:

  1. kEFall and kEFnone
    All or no edges float

  2. kEFbottom
    Bottom edge only floats

  3. kEFleftRight
    Left and right edges float; in effect, the component floats to the right or left and does not resize

  4. kEFleftRightBottom
    Left, right and bottom edges float

  5. kEFright and kEFrightBottom
    Right edge only floats, or Right and bottom edges float

  6. kEFtopBottom
    Top and bottom edges float; in effect, the component floats up or down and does not resize

  7. kEFrightTopBottom
    Right, top and bottom edges float

  8. kEFcenterLeftRight, kEFcenterTopBottom, kEFcenterAll
    means the Left & Right edges float, or the Top & Bottom edges float, or All edges will float, and the control will also be centered horizontally and/or vertically within its parent

  9. kEFposn… positioning constants
    all edgefloat constants prefixed with kEFposn… will reposition the control in the specified region of the screen; as you select one of these constants in design mode the control will snap to the chosen region, and when the form is resized at runtime the control will “stick” to this region; the kEFposnClient constant stretches the control to fit the available area within its parent or subform

You can store a different setting of the $edgefloat property for each component, for each different layout breakpoint. When setting $edgefloat in the Property Manager in design mode, you can set the value of $edgefloat for a component on all breakpoints by holding the Control key when selecting the $edgefloat value.

The setting of $edgefloat for a component is used to resize the component (or not if set to kEFnone) when the form or container field is resized at runtime, and when one or more of the following occurs:

  1. When the component is in a subform and the subform is resized (that is, its size at runtime is different to the size of the subform class)

  2. When applying a different mobile device size while running in a mobile device custom wrapper

  3. When the component is in a resizable subform in a subform set and the subform is resized

Centering Objects

There are some kEF… contstants to control how objects are centered relative to the remote form or parent: kEFruntimeLeftRightCenter, kEFruntimeTopBottomCenter and kEFruntimeAllCenter. They are only applied at runtime, and in this case, their behavior is identical to kEFleftRight, kEFtopBottom or kEFall respectively, except that the offset is divided by two, to keep an object or a number of objects centered within the parent.

In addition, the Align context menu for the remote form editor contains options to allow you to center objects vertically, horizontally (or both) in their parent.

Responsive Forms and $edgefloat

To understand what kind of edgefloat properties you can use, you can look at the PicsWebForm in the Pics2.lbs available in the tutorial download (or in the ‘welcome/tutorial/final’ folder); or you could create your own remote form using the form wizard. The PicsWebForm remote form was created using the SQL Remote Form wizard and uses edgefloat properties to control the floating edge behavior of the controls. The form has two layout breakpoints, 768 and 320, and the edgefloat properties is set differently for some of the controls on each breakpoint. The following image shows the layout for the 768 breakpoint, and the $edgefloat setting (a kEF.. constant) for each control is shown in red.

image3

The PicsWebForm uses a Page pane containing all the data controls, e.g. Pic_Name, etc; the $edgefloat property of the Page pane is set to kEFrightBottom to ensure it stretches across to the right and down as the form is resized in a browser window or is displayed on different sized tablet screens.

The $edgefloat property for most of the controls inside the page pane is set to kEFright, so the right edge “floats” or stretches to the right, but the bottom edge is not resized; the ID field has no floating edges so it keeps its size. The $edgefloat property for the push buttons on the right of the form is set to kEFleftRight (i.e. both left and right edges), which means the buttons will “float” from right to left horizontally, but they will not resize or move vertically. The combination of all these edgefloat settings on all of the controls, means that the push buttons keep to the right-hand edge of the browser window or device screen, while the data controls will resize to accommodate any screen or device size. Now examine the layout for the 320 breakpoint:

image4

The push buttons on the 320 layout breakpoint are positioned at the top of the form and their $edgefloat property is set to kEFnone, so they will not move or resize as the form is resized. The $edgefloat property for the data controls is set to kEFright so their right edges will stretch to accommodate different phone sizes, from 320 pixels upwards.

As the form is resized, on a web browser window or is displayed on a larger device screen, the controls will resize to fill the screen, until the next breakpoint is reached, which in this case is a screen or device width of 768 pixels, and the layout for that breakpoint is loaded.

Draggable Component Borders

End users can resize some JavaScript components dynamically at runtime in their web browser by dragging the border of the component. When the end user’s mouse is over the edge of a component that can be resized, the cursor changes to indicate that the border can be dragged and resized.

To allow this functionality, JavaScript components have the $dragborder property, which only applies when a component has its $edgefloat property set to one of the kEFposn… constants (other than kEFposnClient or kEFposnJoinHeaders). If $dragborder is set to true, and you have set $edgefloat as above, the end user will be able to resize the component in the browser by dragging the border of the component with the mouse.

You can store a different setting of the $dragborder property for each component, for each different layout breakpoint, therefore components on the same form could be resizable for web desktop browsers and not for mobile devices. When setting $dragborder in the Property Manager in design mode, you can set the value of $dragborder for all layout breakpoint values by holding the Control key when selecting the $dragborder value.

The appearance of the drag border area can be modified by editing the styles div.omnis-db-vert and div.omnis-db-horz in omnis.css.

Date and Time Formatting

You can set the formatting for Date and Time type data for some of the JavaScript components including Edit controls, Combo boxes, Data grids, Droplists, Hyperlink lists and standard Lists. These components have the properties:

  1. $jscustomformat
    a date-time format string using the characters described below. If $jsdisplayformat is kFormatCustom, and the data is of type 'Date Time', this property is used to format the data. If empty, it defaults to the format set using $clientcommand 'setcustomformat'

  2. $jsdisplayformat
    the format used to display 'Date Time' data, a kJSFormat... constant as follows:

kJSFormatNone No format
kJSFormatTime Default time format for client locale
kJSFormatShortDate Default short date format for client locale
kJSFormatShortDateTime Default short date and time format for client locale
kJSFormatMediumDate Default medium date format for client locale
kJSFormatMediumDateTime Default medium date and time format for client locale
kJSFormatLongDate Default long date format for client locale
kJSFormatLongDateTime Default long date and time format for client locale
kJSFormatFullDate Default full date format for client locale
kJSFormatFullDateTime Default full date and time format for client locale
kJSFormatCustom Use the custom format in $jscustomformat

Date formatting characters

The following standard date formatting characters are supported for $jscustomformat:

D Day (12)
V Day of week (Fri)
w Day of week (Friday)
E Day of year (1..366)
n Month (June)
M Month (06)
m Month (JUN)
y Year (1989)
Y Year (89)
A AM/PM
H Hour (0..23)
h Hour (1..12)

Some additional characters are supported for Date/Time formatting for the JavaScript Client components only, as follows:

j day with no leading zero (6)
P month with no leading zero (6)
K hour with no leading zero (0..23)
k hour with leading zero (1..12)
a am/pm
O timezone offset (+01:00)

There is an entry on the Constants tab in the Catalog (F9) called "Date codes (JavaScript Client only)" that lists the formatting characters.

Date formatting and Locale

When the client connects, the server sends it the date formats, day names and month names for the client locale (the server reads these from ICU). If you assign $ctask.$stringtablelocale in $construct of your remote task, the server sends the client the formats and so on for the assigned $stringtablelocale locale.

Number Formatting

All JavaScript controls that can display number data have the property $numberformat, which specifies how Number and Integer data is formatted or displayed in the control. The JavaScript controls affected include the Edit Control, Combo box, Data grid, Droplist, Hyperlink list and standard List control. The formatting is used when the control displaying the data does not have the focus, that is, the formatting is only applied when the end user tabs or clicks away from the number field.

The $numberformat property uses a single % format tag for the number followed by one or more elements, for example, the number format %.2F displays a number with 2 decimal places with a thousand separator. The following elements are available (in this order):

An optional "+" sign that forces to precede the result with a plus or minus sign on numeric values. By default, only the "-" sign is used on negative numbers.

An optional padding specifier used for padding (if padding is required). Possible values are 0 or any other character preceded by a '. The default is to pad with spaces.

An optional "-" sign, that causes the string to left-align the result of this placeholder. The default is to right-align the result.

An optional number that says how many characters the result should have. If the value to be returned is shorter than this number, the result will be padded.

An optional precision modifier consisting of a "." (dot) followed by a number, specifies how many digits should be displayed for floating point numbers. When used on a string, it causes the result to be truncated.

A type specifier that can be any of:

% display a literal "%" character
b display an integer as a binary number
c display an integer as the character with that ASCII value
d display an integer as a signed decimal number
D as above but include thousand separators
e display a float as scientific notation
u display an integer as an unsigned decimal number
f display a float as is
F as above but include thousand separators
o display an integer as an octal number
s display character(s) after the s specifier as a string, e.g. to display hours you could use %sh to display 5h
x display an integer as a hexadecimal number (lower-case)
X display an integer as a hexadecimal number (upper-case)

Decimal and Thousand Separators

Numbers will be displayed using the default decimal and thousand separators specified by the language set in the client’s browser, so you do not need to do anything to display the correct decimal and thousand separators for a client. However, you can override the default separators by changing the thouChar and dpChar items in the jOmnis client object: you can do this using JavaScript in the $init method for a JavaScript form, for example:

# $init method, which must be client executed
JavaScript:jOmnis.thouChar = ".";
JavaScript:jOmnis.dpChar = ",";

Autoscrolling

You can enable automatic scrolling for Edit controls, Lists, Tree lists, Hyperlink controls, Pictures and Html controls by enabling the $autoscroll property. If this property is kTrue for the control, and the client is not a mobile device, the client automatically displays scrollbar(s) when not all of the content in a field is visible.

Setting $autoscroll to kTrue changes $horzscroll and $vertscroll to kFalse, and in doing so means you cannot set $horzscroll and $vertscroll. By default, $autoscroll is enabled for Edit controls, Lists and Tree lists, while for Hyperlink controls, Pictures and HTML controls $autoscroll is set to kFalse.

Note that in addition to controlling scroll bars, Data Grids and Lists have the $vscroll and $hscroll properties which allow you to scroll a grid or list vertically or horizontally at runtime in the client browser: the numeric value of these properties is either column or row offset for grids, or the pixel offset for lists.

Component Borders

The borders of JavaScript components are drawn within the bounds of the control, for both Windows and macOS, and have the same dimensions for both platforms. The color is controlled using $bordercolor.

Some components can have rounded borders by specifying the corner radius in pixels in the $borderradius property; for buttons this is $buttonborderradius (single value only). To set all the corners of the object to the same radius you can enter a single value, or to specify the radius for different corners you can use the syntax "n-n-n-n" which follows the same rules as CSS 3 rounded border syntax. The order for the radius parameters is top-left, top-right, bottom-right, bottom-left. If bottom-left is omitted the top-right value is used, if bottom-right is omitted the top-left value is used, if top-right is omitted the top-left value is used.

Control Classnames

All JavaScript controls have a base class name to allow you to control the appearance of controls using CSS, to allow you to apply a consistent appearance for each type of JavaScript control. (Note that from Studio 10.2 onwards you can use JS Themes to manage the colors for controls on a remote form.)

The classnames listed below can be added to the ‘user.css’ and CSS properties applied to the classname to control the appearance of each type of control. Note these classnames are contained in the JavaScript controls by default and if they are added to the user.css are applied to the control automatically, that is, these classnames do not need to be included in the $cssclassname property of a control to be applied (this property is used to apply your own custom style names, see below).

JS Control Class Name Additional notes
‘Frame’ element for all controls omnis-[control]-frame
Activity Control omnis-activity
Background Control omnis-background
BarChart Control omnis-barchart
Button Control omnis-button
Checkbox Control omnis-checkbox
ComboBox Control omnis-combo

The dropped list has “ctrl-drop-list” assigned.

If ($cssclassname) the opened items list will be assigned the class of the first class in $cssclassname suffixed with ”-dropped-list”

Complex Grid omnis-complexgrid

omnis-complexgrid-header and omnis-complexgrid-hheader for header and horizontal header areas.

Each row has omnis-complexgrid-row and either ‘odd’ or ‘even’ depending on their line number.

If ($cssclassname) the header/hheader will have class $cssclassname+”-header” and “-hheader”

Date Picker Control omnis-date
Data Grid Control omnis-datagrid
Droplist Control omnis-droplist

The dropped list has “ctrl-drop-list” assigned.

If ($cssclassname) the opened items list will be assigned the class of the first class in $cssclassname+”-dropped-list”

Edit Control omnis-input
File Control omnis-file
HTML Object omnis-html
Hyperlink Control omnis-hyper
Label Object omnis-label
List Control omnis-list
Map Control omnis-map
Menu - used for context menus, popup menus and tab menus omnis-menu

omnis-menu-main for containing <div> omnis-menu-table for table <div> omnis-menu-row for row <div>

omnis-menu-cellcheck for check or icon element in the menu

omnis-menu-celltext for the text element

omnis-menu-cellcascade for the cascading menu element

Popup and tab menus will implement If ($cssclassname) the opened items list will be assigned the class of the first class in $cssclassname+”-opened-menu”

Native List Control omnis-nativelist
Native Slider Control omnis-nativeslider
Native Switch Control omnis-nativeswitch
Navigation Bar Control omnis-navbar
Navigation Menu Object omnis-navmenu
Page Control omnis-pagectl
Paged Pane omnis-pagedpane
Picture Control omnis-picture
Popup Menu Control omnis-popup Also contains the classes from omnis-menu as it uses this object for the menu element of the control.
PieChart Control omnis-piechart
Progress Bar Control omnis-progress
RadioGroup Control omnis-radio
Rich Text Editor Control omnis-rich
Segmented Control omnis-segmented
Slider Control omnis-slider
Subform omnis-subform
Switch Control omnis-switch
Tab Control omnis-tabs Also contains the classes from omnis-menu as it uses this object for the menu element of the control.
TransButton Control omnis-trans

omnis-trans-text

To address text element of a trans button.

Video Control omnis-video

For example, to add CSS styling to all the Edit controls in your remote forms you could add the following CSS to the user.css file in the ‘html/css’ folder in the main Omnis folder: in this case, the base classname .omnis-input is used with the properties 2px solid grey border and a 6px radius.

.omnis-input {
border: 2px solid grey;
border-radius: 6px;
}

Custom CSS Styles

You can create your own CSS classes or styles (in addition to the base class names listed above) and apply them to the objects in your web and mobile apps, allowing you to have more control of the styling, coloring, and overall design of your apps.

CSS classes for Controls

All the JavaScript components have a property called $cssclassname which allows you to apply your own CSS class to the component. You can add the CSS classes to a file called ‘user.css’ which is located in the ‘html/css’ folder in the main Omnis Studio folder. A style can be applied to a control by setting its $cssclassname property to the name of a style. The properties you define for each style in user.css must be flagged as !important to override the JavaScript Client inline styles.

When you deploy your application on the Omnis App Server, you must put your custom ‘user.css’ file in the ‘html/css’ folder on the server.

Form Errors

It is possible to display form errors either to the right or under controls in a remote form. This makes it easier for end users to fill out forms in your web and mobile applications by providing them with helpful tips if they make a mistake in the form. The errors appear on the form as a text field either under a control, or to the right of a control, so you need to design your remote forms to allow space for the error text. The style of the error text and the outer HTML of the control containing the error are controlled in CSS which you can change if required.

image5

$errortext

All JavaScript Client controls have the $errortext property which contains the text to be displayed when there is an error in the field or control. The initial value of $errortext when a form is constructed is empty.

The $errortext property is only supported for subform controls when they are not scrollable, i.e. when $vertscroll & $horzscroll are both kFalse and the subform class is not responsive.

$errortextpos

The $errortextpos property specifies the position of the error text set using $errortext. The value can be one of:

  1. kJSErrorTextPosUnder
    The error text is positioned under the control, the default.

  2. kJSErrorTextPosRight
    The error text is positioned to the right of the control.

  3. kJSErrorTextPosHidden
    hides the error text, so just the control outline indicates that there is an error (default is a red border). This might be useful where there is limited space to display the error text in the remote form, but you still want to show the end user that there was an error; the style of the error outline is set in the omnis.css style sheet as div.om-error-border

Note that Omnis stores a separate value of $errortextpos for each screen size. As a shortcut when designing a form, you can hold the control key down when assigning $errortextpos, in order to assign the value to all screen sizes.

$errorline

$errorline is a runtime property of the JavaScript Complex Grid control, used when assigning $errortext to an object in the row section of a complex grid. The line number to which $errortext will apply.

Clearing form errors

The client command “clearerrors” allows you to clear all error text messages for the form:

Do $cinst.$clientcommand("clearerrors")

equivalent to assigning $errortext to empty for all controls on the form which have error text.

Changing the appearance of error text

The following CSS classes control the appearance of the error text and border. These classes are stored in the omnis.css which you can edit if required.

  1. div.om-error-text
    This class styles the error text.

  2. div.om-error-border
    This class styles the outer div of a control which has error text.

Field List

The Field list provides a list of all the components on a remote form and is often useful if you need to select a specific component which is partly obscured or hidden in the form. To open the Field list, Right-click/Cmnd-click on the form or a component and select the Field List option. The currently selected component is checked in the Field list, expanding the tree nodes and scrolling the list if necessary. Conversely, you can open the Field List and check a component name in the list to select it in the form.

image6

When the focus is in the Field List, you can use the arrow keys to navigate up and down the list and use Space bar to select a control, as required. The Shift-Space keypress allows you to select (or deselect) multiple, discontinuous controls in the list.

The Field list can be useful if you need to select the background of a form, for example to set its properties in the Property Manager, but the form is completely filled with components and no form background is available to click on, as can be the case for mobile forms. To select the form in this case, you can open the Field List and check the form name at the top of the list (which will deselect any components), or if you click on any individual component, then shift-click it to deselect it, the focus will be returned to the form background and its properties will be shown in the Property Manager.

JavaScript Component Events

Most of the JavaScript components report events which you can handle in a special method called an “event method” which is inserted behind the component. The event method for a component must be named $event. For example, when the end user clicks a button, an evClick is generated which you can trap in the $event method for the button; this method could contain code to display a message, call another method or determine some other action depending on the code in the event method itself. Most of the components contain a template $event method with a code stub for you to use as a starting point to handle the event.

Enabling Events

In order to report an event, the event must be enabled for the component. Many of the components have their events enabled by default, but for some you may need to enable specific events in the $events property for the component.

To enable an event

  1. Select the component and open the Property Manager (press F6)

  2. Click on the $events property in the Property Manager to drop down the list of events for that component (the property will show “No Events” when no events are selected)

  3. Check (enable) the events you wish to trigger for this component

You can select multiple objects of the same type and specify the events for all of the objects at the same time. For example, you can select a number of check boxes and enable the evClick event under the $events property to enable the event for all the selected check boxes.

Editing Event Methods

If you double-click a component in design mode, the Method Editor will open displaying the method for that individual component. For components with events, the $event method will be shown automatically. For example, if you double-click on a button, the Method Editor will open displaying the $event method containing the code On evClick; you can add more code after this line to be run when the end user clicks the button. See the example code for each component for example $event methods.

For some components, the $event method may not contain any template code including the On event command, but you can add you own. You will need to enter the On command and select the appropriate event code (a constant beginning ev) from the Helper window in the Code Editor.

Event Method Validation

Omnis validates the event codes you have entered when adding or editing On event commands in the Code Editor. Therefore, Omnis will check to see if the event code is valid for the current object, and if not, it will flag it as an error.

If the event is not specified in the $events property, Omnis will add it to $events automatically when editing a method named $event in a non-inherited object (Omnis displays a temporary status bar message when it does this).

You can turn off this validation using the validateEventsForOnCommand entry in the methodEditor group of config.json; set it to false to turn off event method validation.

Standard Field Events

Most JavaScript fields or controls report the evBefore and evAfter events, which are triggered when the focus is about to enter or leave the control, respectively. Note that for edit controls, if the data does not change then an evAfter is not triggered as the focus leaves the control.

You can use the On event command to detect events in your event handling methods, and for most controls the $event method will contain a template event handling method into which you can add your own code. For example, in the $event method for an Edit control you could use the following commands to detect the evBefore or evAfter event.

On evBefore
 # do something..
On evAfter
 # do something else..

Buttons and Lists

Buttons and all the list type JavaScript controls report the evClick event, as well as evBefore and evAfter; and some list types also report the evDoubleClick event. For example, the Data Grid control reports evDoubleClick which you could detect and initiate a search based on the content of the grid line clicked on.

evAfter event queue

When an event is being executed in the JavaScript client, such as a click on a button, a transparent overlay is applied to the whole remote form, to prevent user interaction anywhere else in the form and to maintain the Omnis event ordering. If the user clicks on this overlay, the click will be prevented, although most events happen almost instantaneously so in this case the overlay is not displayed.

For evAfter events that show the overlay, Omnis shows a feedback effect at the point of the click when the overlay prevents the click, to make it clear to the user that their click was not registered. The feedback effect is a No Entry icon, with “bubble” animation, that appears and disappears directly after the user click. In this case, the click will be queued and will fire once the overlay is removed.

Unfortunately, Firefox does not treat the active state of elements in the same way as other browsers. As such, it was not possible to implement these changes for that browser.

Drag Border Event

All JavaScript controls report the evDragBorder which is triggered when the border is dragged – the event is reported to the control containin the border being dragged and any that share the border area being dragged. When it is triggered it could mean that the end user has resized the field (and therefore other fields in the same parent have resized) using the drag border.

JavaScript Component Icons

Some of the JavaScript Controls, such as the Button control, allow you to add an icon to create a better appearance and UX for your apps. Such controls that support icons have the $iconid property which allows you to specify an icon image file to be used for the control. From Omnis Studio 10.2 onwards, you can use SVG image files for JavaScript component icons, as well as PNG image files, as supported in previous versions. You can use SVG image files in an icon set, alongside an existing icon set containing PNG files, and these will appear in the Select Icon dialog when you assign an icon to a JS component.

Selecting an icon

You can assign an icon to a JavaScript Component by setting its $iconid property in the Property Manager under the Appearance tab: when you click on the dropdown menu for the $iconid property the Select Icon dialog opens, allowing you to select an icon image from those available in Omnis.

image7

When you first open the Select Icon dialog you should see the ‘material’ icon set from which you can select an icon; the 16x16 icon size is selected under the Size list but you can select a different icon size, including 32x32 or 48x48. You can scroll the list of material icons to find an icon or you can enter a search string into the Search box to filter the list; the following screen shows the 48x48 material icons and the search ‘add’.

image8

You can add your own icons to the Select Icon dialog by adding your own icon set; see below. You should use scalable SVG icons for your web and mobile applications, which will be displayed correctly in high definition on phones, tablets and HD monitors. In most cases, you should add your own icon set, tailored to the unique functionality or style of your application, and for all new applications you are advised to use SVG images for icons.

You can use the icons in the ‘studio’ icon set but these are PNG image files and may not lend themselves to your application, so you are advised to source your own SVG icons.

IMPORTANT: You are advised not to use any icons listed under ‘Omnispic’, ‘Userpic’, ‘#ICONS’, or ‘IPHONECONTROLS’ since these only contain low definition or non-alpha image files and are only present for backwards compatibility with older applications.

Icon sets

SVG icon image files must be stored in an icon set, which is a sub-folder of the ‘iconsets’ folder in the main Omnis tree (do not use the ‘icons’ folder which contains legacy icon datafiles). Note that an icon set cannot be named ‘datafile’, ‘lib’, ‘studio’, or ‘studioide’ since those names are already in use and would cause a conflict.

In order to use any icons in an icon set, you need to add the icon set name to the $iconsets library preference, which is a list of icon sets for the library: note this preference was called $iconset in versions prior to Studio 10.2 and only allowed a single icon set to be used. Once you have added an icon set to $iconsets for a library, the icons will appear in the Select Icon dialog, prefixed SET.

Icon Search Order

Icons can potentially be stored in various locations in Omnis including the ‘studio’ icon set, as well as any icon sets you have added, plus the various icon data files used in older versions of Omnis: this may become an issue where duplicate icon names or IDs exist across the different locations, so Omnis employs a specific ‘icon search order’ that determines how icons are located and displayed. If an icon with the same name or ID is included in another folder, after an icon has been found, it is ignored in subsequent folders and an error is written to iconsetlog.txt. You should therefore avoid having the same icon names, IDs, or icon set names in multiple folders to avoid any potential confusion. Omnis looks in the following icon sets or datafiles in this order:

1. The icon set(s) specified in the $iconsets library preference, in the order listed in the property

2. #ICONS for the library, if used (would only be the case for older applications not using SVG or HD PNGs)

3. User icon datafiles (other than Omnispic and Userpic), if used; this is for legacy apps only

4. The ‘studio’ icon set, under the ‘iconsets’ folder

5. Omnispic or Userpic (.df1 files located in ‘icons’ folder), if used

When using a web server for deploying your web or mobile application, any icon sets used in your library must be placed in the ‘html/icons’ folder in the web server tree, even if they are in one of the other folders in the Omnis Server tree.

During SCAF generation (for the serverless client), the Omnis Server now passes all the files for all icon sets in $iconsets to the serverless client library.

SVG Icons

SVG images are vector based and are inherently scalable, therefore a single SVG file can provide multiple sizes for icons: in practice, an SVG icon will scale to fit the icon area available in a control, such as a button (unless you fix its size, see below). By contrast, PNG images have a fixed size and therefore you have to create a separate image file for each icon size or resolution you wish to support and place all the separate files in an icon set in the Omnis tree. In addition, a single SVG image will have a much smaller file size than mulitple PNG files, giving your app a smaller footprint on the client.

On macOS, SVG icons only render in the thick client when using macOS 10.13 or later.

On Windows, SVG icons only render when using the Windows 10 Creators Update or later. In general, support for SVG in Windows is more limited than on macOS, for example, Windows does not support classes in SVG files – read here about Windows SVG support:

https://docs.microsoft.com/en-us/windows/win32/direct2d/svg-support

Material SVG icon set

Google provides a large set of SVG icons in its Material design scheme, which are issued under the Apache License Version 2.0 (https://material.io/resources/icons), and you are free to use these in your Omnis applications with the proper attribution in your product licensing.

We have selected over 100 of the Material icons (from the “black rounded” style) and placed them in an icon set folder called ‘material’ under the ‘html\icons’ folder in the Omnis tree; the material icon set will appear in the Select Icon dialog by default, and you are free to use these in your applications.

image9

These material icons have been ‘themed’ and therefore support JS Themes (but themed icons cannot be used for thick client controls). You could download other icons from the Material website and add them to this folder, if required, and use the theming tool if you want them to support themes.

Themed SVG Icons

In order to use JS Themes, an SVG icon needs to be converted to a “themed” SVG file. Such themed icons only appear in the Select Icon dialog for JavaScript remote forms (and Remote Menus), but not for window class controls. The Material icons in the ‘material’ icon set, provided in the main Omnis iconsets folder, have been themed. See the Themed Icons section about how to theme icons.

Using SVG Icons

If a JavaScript component can support SVG icons (and most do), then the icon names of any SVG icons will appear in the Select Icon dialog when you assign the icon via the Property Manage and the Select Icon dialog (if a component does not support SVG icons, then they are not shown in the Select Icon dialog).

In general, SVG icons are supported by any controls that previously required an icon, including the following classes or features:

  1. Remote Form class components (JavaScript Client controls), including buttons, menus, toolbars, lists, tabs, check boxes

  2. Window class controls (thick client), including menus and toolbars, together with some external component window controls including clock, treectrl, html icon link, hyplinks, etc.

  3. Styled text, including styled text on reports sent to the Omnis PDF report destination

  4. The background icon for the main Omnis window on the Windows platform ($root.$prefs.$backgroundiconid)

  5. The $componenticon class property

You should note the following for JS controls only:

  1. Some JS controls use background-image CSS, so when using an SVG image, it will not always scale as expected if the aspect ratio in the SVG is fixed, and the desired dimensions of the background-image do not have the same aspect ratio.

  2. JS Popup menu and JS Navmenu controls have hot iconid properties – in this case, the hot and equivalent non-hot iconid properties must either both use SVG or both use PNG

Creating SVG Icons

You can create your own SVG icons, or you may be able to acquire a set of icons from a third-party, either paid-for or for free (subject to the appropriate licensing). SVG image files must be saved with the .svg file extension (see naming below) and should be placed in an icon set in the ‘iconsets’ folder in the Omnis tree, and the icon set name needs to be added to the list of icon sets in the $iconsets preference in your library.

From our testing, we found that Adobe® Illustrator® allows you to export vector images in SVG format, and on the export to SVG options dialog you can select the ‘Inline Style’ option to ensure classes are not used in the output SVG. There are many other image editors that can output SVG.

SVG icon file names

The base icon ID of an SVG icon is the name of the SVG file, without the file extension, and converted to lower case, up to a maximum of 32 characters. The naming restrictions for SVG icons are as follows:

  1. The base icon ID must not represent an integer (the icon ID had to be an integer for PNGs, but does not have to be for SVG image files)

  2. The base icon ID must not contain the characters + # , ; = ? (plus, hash, comma, semicolon, equals, or question mark); note + is used to add a size restriction, see below

An icon ID or name can now be either an integer or a string, and integer icon IDs work exactly as they did before (the naming of PNG icon images remains the same).

You cannot use the same file name with different case in an icon set folder, plus it’s always good practice to make icon IDs or names unique across different icon sets, since the icon with the first instance of a specific icon ID or name is used.

Any errors related to the naming requirements are written to the icon set log file, which is in the folder logs/iconsets, in the data part of the Omnis tree.

Multi-state SVG Icons

If you want to include icons for different states of a control (for example, checked, highlighted, and checked highlighted for a check box control), you can include separate SVG files with a suffix in their name:

  1. _c for checked

  2. _h for highlighted

  3. _ch for checked and highlighted

For example, SVG files for a check box could include the files: checkbox.svg (for the unchecked icon), checkbox_c.svg, checkbox_h.svg and checkbox_ch.svg (for the different states). These 4 files all result in a single icon with id ‘checkbox’, and Omnis will select the correct SVG file according to the state of the checkbox.

Fixed and Custom Icon Sizes

An SVG icon will always expand to fit the available space within a control, but it is possible to fix or restrict the size of an icon by adding size information to the end of the icon ID name. The size information has the syntax +<w>x<h> where <w> is the integer width and <h> is the integer height. For example, an SVG icon ID could be any of the following:

  1. testsvg (unrestricted size)

  2. testsvg+16x16 (restricted to 16x16, for example, for a menu)

  3. testsvg+32x48 (restricted to 32 wide x 48 high)

When selecting an SVG icon, the size list includes the configured sizes from config.json, and the current size of the icon, in addition to the standard sizes and kDefSize. There is a + button in the heading of the size list that allows you add a new size. There is an option on the dialog to add the new size to config.json.

The ‘customSizes’ item in the ‘svg’ section of config.json allows you to add other sizes. The size list in the Select Icon dialog will show any other sizes specified in the config.json file:

"svg": {
"customSizes": [
"256x256",
"64x64",
"128x128"
]
}

When a custom size is selected in the size list for a full page SVG icon, in addition to the + button, there is a - button which you can use to remove the size from the list, and optionally remove it from config.json.

Omnis uses the default width and height specified in an SVG file to determine the aspect ratio of the icon image. To obtain this, Omnis looks for the width and height attributes of the svg element in the SVG file and uses these if present. If width and height are not present, Omnis uses the viewBox attribute of the svg element to determine the aspect ratio. In this case, you can add a size using the + button in the Select Icon dialog, and use the Keep Aspect Ratio option, to fix the aspect ratio.

Icons for Lists

Certain controls, such as the Icon Array, use a list column to contain an icon ID. To make use of SVG icons, this column needs to be defined as Character. Where you use a mixture of SVG icons and existing PNG icons, the icon IDs can be specified as strings or integers as appropriate.

Icon Caching

You can control the cache size for all icon sets (using PNG and SVG icons) in config.json using the maxCachedIconSetBitmaps entry. This is an integer, which defaults to 1000 bitmaps. If Omnis needs to create a new bitmap for an icon from an icon set, and the current number of cached bitmaps is at this limit, Omnis will free up the least recently used bitmap.

Assigning a URL for images

When you set the $iconid of a JavaScript control you can also assign a URL. In server methods, if the value being assigned is a character value that contains a “/” character then Omnis treats it as a URL generated by the iconurl function (meaning that it can contain alternative icon files for the different client resolutions, and also that the server will pick the correct icon for the client resolution).

In client methods, if the value being assigned is not an Icon ID (a literal integer or integer + icon size constant) then Omnis treats the value as a URL generated by the iconurl function on the server, and the client picks the correct icon for its resolution.

You could generate the required URLs with iconurl() (see below) in the $construct() method of your remote form, and store them in an instance variable list which could then be used in client executed code to assign the correct image to each object.

Image handling for tree lists

For the JavaScript Tree control, the iconid column is an iconurl column, and the $iconurlprefix property is redundant although existing libraries that use $iconurlprefix will continue to work. Instead, the iconurl column should be defined to be of type character, and it should be populated using a server-only function, iconurl(iconid), which returns a URL string containing the name of the image file or a semi-colon separated list of file names if an icon exists in more than one resolution. This enables the client to pick the correct icon for its resolution.

Exporting Icons from an Icon Datafile

You may want to use some existing icons located in an Icon Datafile and either add to or replace some of them with higher resolution versions. To enable you to export existing icons as separate files, there is a tool in the Tools>>Add Ons menu, called the ‘JS Icon Export’ tool, which is available in the ‘Web Client Tools’ dialog (scroll to the bottom of the list of Web Client tools). The ‘JS Icon Export’ tool will export all the icons in a selected Icon Datafile and place them in a folder in the ‘iconsets’ folder, applying the correct image file names. The $iconid property of a control will now reference the external image file in the icon set and not the icon datafile image, since Omnis looks in the iconset folder for the library before any icon datafiles. The Icon Export tool will only export icon images that support Alpha, i.e. the icon page containing the existing icon(s) must be set to Alpha.

Icons Folder Name

Apache often redirects a URL with "/icons/" to the /usr/share/apache2/icons folder, and you would then need to place all the icons for your app in that folder. Therefore, if you deploy your web or mobile app to an Apache server, you may want to rename the ‘icons’ folder in Omnis by editing (adding) an entry in the Omnis configuration file (config.json). The "iconsFolder":"omnis_icons" configuration item in the server group of config.json defaults to "icons" if omitted or is empty, so you can change the name by adding your own value. You are recommended to use the same value for development and runtime, since the folder name is stored in the HTML for each remote form class.

PNG Icons

From Studio 10.2 onwards, you are advised to use SVG images for component icons, although you can still use PNG images. In this case, you can create PNG image files that are 16x16, 32x32, or 48x48 pixels either at a standard pixel density suitable for displaying on standard monitors, or image files that are 1.5 and 2 times the size, suitable for displaying on phones and other HD devices.

PNG Image File names

Each PNG image file within an icon set must conform to the following naming convention:

<text>_<id>_<size><state>_<resolution>.png
  1. <text> is a string, i.e. the name of image, which must not contain underscore. This string is used in the icon picker dialog when you set an object’s $iconid in the Property Manager so it should describe the icon. Icon files that are the same image, but different resolutions should have exactly the same <text> name.

  2. <id> is the positive integer id to be used as the icon id. It can be in the range 1 to 10000000. Icon files that are the same image, but different resolutions should have exactly the same <id>.

  3. <size> is the CSS pixel size of the image, i.e. the resolution independent size of the image, meaning that for all resolutions of the same image this has the same value.

The value of <size> has the form <width>x<height>, where the values 16x16, 32x32 and 48x48 are special values since they correspond to the standard icon sizes supported by Omnis.

  1. <resolution> is the factor by which the pixel density is greater than a standard monitor and is one of the following:
    “_2x” for HD devices such as the Retina display
    “_15x” for some devices e.g. certain Android phones that have a 1.5x pixel density.
    an empty string is the default and is for standard resolution devices, equivalent to _1x

Any files (or folder names) that do not conform to the naming conventions are ignored.

Note that the image file names are case insensitive and they must be unique across all platforms and file systems (that is the case of file names is ignored).

If you are unsure about the file naming for PNG icons, you can examine the icons in the ‘iconsets/studioide’ folder.

PNG Check Boxes Icons

You can use PNG images for check box and radio button icons, using the following naming:

  1. <state> is the checked, highlighted, or normal state of the icon for multi-state icons and can be one of the following:
    an empty string for the normal state of the icon
    “c” is the checked state of the icon
    “h” is the highlighted state of the icon
    “x” is the checked highlighted state of the icon

PNG Image Scaling

You do not have to create an icon PNG image for all resolutions, although it would be advisable to do this for the best appearance. Omnis will use an icon image closest to the resolution being referenced, scaling as appropriate, and as with all image scaling it is better to force Omnis to scale an image down rather than scale it up. In this case, you may like to provide the highest possible resolution image for your icons and allow Omnis to scale the images down to display an icon for lower resolutions, but the scaling may produce unexpected results.

When the JavaScript Client connects, it sends its resolution to the Omnis App Server. This allows the server to use the appropriate icon when setting iconid properties in server methods.

Non-standard PNG image sizes

You can create PNG images with a size other than the standard sizes (16x16, 32x32, 48x48) by creating the image at a non-standard size and including the image size in the file name when the file is saved. For example, you can create an image 100x200 pixels and name it something like “mygraphic_1688_100x200.png”, and you can create a high resolution version at 200x400 pixels and name it “mygraphic_1688_100x200_2x.png”. (This is the equivalent of an ‘Icon Page’ in older versions of Omnins.)

Icon Data files and #ICONS

NOTE TO EXISTING USERS: The method of storing icons in #ICONS or an Icon data file (such as Omnispic) and assigning the numeric Icon ID ($iconid) to controls will continue to work, but this is only useful for icon images that are 16x16 pixel (or 32x32 for high def). In this case, if you run your application on an HD display and your library uses an icon data file or #ICONS, Omnis will try to use a 32x32 icon (if it exists and the icon page is marked as containing 32x32 icons), in place of the corresponding 16x16 icon. If a 32x32 image does not exist in your icon data file or #ICONS, the existing 16x16 image will be used which may have a very poor visual appearance on newer screens and devices. In order to support high definition 16x16 icons you will need to create a new version of each image at 32x32 pixels and import each one into the icon data file or #ICONS into the 32x32 section on the same icon page using the same icon IDs.

If you have used 32x32 or 48x48 pixel icons in your libraries (in #ICONS or an Icon data file), and you wish to display them on HD displays, then you will need to adopt the use of icon sets, which support icon images up to 96x96 pixels, that is, 2x the largest 48x48 icon size. Note that icons in an icon set will take precedence over icons in #ICONS, Omnispic or Userpic in the icon search order.

Drag and Drop Data

Drag and drop for the JavaScript Client provides the ability for end users to drag data from one JavaScript control in a remote form, and drop that data onto another JavaScript control. In addition, end users can drag files from their desktop and drop them onto a JavaScript control within a remote form displayed in their web browser.

IMPORTANT NOTE: Support for drag and drop in JavaScript remote forms is limited to desktop browsers only, including Chrome, Edge, Firefox, IE 11, and Safari – drag and drop is not supported in mobile browsers. Also note drag and drop only applies from one control to another control, or a file onto a control – you cannot drag data to or from a remote form.

To drag and drop some data, the end user can click and hold down the pointer over a JavaScript control on a remote form, then drag the highlighted control onto another control and release the pointer when the target control is highlighted. To enable drag and drop, you have to set various properties in the source and target JavaScript controls, and handle various events in each control as the drag and drop events occur.

Existing users should note that the event constants and their parameters work in a very similar manner to those for the drag and drop mechanism in the thick client, with the addition of the pDropId parameter which identifies the area of a control over which the drop is to occur (see under Events).

Example Library

There is an example library demonstrating how you can drag and drop images between JavaScript controls, and the library allows image files to be dropped onto a control from the desktop. The example library is available in the Samples section in the Hub in the Studio Browser, and in the JS Component Gallery on the Omnis website: www.omnis.net

Dragging Data

Dragging data is limited to certain data-bound JavaScript controls and is not possible for all types of JavaScript controls. JavaScript client controls that support dragging data will have the $dragmode property. This can be set to either kNoDragging or kDragData.

Note that the $dragiconid property used in the thick client is not supported for drag and drop in the JavaScript client, for a number of technical limitations in various browsers. The dragged image is typically an image of the dragged element created by the browser, using the content of the element when the drag starts – the client performs various temporary adjustments to the element to make the dragged image correspond to the dragged data as appropriate.

Dropping Data

A drop can occur on any JavaScript control, but remotes forms do not accept drops. You can specify that a control can accept dropped data by setting its $dropmode property. When a control can accept some data, the JavaScript client highlights the destination control. For JavaScript client controls, $dropmode can be one of the following constants:

  1. kAcceptControl
    Data from a JavaScript client control can be dropped onto this control.

  2. kAcceptFiles
    Files dragged from the system (desktop) can be dropped onto this control.

In addition, the list, tree and data grid controls have the $hiliteline property, indicating that data can be dropped on a specific list line or tree node rather than the entire control. This also means that rather than highlighting the entire control, the client highlights the current destination line or node when a drop can occur.

Scrolling

When the end user is dragging data, they can scroll a destination control vertically by placing and holding the pointer near the bottom or top of the control. This is useful with long lists, grids or tree controls, when the $hiliteline property is enabled.

Events

In order to process a drag and drop procedure, you have to handle some events in the $event method in the source and target controls. The drag and drop events must be enabled as required in the $events property for a control.

evDrag

The client sends evDrag when the user attempts to start a drag. evDrag must be executed in a client-executed $event method, and it has the following event parameters:

Parameter Description
pDragType Always set to the value kDragData
pDragValue Described in the Drag Values section below.

If you use Quit event handler (discard event) during evDrag, you prevent the drag from starting.

Since it is not always convenient to mark $event for a control as client-executed, the client provides an alternative mechanism. You can implement a client-executed method named $drag for the object, with two parameters (type Var): pDragType and pDragValue. $drag returns true if the drag is allowed, false if not.

The client first attempts to call $drag. If $drag exists and returns true or false, then the drag starts or is not allowed to start respectively. If $drag does not exist, or does not return a value, Omnis sends evDrag if it is selected to execute in $events, and if $event is client-executed.

The drag will only fail to start if $drag executed and returned false, or if evDrag was sent and discarded by Quit event handler.

Data grids, lists and tree controls may select a line or node when the drag starts. This will result in a click event being sent just before $drag is called or evDrag is sent. If the click is sent to the server, it will execute in parallel with evDrag or $drag.

evDragFinished

The client sends evDragFinished when the user has finished a drag (released the pointer). It has no event-specific parameters. evDragFinished can be server or client executed.

evCanDrop

The client sends evCanDrop when the pointer is over a control that can accept a drop of the current drag type (kDragData or kDragFiles). evCanDrop must be executed in a client-executed $event method, and it has the following event parameters:

Parameter Description
pDragType kDragData if data is being dragged from a control, or kDragFiles if a file or files are being dragged from the system
pDragValue Described in the Drag Values section below. Note that if pDragType is kDragFiles, this is empty during evCanDrop, since information about the files being dragged is not provided by the browser
pDragField

If pDragType is kDragData, this contains the name of the field from which data is being dragged.

If pDragType is kDragFiles, this is empty

pDropId The identifier of the area of the control over which the drop is to occur. Either a line number or ident (when $hiliteline is true), or zero if the control is not list-based (or $hiliteline is false).

If you use Quit event handler (discard event) during evCanDrop, you prevent a drop on to the current control and pDropId combination.

Since it is not always convenient to mark $event as client-executed, the client provides an alternative mechanism. You can implement a client-executed method named $candrop for the object, with four parameters (type Var): pDragType, pDragValue, pDragField and pDropId. $candrop returns true if the drop is allowed, false if not.

If pDragField=$cobj.$name
  Quit method kFalse
End If

The client first attempts to call $candrop. If $candrop exists and returns true or false, then the drop is allowed or not allowed respectively. If $candrop does not exist, or does not return a value, Omnis sends evCanDrop if it is selected to execute in $events, and if $event is client-executed.

The drop will only be denied if $candrop executed and returned false, or if evCanDrop was sent and discarded by Quit event handler.

evWillDrop

The client sends evWillDrop when a drop occurs over a control and drop id combination for which which a drop is allowed according to the can drop processing. The client sends evWillDrop to the control being dragged - therefore, evWillDrop is not sent when dragging files from the system. evWillDrop can be server or client executed. It has the following event parameters:

Parameter Desciption
pDragType kDragData
pDragValue Described in the Drag Values section below.
pDropField The name of the control where the data is being dropped.
pDropId The identifier of the area of the control over which the drop is occurring. Either a line number or ident (when $hiliteline is true), or zero if the control is not list-based (or $hiliteline is false).

Quit event handler with discard event has no effect on evWillDrop.

evDrop

The client sends evDrop when a drop occurs over a control and drop id combination for which a drop is allowed according to the can drop processing. evDrop can be server or client executed. It has the following event parameters:

Parameter Description
pDragType kDragData if data is being dragged from a control, or kDragFiles if a file or files are being dragged from the system
pDragValue Described in the Drag Values section below.
pDragField

If pDragType is kDragData, this contains the name of the field from which data is being dragged.

if pDragType is kDragFiles, this is empty

pDropId The identifier of the area of the control over which the drop is occurring. Either a line number or ident (when $hiliteline is true), or zero if the control is not list-based (or $hiliteline is false).

Quit event handler with discard event has no effect on evDrop.

The following $event method is behind an image control and processes the dropped data (this is available in the example library).

On evDrop
  If pDragType=kDragData
    If pDragField='LeftImage'
      Calculate iLeftImage as iRightImage
      # pDragValue is base64, convert to binary for consistancy
      Calculate lBase64 as mid(pDragValue,pos(',',pDragValue)+1)
      Calculate iRightImage as binfrombase64(lBase64)
    End If
  Else
    Calculate lLine as 1
  # pDragValue can contain many lines use first file only
    Calculate iRightImageIdent as pDragValue.[lLine].4
    Do $cinst.$clientcommand(
    'readfile',row(iRightImageIdent,'iReadFileBin',kTrue))
    # readfile is a client command - see below
  End If

Drag Values

This section describes both the controls for which data can be dragged, and the drag values generated for each drag.

Combo box

pDragValue is the selected text dragged from the current selection in the entry field component of the combo box. To drag text, you must click and hold the pointer somewhere in the selection before dragging.

Data grid

pDragValue is a list. For a single select data grid, the list has one line, containing the list line being dragged. For a multiple select data grid, the list contains the selected lines being dragged.

Entry

pDragValue is the selected text dragged from the current selection in the entry field. To drag text, you must click and hold the pointer somewhere in the selection before dragging.

List

pDragValue is a list containing the list line being dragged.

Picture

pDragValue is a character string containing the URL of the picture being dragged. If the picture is populated using a variable and $mediatype, the URL is a data URL.

Rich text

pDragValue is the selected text dragged from the current selection in the entry field component of the rich text control; note that this is the plain text without any formatting. To drag text, you must click and hold the pointer somewhere in the selection before dragging.

Tree

The tree only supports dragging when it is in dynamic mode (i.e. when $datamode has the value kKSTreeDynamicLoad). pDragValue is a row containing information about the node being dragged. The row has 3 columns:

Column Description
ident The ident of the node
tag The tag of the node (a character string)
text The node text

If the $hiliteline property is kTrue for a tree control, and the dropmode indicates that the tree is a potential drop target, the client will expand a node when the pointer enters it while dragging.

Tab control

The tab control contains some special logic that allows you to switch tabs while dragging, if this is the functionality you require. For can drop, it sets pDropId to the tab number of the tab under the pointer (or it sets pDropId to the current tab number if the pointer is over an area of the control which is not a tab). To switch tabs, implement a client-executed $candrop method for the tab control which executes:

  Calculate $cobj.$currenttab as pDropId
  Quit method kFalse

Dragging and Dropping Files

In addition to dragging and dropping data from one control to another, end users can drag files from their desktop and drop them onto a JavaScript control in a remote form in their browser. There are two client commands that allow you to process dropped files, using the $clientcommand method.

closefile

The client records file idents (and their JavaScript File objects) in a table. Use closefile to remove the table entry and release resources. You should really do this for every ident passed in the drag value to evDrop, unless you use readfile which removes the table entry after reading the file.

The row passed to the “closefile” $clientcommand has a single column, which is the ident of the file to remove from the table. If you pass a row where the ident is zero, the client removes all entries from the table.

readfile

The readfile client command allows you to read the contents of a file identified by its ident. After attempting to read the file, the client removes the ident from the table, so a call to closefile is not required.

The row passed to readfile has the following structure:

row(ident,instance variable name,base64)

The columns are as follows:

Column Description
ident The ident of the file
instance variable name The name of an instance variable in the form used to call $clientcommand, that will receive the contents of the file. Note that this is a character string containing the instance variable name, not the instance variable itself
base64 A Boolean. If true, the file is read as base64; otherwise the file is read as text

The JavaScript FileReader which the client uses to read the file operates asynchronously, so a call to readfile starts the file reading process. When the file read is complete, the client calls the client-executed method $filereadcomplete in the form used to call $clientcommand. $filereadcomplete has two parameters:

Parameter Description
ident The ident of the file.
error text

Empty if the file was read successfully, meaning that the named instance variable has been populated with the file contents (either as text or base64-encoded text).

If not empty, some text describing why the file read failed

Files dragged from system

For file dragging, pDragValue is only populated for evDrop. It is a list of the files dragged from the system, with columns defined as follows:

Column Description
name The file name. Note this is just a name, not the path to the file
type The MIME type of the file if this was determined by the browser before passing it to the drop event
size The size of the file in bytes
ident An integer, unique in the context of the client, that identifies this dropped file. You can use this with the client commands described in the later section about processing files.

Drag and Drop for Thick Client

evCanDrop, evWillDrop and evDrop for the thick client have the pDropId parameter. This is significant when $hiliteline for the control is true, and contains the id of the location in the control where the drop would occur or is occurring, e.g. the list line for a list.

Accessibility

This release contains several enhancements to support the Web Content Accessibility Guidelines (WCAG 2.0) which will help to make your applications more accessible, primarily for people with disabilities. These guidelines have been adopted by many government agencies and guarantee an acceptable level of access to information and services via websites and applications for people with disabilities. You can read the following pages to gain a basic understanding of the WCAG requirements:

https://www.w3.org/WAI/standards-guidelines/

The WCAG implementation in Omnis Studio calls on the ARIA specification, which according to W3.org is “Accessible Rich Internet Applications (ARIA) defines a way to make Web content and Web applications more accessible to people with disabilities. It especially helps with dynamic content and advanced user interface controls developed with [various web technologies],” which includes technologies such as the JavaScript Client in Omnis Studio.

In practice, this means we have added various ARIA compliant properties to the controls for JavaScript remote forms which you can use in your web and mobile apps to support end users with disabilities. These properties will be read automatically when the screen reader capabilities are enabled in the end user’s browser or mobile device. (For testing, we have used ChromeVox by Google, but there are many other screen readers for Chrome and other browsers.)

Accessibility Properties

Most JavaScript controls have a set of basic ARIA and other accessibility properties which are interpreted by the screen reader in the browser. The ARIA properties in Omnis map closely to their equivalent ARIA attributes in HTML.

General properties

Several of the JavaScript controls have the following ARIA properties, while some other controls have additional properties (listed below). These properties are designed to work in a similar way as their equivalent ARIA attributes in HTML.

  1. $arialabel
    the text for the aria label, which is used when a text label is not visible on the form. If there is a label for the control, use the $arialabelledby property instead

  2. $arialabelledby
    the name of a control to act as a label for this control; for example, you could enter the name of a label object to link it to the control. A value in $arialabelledby will override the value in $arialabel; you can use a space separated list of controls to assign multiple controls as labels for the component

  3. $ariadescribedby
    the name of a control used to describe this control: similar to $arialabelledby, but could be used to provide more information or a longer description about the control; you can use a space separated list of controls to assign multiple controls as labels

You should note that JavaScript controls now have an $active property which works alongside $enabled allowing you to make controls active, inactive, enabled, or disabled, which helps you control accessibility and tab order in your remote forms.

Image based controls

You can assign an Alt text value to image-based controls, such as Picture and Activity, using the $alttext property:

  1. $alttext
    a short text to describe the appearance or function of an image, and equivalent to the “alt” attribute in HTML; this property is relevant for controls that contain an image or have a significant visual appearance, such as the Picture and Activity controls.

Page panes and Landmarks

So-called “Landmark Roles” in standard accessibility guidelines allow you to identify different areas of a form to allow screen readers to describe the structure of the page to end users. You can define Landmarks in your JS remote forms using Page panes and by assigning the appropriate value to the $landmark property for each pane: the options for $landmark correspond to the same keywords used for landmarks in the accessibility guidelines (Main, Navigation, Banner).

  1. $landmark
    specifies a role to make the page pane an ARIA landmark region, a kLandmark… constant with kLandmarkNone as the default.

The Landmark options are:

Landmark option Description
kLandmarkMain A “Main” landmark which identifies the primary content of the remote form
kLandmarkNavigation A “Navigation” landmark which identifies an area containing navigation type control or list of links used for navigation
kLandmarkBanner A “Banner” landmark which identifies an area usually at the top of the form, possibly containing logo, company or application name and search box
kLandmarkContentinfo A “Contentinfo” landmark which typically identifies common information at the bottom of a form
kLandmarkComplementary A “Complementary” landmark which many contain supplementary information or further links, such as a sidebar
kLandmarkForm A “Form” landmark which identifies an area containing a number of input controls or other form controls
kLandmarkSearch A “Search” landmark which typically would contain a Search field and button
kLandmarkNone No landmark definition

Label controls

You can link a Label control to a specific Edit control, or you can tag a label as one of the HTML header types, using the following properties:

  1. $labelfor
    links a label to a control. If you use this with some controls such as the Edit control, the linked control will get the focus if the label is clicked. It can be used in addition to $arialabelledby.

  2. $tagtype
    can be used to set a label’s HTML tag type to one of the header types (<h1> etc.) which would allow the end user to navigate to different sections of a form: the default value is kJSLabelTypeLabel, which is a standard untagged label, and the other values include H1 to H6 for the header types.

Control text

If a control has some text assigned (e.g. a button), the screen reader will read out the text by default, therefore it is not always necessary to assign the ARIA properties to describe such controls. For example, the text for a Button control will be read by the screen reader, if no ARIA properties are specified, however the value in $text will be overridden if you specify $arialabel or $arialabelledby.

Content tips

The Edit control has the $::contenttip property which is a text string which is displayed in the edit field when it is empty and before the end user has entered any text. This can be used in addition to the ARIA label properties, to help label the edit controls on your forms: note it is good practice to add labels to all the edit controls on your form to help with accessibility, so do not rely solely on content tips to describe edit controls.

Keyboard Accessibility

As well as the ARIA properties, the behavior when using various keys to navigate a remote form, or inside more complex controls, has been improved. For example, when the end user presses the Tab key, the focus will jump from one control to another in a remote (web) form, or for complex items such as a Tab bar, the Tab key will put the focus inside the control and the arrow keys can be used to move from one element to another. In addition, the Arrow keys can be used to interact with controls, such as dropdown menus, while Enter and Spacebar can be used to select options or items. The Page Up/Down keys can be used to scroll a form or long list which has the focus.

Tabbing Order

The $order property determines the tabbing order for the controls within a remote form. The value of $order for each control is assigned automatically as you add controls to a form in design mode, starting at 1 and increasing by 1 for each control (note the $order values do not change if you move or rearrange the controls on the form). You can change the $order value of a control to change its tab order: when you change the value of one control, the $order value of other controls on the form will be adjusted in sequence automatically.

When you tab into a container, such as a page pane, the tab order takes you through all of the fields in the container, before tabbing out of the container.

The $startfield property specifies which field in a remote form will get the focus when the form is opened, overriding the control with its $order property set to 1; $startfield takes the field number as specified in the $order property of the control. Note this property may have an impact on accessibility, insofar as the field specified in $startfield may not be the first field on the form, thereby going against most accessibility practice.

Design tab order

All JS components have a $taborder read-only property in design mode which shows the resolved tab order within the form, taking into account container fields, such as paged panes. The context menu on a remote form has a "Show $taborder" option, so that you can see the value of $taborder for all controls on the form. You can still alter the tab order of the controls in a form by modifying $order for each control.

Next Tab Object

All JS components have a property $nexttabobject which allows you to override the default tab order set by the $order property for all the controls in a remote form. The $nexttabobject property allows you to specify the name ($name) of the control you want the end user to tab to after the current object, overriding the tab order set by $order. You should not overuse this property, as it does incur some overhead by setting up additional event listeners.

Accessibility and tabbing order

For increased accessibility in your applications, you should carefully consider the tab order of the controls in your forms. In general, it is good practice to make the tab order run consecutively, that is, from one control to the next in a logical order: this could be from left to right starting at the top of the form, but the exact order may depend on the specific functions of your app. The tabbing order of the controls in the form is also used by the screen reader to “read out” or describe the contents of the form, so it’s important how you specify the tabbing order of the fields in your form.

Form Example

With the ARIA labels specified and the correct tabbing order defined, the end user can navigate the controls on a form from the keyboard, and, in addition, the screen reader can describe each control or area of the form page in turn.

Consider the following JavaScript remote form. In the first image, as the end user tabs to the First Name edit field, the field border will highlight, the screen reader will say aloud: “First name, Edit text”, and if there is a value in the field, as in this case, it will read that as well: “First name, Peter, Edit text”.

image10

Using the Tab key, the end user can move from one control or area of the form to another. Successive tab presses will enter the Tab bar at the top of the form, then the Right and Left Arrow keys can be used to move along the Tab bar, and the Return key can be used to select a tab. Once the tab is selected, the screen reader will describe the item selected: “Careers / Education Experience, Tab selected, 2 of 4”.

image11

JS Themes

You can apply a consistent set of colors to JavaScript components on a remote form by selecting colors defined in a theme – underlying a theme is a set of CSS styles which are applied to controls at runtime on the client. Omnis has a number themes which you can use to style your JS client applications: a default theme, which provides an effective and pleasing UI across all JS controls and devices, and a range of different color themes, such as the dark theme, which provides an alternative set of darker colors.

When designing a remote form, you can change the current theme in the JS Theme Select dialog by pressing Ctrl-J/Cmnd-J, or select the JavaScript Theme option from the View menu (you can edit a theme from here by Right-clicking on a theme or background of the dialog and selecting the Open JavaScript Theme Editor option). To select a theme, click on the theme preview and close the dialog. The selected theme is applied to the current remote form and to all the remote forms in your library since the theme is an Omnis-wide preference.

image12

The current theme is stored in a new Omnis root preference, $javascripttheme (in $root.$prefs), which is set to the default theme initially, and controls which theme is used to render themed colors for all remote forms in design mode (but you can set or change the theme on the client using the ‘settheme’ client command; see later).

Selecting Colors

When you select the color for a JS control in design mode in the Property Manager, you can choose a theme color from the color picker, under the Theme color button (the default) in the color picker toolbar. For example, select a button, click on the Text tab in the Property Manager and click on the color picker for $textcolor.

image13

The color setting for most properties, such as $textcolor, is set to kColorDefault, which means the appropriate color from the current theme is used. If a text color property is set to kColorDefault, and it sits on an element with a background color which comes from a themed color constant, the text will be rendered in the associated <theme color>Text color. For example, if a button’s $buttoncolor is set to kJSThemeColorPrimary and its $textcolor is set to kColorDefault, the text will be rendered using kJSThemeColorPrimaryText.

The colors defined in a theme and shown on the color picker have corresponding color constants, whose names begin kJSThemeColor, as follows:

kJSThemeColorBackground kJSThemeColorPrimary
kJSThemeColorBackgroundText kJSThemeColorPrimaryDark
kJSThemeColorBorder kJSThemeColorPrimaryDarkText
kJSThemeColorDialog kJSThemeColorPrimaryLight
kJSThemeColorDialogText kJSThemeColorPrimaryLightText
kJSThemeColorDialogTitle kJSThemeColorPrimaryText
kJSThemeColorDialogTitleText kJSThemeColorSecondary
kJSThemeColorDisabled kJSThemeColorSecondaryDark
kJSThemeColorDisabledText kJSThemeColorSecondaryDarkText
kJSThemeColorError kJSThemeColorSecondaryLight
kJSThemeColorErrorText kJSThemeColorSecondaryLightText
kJSThemeColorFocusedRow kJSThemeColorSecondaryText
kJSThemeColorFocusedRowText kJSThemeColorSurface
kJSThemeColorNeutral kJSThemeColorSurfaceText
kJSThemeColorNeutralText

Theme Editor

You can create new themes, or modify an existing theme using the JS Theme Editor, available under the Add-Ons > Web Client Tools menu option and select JS Theme Editor.

image14

The editor provides a preview of the current theme on the right side of the editor screen, and you can click on an area or text item within the preview to view or set its color (you can also set colors by clicking in the list on the left).

The colors in a theme are categorized as Primary and Secondary, plus there are specific color for errors, borders, dialogs, and so on. The primary colors are used throughout your application and set the general tone or style of the theme, while the secondary colors provide an accent to certain parts of the UI.

Creating a new theme

To create a new theme, you can duplicate an existing theme and make any changes to the copy. To do this, open the Theme Editor, select a theme from the dropdown list or use the default theme (selected initially by default), click on Save as and give the new theme a name – then change individual colors and use the Save option to save any modifications. The Set theme option sets the $javascripttheme preference to the theme currently shown in the editor. If you make any modifications to the current theme, all open remote forms will be updated automatically.

A theme is stored as a .json file and an associated .css file in the ‘html/themes’ folder. When deploying your application, the themes folder and its contents must be copied to the corresponding location on the Omnis App Server.

When designing the colors in a new theme, you may want to follow the guidance provided by the Google Material design system, which may help you create a theme containing colors which complement one another and provide maximum usuability and accessibility across different platforms and devices. Google provides a Material Color Tool which you may find useful to create a set of complementary colors for the dark/light variants.

Themed Icons

This version of Omnis supports the use of SVG images for component icons (see the next section in this doc regarding how to use SVG icons). For the JS client only, SVG icons can be “themed” which means an icon will be tinted using the control’s text color as specified in the current JS theme (the ‘fill’ color in a themed SVG file is set to the text color from the theme). This allows a single themed SVG icon file to be used with different themes and its color is set automatically.

Omnis includes an icon set named ‘material’ which contains over a 100 themed SVG icons; note that icons from this icon set can only be used with the JS Client. In order to use these icons, you need to add the ‘material’ icon set name to the $iconsets library property in your library ($iconsets now allows a list of icon set names). The material icon set is located in the ‘\html\icons’ folder and if you have used any of the icons in your app the icon set needs to be copied to the Omnis App Server when deploying your application.

The following are examples of a single icon from the material icon set with different color themes applied (note the icon is rendered using the button text color):

image15

SVG icon files can be ‘themed’ using the SVG Themer tool under the Add Ons > Web Client Tools menu option. You can open a single SVG file, preview it using one of the test colors (the preview colors are not saved to the file), and save it using the Export button.

image16

The SVG Themer tool converts a standard SVG image file into an Omnis themed SVG file format: specifically, the first element in the root svg element in the original file is converted to a ‘g element’ with fill="var(--om-tint-color)" and id ‘omTheme’ which reference the color from the current theme. The Image Data tab shows the source for the converted SVG file which you can edit if required, although the converter converts the the SVG file as necessary.

Like other SVG icon files, any themed SVG icons need to placed in an icon set folder. For example, you could create or acquire a set of SVG icons and convert them using the SVG Themer tool ready for use in your JS client apps.

HTML Template & Client theme setting

The JS client’s theme is set in the ‘data-themename’ attribute in the omnisobject div in the HTML file for your remote form, e.g. data-themename="dark".

The special value of “_JT_” is used in the HTML template (jsctempl.htm) which is replaced this with the current value of $javascripttheme when Omnis generates the HTML file for your remote form.

In addition, the 'data-appid' attribute specifies the application a page belongs to. It defaults to '<lib name>.<form name>' each time a form is tested (the '_APPID_' placeholder in the template .htm file is replaced when a from is tested).

Changing the Theme

You can change the theme on the JS client in your code using the ‘settheme’ client command ($clientcommand) which takes a row parameter whose first column is the name of the new theme. Note that a remote form needs to be reloaded in the browser for a change of theme to take effect. Once you have set the theme using the ‘settheme’ clientcommand, the client stores it in the client localStorage and will use that theme for subsequent visits to the page. To revert to the default theme specified in the HTML page, you need to call the 'settheme' clientcommand, passing an empty string as the theme name (or clear the client's localStorage).

The current theme: $construct

The current theme is passed in the $construct row parameter, in a column named theme.

Component Transparency

The majority of the JavaScript components have the $alpha and $backalpha properties which allow you to set the transparency of the foreground and background colors of the component.

$active & $enabled Properties

All JavaScript controls have the $active property, which is set to kTrue for all new controls (except the Label Control which is kFalse). The $active property allows you to control whether a component is active (kTrue) or inactive (kFalse) – in an inactive state, a component cannot be interacted with at all, so the end user cannot tab to it, the contents cannot be selected or scrolled (in a list), and user clicks on an inactive control are ignored. Therefore, when a control is inactive, it is completely ignored in the tabbing order, so when the end user tabs the focus will jump to the next active control – in the context of accessibility, an inactive component will be ignored.

The $enabled property allows you to disable a control, and many controls have this property, including: Bar Chart, Combo Box, Data Grid, Date Picker, Edit, List, Map, Pie Chart, Rich Text, and Tree list.

Disabled Appearance Property

All controls that have the $enabled property have the $defaultdisabledappearance property. When $enabled = kFalse the $defaultdisabledappearance property defaults to true and the 'omnis-notenabled' css class is applied to the client element of the control. If $defaultdisabledappearance = kFalse, this class is not applied, which is what sets the text colour to grey when disabled.

Creating Customized JavaScript Components

You can add your own customized JavaScript components to the Component Store under your own tab. This might be useful if you always want to create edit controls or buttons with certain properties (e.g. colors or fonts), so creating your own custom JS components might save you some time. You will need to edit the Component Store library (comps.lbs) to change the contents of the Component Store.

To create your own customized JS components, you need to create a new JS remote form in the Component Library, copy any components you want to customize from the JSFormComponents form, add them to your own form, and then customize then as required.

Opening the Component Library

You can open the Component Library by Right-clicking on the Libraries node in the Studio Browser tree and selecting the Show Comps.lbs option. Unless you want to copy classes from another library to the Component Library, it is recommended that you close all other libraries before you edit the Component Library.

When you select the Show Comps option, the contents of the Component Library is displayed in the Browser Browser. You can switch the Browser to Details view and click on one of the column headings to show the different types of component either by Name or Type. You can hide and show specific types of class in the Component Library using the Class Filter option in the Browser.

Adding your own form and components

We recommend that you do not change the components in the JSFormComponents form since these are the default components that appear in the Component Store, rather you should create your own customized components using the following method.

Add a new JS remote form class to the Component Store library (comps.lbs); note that the name of the new remote form will be used as the tab name in the Component Store toolbar so choose something appropriate. Set the $componenttype property of the remote form to kCompStoreDesignObjects using the Notation Inspector: to do this, open the Notation Inspector, click on the Search button (the cursor changes to a spy glass), click on your remote form in the Studio Browser, and in the Property Manager set $componenttype to kCompStoreDesignObjects (note the $componenttype property will only be displayed via the Notation Inspector). Then set the $layouttype of the new remote form to kLayoutTypeSingle (not kLayoutTypeResponsive).

With your new remote form open, open the JSFormComponents remote form next to it (this form contains all JS components). Drag any JavaScript controls you want to customize from JSFormComponents into your new remote form and change their properties or appearance as required. After you hide the Component Store library, the customized JavaScript controls will be available in the new group in the Component Store.

JavaScript Component Templates

When you add a JavaScript Component to a remote form in your code at runtime, Omnis uses a template to create the object with all the required properties and methods. There is a template for every type of JavaScript Component, and the templates are located in the \studio\componenttemplates folder.

The component templates match the default components in the Component Store, and should not be edited. There are templates for report and window class components as well.

Position Assistance

When you move or resize objects using the pointer Position Assistance provides visual guides (colored dashed lines and arrows) that enable you to easily align and distribute controls and other objects in a design window in relation to the other objects. As you move or resize objects on a remote form, colored lines are shown automatically, and objects will snap into position to help you arrange the objects in a form. For example, when you place a number of fields on a form Position Assistance can help you align their left-hand or top edges and ensure they are spaced evenly. Position Assistance is also provided when you use the Arrow keys to position or resize objects.

The Show Position Assistance option on the remote form context menu allows you to toggle the Position Assistance feature (enabled by default). There is a single setting for this, shared by all editors, that is saved to omnis.cfg when Omnis shuts down.

image17

Position Assistance for sizing does not apply when Size to Grid is turned on, and for moving object it does not apply when Align to Grid is turned on.

The positioning lines are drawn using the colorhighlight color in the system group of appearance.json. The entry positionAssistantKeyboardTimer in the ‘ide’ section of the config.json specifies the time that the position assistance remains visible after you stop pressing an arrow key; this defaults to 750 milliseconds.

When positioning objects in the center of a remote form, Position Assistance uses the center of the current layout breakpoint, not the center of the remote form design window.

Positioning & Aligning Objects

When the Position Assistance is enabled, Omnis gives precedence to distribution over alignment, and within alignment it prioritises the top edge, over the center, and the center over the right edge. As soon as a visual guide is displayed for a target, any other targets that would also cause the object to move in the same axis are dropped.

As you move or size objects Omnis displays a visual guide when the object(s) being moved or sized are within +/-2 pixels of a specific alignment or distribution target, e.g. an alignment target is the top edge of another object or objects. When you release the mouse, the objects will snap to the displayed target. Position Assistance is applied to objects dragged from the Component Store, as well as objects being moved or sized within a design window. Position Assistance is provided when moving an object even if the adjacent objects are contained inside a container field.

When sizing objects, assistance is not provided if the objects being sized have more than a single container, that is, the component that is the parent of the objects – this can be more granular than a field, such as for complex grids, there are several containers such as the row and header sections.

Position Assistance is provided within each section of a Complex Grid, that is, the row and header sections of a Complex Grid, and the above behavior for container fields applies to each section independently.

Distribution

Position Assistance attempts to distribute objects by allowing them to be evenly spaced. The visual guide for distribution is a line drawn between the objects with arrow heads.

image18

The guides are drawn for as many objects as possible, immediately adjacent to the object(s) being moved or sized. Position Assistance works best when objects are already reasonably well arranged, either vertically or horizontally, so for more complex arrangements, with overlapping fields may result in no visual guides being presented.

Alignment

Position Assistance attempts to align objects by giving them the same top or bottom coordinate, or centered relative to each other. When you try to center objects, you only get visual guides when moving objects, and when the appropriate side of the rectangle representing the objects being moved either fully encloses or is fully enclosed by the appropriate side of the object in which it is being centered. The following illustrate how the Position Assistance is applied for different cases when aligning objects.

image19 image20
Top alignment Bottom alignment
image21 image22
Left alignment Right alignment

Positioning for Paged Panes (Container fields)

Assistance is provided to help you align fields inside a container field, such as a Paged Pane. In addition to the left/right, top/bottom positioning, when you move an object inside and near to the center of a container, a line across either the vertical or horizontal center of the container is drawn and the object will snap to the line.

image23

When positioning objects inside a Paged Pane (or any container), Position Assistance is only provided for the controls within the Paged Pane itself, so objects outside the Paged Pane are not included in the current object grouping. Similarly, if you are positioning objects outside, but near to a Paged Pane, the objects inside the Paged Pane are not included in the current grouping.

Activity Control

The Activity Control provides an animated image to show some activity on the client, for example, during a long list calculation or search operation on the Omnis Server.

There is an example app in the Samples section in the Hub in the Studio Browser showing the different activity controls available and how to set a custom animated Gif; the same app is available in the JavaScript Component Gallery.

The Activity Control has the following custom properties:

Property Description
$activitystyle The style of the indicator, one of the following constants:
kJSActivityBar: a moving bar
kJSActivityBlock: a moving block
kJSActivitySmallSpinner: a small rotating spinner
kJSActivityCustomLink: the image in $customlink is used
$customlink The path of an animated GIF which can be displayed when $activitystyle is set to kJSActivityCustomLink

The $activitystyle property specifies the style of the control, either a Bar, Block, a small Spinner, or a custom Gif specified in $customlink.

image24image25image26

The following code assigns a custom link to the activity control:

As an alternative to using the Activity Control you could consider using the showloadingoverlay client command to show a loading indicator (animated image) over a remote form or specific control.

Background Control

The Background Control allows you to draw various shapes in your remote forms: you assign the shape to the object by setting the $::shape property to one of the kJSBack... constants. It can be assigned one of a number of shapes including: Ellipse/Circle, Rectangle/Square, Rounded rectangle/Square, Triangle, Horizontal Line, Vertical Line, and Image.

image27image28image29

If the object is an Image, the image source is specified in $imagepath as a URL relative to the Omnis tree during development or your web server for deployment.

You can assign a solid color or gradient fill to a background component by setting its $backpattern, $forecolor and $backcolor. You can also assign the stroke (border) thickness and color by setting $strokewidth and $bordercolor.

Animations and Changing Attributes

The Background Control has the $animation and $attr properties which allow various animations or effects to be assigned to the object, such as fading the object in or out, or for $attr various attributes of the object to be changed. The $animation and $attr properties must be assigned at runtime and accept a string containing various parameters depending on the function or attribute.

There is an example app in the Samples section in the Hub in the Studio Browser showing how can use animations to move and fade objects to create a richer UI; the same app is available in the JavaScript Component Gallery.

image30

Apart from the scale attribute, the browser must support the Raphael JavaScript library to allow animations and attribute changes (more details about the parameters you can use are available from http://raphaeljs.com).

The $animation property follows the general format:

function( newvalue, time(milliseconds), ease(optional), complete_context(optional) )

The functions available in $animation are:

  1. scale
    increases and decreases the size of the object

scale( newvalue, time(milliseconds), ease(optional), complete_context(optional) )
  1. alpha
    changes the transparency of the object

alpha( newvalue, time(milliseconds), ease(optional) , complete_context(optional) )
  1. rotate
    rotates the object

rotate( newvalue, time(milliseconds), ease(optional) , complete_context(optional) )

For example:

Calculate $cinst.$objs.backgroundobject.$animation as "alpha(0,500,<>,fade_complete)"

fades the object to alpha value 0 over 500 milliseconds using a ‘slow, faster, slow’ easing method (see below) and when complete calls evAnimComplete with a parameter "complete_context".

You can use the complete event to chain the next animation, therefore to pulse an object you could use:

Calculate $cinst.$objs.backgroundobject.$animation as "alpha(0,500,<>,fade_off)"

You could use the event handling method:

On evAnimComplete
  If pAnimContext="fade_off" )
    Calculate $cwind.$objs.backgroundobject.$animation as       "alpha(0,500,<>,fade_on)"
  Else ifpAnimContext="fade_on" )
    Calculate $cwind.$objs.backgroundobject.$animation as
      "alpha(0,500,<>,fade_off)"
  End if

Ease transition effects

The following ease transition effects or “eases” are supported for animations:

= linear and default if not specified
> fast then slowing
< slow then faster
<> slow, faster, slow
bounce object bounces
elastic object stretches
backIn object backs in
backOut object backs out

Changing Background Attributes

The $attr property allows you to change various attributes of the object, such as their transparency. For example, you can assign an alpha gradient to an object using the following method:

# note must be assigned at runtime
Do $cinst.$objs.backgroundobject.$attr.$assign('attr(gradient, 0-#FFFFFF:10-#FFFFFF)')
Do $cinst.$objs.backgroundobject.$attr.$assign('attr(opacity,0.0)')

Bar and Pie Chart Control

Omnis Studio provides two chart controls: a Bar Chart Control and a Pie Chart Control. The data to be represented in both these controls is contained in a list variable which is assigned to the $dataname property of the control. There is a sample app for both Bar charts and Pie charts in the JavaScript Component Gallery, and under the Samples option in the Hub in the Studio Browser.

image31

There are various properties (on the Appearance tab in the Property Manager) that allow you to control the appearance of a Bar or Pie chart. The bars and segments use a set of default colors, but you can specify your own colors at runtime.

For Bar charts you can set $chartdirection to vertical (the default) or horizontal bars, the style of the bar ends as the $barends property (kJSBarEndSharp is shown below), and you can display data values when the end user’s mouse hovers over the bar by setting $showvalue to True (the default).

image32

Specific properties for Pie charts are described under the Pie Chart Control section.

List data structure

To draw a simple bar or pie chart, the list variable assigned to the $dataname property of the chart component needs to contain at least two columns. The first column contains the value for the data point, and the second column contains the label or name for the data point. For example, to construct a simple bar chart showing a list of figures for sales agents, you could use the following method:

# create vars bar_data (List), amount (Number), name (Char)
Do bar_data.$define(amount,nam)
Do bar_data.$add(120,'Steve')
Do bar_data.$add(230,'Dave')
Do bar_data.$add(245,'Anita')
Do bar_data.$add(125,'Claire')
Do bar_data.$add(280,'Ben')

With the $showvalue property enabled (a value is displayed when the end user passes the pointer over each bar), the method produces the following chart.

image33

When $showvalue=kTrue, the popup label will use $backcolor for the text and $textcolor for the background of the label so that it can be seen against the background of the control.

Main and Axis Titles

There are a number of properties in the Bar Chart to allow you to add a main title, as well as titles for the x and y axis. In addition, there are properties to show (the default) or hide the x and y axis details or units.

$maintitle The main title for the chart
$xtitle title for the x axis
$ytitle title for the y axis
$showxaxis if kTrue the chart shows x-axis details
$showyaxis if kTrue the chart shows y-axis details

image34

Text and Axis Colors

The $textcolor and $axiscolor properties allow you to set the color for text and axis, including theme colors; $textcolor applies to the color of the title, labels, axis text, and legend in the chart, where applicable.

The $axiscolor property for a Bar chart applies to the color of the both axes lines, and the unit lines which run across the bar chart.

When set to kColorDefault, both properties will set their color dynamically according to the color of $backcolor.

Bar & Segment Color

You can specify your own colors for the bars or segments in a Bar or Pie chart using the runtime-only property $colorlist, rather than using the default colors. You need to create a list of strings representing CSS colors and assign the list to the $colorlist property, for example:

Do iColorList.$define(iColor)
Do iColorList.$add("#CE3D3D")
Do iColorList.$add("rgb(81, 206, 61)")
Do iColorList.$add("hsl(230, 60%, 52%)")
Do iColorList.$add("Gold")
Do $cinst.$objs.PieChart.$colorlist.$assign(iColorList)

The accepted color formats are: Hex Code RGB, Decimal Code RGB, HSL, or Color Name, and the formats can be mixed throughout the list as in the example above.

If there are not enough colors available in the color list for the number of segments in the chart, then Omnis will repeat the colors in $colorlist. Therefore, if you want to avoid repeating colors, create a color list containing more colors than you will generally need to cater to the number of data points in your chart.

Theme Colors

The $colorlist property can contain kJSThemeColor... constants to allow you to match the colors in the current JS theme. Note you cannot use standard Omnis color constants (such as kRed, etc.) in this context, since these are taken as literal text on the client.

Events

Bar charts report the evBarClicked event with the bar clicked in the pBar parameter. Similarly, Pie charts report the evSegmentClicked event with the segment clicked reported in pPieSegment.

# event method for bar chart, message is a field on the form
On evBarClicked
  Calculate message as con("Bar clicked: ",pBar
# event method for pie chart
On evSegmentClicked
  Calculate message as con("Segment clicked: ",pPieSegment)

Button Control

The Button control is a basic pushbutton that the end user can click with the pointer or tap on a mobile device to confirm something or initiate a process, such as an OK or Cancel button, or a Print or Send button. Many of the sample apps in the JavaScript Component Gallery contain buttons, including plain text buttons or ones with icons.

The text is specified in $text as a single line of plain text, unless $textishtml is set to true and the text is treated as HTML; see below. $align sets the alignment of the text inside the button and is centered by default.

image35

The button can display an icon, specified in the $iconid property, which can be an SVG or PNG image file from an Icon set chosen from the Select Icon dialog; the ID can be an icon name or a URL pointing to an image file in the ‘html/icons’ folder. See earlier in this chapter about JS Component Icons and specifically SVG Icons.

The Button has the following additional text and appearance properties:

Property Description
$buttonbackiconid The icon id of background image for the button. To use the default system button, set $buttonbackiconid to zero and $buttoncolor to kColorDefault
$buttoncolor The color of the button. To use the default system button, set $buttonbackiconid to zero and $buttoncolor to kColorDefault
$borderwidth The border width in pixels (the default is 0 or no border)
$bordercolor Sets the border color when $borderwidth is set >0
$textbeforeicon If true, and the control has both text and an icon, and the text is displayed to the left of the icon
$::vertical If true, the text and icon are arranged vertically
$textishtml Specifies that the text entered in $text is treated as HTML
&isflat If true, the button has a flat appearance

Flat Button Style

The flat style of a button is controlled using the $isflat property. The style for all new buttons (and buttons in converted libraries) is flat (from Studio 10.2 onwards), so $isflat is set to true. In addition, if the value of $buttonborderradius in converted libraries is set to 0, it will now be changed to the new default of 4; any other value will be retained on conversion.

When $isflat is disabled a button has a small drop shadow and when the button has the focus a larger difused drop shadow is displayed around the button.

Disabled Appearance

The appearance for flat buttons when they are disabled ($active = kfalse) is as follows: if $isflat is kTrue (the default), the button back color will become transparent (if it isn't already) and the text color will take on the disabledText color. If $isflat is kFalse, the button back color will take on the disabled color and the button text color will take on the disabledText color.

In addition, if $bordercolor for buttons is set to kColorDefault the color will match $textcolor. When disabled ($active = kFalse), the border will match the disabled text color to maintain a consistent disabled appearance.

HTML Button Text

When set to kTrue the $textishtml property specifies that the text for the button (entered in $text) is treated as HTML, therefore any HTML can be used to style the text. For example, you can insert a line break by setting this new property to kTrue, and using <br> in $text for the button wherever a line break is required.

The $textishtml property also allows other styling of the button text using various character and color attributes. Note that design mode does not render the HTML (the raw HTML code is displayed), and if you use attributes in the HTML they must be enclosed in single quotes.

Events

When a Button is clicked an evClick event is triggered which you can handle in the event handling method behind the button.

On evClick
  Do something…

Example

The sample apps in the Applets section in the Hub have an About window which is loaded into a subform and displayed using an animation; see the Animations section for the About button code. The Close button on the About windows simply closes the About form by sending a message to the main remote form to run a method; it has the following code:

On evClick
  Do $cwind.$closeAbout()

In this case, $cwind is a reference to the main parent form which contains a method called $closeAbout which contains code to fade out the About form and reset various buttons on the main form.

Checkbox Control

The Checkbox control can represent On / Off or Yes / No values and is typically used to allow the end user to turn an option on or off, or accept or decline a preference. Several of the sample apps in the JavaScript Component Gallery feature check boxes, such as the Map example.

The variable you specify in the $dataname property of a Checkbox should be a Number or Boolean variable. The $text property specifies the label text for the Checkbox. The $checkboxcolor property specifies the color for the Checkbox (and check boxes when they appear in Lists, Data grids & Tree lists).

When a Checkbox is clicked an evClick event is triggered with the current value reported in the pNewVal parameter.

Example

There is an example app in the Samples section in the Hub in the Studio Browser to show how you can use a check box (and a Radiogroup); the same app is in the JS Component gallery on the Omnis website at: www.omnis.net. The example uses a series of check boxes and a radio button group to filter a list of people based on their gender and age group. The group of controls on the remote form could look like this (the following screen shows the ‘professional’ JS Theme in use):

image36

The $dataname for each of the check boxes is iAgeRange1, iAgeRange2, and iAgeRange3 respectively. These are all Boolean variables defined in the remote form, and the $dataname of the Radio button group is iFilter, which is defined as a Short integer. Each separate check box and the Radio group has a simple event method, which is:

On evClick
  Do method filter

which will call the ‘filter’ class method when any of these objects is clicked. The filter method filters the contents of the list called iList based on the selection of the check boxes and radio buttons, and has the following code:

Do iList.$unfilter(0)

If not(iAgeRange1)
 Do iList.$filter(not(iAge<=20))
End If
If not(iAgeRange2)
  Do iList.$filter(not(iAge>=21&iAge<=40))
End If
If not(iAgeRange3)
 Do iList.$filter(not(iAge>40))
End If
Switch iFilter
  Case 1
    Do iList.$filter(iGender='F')
  Case 2
    Do iList.$filter(iGender='M')
End Switch
  

Note the ‘Smart list’ capability has to be enabled on the iList variable to allow the built-in filtering using the $filter method; this is done in the $construct method of the form in the example, using the following code:

Do iList.$smartlist.$assign(kTrue)
  

Combo Box

The ComboBox control is a combination of a data field and a dropdown list from which the end user can make a selection or enter their own value into the field. There is an example app in the Samples section in the Hub in the Studio Browser (called JS Droplist, Combo, Popup); the same app is available in the JavaScript Component Gallery. The following screen shows a Combo Box using the Soft JS Theme.

image37

The variable for the data field part is specified in the $dataname property. You can specify a default list of options in the $defaulttext property, which is a comma-separated list of options, or build the list dynamically (with $::listname, see below). When $defaulttext is specified, $defaultline specifies the list line which is selected when the form is opened (set to 1 by default). The $::listheight property specifies the height of the droplist. The Combo Box has the $negallowed property which means it can display negative numbers.

Rather than using a default list specified in $defaulttext, you can assign the name of a list variable to the $::listname property to assign the contents of the list to the droplist part of the combo box; $listcolumn specifies which column of the list variable is used to populate the droplist part of the combo box.

When the list in a ComboBox is clicked an evClick is generated with the selected list line reported in the pLineNumber parameter.

Content Tips

The Combo box control has the $::contenttip property which is a text string which is displayed in the edit field part of the combo box when it is empty to help the user understand what content should be entered into the field. For example, for a Last name field you could enter ‘Enter your last name’ into $::contenttip to prompt the end user for their last name.

Auto correction and capitalization

Combo boxes have the $autocorrect and $autocapitalize properties, which when enabled means that any text entered into the edit field section of the control is corrected for spelling and capitalization automatically.

Example

The maintenance screen in the Webshop sample app allows the user to enter new products or delete existing ones: specifically, the data in the Webshop app contains food and drink items, but it could be any type of products. When the user enters a new product, they can select the product type from a Combo control; this allows the user to select from a list of given product types or enter a new one.

image38

The $dataname of the combo control is set to iDataRow.product_group, and the $::listname is iGroupList. The evAfter event is enabled in the $events property of the control. In the $construct method of the form, the iDataRow row variable is defined from the T_Products table class, as follows:

# $construct of jsMaintenance form
# sets up form sizes, etc, then…
Do iDataRow.$definefromsqlclass($tables.T_Products)
Do $cinst.$objs.$sendall($ref.$construct())

The last line of code triggers all the field specific $construct methods which in this case includes the Combo box control; the code defines the iGroupList from the product_group column in the T_Products table class, performs a select on the data, and fetches all the data back into the iGroupList variable.

Do iGroupList.$definefromsqlclass($tables.T_Products,'product_group')
Do iGroupList.$selectdistinct()
Do iGroupList.$fetch(kFetchAll)

When the user selects an item in the list or enters a new item into the entry part of the combo box, an evAfter event is triggered and the $event method behind the combo control is called, as follows:

On evAfter
 Do method newItem
 Do $cinst.$setcurfield('product_name'## puts the focus in the product_name field

The newItem method is placed behind the Combo box control itself and contains the following code:

Do iGroupList.$search(
  $ref.product_group=iDataRow.product_group,kTrue,kFalse,
  kFalse,kFalse## test iGroupList for group/type entered
If iGroupList.$line=0 ## if not found in the group list
  Do iGroupList.$add().product_group.$assign(
  iDataRow.product_group## add a new group to the list
End If

Complex Grid

A Complex Grid can display multiple rows and columns of data taken from a list variable specified in the $dataname property of the control. You can use a $construct method behind the grid control itself to build the list data to populate the fields in the complex grid. To create a complex grid, you can place other controls in the row and header sections of the grid control, including standard entry fields, droplists, buttons, and check boxes: these controls are duplicated for every row in the grid, displaying each row of data from the data list. The $dataname of each component you place in the grid must correspond to a column in your list variable supplying the data to the grid. A complex grid is a container field having its own $objs group containing the objects inside the grid control.

There is a Complex Grid example app in the Samples section in the Hub in the Studio Browser; the same app is available in the JavaScript Component Gallery, plus there is a Webshop app that uses complex grids in the Applets section; the webshop app is described later in this section.

image39

Events

You can place event methods behind the embedded controls to react to user input and clicks within individual fields/cells in the grid. For example, you can have a button in each row of the grid which when clicked triggers an evClick event which runs the $event method for the button that performs an action based on the row clicked.

The Complex Grid itself can have evClick & evDoubleClick events. When clicking on the background of a complex grid row, or a control within the grid which does not have a click event enabled, the evClick or evDoubleClick will be fired. Both of these events receive pLineNumber parameters indicating the line number which was clicked. If no line was clicked (the end user has clicked on empty space), pLineNumber will be 0.

Object position in the grid

Every field or object in a Complex grid has the $gridsection property which tells you the section the object is in, while $gridcolumn which tells you its column. The $gridsection property is shown in the Notation Inspector so you can inspect its value for an object in a grid section at runtime.

List Pager

The Complex Grid control has the $pagesize property that allows you to display the lines in the grid as separate pages: see the List Control section for more details.

image40

Scrolling

The complex grid has the properties $vscroll and $hscroll to allow you to scroll a grid dynamically. The $vscroll property takes the row number in the grid to scroll to. The $hscroll property takes the absolute horizontal pixel position to scroll to in relation to the left edge of the grid control, that is, the grid will not scroll by a specified amount, rather the grid will scroll to the absolute position in the grid specified by $hscroll.

Scroll Tips

You can use the property $vscrolltips to display a scroll tip when a complex grid scrolls vertically. If $vscrolltips is kTrue, the default scroll tip is the contents of column 1 of the list for the first fully displayed row. To override this default scroll tip, implement a client-executed method for the complex grid object, called $getscrolltip. $getscrolltip accepts a single parameter (the row number for which the scroll tip is required), and returns the scroll tip text.

A complex grid can include a scrollable footer section similar to the existing scrolling header section. To enable a scrollable horizontal footer, you need to set $showhorzfooter to true. The complex grid has the following properties to control the appearance of the footer:

  1. $horzfooterheight
    The height of the grid horizontal footer

  2. $horzfooterfillcolor
    The fill color for the grid horizontal footer

  3. $horzfooterborder
    The border style for the grid horizontal footer

  4. $horzfooterlinestyle
    The line style for the grid horizontal footer

Row divider line style and Field Styles

The $rowdividerlinestyle is assignable at runtime and by $fieldstyle. As $rowdividerlinestyle is a custom field in a $fieldstyle it gets assigned at runtime, and is treated like any other runtime property change, therefore it is assignable at runtime. Note that $rowdividerlinestyle changes just the border between each row in a Complex grid, unless $rowborder is set to kJSborderPlain, in which case it also effects the border around the client, i.e. the section of the complex grid which contains the rows.

Extra space

The $extraspace property can be used to add extra space to the line content in the grid. If $extraspace is zero, the height of each row is the default height of the row content. If $extraspace is greater than zero, the height of each row is the font height + $extraspace.

Dropping data onto a grid

The end user can drag data from a remote form field and drop it onto a cell in the grid. Complex grids have the evCanDrop and evDrop events, and the $dropmode property to enable drop support. The pDropRow event parameter is available for evCanDrop, evWillDrop and evDrop events, and reports the row of the complex grid on which the drop is to occur (zero if the control does not belong to a complex grid).

It is possible to drop data onto a single control in the grid (a cell) in any row in the grid, as long as it has its $dropmode enabled. If not, the complex grid itself will receive the drop.

Exceptions

You can format individual cells in a complex grid by applying “exceptions” to those cells: you can then apply different formatting to those cells. For example:

Calculate $cinst.$objs.Products.$objs.Product.6.$backcolor as kBlue

or using indirection:

Calculate lNum as 4
Calculate lProp as "$backcolor"
Calculate $cinst.$objs.Products.$objs.Product.[lNum].[lPropas kBlue

You can attempt to set an exception for any property, although in practice this may not be satisfactory for some properties. Appearance properties, and button text for example should however all work as expected.

You can set exceptions in both server and client executed code.

In addition, the method $clearexceptions() can be used to clear exceptions. For example (Products is a complex grid object):

# Clear all exceptions for the Product object on all lines where it has exceptions
Do $cinst.$objs.Products.$objs.Product.$clearexceptions()
# Clear all exceptions for the Product object on line 4
$cinst.$objs.Products.$objs.Product.$clearexceptions(4)
# Clear all exceptions set in the complex grid
Do $cinst.$objs.Products.$clearexceptions()
# Clear all exceptions set on line 4 of the complex grid
Do $cinst.$objs.Products.$clearexceptions(4)

You can execute $clearexceptions() in both server and client executed code.

Existing users should note: Prior to the implementation of exceptions, objects in the row section could lose property values set at runtime, when updating the grid data. This issue has been resolved as part of the exception implementation.

Complex Grid Restrictions

A complex grid cannot contain another complex grid as a member, in any section. A complex grid cannot contain a subform in the row section. These restrictions apply to controls that would be direct members of the section, or indirect members that are children of a paged pane. Omnis enforces this by preventing you from dropping these controls into the relevant section(s).

Note: the $add() method for remote form class objects has not been updated to enforce this restriction, therefore using $add() to place controls in a section which does not support them could lead to undesirable results.

Example

The Webshop sample app, available in the Hub in the Studio Browser, uses a Complex grid in the main product remote form to display a list of products. Individual fields for the picture, name, description, price/size of the product are added to the first line of the complex grid; when the form is opened on the client and the data is loaded into the grid, these fields and are repeated for each row in the data list (one row per product).

image41

The $dataname of the complex grid is set to iProductList which is built from a table class T_Products which is linked to a schema class sProducts. A $construct method is placed behind the complex grid that builds the list needed for the complex grid data.

# $construct of complex grid control in jsShop form
Do iProductList.$definefromsqlclass($tables.T_Products)
Calculate whereClause as con('WHERE product_group = ',kSq,'Appetizers',kSq)
Do $cfield.$build(whereClause## calls $build
# $build method also behind complex grid control in jsShop form
Do iProductList.$select(pWhereClause,' ORDER BY product_isfood desc')
Do iProductList.$fetch(kFetchAll)

When the form is opened, the $construct method is run and the product list is built from the database, while the data itself is displayed in the various fields embedded in the complex grid with each product shown on a separate line in the complex grid.

image42

There are three order buttons placed in the row of the complex grid; they are repeated for each product in the list and allow the end user to order different sizes of product, such as a small, medium, or large drink or pizza. Each of the buttons has a simple method behind it that passes a number to the process_order class method; the first button sends value 1, the second button value 2, and the third button value 3.

# ‘Order now’ button method
On evClick
  Do method process_order (1)

See the Data Grid section for the process_order method which updates the iOrderList and the Orders data grid accordingly.

Data Grid Control

The Data Grid is a powerful and versatile control that can display character and numeric data in a grid like structure, much like a table or spreadsheet format, allowing you to create compact, data-rich UIs for your web and mobile applications. There is an example app in the Samples section in the Hub in the Studio Browser (the same app is available in the JavaScript Component Gallery), showing how to use Data grids, including how to use custom cell formatting; the following screen shows the Vintage JS Theme in use.

image43

In addition, the Webshop example under the Applets section in the Studio Browser uses a data grid which is described later in this section.

The content for a data grid is supplied from a list variable specified in the $dataname property. The number of columns in your grid would normally correspond to the number of columns in your data list, while the number of columns in the grid object itself in set by $designcols. For each column in the grid (under the Column Tab in the Property Manager) you need to assign $columndatacol to map the grid column to a column in your data list: you can use the column name or number in $columndatacol.

The $hasheader property specifies whether or not the grid has a main header, while $columnheaderheight is the height in pixels of the column header; if set to 0 (the default) the header height will be the same as $rowheight. The $headertext property specifies the text for the header and $::boldheader lets you specify a bold header. The $columnnames property lets you specify the heading text for each column in the grid (a comma separated list of names), which do not have to be the same names as the column names in your data list variable. You can use \n in the text for $columnnames to create a line break.

The $currentcolumn property is the current grid column for which properties are being displayed under the Column tab in the Property Manager. The $movecolumn property allows you to move a column to the specified position in the grid during design mode.

The end user can enter data into the cells of the grid if $enterable is enabled, and as the end user tabs the grid can grow by adding more lines to accommodate more data if $extendable is enabled. If $autoedit is true, and a cell is editable, it will automatically go into edit mode when it is selected (and $hcell or $vcell are set).

The height of the rows in a data grid adjusts to fit the height of the font size specified in $fontsize, unless you specify a fixed height in pixels in $::rowheight. In addition, the height of the header area is adjusted automatically according to the font, but you can fix the height in $::headerheight.

Events

Along with the standard evClick and evDoubleClick events the Data Grid reports a number of events which you can detect in an event handling method behind the grid control.

  1. evClick and evDoubleClick (pHorzCell, pVertCell, pDataColumnName)
    sent after the data grid has been clicked or double-clicked

  2. evCellChanged (pHorzCell, pVertCell, pDataColumnName)
    sent when the current cell has changed, e.g. when navigating between cells with the arrow keys or clicking a cell that isn't the current cell.
    pHorzCell - The column number of the new current cell.
    pVertCell - The row number of the new current cell.
    pDataColumnName - the data list column name (or number) when the event is triggered

  3. evCellValueChanged (pHorzCell, pVertCell, pDataColumnName)
    sent when the user has changed the value of a cell.
    pHorzCell - The column number of the cell in the grid that has changed (not the column of the data list belonging to the data grid)
    pVertCell - The row number of the cell in the grid that has changed.
    pDataColumnName - the data list column name (or number) when the event is triggered

  4. evColumnsResized (pColumnWidths)
    sent when the user has resized a column.
    pColumnWidths - a comma separated list of the new column widths

pDataColumnName

The pDataColumnName event parameter contains the data list column name (or number) when the event is triggered. This is useful when columns in the data list do not map directly to the columns of the form data grid (that is, if $columndatacol is used to set the column order. If the list column does not have a name, the parameter contains 'C1', 'C2', etc, so it can be used notationally. The value of the cell can be obtained with: iDataList.[pVertCell].[pDataColumnName].

List Pager

The Data Grid control has the $pagesize property that allows you to display the lines in the grid as separate pages: see the List Control section for more details about the List Pager.

image44

Column Width

The $::columnwidths property allows you to set up the widths of the columns, which is a comma separated list of integer values representing each column width in pixels. In order for the data grid to cater for multiple screen sizes, the $columnwidthsarepercentage property allows you to switch to using a percentage in the $::columnwidths property. If true, the column widths in the data grid specify a percentage of the width of the control rather than a specific number of pixels. This affects the properties $columnwidth, $::columnwidths, and $columnminwidth.

Pick List

You can add a dropdown list or “picklist” to one of the columns in your data grid to allow the end user to select a value from a list of preset values. You must create another list containing the list of preset values and specify its name in the $columnpicklist property for the column in which you want to add the picklist. The datatype of the column in your main data list variable corresponding to the picklist column must be an integer, and $columnmode for the grid column itself must be set to kJSDataGridModeDropList. The integer value stored in this column will correspond to the line number of the selected line in the picklist.

For example, if you want to list a product in your main grid field that has only four possible colors, you could create a sublist containing those color values and assign this sublist to a column in your grid field corresponding to an integer column in your main data list: this would allow the end user to choose a color from a preset list of colors.

Cell Formatting

You can apply your own formatting to individual cells in a Data Grid. For user-defined Data Grids (where $userdefined is set to true) and where a column has its columnmode set to kJSDataGridModeCustomFormat, you can customize the HTML used to layout or format an individual cell in the grid.

When the grid is rendered (this occurs on demand e.g. when scrolling to make new data visible), it calls the object client method:

$formatcell(list line number, designed grid column number) 

which you implement to return html for the formatted cell contents. This HTML can, within reason, be anything you like: you can also just return a text string. To assist this, there are two new calls you can make:

  1. styledtohtml(text)
    the styledtohtml(text) function returns the HTML representing the text string containing embedded styles inserted using style() function. This is a built-in function, under the General tab of the Catalog, which must be run in a client-executed method in the JavaScript Client only.

  2. $addcolorcss(cClassName,iRgbColor,iAlpha)
    is a method of the data grid object (as such it can only be executed in client-executed methods). Call this in $init to add your own background color class to use with the html returned by kJSDataGridModeCustomFormat.This class takes browser specific issues with transparency into account.

For example, you can use the following method:

Do $cinst.$objs.dat.$addcolorcss("myclass",rgb(255,0,0),128)

in $init, and then do the following in $formatcell:

Calculate columnvalue as iList.[row].[col]
if (columnvalue == "bad")
  Quit method con(
    '<div class="myclass"
    style="padding:0;margin:0;height:16px">
    ',columnvalue,'&nbsp;','</div>')
  Quit method columnvalue

Using transparency in the CSS background allows the selection color to show through the formatted cell.

There is an example app in the Samples section in the Hub in the Studio Browser to show how you can use the grid formatting; the same app is available in the JS Component gallery on the Omnis website at: www.omnis.net.

image45

Data Grid Filter

You can add a filter to a data grid by enabling the $hasfilerarea property. When true, the grid has a filter area which can be opened by clicking on a ‘spyglass’ button in the data grid header; the search filter will be applied to the current column (the Product column in the screen shown below). The end user can type into the filter entry box to filter the contents displayed in the column. The following image shows the filter enabled for column 1:

image46

The other properties to set up the filter include:

  1. $filtercol
    The grid column to which the filter will apply; this can be changed at runtime in a client method, see below

  2. $filterareaheight
    The height of the filter area (when $hasfilerarea is enabled); if zero, the height is calculated automatically

  3. $filterlabel
    The text label for the filter entry field

  4. $filtervalue
    The name of an instance variable that contains the value used for filtering

  5. $multifilters
    enables a filter for all the columns in the data grid; see below

The following code is the $event method for a data grid, set to execute on the client:

On evCellChanged
 Calculate iHorzCell as pHorzCell
 Calculate iVertCell as pVertCell
On evHeaderClick
 Calculate $cobj.$filtercol as pHorzCell
 # assigns the filter to the selected column
 Calculate lColNames as $cobj.$columnnames
 Calculate lColIndex as pHorzCell-1
 # Find the display name of the column clicked:
 JavaScript:lFilterNamelColNames.split(",")[lColIndex];
 Calculate $cobj.$filterlabel as con(lFilterName,": ")

Filter control method

You can implement the $filtergrid control method on a data grid, which will be called whenever the user types text into the filter box for a single filter enabled grid (if enabled); this control method does not apply when $multifilters is enabled.

The $filtergrid data grid method should be set to execute on the client.

$filtergrid(Column dat, Filter String) 

The $filtergrid method receives two parameters: ColumnData & FilterString, the data in the filtered column for the row in question and the current filter string.

You can return true to say that the row should be included, or false to exclude it. If you return null (or nothing), the default handling will be applied to determine if the row should be shown.

Open filter method

The $openfilter client-executed method can be called from $init to allow you to open the filter area in the grid when the form is opened.

  1. $openfilter([bOpen])
    opens or closes the filter area if the grid has one, and returns kTrue if the operation was completed. bOpen: Use kTrue to open the filter area or kFalse to close it. Defaults to kTrue if unspecified.

Multiple filters

In addition to being able to set a single filter for any column, you can enable a filter for all the columns in the grid by enabling the $multifilters property (and in this case $filtercol is ignored). When $multifilters is enabled, a default filter is added to each column in the grid (when the spyglass is clicked).

image47

The filter has a number of operators to allow the end user to select the search type; the list of operators in the filter menu is determined by the data type of the column. When a search type is selected, a search field is displayed allowing the end user to add a search string; for date columns a date picker is also displayed.

The end user can use various keys to navigate the filter menus.

  1. Tab or Shift Tab will jump to the next or previous column filters.

  2. Space / Return on a filter type button will reveal the context menu.

  3. Up/Down arrows to move up and down the filter menu items.

  4. Escape closes the filter menu, returning to filter button.

  5. Space / Return on a filter menu item will select the item.

By default a column will show a full set of filter types based on the column data type. You can override this and only show a subset, or remove the filter from the column altogether. You can do this using a client method called $multifiltermenu(pCol), which is called before a popup filter menu is shown for a column. You can assign the filter types for each column using the pCol parameter; the filter types can be summed for multiple filter types, for example:

If pCol=6
    Quit method kJSDataGridFilterContainskJSDataGridFilterNotContains
Else If pCol=7
    Quit method kJSDataGridFilterHidden
End If
Quit method kJSDataGridFilterDefault

If you assign any filter types that are not supported by the column data type, the filter types will be ignored. You can use the following filter type constants:

kJSDataGridFilterContains Include contains (case insensitive)
kJSDataGridFilterDefault Include all filter types for the column data type
kJSDataGridFilterEmpty Include must be empty
kJSDataGridFilterEquals Include equals (case insensitive)
kJSDataGridFilterHidden Hide the column filter at runtime
kJSDataGridFilterLessThan Include less than
kJSDataGridFilterLessThanEqual Include less than or equal
kJSDataGridFilterMoreThan Include more than
kJSDataGridFilterMoreThanEqual Include more than or equal
kJSDataGridFilterNotContains Include does not contain (case insensitive)
kJSDataGridFilterNotEmpty Include must not be empty
kJSDataGridFilterNotEquals Include does not equal (case insensitive)

Localisation

The filter menu name and filter text signs can be localized (e.g. == for equals) and are stored in the Omnis omnisloc.js. The menu name and sign is separated with a “:” colon character and both parts are required.

"ctl_dgrd_filter_none": "No Filter:?",
"ctl_dgrd_filter_equals": "Equals:==",
"ctl_dgrd_filter_notequals": "Not Equals:!==",

Row Formatting

The $setlineheight property allows you to center text vertically in the rows in the data grid. If true, the grid sets the line height so that text is vertically centered in each row (the default is kFalse).

Header Formatting

You can create your own formatting for column headers by adding a client-side method called $formatheader which takes two parameters:

  1. Parameter 1: the text for the column header

  2. Parameter 2: the design grid column number (1-n)

The return value is HTML to use for the header, for example, for a bold header:

<b>Param 1</b>

For red text:

<span style="color:red">Param 1</span>

For right justified text (using float so that sort indicators still appear):

<div style="float:right;">Param 1</div>

You can reassign the column name to force a call to recalculate the HTML for the column header, even if the text has not changed.

Row Styles

The $rowcsscol property allows you to specify CSS styles for a row in a data grid. The $rowcsscol property specifies the column number in the $dataname list for specifying custom CSS class names to apply to individual rows. Multiple class names can be assigned with a space separated list.

The CSS rules for classes can be added to user.css: it may be necessary to use !important to override existing styles. For example, in user.css:

.omnis-datagrid .highlight {
background: red !important;
color: white !important;
}

Column Data Type Formatting

When you set $columnmode to kJSDataGridModeFormatted, the mode acts like kJSDataGridModeAuto, in that the data grid automatically handles the data based on its type. However, the grid formats the data using the properties $columndateformat, $columndateformatcustom, and $columnnumberformat, rather than the $js...format... properties.

You can use an integer column data type to represent a checkbox. To do this set $columnmode to kJSDataGridModeFormatted and set the $columnnumberformat to “bool”. This will cause integer data to be treated as Boolean, where non-zero means true, and zero means false. If the end user updates the grid using the check box, 1 will be stored in the list for true, and zero for false.

Highlighting Cells

The properties $hilitefocusedcell and $cellhilitecolor allow you to highlight the cell that has the focus.

  1. $hilitefocusedcell
    If true, the focused cell will be outlined in the color specified by $cellhilitecolor

  2. $cellhilitecolor
    The color of the focused cell's outline, provided $hilitefocusedcell is kTrue

Grid Scrolling

JavaScript Data Grids have $vscroll and $hscroll properties which allow you to scroll a grid vertically or horizontally at runtime in the client browser; note these properties are write-only meaning that you cannot return their values at runtime.

The vertical scroll value assigned using $vscroll is the position of the scroll bar according to row number in the control. The horizontal scroll value assigned using $hscroll is the designed grid column number for a data grid.

Tabbing through cells

The property $tabthroughcells allows you to change the action of the tab key while the focus is on a data grid. If set to kTrue (default is kFalse), tabbing from a cell which is not being edited selects the next cell, or Shift+tab selects the previous cell. In addition, setting $hcell or $vcell triggers edit mode if $autoedit=kTrue.

Auto Correction and Capitalization

Datagrids have the $autocorrect and $autocapitalize properties which means that text entered into the cells of a data grid are corrected for spelling and capitalization automatically.

Validating data

The $validate method allows you to validate the data entered into any cell in the grid. If present, the method is called when an edit is made to a grid cell, with the parameters pRow, pCol, pNewValue being passed to the method. The method returns true to indicate that the change is valid, depending on the validation code you add to the method, otherwise the value in the cell will revert to the previous value.

Numeric Data Validation

Data entered in grid columns with the numeric data type will be validated automatically, as it is entered. When the end user tries to enter invalid data into the grid column field, such as an alphabetic character, the data is rejected, and the field is highlighted momentarily to indicate an error (the default action is to show a red border).

When leaving the entry field, the value is normalized, that is, integer data is constrained to the valid range or for other numbers it is rounded to the correct number of decimal places; also, leading zeroes are removed, and so on.

Initial Row Values

When a Data grid has $enterable & $extendable enabled, the user can add a new row by entering data into the empty 'extendable' row at the bottom, and the remainder of the columns in that row are given default values.

However, if you want to override these defaults, you can now implement a method named $initextendrow on the data grid control. This method should return a row with column values set to the appropriate defaults you wish to use. The order and the data type of the columns must match the order and types of the columns of the list defining the Datagrid and specified in $dataname.

Inserting Dates as null values

Data Grid columns have the property $columnallownulldateinput to allow a null value to be added to a row of data when the end user tabs out of the last line of the grid to create a new line automatically.

If $columnallownulldateinput is true, and the datatype of the column is Date, cells in the column will default to a value of null when added through the UI. Additionally, if this property is enabled, the end user can change a date to be null by pressing Backspace or Delete while the cell has focus.

If false (the default), the behaviour is unchanged from previous versions. Note it is not possible for the end user to input null values into the grid, via the popup date picker, for example.

Using the Date Picker

The Data Grid uses the appropriate Date Picker according to the constant specified in $dateformat or $columndateformat. If this is set to kJSFormatCustom, then $dateformatcustom or $customdateformatcustom is used as above. If set to kJSFormatNone, then it will attempt to use the data subtype applied to the dataname of the column to determine which picker to use.

Data Grids have the $datepickermode and $datepickerpopupstyle properties, as well as $columndatepickermode and $columndatepickerpopupstyle. The latter two work in the same way, but on the given column when $userdefined = true.

Entering Dates Manually

The properties $editdatetext and $columnallownulldateinput allow end users to enter a date manually via the keyboard rather than using the date picker. When set to true, $editdatetext (and $columneditdatetext when $userdefined=kTrue), allows keyboard entry of a date/time. If a date that cannot be parsed is entered, it will revert to the previously stored date, unless $columnallownulldateinput=kTrue, in which case the field data will become null.

Note this has no effect on the date picker popup control, so if you don’t want to use the picker you need to apply the following css rule to hide the picker:

.datetimepopup-button {
visibility: hidden;
}
 

Copying data

The end user can copy data from selected rows. Data grids return the copied rows as tab-separated values. You can add a client executed method named "$clipboardcopy" to the control to handle the clipboard content. The method can return character data or a list. If it is a list, column 1 must be the MIME type and column 2 must be the content.

For example:

# $clipboardcopy client method
Do lList.$define(lMime,lContent)
Do lList.$add("text/plain","Copy this as plain text")
Do lList.$add("text/html","Copy this as <b><u>HTML</u></b> instead")
Quit method lList

Fixed Columns

The $frozencolumns property allows you to fix or “freeze” a number of columns to the left of the grid, so they do not scroll when the other columns in the grid are scrolled horizontally. The property takes a number value from 1 upwards corresponding to the first column on the left of the grid. For example, you could specify a value of 1 to create row headings that are fixed to the left of the grid.

Column Header Justification

The following properties allow you to justify content in data grid column headers.

  1. $headerjst
    A kJSDataGridJst… constant that sets the alignment of the data grid header

  2. $columnheadersjst
    A kJSDataGridJst… constant that sets the alignment of all the column headers; overrides $columnheaderjst

  3. $columnheaderjst
    A kJSDataGridJst… constant that sets the alignment of all the current column’s header; $columnheadersjst must be set to kJSDataGridJstDefault

Color Picker

The kJSDataGridModeColorPicker column type displays a color picker in the data grid cell allowing the end user to select a color. A numeric color value is returned from the picker, or a color function can be used to set the color of the column, such as truergb(kDarkGreen), or rgb(255,0,0).

For example, to set the colors for the first 3 lines in the third column, use the code:

 Do iList.$add('Bag','21/02/12',truergb(kDarkGreen),'19.00',kTrue,'')
 Do iList.$add('Balls','20/02/12',rgb(255,0,0),'4.55',kFalse,'Delivery next week')
 Do iList.$add('Clubs','20/12/11',rgb(0,0,255),'299.99',kTrue,'')

image48

You can specify the text for the OK and Cancel buttons on the color picker using $colorpickeroktext and $colorpickercanceltext.

An entry field has been added to the color picker which accepts colors in the hex (the default), rgb or color name formats. Localizable strings have been added for the color entry field for the aria-label and aria-describedby accessibility properties, "ctl_dgrd_color_input" and "ctl_dgrd_color_input_desc" respectively. In addition, end users should be able to navigate the color picker from the keyboard without the picker losing the focus.

Number Columns

Data grid columns with type Number have a the property $columnzeroshownempty which specifies that values of zero are shown empty rather than displaying a 0 digit.

Hiding a column

The $columnhidden property allows you to hide the specified column at runtime. The default is false, meaning the column is visible.

Example

The Webshop sample app, available under the Applets section in the Hub, uses a data grid to display a list of products that have been ordered in the main product jsShop remote form. The data grid control is called ‘orderGrid’ and is seen here in design mode:

image49

The $dataname of the data grid is set to iOrderList which is defined from a table class T_qOrders which is linked to a query class qOrders. When the product form is opened, the $construct method behind the data grid defines the list from the table class.

# $construct behind the data grid
Do iOrderList.$definefromsqlclass($tables.T_qOrders)

When the end user clicks the ‘Order Now’ button in the product window, the data for the selected product and size/type is passed to the process_order method (as value 1, 2, or 3), which inserts the data into the list (after a check to see if the user has already ordered the same product) and the list is redrawn. The process_order method is as follows:

# process_order class method in the jsShop form
# contains pButtonNumber parameter (Short Int) to receive the value of the product button clicked
If iProductList.product_price_[pButtonNumber]>0 ## price must be greater zero
  Do iOrderList.$search(
    $ref.order_product_id=iProductList.product_id
    &$ref.order_size=iProductList.product_size_[pButtonNumber],
    kTrue,kFalse,kFalse,kFalse)
  If iOrderList.$line ## found one so increment existing order
    Calculate iOrderList.order_amount as iOrderList.order_amount+1
  Else ## new one so add to iOrderList
    Do iOrderList.$add#NULL,#D,iProductList.product_id,iProductList.product_name,
      iProductList.product_size_[pButtonNumber],
    1,0,iProductList.product_price_[pButtonNumber])
    Do iOrderList.$line.$assign(iOrderList.$linecount())
  End If
  Calculate iOrderList.tot as
    iProductList.product_price_[pButtonNumber]
    *iOrderList.order_amount
  Do $cinst.$objs.checkOutBtn.$enabled.$assign(
    iOrderList.$linecount()>0)
    Do $cinst.$objs.orderGrid.$redraw()
Else
  Do $cinst.$clientcommand('yesnomessage',row(con('Would you like     to order >',iProductList.product_size_1,'< instead?'),'Not     available','$orderYes'))
End If

The Apps Gallery on the Omnis website has a further example showing how you can use the Data grid component.

Date Picker Control

The Date Picker control allows the end user to select a single date, a date range, and/or a time, rather than having to enter a date or time from the keyboard; in this case, the UI is better and issues with formatting a date or time are avoided. There is a sample app in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

You can assign a Date/Time instance variable to the $dataname property to load the date/time selected by the user, or you can assign a two column instance row variable to contain the date/time and time zone offset of the client in the respective columns (see below for info on the time zone offset).

Date Picker Style

The $datestyle property specifies the style or date/time content of the date picker control, which can be a combination of date & time, date only, time only, or a calendar view, as specified by a kJSDatePickerStyle… constant:

Constant Description
kJSDatePickerStyleDate a date display only
kJSDatePickerStyleDateTime a date and time are displayed (right below)
kJSDatePickerStyleTime a time display only
kJSDatePickerStyleCalendar a calendar is displayed (left)
kJSDatePickerStyleCustomr a custom format, see below

The color of the Date Picker is specified with $datefacecolor while $datefacealpha sets the transparency (value 0-255).

There is an example app in the Samples section in the Hub in the Studio Browser showing how you can use the Date picker to allow the end user to select a date; in addition, the Holidays example app under the Applets option in the Hub uses the Date picker, which is described later in this section.

image50

Mode & Popup Style

In addition to the $datestyle property, you can use the $datepickermode and $datepickerpopupstyle properties to control the mode and popup style of the date picker (also applies to data grid cells and columns).

  1. $datepickermode
    controls the type of picker to be displayed, one of the following constants:
    kJSDatePickerModeAuto: Date picker type is assigned automatically based on $dateformat
    kJSDatePickerModeCalendar: calendar type is displayed
    kJSDatePickerModePicker: a picker type is displayed

  2. $datepickerpopupstyle
    controls how the popup is displayed, one of the following constants:
    kJSDatePickerPopupStyleAuto: Popup style is determined by device type
    kJSDatePickerPopupStyleInline: Popup style will always be displayed adjacent to the control
    kJSDatePickerPopupStyleModal: Popup style will always be displayed modal

(Note that Internet Explorer does not correctly display the modal type, and so falls back to inline on these clients.)

The inline style picker will position itself underneath the parent control, but from the right so it is closer to the icon which opens it. If there is not enough space beneath the parent control, the picker will be placed above, where space permits.

Calendar Style Picker

The Date Picker control can be switched to display a calendar style date picker, by setting $datestyle to kJSDatePickerStyleCalendar. There are a number of properties that apply to the control when the date style is set to calendar.

Picker style on mobile devices

When $datestyle is set to kJSDatePickerStyleCalendar desktop browsers will display the calendar as expected. On mobile devices however, even when $datestyle is set to kJSDatePickerStyleCalendar, a calendar will be replaced with a date picker (same as kJSDatePickerStyleDate), since a picker style date selector is the preferred style on mobile devices. This can be overridden by setting the property $datestyleusepickeronmobile to kFalse.

Custom Date Style

The $datestylecustom property can be used in conjunction with setting $datestyle to kJSDatePickerStyleCustom to set the style or format of the date shown. You can enter a string of characters to represent the columns required as per the Omnis date/time format strings, for example, "mdy" to specify Month, Day, Year columns in that order.

In addition, you can specify a grouped column by enclosing the date characters in parenthesis, for example, "(wdm)" will specify a single coumn containing Weekday, Day, Month. Note: this column will always alter the day by one by increasing or decreasing it, so it only makes sense to use this type of column if it includes a day or weekday. Time elements entered into a grouped column will be ignored. Repeated characters are ignored and only one group can be used (further groups are ignored). Groups take precedence over individual columns, therefore "d(wdm)y" will be treated as "(wdm)y".

Date pickers (other than custom) pick up the locale of the client and display the picker in their standard format. For example, the date picker will display Day, Month, Year in the UK, and Month, Day, Year in the USA (assuming their location settings are set correctly).

Selecting a Date Range

When specified, the properties $rangeselection and $rangeenddataname allow the end user to select a date range, that is, a start date and an end date. The first being a boolean to put the calendar into range selection mode. When true, the end user can select a range of dates by selecting one date after another. The $rangeenddataname property is the name of an instance variable to store the end of the data range and should be of type Date. The variable in $dataname will always hold the start date in range selection mode.

A boolean parameter, pInRangeSelection, will be passed as true with evDateClick when the end user has selected the first date, and false once they have selected the second. If $rangeselection is kFalse, this parameter is not passed, and therefore will return NULL if tested on evDateClick.

The evDateRangeChange fires every time a date range selection has been completed (and $rangeselection is kTrue). This passes two parameters: pStartDate and pEndDate. This means you can obtain a date range without using instance variables if you just need to react to the date range selected. evDateChange does not fire when $rangeselection is kTrue.

The $currdaycolor property applies to inside the current day indicator ring and not the whole cell. This ensures the type of cell is still understood by the end user. E.g. When $todayscolor is different to $daycolor, the end user can still see that it is today, even when they have selected it as the current day.

Events

The following events are generated when the end user clicks on a date picker and/or selects a date: you can create an event handling method on the control allowing you to load the selected date.

  1. evDateChange
    Sent to the control when the current date is changed (not fired when $rangeselection is kTrue)

  2. evDateClick
    Sent to the control when the user clicks on a date; only applicable to Calendar type date pickers.

  3. evDateDClick
    Sent to the control when the end user double clicks on a date (not fired when $rangeselection is kTrue)

  4. evDateRangeChange
    Sent to the control when a date range has changed (only fired when $rangeselection is kTrue)

Example

In the Holidays sample app uses the Date picker control set to kJSDatePickerStyleCalendar to allow users to select the dates for the holiday applications. The jsUserForm in the Holidays app has two buttons to allow the end user to select a “From” date or “To” date to specify the Begin and End dates for their holiday request. The “From” button has the following code:

On evClick
  Calculate iUsingCalendar as kTrue
  Calculate iSelectFrom as kTrue ## this is the From button
  Do method openCalendar

The openCalendar class method moves the calendarPane into view on the main form and has the following code:

Do method enableFields (kFalse## enables the calendar pane & disables the name pane
Do $cinst.$objs.calendarPane.$top.$assign(90)
Do $cinst.$objs.calendarPane.$left.$assign(150)
Do $cinst.$objs.calendarPane.$visible.$assign(kTrue)

image51

If you examine the Holidays app to look at the Date picker note that it is on a page pane field called calendarPane located on the jsUserForm. The $left property for the calendarPane is set to 990, to hide it from view, therefore you’ll need to select it using the Field List (right-click the remote form, select Field List and check the calendarPane) and set its $left property to 200 in the Property Manager in order to see it.

The $dataname of the Date picker control itself is set to iCalendarDate, an instance variable of type Date Time and subtype ‘D m y’; when the end user selects a date this variable is set to the selected date automatically.

The Date picker has a simple event method to detect when the end user double-clicks on a date cell; it has the following code:

On evDateDClick
  Do method closeCalendar

The closeCalendar class method passes the date from iCalendarDate into either the iFromDate or iToDate variable defined in the form; it has the following code:

If iSelectFrom ## if the From button
  Calculate iFromDate as iCalendarDate
Else ## it must be the To button
  Calculate iToDate as iCalendarDate
End If
Do $cinst.$objs.calendarPane.$left.$assign(1250)
Do method enableFields (kTrue

The final two lines of the method move the calendarPane off to the right and enables the fields on the Name pane.

Time Zone Offset

You can return the time zone offset of a date value when it is passed back from the client by using a two column row variable in $dataname; the first column should be defined as a Date Time variable and the second of type Number. If the server passes a new value to the client, then only the first column is significant and should specify the new date to be sent to the client.

When evDateChange signals that there has been a change on the client then the updated date is passed back to the server in the first column of the row variable as a UTC/GMT date value and the time zone offset of that value in the client's current time zone is passed back in the second column. The time zone offset is the number of minutes from UTC/GMT, e.g. GMT+2 the time zone offset is 120. This can be used to calculate the date in the time zone of the client.

If time zone offset information is not required, $dataname can be specified as a Date Time instance variable only.

Date Picker Localization

The following strings are available in the JS localization string table to allow you to localize strings for the Date Picker. Note that some of the strings are now arrays of strings to simplify localization (e.g. for months, days of the week, etc).

Date picker specific strings

The following are specific to the date picker control:

"ctrl_date_increase": "Increase"
"ctrl_date_decrease": "Decrease,
"ctrl_date_time_button": "Open time picker"
"ctrl_date_calendar_button": "Open date picker"
"ctrl_date_header": ["Select a Month", "Select a Year", "Select a Decade", "Select a Time"]

Generic strings

The following strings are available for controls that refer to dates, including the date picker:

"month_names": ["January", "February", "March", "April", "May", "June", "July", "August",
"September", "October", "November", "December"]
"month_names_short": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec"]
"day_names": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday"]
"day_names_short": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
"date_units": ["Day", "Month", "Year", "Decade"]
"time_units": ["Hour", "Minute", "Second", "Millisecond"]

The following example applies Spanish text to the Calendar:

<script type="text/javascript">
jOmnisStrings.es = {
"month_names": ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
"month_names_short": ["enero", "feb.", "marzo", "abr.", "mayo", "jun.", "jul.", "agosto", "sept.", "oct.", "nov.", "dic."],
"day_names": ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"],
"day_names_short": ["DOM", "LUN", "MAR", "MIÉ", "JUE", "VIE", "SÁB"],
"date_units": ["Día", "Mes", "Año", "Década"],
"time_units": ["Horas", "Minutos", "Segundos"],
"ctrl_date_header": ["Selecciona un mes", "Seleccione un año", "Seleccione un década", "Seleccione una hora"]
};
</script>

See the Localization chapter in the Creaing Web & Mobile Apps manual for more information about setting the strings in the jOmnisStrings object.

Device Control

The Device Control allows access to features on a mobile device, such as getting the location of the end user’s device using GPS, retrieving the contacts information from the device, or returning images from either the camera or photo library on the device. Depending on the type of application you are creating, some or all of these features may be useful to enhance the interactivity and functionality of your app for end users when they run your app on a mobile device, such as a smartphone or tablet computer.

The Device control itself is invisible and to enable access to the device functionality you need to add the Device Control to your remote form and assign an action to the $action property of the control at runtime using methods: see the possible actions later in this section.

Running the Device Control and Compatibility

Important Note: in all but a few specific cases, the actions enabled via the Device Control only work in an application that is running within one of the JavaScript Wrappers or Omnis App Manager on a mobile device. The exceptions to this are the Email, Call, and SMS actions which will attempt to work if the app is running in a standard web browser, but it’s not guarenteed the actions will always work as expected.

Therefore, you will need to compile your app as a standalone mobile app using the JavaScript Wrappers (for iOS or Android), and test your app in a simulator or directly on a mobile device by running the native app, for the majority of the actions in the Device control to work. Alternatively, on iOS you can use the Omnis App Manager to test your mobile app and the functions of the Device Control, prior to compiling it into a standalone app using the iOS wrapper.

The Device control supports several hardware functions, some of which may not be available on specific devices. You should test your app thoroughly on the specific devices you wish to support with each of the device functions that you want end users to access.

For some of the hardware features, Omnis can detect if they are not present on the current mobile device running the app. For example, if a device does not have a hardware camera, then the action kJSDeviceActionTakePhoto will report an evPhotoFailed message.

Properties

Note the Device control is invisible, therefore some of the visual properties normally associated with JavaScript components may not be relevant, such as $alpha.

Property Description
$action The “action” for the Device control which specifies which function on the client mobile device is accessed; this is assigned as a kJSDevice… constant: see below
$communicationaddress

Character value determining the phone number when the Make Call and Send SMS device actions are used (for SMS only, can be a list of phone numbers), or email address when the Send Email device action is used.

Can only be assigned at runtime.

$communicationdata

Character data to be sent as the message body when the Send SMS or Send Email device actions are used.

Can only be assigned at runtime.

$communicationsubject

Character data to be sent as the subject when the Send Email device action is used.

Can only be assigned at runtime.

$dataname The name of a List instance variable for the Device control. It will be populated with contact details when using the Get Contacts device action.
$deviceimage Contains a Character/Binary instance variable name used for holding the image returned from the device. The image will be in base64 format.
$imageaspect Sets the aspect ratio of the image, a floating number, indicating width divided by height. A value of 0 no aspect ratio will be enforced, a value of 1 enforces a square image
$imagejpeglevel The JPEG quality of images returned (0-100). 100 being max quality, 0 being max compression.
$imagemegapixel A float value indicating the maximum Megapixel resolution of images returned. 0 means no limit.
$imagesizemenu If true, a dialog will be opened when using the device image actions, to allow the user to pick a size for the image, respecting $imagemegapixel.
$soundname Name of the sound sample to be played when the Beep device action is called.
$contact… The $contact… properties determine whether particular pieces of contact information are returned when using the Get Contacts device action, e.g. disabling $contactphotos can significantly reduce the time taken to fetch contacts.

Contact properties

There are a number of properties that are only relevant when the device action is set to kJSDeviceActionGetContacts which allows you to obtain information from the contacts database on the device. By setting these properties you can control what information is returned from the Contacts data on the device. For example, if $contactname is set to kTrue the contact request will include name info, and so on.

Setting the Action Property

The following list summarizes the actions available, and the constant needed for the $action property:

  1. kJSDeviceActionBeep – Beep Device
    forces the device to play the default beep

  2. kJSDeviceActionGetBarcode – Get a Barcode or QR code
    returns the output from Barcode/QR-code scanning function on the device (if available); the output is usually a string which can be a URL

  3. kJSDeviceActionGetContacts – Get contact info
    returns contact information from the device; note there are other properties to determine the content or extent of the contact information returned

  4. kJSDeviceActionGetGps – Get the device location
    returns the location data using the GPS function on the device

  5. kJSDeviceActionGetImage – Get an Image
    returns an image from the device’s image gallery

  6. kJSDeviceActionGetUniqueID – Get Unique ID
    returns the unique ID of the device

  7. kJSDeviceActionTakePhoto – Take a Photo
    forces the device to take a photo (if a camera is available)

  8. kJSDeviceActionVibrate – Vibrate the Device
    forces the device to vibrate (if available)

  9. kJSDeviceActionMakeCall – Make a Phone Call
    forces the device to make a phone call (if available)

  10. kJSDeviceActionSendEmail | kJSDeviceActionSendSms – Send an Email or SMS
    forces the device to send an Email or SMS / text message (if available)

The basic method to assign an action to the Device control is as follows:

Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceAction…)
# where oDevice is the name of the Device control

Events

Event Description
evBarcodeFailed

Sent when no Barcode could be obtained from the device.
Parameters

pEventCode The event code
evBarcodeReturned

Sent to the device control when a Barcode is ready for processing.
Parameters

pDeviceBarcode The Barcode data
pEventCode The event code
evContactsFailed

Sent when no contacts could be obtained from the device.
Parameters

pEventCode The event code
evContactsReturned

Sent to the device control when contacts info is ready for processing.
Parameters

pEventCode The event code
evGpsReturned

Sent to the device control when Location Data is ready for processing.
Parameters

pDeviceGps The GPS location
pEventCode The event code
evImageFailed

Sent when the device failed to return an image.
Parameters

pEventCode The event code
evImageReturned

Sent to the device control when an image is ready for processing.
Parameters

pEventCode The event code
evPhotoFailed

Sent when the device failed to take a photo.
Parameters

pEventCode The event code
evPhotoReturned

Sent when an image is returned from camera ready for processing.
Parameters

pEventCode The event code
evUniqueIDReturned

Sent when a unique ID is returned from the device.
Parameters

pDeviceUniqueID The unique ID
pEventCode The event code
Standard evExecuteContextMenu evOpenContextMenu

Beep Device Action

To make the device play a given sound sample, you need to assign the constant kJSDeviceActionBeep to the $action property. This is one-way communication with the device which will result in the device playing a sound sample. To specify which sound to play, you need to set the $soundname property to the name of the sound sample to be played which must be compiled into the wrapper application. The wrapper contains a default sound called “notify”.

Example
On evClick
  Calculate $cinst.$objs.oDevice.$soundname as "notify"
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionBeep)

Get Barcode Device Action

You can return a Barcode or QR code by assigning the constant kJSDeviceActionGetBarcode to the $action property. If the action is successful an evBarcodeReturned event is sent to the Device Control and the barcode data is returned in the pDeviceBarcode event parameter; the barcode data is usually a string containing Alphanumeric characters, such as a product number or name, or in the case of a QR code it could be a website URL.

Example
# event method for “Scan” button
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionGetBarcode)

The event method for the Device Control could be:

On evBarcodeReturned
  Do iProducts.$search(iProducts.iProdQrCode=pDeviceBarcode,kTrue,kFalse,kFalse,kFalse)
  If iProducts.$line=0
    Do iProducts.$line.$assign(iProducts.$linecount## other
  End If
  Do iProducts.$loadcols()
  Calculate iAmount as 1
  If iProdName='Other'
    Calculate iProdName as pDeviceBarcode ## show the value of the barcode
  End If

There is a Tech note describing how you can return the info from a barcode or QR code using the Device control and the Omnis App Manager to test the Device control: see TNJC0013 “Reading a barcode or QR code in a mobile app”.

Vibrate Device Action

To make the device vibrate you need to assign the constant kJSDeviceActionVibrate to the $action property. This is one way communication with the device which will result in the device vibrating for a short period of time.

Example
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionVibrate)

Get GPS Device Action

To receive location (GPS) data from the device you need to assign the constant kJSDeviceActionGetGps to the $action property. The evGpsReturned event is sent when the location data has successfully been returned. The event parameter pDeviceGps will contain the returned data which is formatted as a string containing longitude and latitude data separated by a colon “:”. If the device fails to obtain location data or the device does not support location tracking, the returned data will be a longitude and latitude of zero, i.e. “0.0:0.0”.

Example
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionGetGps)
On evGpsReturned
  Calculate $cinst.$objs.oMap.$latlong as pDeviceGps

Take Photo / Get Image Device Action

To take a photo with the device (if a camera is present) or to return an image from the device’s gallery the kJSDeviceActionTakePhoto or kJSDeviceActionGetImage constants need to be assigned to the $action property. The $deviceimage property of the Device component needs to be assigned to an Instance Variable of type Binary or Character to hold the incoming image data from the device. If the device is successful in returning an image, the event evPhotoReturned or evImageReturned will be called to indicate that an image was returned, whereupon the instance variable specified in $deviceimage will be populated with the base64 encoded image data. In the event of the device failing to return an image or the user cancels the request, the event evPhotoFailed or evImageFailed will be sent.

Example
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionTakePhoto)

In this case the instance variable iImage is a Binary variable. The $deviceimage property is set to iImage. There is another Binary variable called ipic which is associated to a picture component. By copying the returned image in iImage into the picture component variable you can display the image returned from the device.

On evPhotoReturned
  Calculate iPic as iImage

In addition to the TakePhoto action, the device control has the client-executed method, $takephoto(iWidth, iHeight) which provides a shorthand way of taking a photo with specific dimensions.

Image Aspect Ratio

The $imageaspect allows you to specify the aspect ratio of a photo; it only affects images taken with the TakePhoto device action, not the GetImage action. This functionality is only available in the iOS and Android wrappers - version 3.1.0 & later; also note the minimum Android version is now API21 (5.0, Lollipop).

The $imageaspect property takes a floating number, indicating width divided by height. If set to 0, no aspect ratio will be enforced, and the standard camera application will be used for taking photos. If greater than zero, a custom camera view within the app will be used, which shows the preview stream in the specified aspect ratio, and an image of the specified aspect will be returned. A value of 1 will enforce a square image.

The $imageaspect property can be used in conjunction with $imagemegapixel to take an image of specific dimensions, that is:

$imageaspect = targetWidth / targetHeight

$imagemegapixel = (targetWidth * targetHeight) / 1,000,000

Get Contacts Device Action

To obtain information from the contacts database on the device the kJSDeviceActionGetContacts constant must be assigned to the $action property. To accommodate the contact database the $dataname property needs to be assigned to an Instance Variable of type List. The properties starting with $contact... determine which contact fields will be obtained from the device: setting these properties to true or false will determine if that specific field is returned from the device.

The evContactsReturned event is triggered when the contact database has been returned, and in the case of the device failing to obtain the contact database the evContactsFailed event is triggered.

Example
On evClick
  Do $cinst.$objs.oDevice.$action.$assign(
      kJSDeviceActionGetContacts)
# retrieve info from the Contact list
On evContactsReturned
  Set reference lNameRow to iDeviceList.nam.1
  Calculate iNameRow.FirstName as lNameRow.givenName
  Calculate iNameRow.MiddleName as lNameRow.mid
  Calculate iNameRow.Surname as lNameRow.familyName
  Calculate iNameRow.Prefix as lNameRow.honorificPrefix
  Calculate iNameRow.Suffix as lNameRow.honorificSuffix
  Calculate iNameRow.Nickname as iDeviceList.nickName

Contacts data structure

  1. displayName: The name of this Contact, suitable for display to end-users (String).

  2. name: A row containing all components of a contact’s name.
    formatted: The complete name of the contact (String).
    familyName: The contact’s family name (String).
    givenName: The contact’s given/first name (String).
    middleName: The contact’s middle name (String).
    honorificPrefix: The contact’s prefix (example Mr. or Dr.) (String).
    honorificSuffix: The contact’s suffix (example Esq.) (String).

  3. nickname: A casual name to address the contact by (String).

  4. phoneNumbers: A list of all the contact's phone numbers.
    type: A string that tells you what type of phone number this is
    (example: 'home') (String).
    value: The phone number (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  5. emails: A list of all the contact's email addresses.
    type: A string that tells you what type of email this is (example: 'home') (String).
    value: The email address (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  6. addresses: A list of all the contact's addresses.
    pref: Set to true if this is the user's preferred value (Boolean).
    type: A string that tells you what type of address this is (example: 'home') (String).
    formatted: The full address formatted for display (String).
    streetAddress: The full street address (String).
    locality: The city or locality (String).
    region: The state or region (String).
    postalCode: The zip code or postal code (String).
    country: The country name (String).

  7. ims: A list of all the contact's IM addresses.
    type: A string that tells you what type of IM this is (example: 'home') (String).
    value: The IM username (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  8. organizations: A list of all the contact's organizations.
    pref: Set to true if this is the user's preferred value (Boolean).
    type: A string that tells you what type of organization this is
    (example: ‘work’) (String).
    name: The name of the organization (String).
    department: The department the contact works for (String).
    title: The contacts title at the organization (String).

  9. birthday: The birthday of the contact (Character).

  10. note: A note about the contact (String).

  11. photos: A list of the contact's photos. In general, there will be only one row.
    type: A string that tells you what type of field this is (example: 'home') (String).
    value: The photo data, encoded as base64. These are small, thumbnail photos.
    (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  12. categories: A list of all the contacts user defined categories.
    type: A string that tells you what type of category this is
    (example: 'home') (String).
    value: The value of the field (such as a phone number or email address) (String).
    pref: Set to true if this is the user's preferred value (Boolean).

  13. urls: A list of web pages associated with the contact.
    type: A string that tells you what type of web page this is
    (example: 'home') (String).
    value: The website URL (String).
    pref: Set to true if this is the user's preferred value (Boolean).

Make a Call Device Action

To make a phone call from the device the kJSDeviceActionMakeCall constant is used. Before assigning this action the phone number for the call should be specified in the $communicationaddress property.

Example
Do $cinst.$objs.oDevice.$communicationaddress.$assign("0123456789")
Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionMakeCall)

Send an SMS or Email Device Action

To send an SMS (text message) or Email from the device the kJSDeviceActionSendSMS or kJSDeviceActionSendEmail constant is used. Before assigning this action the phone number or list of numbers (for the SMS action) or the email address (for Email) should be specified in the $communicationaddress property. The message body of the SMS or email can be specified in $communicationdata. The subject of the email can be specified in $communicationsubject.

Example
Do $cinst.$objs.oDevice.$communicationaddress.$assign("0123456789")
Do $cinst.$objs.oDevice.$communicationdata.$assign("A message")
Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionSendSMS)

You can send a SMS to multiple recipients by assigning a comma-separated list of phone numbers to $communicationaddress. For example:

Do cinst.$objs.oDevice.$communicationaddress.$assign(
  "0123456789,0987654321,0192837465")

Getting the Unique ID Action

You can return the unique ID of the device running your standalone app using the kJSDeviceActionGetUniqueID action.

Do $cinst.$objs.oDevice.$action.$assign(kJSDeviceActionGetUniqueID)

The ID is unique to each JS wrapper installation and changes when the app is re-installed.

If successful, the action triggers the evUniqueIDReturned event with pDeviceUniqueID containing the ID. You can use the $event method of the device control to return the ID:

On evUniqueIDReturned
 Calculate iDeviceID as pDeviceUniqueID

Running Device Actions in the Browser

Some of the Device actions (those listed below) may work in your application when running in a normal web browser, that is, outside a wrapper. However, the results of running any of these actions in a web browser are very unpredictable, mainly due to the great variation among different web browsers and operating systems, therefore we do not recommend or support apps using these actions in a web browser. If you do use them however, you should test these actions thoroughly.

Call, SMS, and Email actions

You can use the Call, SMS, and Email actions in an application running in a browser, and not in a wrapper, and the web browser on the client will attempt to execute the relevant action (this only applies to these actions: all other actions have to be executed inside the wrapper). For example, if you run the Email action in a web browser it will attempt to initiate an email in the email program on the client.

Vibrate and Location actions

When run outside the wrapper the Vibrate action is not currently supported on iOS Safari, and hence other iOS browsers, as they all have to based on Apple's WebKit.

The Location action only works over HTTPS in recent browsers.

Droplist Control

The Droplist control displays a dropdown list from which the end user can make a selection; the contents of the list can be supplied from a default list or a list variable which can be built dynamically. There is an example app in the Samples section in the Hub in the Studio Browser (called JS Droplist, Combo, Popup), and the same app is available in the JavaScript Component Gallery. The following screen shows the Vintage JS Theme in use.

image52

You can specify a default list of options in the $defaulttext property, which is a comma-separated list of options; $defaultline is the default line (set to 1) which is selected when the form is opened (only when $defaulttext is used). Alternatively, you can assign the name of a list instance variable to $dataname to populate the list; $listcolumn specifies which column of the list variable is used to display the list. The $::listheight property specifies the height of the droplist.

When a line in the droplist is selected an evClick is generated with the selected list line reported in pLineNumber.

Horizontal Padding & Extra space

The Droplist and Combo Box controls have the property $horzpadding to allow you to add extra horizontal padding, in pixels, to the text in the list part of the control. This property has also been added to Combo boxes.

The $extraspace property can be used to add extra space to the line content in the list. If $extraspace is zero, the height of each row is the default height of the row content. If $extraspace is greater than zero, the height of each row is the font height + $extraspace.

Selected Value

The $seldataname property allows you to specify the name of an instance variable, which will be populated automatically with the selected value from the droplist.

Example

The jsUserForm in the Holidays sample app uses a droplist to allow users to select an employee to view their holiday leave requests. The $dataname of the empList Droplist control is set to iEmployeeList which is built via the $construct method when the form is opened.

# buildEmpList class method in the jsUserForm
Do iEmployeeList.$definefromsqlclass('sEmployee'## the schema
Do iEmployeeList.$sessionobject.$assign(iSQLObjRef)
Do iEmployeeList.$select()
Do iEmployeeList.$fetch(kFetchAll)
Do iEmployeeList.$cols.$add(iEmpFullName)
Calculate lTotal as iEmployeeList.$linecount
For lNum from 1 to iEmployeeList.$linecount step 1
  Calculate iEmpFullName as con(
    iEmployeeList.[lNum].FirstName,kSp,
    iEmployeeList.[lNum].LastName)
  Do iEmployeeList.[lNum].$assigncols(,,,,,iEmpFullName)
End For
Do iEmployeeList.$line.$assign(1)
Calculate iName as iEmployeeList.iEmpFullName

The droplist control contains a $event method which is triggered when the user selects a line in the list; the code in the event method redraws the holiday list for the selected employee:

On evClick
 Do method buildHolidayList
 Calculate iName as iEmployeeList.[pLineNumber].iEmpFullName
 Do $cinst.$objs.pagePane.$objs.holidayList.$redraw()
 Do $cinst.$objs.pagePane.$objs.empName.$redraw()

The buildHolidayList class method builds the list of holiday requests for the selected employee and redraws the form.

Edit Control

The JavaScript Edit control is a standard Single Line Edit field which you can use to display data or allow the end user to enter data into, such as in a Contact form; in this case you would normally add a label to each edit control on the form, or you can add a ‘content tip’ ($::contenttip) to each edit control to help the end user.

image53

Many of the sample apps in the Hub in the Studio Browser use Edit controls, as well as the apps in the JavaScript Component Gallery. You can examine these apps and code to see how edit controls can be used.

Dataname: $dataname

The Edit control can handle all types of character or numeric data stored in the instance variable specified in $dataname: the type of data the edit control can handle will depend on the data type of the variable assigned to the control. To create an Edit control, you need to drag the Edit control from the Component Store and drop it onto your remote form; then you can assign the variable in the $dataname property. If you use one of the wizards to create a remote form, the edit controls are added to the form and the required variables are assigned to their $dataname properties automatically.

When the $issingleline property is kTrue (the default), the edit control only allow data entry on a single line, otherwise when kFalse the field can be extended downward to allow data to be entered on multiple lines. When kTrue, the $ispassword property ensures a place-holder character is displayed when the end user enters something in the field (only applies when $issingleline is kTrue).

Text or Font Style

The style of the text or font of an Edit control is controlled by the $fieldstyle property under the Appearance tab in the Property Manager. The field styles are set up in the #STYLES system table in the library and are available for many control types. You can set the $fieldstyle to <None> and assign your own font and style properties under the Text tab, including the $align, $font, $fontsize, $fontstyle, and $textcolor properties.

Borders

The $effect property lets you set the type of border for the edit control and its value is one of the kJSborder… constants. The kJSborderDefault setting means the control has the default border type as specified by the current client operating system and browser type. For some clients the border may change when the state of the control changes.

The $borderradius property lets you add rounded corners to the edit control. A single value specifies the radius for all four corners, but you can specify a different value for each corner by specifying four-pixel values separated by – (hyphen), in the order topleft, topright, bottomright, bottomleft. If bottomleft is omitted, the topright value is used. If bottomright is omitted, the topleft value is used. If topright is omitted, the topleft value is used.

Horizontal and Vertical Padding

The property $horzpadding allows you to add extra horizontal padding, in pixels, inside the control; when applied this property adds padding on the left and right of the text within the edit control.

Existing users should note: when a library is converted to Studio 10.2, the $horzpadding property for all JS Edit controls will be set to 4 automatically if they were previously set to 0, which is the default for all new Edit controls; if $horzpadding is set to any other value it is not changed. After conversion, you can change the value of $horzpadding.

The $vertpadding property allows you to add vertical padding above and below the text inside the control’s border; the property only applies when $issingleline=kFalse as single line edit controls are vertically centered.

Content Tips

The Edit control has the $::contenttip property which is a text string which is displayed in the edit field when it is empty and before the end user has entered any text. Using content tips may help the user understand what content should be entered into fields in the forms in your application. For example, for a Last name field you could enter ‘Enter your last name’ into $::contenttip to prompt the end user for their last name. As soon as the end user starts to type something into the field the content tip will disappear.

Linked Lists

The $linkedobject property allows you to link a list control to the edit control to create a special type of list called a “Linked List” which updates itself automatically as the user types into the edit control: see the List Control section for more information.

Events

The Edit Control reports the evBefore and evAfter events, so you can detect when the focus is about to enter or leave a field in the $event method and process the event accordingly: note evAfter is only reported if the data in the control has changed. You must enable any of the events for the Edit control in its $events property before any of the events are reported.

In addition, the evKeyPress event is reported allowing you, amongst other things, to create a “Linked List”: see the Linked Lists section.

Soft Keypad Input Type

Many iOS and Android devices have different software keypad layouts which are displayed depending on the type of data required, that is, the keypad content and layout adapts to the content required. For example, if numeric content is required, a numeric keypad is displayed. The $inputtype property allows you to specify which keypad is displayed on touch devices depending on what type of content you wish the end user to enter into the edit control. This property only applies to touch devices and in this case $inputtypetouchonly is set to kTrue by default, and it only applies if $ispassword is false (if true the default keypad is shown).

  1. $inputtypetouchonly
    When true (the default for touch devices) the specified $inputtype is applied on touch devices, otherwise it is ignored

  2. $inputtype
    The HTML input type used by the edit field. The browser may give this special handling, e.g. by popping up a specific software keypad. (The property is ignored if $ispassword is enabled.) The input type is specified using a constant:
    kJSInputTypeDefault: the standard Qwerty keypad (in most cases)
    kJSInputTypeNumber: the standard Qwerty keypad flipped to numbers
    kJSInputTypeTelephone: the telephone number keypad
    kJSInputTypeEmail: the Qwerty keypad plus the @ and dot keys
    kJSInputTypeUrl: the Qwerty keypad plus dot, forward-slash, and ‘.com’ keys
    kJSInputTypeDate: shows a date picker; see below

If $negallowed is true, the 'number' type is not selected as this does not guarantee the presence of a minus key. You should note that a touch device's virtual keyboard is more likely to use a numeric keyboard if $negallowed is false.

Selecting Dates

The constant kJSInputTypeDate can be assigned to the $inputtype property to allow the end user to select a date using the Date Picker. When $inputtype is set to kJSInputTypeDate, and $inputtypetouchonly is set to false, a date/time picker will be used to pick the value for the Edit control. $dataname must be set when using kJSInputTypeDate and other input types such as kJSInputTypeNumber.

The format of the date picker should be calculated from $dateformat ($dateformatcustom if $dateformat == kJSFormatCustom). If $dateformat is kJSFormatNone, then the control attempts to fall back to the dataname subtype.

Input Masks

You can control the format of the data entered into an Edit control by defining an input mask using the $inputmask property. If the user enters an invalid character, the control will briefly become highlighted and the input will be rejected. For edit fields of character type, the data variable will contain mask characters. For number/integer fields, the data is the unmasked number value.

The #JSMASKS system table stores the input masks for JS Edit controls for the library, which are also accessible in the $javascriptinputmasks notation group.

There are a number of differences between the existing Masked entry field on the thick client and the new input masks for JS Edit controls:

  1. On the thick client, the user must complete the masked entry field before focus can leave the field. This is not the case with JS masked edit fields - fields can be left partially filled.

  2. JS input masks do not support any of the 'control characters' which can be used on the thick client.

  3. The JS edit control does not have a $formatstring property (like the thick client masked entry field).

  4. The JS edit control has two unique properties: $inputmaskguide and $maskvaluevalid.

  5. JS input masks can be changed dynamically as the user types using the $processmask client method.

  6. There is visual feedback when entering invalid characters in a masked JS edit field.

Incompatible input types are prevented from being used with input masks. For example, the kJSInputTypeNumber and kJSInputTypeEmail values of $inputtypes are incompatible with input masks. If $inputtype is one of these values, and $inputmask is set, the input element will use the text type (effectively kJSInputTypeDefault).

$inputmask

The value of $inputmask may contain a combination of fixed and special characters. Note that underscores cannot be used as these are used as placeholders.

Special character Description
# Any digit
@ Any character
a Any letter
A Any uppercase letter
n Alphanumeric
N Alphanumeric, uppercase
“ABC" Any character from list
“A-D" Any character from A to D inclusive
\ (back slash) Escape character (next character is displayed literally, use to escape special mask characters, double quotes or backslash)

$inputmaskguide

The $inputmaskguide boolean property controls whether or not a guide is shown. If true, placeholder and non-placeholder mask characters are always displayed. If false, placeholder characters are hidden, and mask characters are only shown when the user reaches them as they type. The property is false by default.

$maskvaluevalid

The $maskvaluevalid property is a boolean, read only, runtime only property. A value of kTrue indicates that the field is completed, and therefore valid.

$processmask

A client method named $processmask can optionally be added to an edit control. This allows the mask to be changed as the user types. The method is called any time the value in the field changes, and receives a parameter pInput which contains the user input. Note that the user input parameter could contain anything as the event is sent before mask validation occurs (the mask needs to be updated before it can validate input). As a general use case, $processmask could be used to create the effect of optional characters.

Custom Date Formats

You can specify multiple date formats in the $dateformatcustom property for entry fields in a remote form, which allows end users to input a date using one of a number of possible formats, rather than being limited to a single date format. The multiple date formats can be entered into $dateformatcustom separated using “|” (the pipe character), for example:

D/M/y|D m y|d-m-y|D/M/Y|D/m/y|D-M-y|D M y

When parsing data entered by the user, the client uses each format in order, until one successfully matches the user input. The client uses the first format in the list to format the data for display.

Numeric Data Entry Validation

Entry fields (and data grids) validate numeric data as it is entered, for JavaScript remote form variables with a numeric data type. When the end user tries to enter invalid data into the field, such as an alphabetic character, the data is rejected, i.e. it cannot be entered into the field, and the field is highlighted momentarily to indicate an error (the default action is to show a red border).

When leaving the entry field, the value is normalized: so for integer data it is constrained to the valid range or for other numbers it is rounded to the correct number of decimal places; also, leading zeroes are removed, and so on.

Negative Numbers and Uppercase

The $negallowed property for Edit controls allows for the display of negative number values. If this is kFalse and the end user tries to enter a negative sign, the sign will be rejected. When set to kTrue, the $uppercase property forces uppercase for character data.

Multiline Edit Scrolling

Text wrapping for the Multiline Edit field is prevented if the $horzscroll property is enabled (kTrue). However, if $autoscroll is true, then text wrapping does occur (since $autoscroll is on by default).

Shortcut Keys

There are a number of shortcut keys defined in the Edit control that allow end users to select text and move the insertion point within the control (the shortcuts also apply to Window class Entry fields).

The shortcut keys are stored in the Omnis preference $keys which can be edited in the Property Manager (click on the Prefs option in the top level of the Studio Browser). The shortcut keys for Edit controls are stored in a configuration file called ‘keys.json’ and located in the Studio folder (this is the same file containing the shortcut keys for the Method Editor). The file is created the first time you edit the shortcuts in the Property Manager and click OK.

Shortcut key Action
Alt+End End of Text Alternative
Alt+Home Start of Text Alternative
Ctrl+Alt+DownArrow Scroll Down
Ctrl+Alt+LeftArrow Scroll Left
Ctrl+Alt+RightArrow Scroll Right
Ctrl+Alt+UpArrow Scroll Up
Ctrl+DownArrow Paragraph Down
Ctrl+End End of Text
Ctrl+Home Start of Text
Ctrl+LeftArrow Backwards Word
Ctrl+RightArrow Forwards Word
Ctrl+UpArrow Paragraph Up
End End of Line
Home Start of Line
PageDown Page Down
PageUp Page Up

Auto Correction, Capitalization, Completion

You can control the Automatic Correction, Capitalization And Completion of text entered by the end user into an edit control. This functionality is built into the browser whereby text is ‘corrected’ or updated automatically: note that not all browsers support all of these functions, so you should check support in individual browsers on different platforms.

You should note that Auto correction, Auto capitalization and Auto completion (the properties $autocorrect, $autocapitalize & $autocomplete) only work in Omnis when they are enabled on the client Mac computer. Note also that $autocapitalize only applies when using a virtual keyboard on a device.

Auto Correction

If true, the $autocorrect property specifies that text entered into a JavaScript Edit control is auto-corrected, as the end user types into the field. Currently this feature is only implemented in Safari and iOS browsers (note some browsers, such as Chrome, will highlight incorrectly spelled words, but not correct them automatically). This property defaults to kTrue for backwards compatibility.

Auto Capitalization

The $autocapitalize property controls whether or not text typed into an edit field is capitalized, as appropriate, automatically. Possible values include:

  1. kJSAutoCapitalizeSentences
    Automatically capitalise the first character of new sentences (default and previous behaviour)

  2. kJSAutoCapitalizeWords
    Automatically capitalise the first character of each word

  3. kJSAutoCapitalizeNone
    No automatic capitalization

Auto Completion

The $autocomplete property controls whether or not text is completed automatically. If true, the browser will attempt to complete text based on content previously entered into this type of field (e.g. name type fields will display a list of names based on the first letter typed): the browser will display a list of suggested text for the end user to select from. There may be many possible values for some types of field, which will be based on values previously entered into any website for a field with the same 'autocomplete' value, e.g. 'email'.

Content Selection

The $setselection method allows you to select a range of characters within the Edit control.

  1. $setselection(iFirstSel[,iLastsel]))
    Sets the focus on and selection range of the content in the Edit control. If iLastSel is omitted selection will occur to the end of the edit field. Returns the selected text.

$setselection has two parameters, both Integer, iFirstSel and iLastSel to set position of the characters to be selected within the edit control. iLastSel selects up to, but not including, the character specified, and if omitted the content in the edit field is selected to the end. The method returns the content selected.

Dictation Text Entry

You can enter text into an edit field using the built-in Dictation feature on macOS, which tries to convert audible speech into meaningful text. To allow dictation to occur the focus must be in the edit field, which must itself be editable, i.e. not disabled, and dictation must be enabled on the client computer. Dictation is available in Single- and Multi-line edit fields, the edit part of Combo boxes, and edit fields in Complex grids in remote forms (and window classes), that is, wherever text input is required.

Enabling Dictation

Support for Dictation is turned on in Omnis by default, but you can change it in the config.json file. There is a “useDictation" option in a new “macOS" member in config.json, which is set to true to enable dictation; note you have to quit Omnis to change the config.json file, and any change will be effective when you restart Omnis.


"macOS": {
        "useDictation": true
    }

Using Dictation in Edit fields

To enter dictation mode, place the cursor in the edit field and select the Start Dictation option from the Edit menu on macOS, or press the Function (Fn) key twice. This will open the dictation popup (usually in the center of the screen, depending on space) and put the computer in listening mode. Dictation can be stopped or cancelled by clicking on Done in the popup, or using the Stop Dictation menu option.

Dictation Levels

There are two levels of dictation provided by macOS: Standard or Enhanced. These can be enabled from System Preferences->Keyboard->Dictation, or on older systems System Preferences->Dictation & Speech.

Standard dictation (the default) requires an internet connection and provides speech to text translation using Apple’s servers. On older systems, the text is not translated until the Done button is pressed on the popup. On newer systems text is translated and placed into the field while the end user is speaking. Dictation will end automatically when text is entered from the keyboard or the field loses the focus.

Enhanced dictation requires the enhanced dictation engine to be downloaded, which is approximately 500MB for each language pack. This will then provide local machine based translation. Features of enhanced dictation are live feedback and offline support. With live feedback the text is rewritten while speaking. Enhanced dictation also provides spoken dictation commands such as “Select All”, “Cut that”, “Move left”, and so on. When enhanced dictation has been started it is possible to change the currently focused edit field and move the popup to the new field and continue to dictate. It is also possible to type and dictate at the same time.

Tooltips and Carriage Return

Text in tooltips will wrap if it contains a carriage return character or other wrapping characters when the text width of the tip would exceed a third of the screen width. In previous versions, tooltips only used CR to line wrap when the width of the tip was greater than half the screen width.

In addition, the CR character is no longer displayed. However, any other control characters (characters less than space, or the character 0x7f) are displayed using the Unicode control character page.

This change also applies to tooltips for window class controls.

File Control

The File Control allows end users to upload or download files inside a remote form: from Studio 10 the control allows multiple files to be uploaded. The control itself is invisible and to enable the upload or download functions, you need to assign an action at runtime, to the $action property. The Upload and Download actions are represented by the constants kJSFileActionUpload and kJSFileActionDownload. There is an example app called JS File Upload/Download in the Samples section in the Hub in the Studio Browser showing how you can upload and download files, and the same app is available in the JavaScript Component Gallery. In addition, the Contacts example app uses the file control, which is described below.

When in Upload mode the File control opens a standard Upload dialog to allow the end user to select a local file to upload. There are various properties to allow you to change the text and error messages on the Upload dialog.

image54

For downloads, the File control can provide a standard hyperlink pointing to the file to be downloaded, or you can assign a row variable to the $dataname of the control containing the binary data of the file to download, or a list for multiple file downloads. The download function is supported for mobile devices, and if the browser can interpret the contents of the file it is shown in a new browser window or tab.

Using Timer and File controls

Note that if a Timer control is present on the page, timer events will not occur while a file upload dialog is open, or while file download is in progress.

Mobile limitations or issues

Support for the Upload or Download function on mobile devices depends very much on the device itself and the mobile operating system. Therefore, if you intend to include an upload or download function in your app, you should test your app thoroughly on all devices you wish to support. With this in mind, we are aware of the following limitations or issues regarding different mobile operating systems.

Upload does not work on iOS because the input element to select a file does not become enabled since iOS does not support it. Download works via the hyperlink because mobile Safari has been implemented to support hyperlinks. However, the other download mechanism does not work: on iOS for example, the download actually transfers the data to the client, but then the browser does not carry out any action with the data, so the downloaded file is lost.

Uploading Files

To enable the upload function, you must set the $dataname property of the File component to a two-column row variable: Column1 should be of type List, and column2 should be of type Character ($dataname should be set before the upload action if triggered). The value assigned to column2 should be the name of a task variable of Binary type which will receive the binary data when the upload is complete. Column1 will receive MIME header list information when the upload is complete.

To trigger the upload dialog, you need to assign kJSFileActionUpload to the $action property. This action opens a file upload dialog which has two formats: one for up to date browsers, and the other for browsers which do not support XMLHttpRequest2, i.e. Internet Explorer and Opera. When a file has uploaded an evFileUploaded event is generated and the List and Binary task variable assigned to $dataname are populated. When the dialog closes the control generates evFileUploadDialogClosed.

The $maxfileuploadsize specifies the maximum size in bytes of a file to be uploaded to the server. Zero means no limit. Some clients (IE and Opera) cannot enforce this limit. See example below for details on how to upload a file.

While the Upload dialog is open, you can close it by assigning kJSFileActionCloseUpload to the $action property (note this does not generate evFileUploadDialogClosed).

On the upload dialog the file name is displayed above the progress bar, to the left, the percentage is shown above to the right, and file upload size information shown below as before. File sizes displayed to the user are in shown in the appropriate unit so when 1000 bytes is exceeded it changes to kB, 1000 kB changes to MB and 1000 MB changes to GB.

Upload File Type

The $uploadtypes property allows you to filter the file types that can be uploaded. The property accepts a comma-separated list of file extensions or MIME types, for example, the string '.png, .jpg, .jpeg' would allow PNG or JPG files, or 'image/*' to allow any image files.

Uploading Multiple Files

The File control allows multiple files to be selected for uploading by setting $allowmultiple to kTrue. It is not supported by some browsers, just like $maxfileuploadsize (IE9 and below, Opera).

The properties $maxbatchuploadsize and $maxbatchuploadsizeerrortext work similarly to $maxfileuploadsize to impose a limit of the total amount of data to be uploaded. This works independently of $maxfileuploadsize so you can impose a limit on single or multiple file uploads. In addition, $uploadedprogresstextbatch has been added to show the progress of the batch of files, and works similarly to $uploadprogresstext.

Error messages shown when file sizes are exceeded, for single or batches of files, give the user feedback on what the size limits are and lists the offending files exceeding the limit.

Multiple file upload dialogs display the same information for each single file, while another progress bar shows progress through the batch of files, including how many files have uploaded out of the total.

Localization

All the text and labels in the File control can be translated via the jOmnisStrings object in the JavaScript client. See the main Localization section for more info.

Downloading Files

URL downloads

In its simplest form, the File control can provide a hyperlink to allow the user to download a file located on the internet. In this case, you would set the $visible property of the control set to kTrue, set $hyperlinkurl to the URL of the file, and $hyperlinktext to the text for the hyperlink. The URL does not have to be a file download URL, it can be any file on the internet and will open in a new browser window or tab. The File control will display the download as a standard hyperlink on the remote form.

Single File downloads

You can also use the File control to download a file from a binary file or one stored in your database. To enable this functionality, you need to assign kJSFileActionDownload to the $action property. To download a single file, the $dataname property of the File control is set to a row variable, with Column1 as the file name, Column2 the media type (e.g. text/plain;charset=utf8), Column3 the name of a remote task variable which should be a binary containing the file data or character containing a file path, and Column4 is an 'Identifier' column (Character type) containing a name for the file.

Multiple File downloads

You can specify a list in $dataname, instead of a row, to provide a list of files to be downloaded. The definition of this list is identical to the row, with each line on the line representing each file to be downloaded. The fourth 'Identifier' column can contain a unique name for each file.

evDownloadSent Event

The File control has an event, evDownloadSent, which indicates if the download was successful, and identifies the file that was downloaded. The event receives two parameters:

  1. pSuccess
    Whether or not the download was successsfully sent.

  2. pIdentifier
    The value of the Identifier column (the fourth column, if provided) in the download list/row which was assigned to $dataname to initiate the download which has now been sent.

The evDownloadSent event will be triggered when the server has sent all of the data for a file to the client. Note that Omnis sends the data in a single chunk, so the client may still be processing the data at this point. However, at the point that the event is fired, the server has sent all of the data, and the task variable containing the binary data (or file path) can now be re-used.

Example

A File control is used in the jsContacts form in the Contacts sample app to allow end users to upload a photo of their contacts. The File control is placed somewhere on the form, its $dataname is set to iFileRow, an instance row variable, and the evFileUploaded and evFileUploadDialogClosed events are enabled in the $events property of the control. The iFileRow variable is setup in the $construct method of the form, as follows:

Do iFileRow.$define(MimeList,"Binary Variable")
Calculate iFileRow.C2 as "tData"

MimeList is a local list variable, and tData is a task variable of type Binary – it’s important to note that the second column of iFileRow is of type Character, and is set to the Name of the binary task variable. Elsewhere on the form is a picture control to display the photo, its $dataname is iPicture, and a button to allow the end user to select an image file and initiate the upload process. The code for the button is:

On evClick
  Do $cinst.$objs.fileControl.$action.$assign(kJSFileActionUpload)

This assigns the kJSFileActionUpload action to the fileControl object which opens the Browse/Upload dialog. The File control has an $event method which detects when a file has been uploaded and the upload dialog has been closed:

On evFileUploaded
  Calculate iPicture as tData
# transfer the pic data to iPicture
On evFileUploadDialogClosed
  Do method setPicBtnTitle (kHavePic) ## changes the button text

When an image is selected by the end user and the file is uploaded the image data is loaded into the tData task variable, as defined in the second column of the iFileRow row variable, which is then transferred to the iPicture variable assigned to the picture field on the form. The Save button saves the contact record including the image file uploaded by the user.

HTML Object

The HTML Object lets you display an HTML page or fragment in a remote form. The $html property contains the HTML content for the control. The HTML content for the control must start with an element declaration such as <div...> or <style>. The $wraptext property is set to true by default meaning that the content in the control will wrap (set it to kFalse to stop wrapping): this property sets white-space for the control to 'normal' if true, and 'no-wrap' if false.

HTML Preview

The HTML control has a property, $showruntimepreview, which defaults to kTrue, which ensures the HTML is rendered in the remote form rather than showing the HTML code text. If $showruntimepreview is false, the HTML code text is shown, but it cannot be scrolled inside the control in the design window.

Custom JavaScript Controls (Deprecated)

Note: This technique using $ctrlname to add custom controls to a remote form is deprecated. You should instead use JSON-defined controls: see the JSON Components chapter.

You can use a custom JavaScript control on a remote form by embedding it in an HTML Object. To do this, the JavaScript file defining the custom control must be placed in the html/scripts folder and referenced in the HTML file containing your remote form (this can be added to the jsctempl.htm file or the specific HTML page containing your remote form). The name of the custom control class (as defined in its JavaScript file) must then be added to the $ctrlname property of the HTML Object.

If you want your custom control to inherit the HTML control's specific functionality (such as the use of $html and its placeholders feature), your custom control must inherit from ctrl_html, rather than ctrl_base (and do not override this.superclass, instead use a different variable to reference the ctrl_html immediate parent class).

HTML Examples

There is an example app in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image55

image56

There are also two examples in the Samples section in the Hub (and in the Component Gallery) to display a Twitter button and a Twitter Timeline that use the HTML component to embed the necessary HTML into a remote form.

image57

The following HTML is used to create the initial Twitter button:

<div><a href="https://twitter.com/intent/tweet?screen_name=omnisstudio&text=I love Omnis" class="twitter-mention-button" data-size="large">Tweet to @omnisstudio</a></div>

Building an HTML block

You can use the Sta: command to build up the HTML content. The following method constructs some HTML and assigns it to $html of an HTML control called HTML.

# lHTML is a local var of Character type
Begin statement
# ===== Styles =====
Sta: <style>
Sta: p {color: #00F; margin: 0 2em; padding: 1em; background-color: #fff; border: #DDD solid 2px;}
Sta: h1, h2 { color: #666; margin-left: 0.5em;}
Sta: img {margin: 5px 0 5px 50px;}
Sta: </style
# ===== Content =====
Sta: <div>
Sta: <h1>HTML Control</h1>
Sta: <p>
Sta: You can display HTML in the HTML con.<br />
Sta: This is the Second line of con.<br /><br />
Sta: <i>And you can do italic etc!</i>
Sta: </p>
Sta: <h2>Pictures</h2>
Sta: <p>You can embed pictures.</p>
Sta: <img src="/images/cat.jpg" width="200" height="176" alt="cat" />
Sta: </div>
End statement
Get statement lHTML
# the html form object is called HTML
Calculate $cinst.$objs.HTML.$html as lHTML

You can embed any of the standard HTML tags into the $html property, including links, styles, and tables. The following text could be added to an HTML control which is placed next to a check box control on a remote form to allow end users to popup a window containing competition rules that are stored in a static html page:

<p>I have read and agree to the <a href="rules.html" target="_blank">competition rules</a></p>

Events

The HTML Control reports the evBefore and evAfter events, as well as evClick and evDoubleClick.

Style and Attribute Placeholders

You can inherit the effects and font attributes that you set for the HTML object in the Property Manager in design mode by inserting various placeholders in the $html property. The placeholders take the format %<letter>, for example, insert %f to inherit the font specified in $font, or %t to inherit the text color set in $textcolor. Most of the placeholders should be inserted into an html element using the style tag, while others are attributes and can be inserted directly into an HTML element.

Placeholder Type Description Property or desc
%b attribute back color and alpha $backcolor and $alpha
%f style font $font
%z style font size $fontsize
%s style font style $fontstyle
%j style font align $align
%t style text color $textcolor
%e attribute effect $effect
%p style position coordinates of omnisobject
%v style vert scroll $vertscroll must be kTrue
%h style horz scroll $horzscroll must be kTrue

For example, you can set $html to <div %e></div> and the text in the control will take on the effect from $effect (or $linestyle or $bordercolor, as these are effect properties).

To use the font specified in the HTML object in a paragraph in your HTML insert: <div><p style="%f">SOME TEXT</p></div>. For example, the following HTML produces some text rendered in plain or default HTML paragraph style and second paragraph of text that uses the font setting specified in $font in the HTML object, which in this case is set to “Verdana,Arial,Helvetica,Sans-serif”:

<div><p>PLAIN TEXT</p><p style="%f”>STYLED TEXT</p></div>

HTML object in Paged Panes and Subforms

If the HTML object appears in a Paged Pane or Subform (i.e. inside any container field), you will need to add the “white-space:normal” parameter to the <div> tag containing your Html to allow the text to wrap correctly inside the object. For example, the following <div> tag will contain text etc within a 300px width:

<div style="width:300px; white-space:normal">
# your HTML
</div>

The Hyperlink Control allows you to present a list of options to the end user, where each option in the list is displayed as a web-style hyperlink; each link option corresponds to a line in the underlying list variable used to populate the list. If the whole list does not fit inside the control, the list will “pop up” when the end user passes the mouse over the control. The $extraspace property specifies extra spacing between links. The Hyperlink control is used in the Studio Browser and is very similar to the JavaScript version of the control.

image58

The options or list contents in the Hyperlink control are based on the contents of a list variable specified in $dataname. The first column in the list should be the text displayed for each option listed in the control, unless $listcolumn is specified which is the column of the list variable used to populate the control. Subsequent columns in the list can be used to specify other values.

When the end user clicks on the list an evClick is triggered with the selected line reported in pLineNumber. You can use the value of pLineNumber in your event method to trigger an action. You can create an empty line by putting ”-“ (hyphen) in the first column.

If $isvertical is kTrue the list pops up vertically, and if $shouldunderline is kTrue the links are underlined. The $selectedtextcolor property specifies the color of the text when the mouse is over it.

Example

There is an example library showing how you can build a dynamic hierarchical list using the Hyperlink control in the Samples section in the Hub in the Studio Browser; the same app is available in the JavaScript Component Gallery.

The following method is the $event() method for the Hyperlink control:

# Do iHyperLinks.$define(iHyperName,iHyperGrp,iHyperCmd)
On evClick
 Do iHyperLinks.$line.$assign(pLineNumber)
 Do iHyperLinks.$loadcols()
 If iHyperGrp=0
Else
 If iHyperCmd=99
Else
 End If
 End If

Label Object

The Label object lets you add standard text labels to your remote form. The text for the label is entered into the $text property in the Property Manager, or you can double-click on the text for the label to edit it. Alternatively, you can assign some text to the $text property in your code.

The font and alignment of the label is setup under the Text tab in the Property Manager. You can use the style() function to style parts of the text assigned to $text, for example:

Calculate $cinst.$objs.label1.$text as con('Mellow ',style(kEscColor,kYellow),"Yellow")

Styled text is only supported if $textishtml is false. When set to true, the $textishtml property means the text in $text is interpreted as HTML, so in this case you can use any HTML tags and styling to format the text. For example:

Calculate $cinst.$objs.labelhtml1.$text as 'This is <span style="color:#ff0000;">RED</span>'

Labels have the $dataname property which means you can assign the text from a variable. In this case, the value in $dataname overrides the value in the $text property, and actually sets $text. You can assign a Date variable to $dataname, in which case the label takes its display format from #FDT, #FD, or #FT depending on whether the variable has a date/time component.

List Control

The standard List control allows you to display a single column list on your remote form allowing end users to select a particular line; the following screen shows the ‘ice’ JS Theme in use.

image59

For lists with many columns, you may prefer to use a Data Grid control, or for a more compact single-column list you can use a Droplist control. If you want to include an icon next to the text in each list line you can use a Tree list by including your data and icon references at the top-level of the list data without using any child data. For a further alternative to the standard List box you can use the Native List to display list data.

If $ischecklist is kTrue in the standard List control each list line has a checkbox which allows the end user to select or de-select the line.

image60

There are a number of example apps showing different types of list control in the Samples section in the Hub in the Studio Browser (see JS List, JS Linked List, JS List Pager), and the same apps are available in the JavaScript Component Gallery.

List data variable

The contents of a standard List is taken from the instance variable (of List type) specified in the $dataname of the control. In this case, the first column of the list contents is used to populate the list control; you can specify an alternative column for the data in $listcolumn. You can build the list via the $construct method of the remote form so it is available to all instances; the list can be built from your database or from a number of static values.

The example app in the Hub uses a simple check list ($ischecklist = kTrue) and a standard List control; the check list is built in the $construct method of the form:

Do iCheckList.$define(iCheckListValue## defines the list
Do iCheckList.$add('Milk'## add the values
Do iCheckList.$add('Tea')
Do iCheckList.$add('Coffee')
Do iCheckList.$add('Sugar')
Do iCheckList.$sort(iCheckListValue## sorts the list
# in addition you can select a line if required
Do iListvar.$line.$assign(1) ## selects the first line

The example app provides a button to merge the selected lines in the check list into the other list. The code behind the button is:

On evClick
 Do iList.$merge(iCheckList,kFalse,kTrue,kTrue)
 # merges the selected lines only

See the ‘Programming Lists’ chapter in the Omnis Programming manual for more information about using list variables in your code.

Selected Line Color

You can control the color for selected lines by setting $selectedlinecolor; use kColorDefault for the default selected line color for the client OS. The $evenrowcolor property sets the background color of even numbered rows displayed in the list; kColorDefault means use the same color as the odd numbered rows ($backcolor).

List Events

When the user selects a line the evClick event is reported with the pLineNumber parameter reporting the selected line number. You can also set the evDoubleClick event for a list control to detect when the end user double clicks on a list line. List events will retuen the pLineNumber parameter containing the number of the line clicked, and you can use this in your event method behind the list to trigger an action.

A double-click event is sent to a List control if the Enter or Space key is pressed while the focus is in the List and if evDoubleClick is enabled on the list. Otherwise, if the control has an evClick event enabled, Enter/Space sends an evClick. If the control does not have the evClick or evDoubleClick enabled, then Enter triggers the okkeyobject (if there is one), as long as the state of the list has not changed, i.e. the current line has not changed, and no checkbox has been toggled.

Lists and Client Methods

Searching Lists

You need to prefix the column name with $ref for a search to work in a client method. For example:

Do iList.$search($ref.iCol="ABC")

Smart Lists and the JavaScript Client

The JavaScript Client does not support smart lists in client executed methods, insofar as if you change the list in some way on the client, it will no longer be a smart list when the updated data is sent from the client back to the server. Smart lists work as expected in server executed methods.

List Scrolling

Data Grids have $vscroll and $hscroll properties which allow you to scroll a list vertically or horizontally at runtime in the client browser; note these properties are write-only meaning that you cannot return their values at runtime. The vertical or horizontal scroll value assigned using $vscroll or $hscroll is the pixel offset for a list.

Changing Current Line from the Keyboard

The $keyboardchangesline property determines whether or not the the current line in the list changes when the end user navigates the list using the keyboard; the property is available in the standard JS List, Native lists, Tree lists, and Data grids, and only takes effect when $multipleselect is kTrue. This allows multiple rows to be selected while also having the keyboard change the current line. To enable users to select non-adjacent lines with the keyboard, $keyboardchangesline can be set to kFalse.

When the list only allows a single line to be selected ($multipleselect is kFalse), navigating the list with the keyboard always uses a focus line and the user has to manually select a current line with the Space or Enter key, at which point evClick is fired.

Linked Lists

You can link a List control to an Edit control to create a “Linked List”, so that when the end user types into the edit field the contents of the list is updated dynamically. There is an example app in the Samples section in the Hub in the Studio Browser to show the use of a Linked list; in addition, the same app is in the JS Component gallery on the Omnis website at: www.omnis.net

image61

The combination of an Edit control with key presses enabled and a List control allow you to create a dynamic list that has the ability to update in response to what the end user types into the edit box. A Linked List is in effect like a Combo box, but with the extra ability to update itself as the user types. To enable this feature, edit controls can detect certain key presses and can be linked to a list control, while for lists themselves there is a property to display selected lines only.

Creating Linked Lists

The Edit Control has the $linkedobject property which is the name of a list control on the current remote form used to display suggestions to the user if the Edit control enables the evKeyPress event. You need to add the code to populate the list in response to evKeyPress, based on the current value of the instance variable specified for the Edit control.

When the end user types into the Edit control, the linked list will appear automatically. It is not necessary to process any events for the list control, since the dynamic list behavior is determined automatically by being linked in this way. Therefore, you would expect the following to happen when end users are using a dynamic linked list:

  1. Clicking on a line in the open list will set the edit control to the value of the clicked line.

  2. Pressing up or down arrow when the focus is on the list control will set the value of the edit control to the new current line of the list.

  3. Pressing the down or up arrow when the edit control has the focus and when the list is not visible will open the list, set the edit control value to the selected line in the list, and move focus to the list.

  4. Typing into the edit control when the list is closed will open the list and keep focus on the edit control.

  5. All the following will close the list: pressing return when the list has focus; pressing escape, or clicking away from the list or the edit control.

Optimizing the Linked List

The list property $selectedlinesonly specifies that only the selected lines in a list will be displayed (this only applies when $ischecklist is false), which in the context of Linked lists allows you to filter the content of a list that is linked to an Edit control. You should optimize the $event method for the edit control in the following way:

  1. Make the $event method for the Edit control execute on the client.

  2. On evKeyPress, if the list of suggestions is empty (or no longer suitable for the data), call a server method to build the list (with lines selected based on the value of the edit control).

  3. In subsequent evKeyPress events that can use the pre-built list, perform a list $search to change the selected lines to the ones which are suitable for the new value of the edit control.

In this way, the list of suggestions is cached on the client, and updates simply by changing the selected lines with a search in your code.

When $selectedlinesonly is true, the processing involving the usual click events and so on all use the line number of the data in the list, not the lines displayed in the list.

Note that if you use the $evenrowcolor property when $selectedlinesonly is true, the even row color applies to the numbers obtained by counting the displayed lines, rather than using the line numbers of the data in the list.

Detecting Key Presses

Edit controls have an event called evKeyPress; the Key press detection was added to support Linked Lists, but it could be used by itself for other purposes. The evKeyPress event has a single event parameter, pKeyList, which is a three column list containing the keys entered since the last evKeyPress event (or since typing started) with a row for each key in the order the keys were pressed.

Each key in the list is either a data character or one of a limited set of system keys (note that not all keyboard keys are supported, such as function keys are not supported). Transitions in shift state, ctrl state, and so on, do not result in a key in the list, so if the user types Shift+a, the character in the list will be A. The supported system keys are:

  1. Backspace

  2. Tab

  3. Escape

  4. Insert and Delete

  5. Up, Down, Left, and Right arrow key

  6. Page Up and Page Down

  7. Home and End

  8. Return

The columns in the list are as follows:

  1. Colum 1: If the key is a system key, column 1 is the keyboard constant value representing the key, such as kEscape. Otherwise column 1 is #NULL.

  2. Colum 2: If the key is a data key, column 2 is the character data for the key. Otherwise column 1 is #NULL.

  3. Colum 3: Is the sum of the following keyboard modifier constants, representing the state of these modifiers at the point the key was added to the list: kJSModShift, kJSModCtrl, kJSModAltOrOption, kJSModCmd.

In addition, there are some properties which control when evKeyPress events are generated. The Omnis preference $keyeventdelay is the minimum number of milliseconds (0-2000) between evKeyPress events. The first evKeyPress will also be delayed for this duration. This allows you to throttle keyboard events in the case where they will be executed on the server, and therefore reduce the load on the server. If true, the preference $systemkeys specifies that evKeyPress events include system keys which do not change the value of the data. If false, only system keys such as backspace are included as they potentially change the data.

While the user is typing, the edit control in the user interface remains enabled (unlike normal event processing where the entire user interface is usually disabled). The value of the instance variable associated with the edit control reflects the current content of the entry field when evKeyPress is generated.

The following method is the $event() method for the Edit field linked to a list of names (from the example app in the Hub):

On evKeyPress
 Calculate iKeyList as pKeyList
 Do iLinkedList.$search(mid(low(iLinkedListCol),1,len(iEditVar))=low(iEditVar))

List Pager

The $pagesize property allows you to display the lines in a list or data grid as separate pages, to improve the user experience when navigating lists or grids with a large number of lines; the default value is zero which means no list pager is displayed. The $pagesize property is available for the JS List, Data Grid, Complex Grid, and Native List (when not using grouped lists). There is an example app showing the List pager for all these list types in the Samples section in the Hub in the Studio Browser.

When assigned an integer value, the $pagesize property forces the contents of the list or grid to be sub-divided into a number of scrollable pages, and a set of page number buttons (as well as forward and back buttons) are displayed under the list or grid box, which allows the end user to “page through” each group of lines in the list or grid.

image62

The value assigned to $pagesize specifies the number of list lines displayed in each page, and therefore the total number of lines in the list, divided by the value of $pagesize determines the number of pages in the list or grid field, as well as the number of buttons displayed in the pager panel. The $pagerpage property allows you to set the page to be displayed, with the first page as the default.

Note that setting $pagesize does not reduce the amount of data sent to or fetched from the server – the full list data is sent to the client, and the setting of $pagesize is only used for displaying the list or grid with the pager element.

Changing the Pager’s Appearance

The appearance of the pager, such as the color of the buttons, numbers, and arrows, cannot be controlled using standard component properties. However, if you wish to customize the appearance of the pager, you can do so by overriding the associated CSS classes. These classes are named ‘omnis.pager<-xxx>’ and are listed in the omnis.css file. Do not edit the classes in omnis.css, rather you should override the classes by adding your own version in the user.css file found in the html\css folder in your Omnis development tree.

Map Control

The Map Control allows you to place a Google Map® on your remote form; this provides many of the functions available in a Google map and as provided by their API. There is an example app in the Samples section in the Hub in the Studio Browser showing the full capability of the Map control; in addition, the same app is available in the JavaScript Component Gallery (app requires a Google API key).

image63

Activation and API Key

In order to use the Map control, you need to register with Google Cloud Platform to obtain a Map API key, which can be entered in the $apikey property of the Omnis Map control; the Map control will not work without the API key. Specifically, you need to:

  1. Create and activate a Google Cloud Platform account (a free trial is available with credits)

  2. In the console under Credentials, create a new API key; copy this API key and add it to the $apikey property of the Map control

  3. Under APIs, navigate to Map APIs and enable the “Maps JavaScript API”. In addition, if you want to use the Geocode function, you need to enable “Geocoding API” (there are other APIs which you may be able to use).

Important Note: By signing up to Google Maps API via the Google Cloud Platform and using Google Maps in your deployed Omnis application, you and your end users must agree to the general “Terms of Use” for Google Maps: there is a link to these Terms of use on the map displayed in the Map control. Omnis Software cannot be held responsible for any third-party products or services and will not be liable for any damage or loss resulting from your use of the Google Maps content or the products.

Apart from the $apikey property, there is no further configuration needed to display a basic Google map in your remote form, however, to make the map really useful you will probably want to display specific locations, add markers on the map, or allow end user interaction with the map: all of these are possible with the JS Map control and are described below.

Map Location and Zoom Level

The $latlong property allows you to specify the center location of the map as “latitude:longitude”, for example, a value of 40.749305:-73.985775 will center the map on New York. If you do not set $latlong initially (by setting the property in the Property Manager in design mode or in the $construct method of the form), the map will open at some unspecified location, usually the default location setup in Google on the client device.

The $::zoom property lets you set the zoom level of the map: the range is 0 to 21, with zero showing the largest area (the whole world) and 21 the smallest possible area. The default zoom level is 8 which shows a reasonable amount of detail for the current center location of the map.

Finding the Latitude:Longitude

The Map component supports Google Geocoding which allows you to convert a street address into a geographic coordinate like latitude and longitude, which you can use to place a marker on a map, or center the map.

To use the Geocoding function you need to access the Geocoding API which itself requires a separate API Key, in addition to the Maps API key, which you can obtain from Google.

A Search button has been added to the JS Map example available in the Hub to show how you can convert a street address to a latitude:longitude coordinate which can be applied to the $latlong map property. Note the example app places the Geocoding API key in the $userinfo property which is then sent to Google.

Alternatively, you can find the latitude:longitude coordinate manually. To do this, Right-click somewhere on a standard browser-based Google map (not the Omnis map control), select the ‘What’s here’ option and the latitude:longitude value of that position is shown on the popup. You need to replace the comma with a colon to be used as a parameter in Omnis, e.g. 52.223460:1.492379.

Map Type and Controls

The $maptype property lets you set the type of map – this can be set to a constant: kJSMapTypeRoad (default), kJSMapTypeSatellite, kJSMapTypeHybrid, and kJSMapTypeTerrain. The end user can change the map type using the map type control shown on the map, assuming the $maptypecontrol property is enabled.

The other standard map controls, including the pan control, scale control, and the street view control are enabled using the properties $pancontrol, $scalecontrol, and $streetviewcontrol, respectively (these are all enabled by default): note you can only change these properties at runtime if the map control itself is enabled ($enable = kTrue).

The zoom control can be further controlled by setting the $zoomcontrol property: it can be set to kJSMapZoomOff, kJSMapZoomDefault (the default), kJSMapZoomSmall, and kJSMapZoomLarge. The latter two settings correspond to a simple Plus|Minus button (Small) or the same button with a vertical slider control (Large) for finer adjustment of the map zoom level.

Map Markers

You can place a marker or set of markers on the map by assigning a row or list containing marker information to the $mapmarkers property. For each marker you must define the latitude and longitude of the marker location in the first column of the setup list in the format latitude:longitude (e.g. “40.749305:-73.985775”), and in subsequent columns you can specify the marker title (shown when you hover over the marker), the tag or title for the popup (shown when you click on the marker), and html content for the popup. An optional fifth parameter can specify an icon for the marker to replace the default map marker (see below). If the third and fourth columns are empty for any marker defined in the list, the marker will not popup when clicked. (See the Events section about how to add markers via user clicks.)

image64

The following code adds markers to a map indicating the Empire State Building and Central Park in New York, it then centers the map on the Empire State Building, and sets a zoom level of 12 which shows a reasonable level of detail in this case:

# create vars map_markers (List), marker_latlong, marker_title, marker_tag, marker_html (Chars)
Do map_markers.$define(
marker_latlong,marker_title,marker_tag,marker_html)
Do map_markers.$add(
"40.749305:-73.985775","Empire State Building","Empire State Building","<div id='content'><h3 id='firstHeading'>Empire State Building</h3><div id='bodyContent'><p><b><img src='http://nyc-architecture.com/MID/esb1.jpg'></b></p></div></div>")
Do map_markers.$add(
"40.766225:-73.972514","Central Park","NY Central Park","<div id='content'><h3 id='firstHeading'>Central Park</h3><div id='bodyContent'><p><b>Central Park Info</b></p></div></div>")
Do $cinst.$objs.map.$mapmarkers.$assign("map_markers")
Do $cinst.$objs.map.$latlong.$assign("40.749305:-73.985775")
Do $cinst.$objs.map.$::zoom.$assign(12)

Map Marker Icons

The marker list assigned to $mapmarkers can have an optional fifth column which you can use to specify the icon URL for an image for the map marker. An empty string in this column (or a missing column altogether) means that the marker will use the default marker icon. The value for the marker icon is an icon URL which you set using the iconurl() function. Since the marker image has to be set for each row in your list you can specify a different image for each marker in the marker list, but if you want the same image for each map marker you still have to set the marker image for every row in your marker list.

Custom Markers

You can assign an alternative marker icon or symbol, including map markers from the Google maps API, by adding a sixth column to the marker list: in this case the fifth column should be omitted.

The definition for the markers list in the JavaScript Map control can be:

Do iMapMarkers.$define(
iMarkerLatLong,iMarkerTitle,iMarkerTag,iMarkerHtml,iMarkerIcon,iMarkerCustom)

where iMarkerCustom is a new string column (column 6) specifying a custom marker. When a marker is defined in the marker list, and the iMarkerIcon (column 5) is empty, iMarkerCustom can be included with the following attributes, separated with a ‘|’ character (you only need to specify the attributes required). An example custom string would be:

"path:google.maps.SymbolPath.BACKWARD_CLOSED_ARROW | fillColor: red | fillOpacity:0.8 | scale: 4 | strokeColor:black | strokeWeight: 1"

Or to draw a five-pointed star marker:

"path:M 125,5 155,90 245,90 175,145 200,230 125,180 50,230 75,145 5,90 95,90 z | fillColor: red | fillOpacity:0.8 |  scale: 0.1|strokeColor:black | strokeWeight: 1 | anchor:122,115"

Or to draw a circle marker:

"path:google.maps.SymbolPath.CIRCLE | fillColor: red | fillOpacity:0.8 | scale: 4"

Where the custom marker parameters are defined as:

  1. path can either be a map symbol, or an SVG notation path, as defined below

  2. fillColor the color used to fill the marker object, an html css color name or value e.g. #FF0000

  3. fillOpacity the opacity of the fill color, a value from 0 to 1, e.g. 0.5 is 50% transparent fill

  4. scale a scaling factor for the object

  5. strokeColor the color used to outline the object, an html css color name or value e.g. #FF0000

  6. strokeWeight the thickness of the stroke line

  7. anchor allows you to set the anchor position or offset the shape. By default, shapes are aligned to the top left of the marker relative to its lat:long

Marker Symbol – prefixed google.maps.SymbolPath. Description
CIRCLE A circle. image65
BACKWARD_CLOSED_ARROW A backward-pointing arrow that is closed on all sides. image66
FORWARD_CLOSED_ARROW A forward-pointing arrow that is closed on all sides. image67
BACKWARD_OPEN_ARROW A backward-pointing arrow that is open on one side. image68
FORWARD_OPEN_ARROW A forward-pointing arrow that is open on one side. image69

For example:

Do iMapMarkers.$define(
iMarkerLatLong,iMarkerTitle,iMarkerTag,iMarkerHtml, ,iMarkerCustom)
Do iMapMarkers.$add(
"52.223460:1.492379","Omnis UK","Omnis UK","","","path:google.maps.SymbolPath.BACKWARD_CLOSED_ARROW|fillColor: red|fillOpacity:0.8| scale: 8|strokeColor:black|strokeWeight: 1")
# the JS Map app uses similar code to show the Omnis offices

The JS Map example app has been updated and includes some of the new markers and polygons, and can viewed or downloaded via the Omnis website (www.omnis.net) from the JavaScript Component Gallery. The following image shows the location of the European Omnis offices using the “Backward-pointing Closed Arrow”.

image70

The map control has a property $fitmaptomarkers that can be assigned value 1 at runtime to force the map to zoom in or out to allow all the map markers to be shown.

Polygon Objects

In addition to icons and standard map markers, you can add polygon objects or irregular shapes to maps in the JavaScript Map control. The $mappolys property specifes the data name of a list which contains the definition of each polygon or shape as follows:

Do iPolyMarkers.$define(
iPolyLatLong,iPolyStroke,iPolyOpacity,iPolyWeight,iPolyFill,iPolyFillOpacity,iPolyTag)
  1. iPolyLatLong the latitude:longitude values for each of the the points of the polygon, so a triangle would have 3 points: the lat:long settings are separated with the ‘|’ character, e.g. 25.774,-80.190|18.466,-66.118|32.321,-64.757|25.774,-80.190

  2. iPolyStroke the color used to outline the polygon, which is an html css color name or value e.g. #FF0000

  3. iPolyOpacity the opacity of the stroke color, a value from 0 to 1, e.g. 0.5 is 50% transparent

  4. iPolyWeight the thickness of the stroke line

  5. iPolyFill the fill color of the polygon object, an html css color name or value e.g. #FF0000

  6. iPolyFillOpacity the opacity of the fill color, a value from 0 to 1, e.g. 0.5 is 50% transparent

  7. iPolyTag the tag name or label for the polygon, which is sent to the evPolygonClicked event method in pPoly

For example, the following code draws the Bermuda Triangle on the map (see the JS Map example app):

Do iPolyMarkers.$add(
"25.774,-80.190|18.466,-66.118|32.321,-64.757|25.774,-80.190","#FF0000","0.8","3","#FF0000","0.35","Bermuda Triangle")

The evPolygonClicked event with the parameter pPoly is called when a polygon on the map is clicked, and pPoly will be set to the polygon tag as defined in the list.

Events

There are various events available in the map control to allow you to detect when and where the map was clicked (evMapClicked, reports latitude and longitude of the click), when the map is dragged by the end user (evMapMoved, reports the latitude and longitude of the new center location), when the map is zoomed using the zoom control (evMapZoomed), or when a map marker is clicked (evMarkerClicked). None of these events are enabled by default, so you have to enable them in the $events property for the control using the Property Manager.

The following $event method could be placed behind a map control to detect when the map is clicked, or when a marker is clicked (assuming a marker has been added), or if the map is moved or zoomed. The add_markers Boolean variable is linked to a checkbox on the window to allow the end user to enable or disable the ability to add markers. When the map is clicked, the evMapClicked event reports the position in pLatlong, and a marker definition is added to the map_markers list. The message variable is assigned to a field on the form to show either the new center of the map, the new zoom level, or which marker has been clicked.

# $event method for map control
# define vars map_markers (List), marker_latlong, marker_title, marker_tag, marker_html, message (Chars), add_markers (Bool), marker_no (Long int = 0)
On evMapClicked
  If add_markers ## linked to checkbox on window
    Calculate marker_no as marker_no+1
    Do map_markers.$define(
    marker_latlong,marker_title,marker_tag,marker_html)
    Do map_markers.$add(
      pLatlong,con("Marker ",marker_no),
      con("Marker ",marker_no),con("This is marker ",marker_no))
    Do $cinst.$objs.map.$mapmarkers.$assign("map_markers")
  End If
  Calculate message as con(
    pick(add_markers,"Map clicked here: ",
    "Marker added here: "),pLatlong)
On evMapMoved
  Calculate message as con("Center is now: ",pNewCenter)
On evMapZoomed
  Calculate message as con("New zoom level: ",pNewZoom)
On evMarkerClicked
  Calculate message as con("Marker clicked: ",pMarker)

Native List

The Native List control appears in the ‘JavaScript Native Components’group in the Component Store, and it provides a list control that looks familiar on different platforms. You can customize the accessories in the list by adding your own HTML content and CSS styling, and therefore provide a very rich UI in a single list format.

In keeping with this philosophy, the JS Native List exposes many appearance properties to allow you to customize the list how you wish. If you leave any of the values as kColorDefault, they will revert to the platform-specific default.

The native list has been designed along the same lines as the iTableView component of iOS forms. The list can either be a standard flat list or a grouped list, using nested lists.

To increase efficiency, the list only draws the displayed rows, along with several more in a buffer zone around them, at any one time. This provides smooth scrolling, and means that the size of the list has very little impact on performance. As a side-effect of this, when scrolling quickly, you will see that the rows may not be rendered immediately.

There is an example app in the Samples section in the Hub in the Studio Browser showing how you can customize the accessories in a native list; the same app is available in the JavaScript Component Gallery.

image71

Defining the $dataname list

The structure of the List instance variable used for the $dataname of the native List control differs based on how you wish the list to display.

The Data tab in the Property Manager allows you to assign column numbers for each row part, i.e. $text1col allows you to specify which column in your list contains the the data to display as the main text of the row. If you do not wish to make use of a particular row part, leave its column set to 0.

You need to define and populate your list in accordance with the column numbers you have set in the Data tab of the Property Manager. The content of these columns should be as follows:

  1. text1col: This should be Character data, to display as the main text for the row.

  2. text2col: This should be Character data, to display as the secondary text for the row.

  3. imagecol: This should be Character data - a URL to an image to display.
    The image will be scaled to fit the size of the row’s image (customized using $imageheight & $imagewidth).
    The URL can make use of Omnis’ support for pixel-density-aware image selection by passing the URL in the format: “<URL to 1x image>;<Name of 1.5x image>;<Name of 2x image>” (where all 3 images are in the same location). This means that on a Retina device it will use the 2x image, but on a standard display device it will use the 1x image. As the image is scaled anyway, you could just always use the 2x image, but this method reduces unnecessary bandwidth usage and processing of larger images

  4. accessorytypecol: This should be a kJSNativeListAccessoryType… integer value. It determines the type of accessory to display on the right edge of the row.
    Use a value of 0 for no accessory. A kJSNativeListAccessoryTypeNone constant will be added in the future.

  5. accessoryvaluecol: Contains the current value of the row’s accessory.
    This is currently only used by the Checklist accessory, to represent the checkbox’s state

  6. accessorycontentcol: This should be Character data, and should describe the content for some accesssory types. The Accessory types which make use of this are:
    Button: For rows with a button accessory, the content should be the text for the button.
    Custom: For rows with a custom accessory, this should be HTML to describe the contents of your custom accessory.
    CustomWithEvent: see below.

Custom Accessories

You can add your own custom row accessories by setting the accessorycontentcol list column to kJSNativeListAccessoryTypeCustom or kJSNativeListAccessoryTypeCustomWithEvent.

kJSNativeListAccessoryTypeCustomWithEvent works in the same way as kJSNativeListAccessoryTypeCustom but will trigger a different click event when you click on the accessory (evClick will be called with pWhat equal to kJSNativeListPartAccessory instead of kJSNativeListPartRow).

When accessorycontentcol is set to a custom accessory, its value should be the HTML content of your custom accessory, encapsulated within a single parent element.

You can set your accessory to a particular size (rather than fill the available space in the row) by providing width & height values in the style tag of your top-level HTML element.

If a size is defined in this way, the native list control will attempt to center the accessory. If this does not work, you may also need to set "position: absolute;" in your style tag. For example:

'<div style="position: absolute; width: 50px; height:25px; background-color: #FF0000;" />'

Creating a Grouped list

If you wish your Native List control to display its data as a Grouped list, you need to change the structure of the list assigned to $dataname. The main list should comprise two columns:

  1. Column 1: Should be defined as being of type “List”, and each row should contain a list structured as defined above (adhering to the columns specified in the Datatab of the property inspector). All of the rows defined in this sub-list become part of a single group.

  2. Column 2: A Character column, defining the name of the group.

Properties

The Native List component has many properties to allow you to customize its appearance. Most of these are self-explanatory and/or are described by their Property Manager tooltips. The following may need futher explanation:

  1. $rowdisplaystyle: Determines how the row is displayed. Value should be a kJSNativeListDisplayXXX constant. Current values allow you to change between displaying the two text fields in a vertical or horizontal fashion.

Advanced Customization

If you wish to alter the default appearance for a particular platform, or wish to change something which is not exposed as a property, you would need to do so using CSS. This is only recommended if you have experience of customizing CSS.

The classes used (when defaulting to platform-specific appearances) are defined in native_list.css.

Rather than altering these classes here, it is recommended that you extend them in your user.css file, to prevent you needing to make these changes each time you update Omnis.

As always, when editing the CSS used by Omnis’ controls, there is the possibility that you may change how a control appears or behaves (especially if you alter sizes), so you do so at your own risk.

Native Slider

The Native Slider control appears in the ‘JavaScript Native Components’group in the Component Store, and it works, for the most part, in the same way as the standard JavaScript Slider component but has a more familiar appearance when running on different platforms. There is an example app in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image72

The current value of the slider is reported in the property $val according to where the slider is positioned. You can specify the range for the slider in the $::min and $::max properties. The $usessteps property is a Boolean determining whether or not the slider should snap to discrete step values specified in $step.

The Slider reports three events: evStartSlider (when the control is starting to track), evEndSlider (when the control has finished tracking), and evNewValue (when the value has changed). You can detect these events in the $event method for the component. These events all pass the current value of the Slider in the pSliderValue parameter. As the user drags the Slider thumb the evNewValue event is triggered and pSliderValue is sent to the $event method for the Slider.

If you do use evNewValue, you should mark your $event method as client-executed and consider enabling the $usessteps property and setting $step to limit the number of events being triggered as the user moves the slider. Alternatively, you could use the evEndSlider event to report the final value since for most purposes this will be the value selected by the user.

Native Switch

The Native Switch control appears in the ‘JavaScript Native Components’group in the Component Store, and it works, for the most part, in the same way as the standard JavaScript Switch component but has a more familiar appearance when running on different platforms. There is an example app in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image73 image74
iOS Android

The Switch has a $dataname property, to which you can assign a Boolean instance variable. This will be kept up to date with the state of the switch, as the end user clicks or taps on the control.

The Switch has $justifyhoriz and $justifyvert properties. For some platforms (e.g. iOS) the switch maintains a specific aspect ratio. These properties determine how the switch is positioned inside the control in these circumstances.

The text displayed on the Native Switch is controlled by two members in the built-in strings object jOmnisStrings in the JavaScript Client. You can use the members "switch_on" and "switch_off" to replace the default text with your own text, for example, if you wish to provide different language equivalents to the default text.

Information about how to change or localise these strings can be found in this manual, under "Localizing Built-in Strings".

If you wish to override the base text, you could use the following code in a separate JavaScript file loaded in your form's html file after omjsclnt.js:

    jOmnisStrings.base.switch_on = "I";
    jOmnisStrings.base.switch_off = "0";

The Navigation Bar Control (or Nav bar) provides a standard navigation bar which end users can use to navigate to different parts of your application. There is an example app in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image75

The Navigation Bar has a main title in the middle of the control, and it can have a left and/or right button which respond(s) to user clicks. The Nav bar can be linked to a Paged Pane via the $linkedobject property to allow you to display different panes in your form in response to clicks in the Nav bar. Actions for the Nav bar can be stacked up using the $push property: see the example below.

The Nav Bar has a number of properties for setting the color, fonts and style of the bar and buttons ($button.. properties), together with the following properties:

Property Description
$disableanimation Disables the animation when moving between pages. This property can only be set in design mode (not at runtime using the notation)
$initiallefticonid If this is not zero, and $initiallefttext is empty, the first navigation bar item has a button on the left hand side, displaying this icon
$initiallefttext If this is not empty, the first navigation bar item has a button on the left hand side, displaying this text
$initialrighticonid The icon for the initial navigation bar button on the right
$initialrighttext The text for the initial navigation bar button on the right
$initialtitle The initial title displayed on the navigation bar
$lefthidden If true, the left hand (back) button is hidden for the current navigation bar stack item
$linkedobject The name a paged pane on the current remote form, used in conjunction with the $push property
$push At runtime, allows you to assign a 2-6 column row to the paged pane referenced in $linkedobject: col1 is the page number of the paged pane, col2 is the title for pushed item, col3 is the text for right button (pass empty for no right button), col4 is the or icon id for the image for right button, and col5 can be non-zero to hide the left button, col6 is the text for left or ’Back’ button (pass empty to display the title of the previous pane by default). The path to the icon referenced in col4 must be obtained in a server method using the iconurl(icon-id) function since icon ids cannot be resolved on the client
$pop Removes a specified number of items off the navigation stack: see below
$righticonid If this is not zero, and $righttext is empty, the current navigation bar item has a button on the right hand side, displaying this icon
$righttext If this is not empty, the current navigation bar item has a button on the right hand side, displaying this text
$::title The title for the current navigation bar stack item

Setting $disableanimation to kTrue disables the animation when moving between pages: this property was added to fix a problem when using the built-in VoiceOver screen reader on an iPad in conjunction with a Nav Bar linked to Page Pane: the problem is avoided by disabling the animation effect on the Nav Bar.

You can use the $pop property to “pop” or remove a specified number of items off the navigation stack: it is analogous to clicking on the left or back button, since it allows you to step back in the navigation stack a specified number of times.

The $pop property can only be assigned at runtime. If you try to pop more items off the stack than exist, it will pop everything except the first item. If you assign to $pop, note that the evUserChangedPage event of a linked paged pane will not be triggered.

In addition, you can set the text or title for the left (back) button for a navbar. If provided, the 6th col in the row assigned to $push allows you to specify the left button text. This can be set to an empty string to default to the previous page's title.

Events

The Nav Bar reports evClickInitialLeftButton when the initial left button has been clicked, and evClickRightButton when the right button has been clicked.

The events evPushFinished and evPopFinished are triggered when the push or pop animations complete. Both events have one event parameter which is the associated page number that has been pushed or popped.

Example

The following Navigation Bar has a main title and a button on the right which is used to display some information on the second pane of a paged pane.

image76

The Nav Bar is placed across the top of the form and its various properties under the General and Appearance tabs in the Property Manager are set, as follows:

$events set to receive evClickRightButton events
$linkedobject set to pPane, the name of the paged pane
$push can only be assigned at runtime; see below
$initialtitle set to “Main Page”
$initialrighticonid set to 1794, the id of an icon in Omnispic
$initialrighttext set to “Info”

The $event method for the Nav Bar ($name = oNav) traps a user click on the right button, and has the following event code:

On evClickRightButton
  Do $cinst.$doPush(2,'Info','','','')

The $doPush method is a class method in the remote form and has the following parameters, variables, and code.

# PaneNo (Short Int)
# Title, RightBtnText, RightBtnIcon (must be an icon url), NoLeftBtn (all Character)
# lRow is local var of type Row
Do lRow.$define(
    'New class','Title','text for right btn',
    'icon url for right btn','no left btn','text for left btn')
Do lRow.$assigncols(
    PaneNo,Title,RightBtnText,RightBtnIcon,NoLeftBtn,LeftBtnText)
Do $cinst.$objs.oNav.$push.$assign(lRow)

The effect of assigning to the $push property is to change the pane number in the paged pane specified in the $linkedobject property which, in this case, displays some information for the end user on the second pane. Assigning to $push adds a left or ‘Back’ button to the navbar which the end user can use to go back to the previous pane; the default text for this button is the name of the previous pane, or you can pass your own text in the 6th column of the row passed to $push.

The Navigation Menu control (or Nav menu) allows you to build interactive cascading menus within your remote forms, providing a navigation method similar to that found on many websites. Such menus typically comprise a number of hot text links, which cause further menus to open below the top level. In addition, each menu option can have an image as a background or link. The nav menu can also operate as a breadcrumb, with a hierarchical set of text links, similar to the folder selection mechanism found in Windows Explorer.

The Nav Menu control has been implemented for both the JavaScript client (remote form class) and the fat client (window class), and the two controls have almost identical properties, with the same look and feel. Unless otherwise stated, the descriptions here apply to both the JavaScript Client and fat client types of control.

There is an example app in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image77

The Navigation Menu control uses a list specified by $dataname to define its content. The list should have seven columns with each line of the list corresponding to a single entry in the menu. The columns in the list are defined as follows:

Column Type Description
Type Integer The menu entry type, a kNavMenuType… constant. See below.
Text Char The text for the menu entry. This can include styles embedded using the style() function, and embedded kCr characters in order to split the text over multiple lines.
Desc Char Optional text describing the menu entry. This can include styles embedded using the style() function, and embedded kCr characters in order to split the description over multiple lines.
Flags Integer Sum of one or more constants that indicate how the menu entry behaves. See table below.
Ident Integer A unique integer value that identifies the menu entry. Note that the control does not enforce uniqueness.
Tag Char A unique string value that identifies the menu entry. Note that the control does not enforce uniqueness. In fact, developers may choose to just use the tag or just use the ident, or make the combination of tag and ident unique.
Info Row A row that contains further information required for the menu entry. Not used for all entry types. E.g. contains the content for a cascaded menu, see kNavMenuTypeCascade.

The flags column can be zero, or a sum of one or more of the following flag values and specifies how the menu entry behaves:

Flag Description
kNavMenuFlag
HorizontalLayout
Only applies to the first line of a menu (or cascaded menu) list. If not set, entries are laid out vertically; if set, entries are laid out horizontally.
kNavMenuFlag
EndOfRowOrColumn
If set, the menu entry for this line is the last entry in the current row or column in the layout for the menu (row or column depends on whether layout is horizontal or vertical respectively)
kNavMenuFlag
Disabled
If set, the menu entry is disabled. This means it will not accept clicks, and it will not hot-track.
kNavMenuFlag
Breadcrumb
Only applies to line 1 of the $dataname menu list. If set, the menu is a breadcrumb control, and for the $dataname list, kNavMenuFlagHorizontalLayout is turned on and kNavMenuFlagEndOfRowOrColumn is ignored.
kNavMenuFlag
BreadcrumbSeparator
If set and kNavMenuFlagBreadcrumb is set and applies to line 1, the entry draws the breadcrumb separator. Note that the control uses the description text color ($descriptiontextcolor ) as the color of the separator.

The first column of your data list sets the type of menu control, using one of the following kNavMenuType... constants:

kNavMenuTypeHeading

Used as a heading to group other menu entries. Typically, this would be a disabled entry, but it can accept clicks if desired. The info column is not used for this type.

kNavMenuTypeEntry

A normal menu entry, typically used to accept a click and generate an event.

kNavMenuTypeImage

A menu (or cascaded menu) list can only have a single image entry (others are ignored). You use the info column to provide an image that will be displayed as a background of the menu, and which will also accept clicks. The control will place the image at the “end” of the menu, irrespective of where the entry is placed in the list. The info column for an image entry is a row with the following columns. Note that only the icon column is mandatory.

Column Type Description
Icon Character or Integer For the JavaScript Client, the character URL of the image, generated by calling iconurl(iconid). For the fat client, the integer icon id of the image.
Horizontal offset Integer You can adjust the horizontal position of the image in the menu by supplying a value here. Defaults to zero.
Vertical offset Integer You can adjust the vertical position of the image in the menu by supplying a value here. Defaults to zero.

kNavMenuTypeCascade

An entry representing another menu which cascades from the entry when either the mouse is over the entry, or when the entry is clicked (this depends on the $openwhenmouseover property described below). Note that the control supports a cascade nesting depth of 15.

The info column for a cascaded menu entry is a row with the following columns (note: when you understand how the properties and events for the control work, you will see that the info row does not always need to be fully specified for a cascaded menu - in many cases only column 1 is required, and in fact, in some cases, the info row is not required at all for a cascaded menu):

Column Type Description
List List A menu list defining the entries in the cascaded menu.
Cascade flags Integer Zero, or a sum of kNavMenuCascadeFlag… flags, see below. Defaults to $defaultcascadeflags.
Open side Integer The side from which the cascaded menu will open. Either kNavMenuSideLeft, kMenuSideRight, kMenuSideBottom or kMenuSideTop. Defaults to $defaultcascadeopenside.
Border edges Integer A sum of kNavMenuSide… constants that specifies the edges of the cascaded menu that are to have a border. Defaults to $defaultcascadeborderedges.
Border color Integer The color of the border of the cascaded menu. Defaults to $defaultcascadebordercolor. For the JavaScript Client control, you must set this column to the result of truergb(color) if the color you are using is a color constant.
Border width Integer The width of the border of the cascaded menu (1-16). Defaults to $defaultcascadeborderwidth.
Background color Integer The background color of the cascaded menu. Defaults to $defaultcascadebackcolor. For the JavaScript Client control, you must set this column to the result of truergb(color) if the color you are using is a color constant.
Background alpha or foreground color Integer For the JavaScript Client, the background alpha value for the cascaded menu (0-255). Defaults to $defaultcascadebackalpha. For the fat client, the foreground color of the cascaded menu. Defaults to $defaultcascadeforecolor.
Background pattern Integer Only applies to the fat client. The background pattern of the cascaded menu. One of the standard pattern constants. Defaults to $defaultcascadebackpattern.

Cascade Flags

The cascade flags are as follows:

Flag Description
KNavMenuCascadeFlag
UseEventToPopulate
If set, the control sends evLoadCascade in order to populate the cascaded menu
KNavMenuCascadeFlag
UseEventWhenRequired
If set, and kNavMenuCascadeFlagUseEventToPopulate is also set, only send evLoadCascade when data is required again for some reason,rather than each time the menu opens
KNavMenuCascadeFlag
OpenOnParentEdge
If set,the cascaded menu opens on the relevant edge of the parent menu, rather than opening on the relevant edge of the parent entry.
KNavMenuCascadeFlag
Expand
If set, and kNavMenuCascadeFlagOpenOnParentEdge is also set, the cascaded menu expands if necessary to the width or height of the parent.
KNavMenuCascadeFlag
UseDefault
If set, use the default cascaded menu flags for the control ($defaultcascadeflags) and ignore any other flags. This allows you to use default cascade flags, and then override other properties using the info row.

In addition to the standard control properties, the Nav Menu control has the following properties:

Property Description
$borderedges A sum of kNavMenuSide… constants that specifies the edges of the control that are to have a border.
$borderwidth The width of the border of the control (1-16).
$closeboxiconid

The icon id of the close box for cascaded menus (only relevant when $openwhenmouseover is kFalse, and the control is not in breadcrumb mode). Note that when $openwhenmouseover is kFalse, on a non-touch device, menus still close automatically when the mouse leaves the control or its open cascaded menus. If you do not want a close box, set this to zero.

On a touch device you can close all open cascaded menus by touching an area away from the control and its open cascaded menus.

$defaultcascade… Default properties for cascaded menus (see the description of the info row for cascaded menus). These eliminate the need to repeat this information for every cascaded menu.
$horizontalcascadeiconid The id of the icon used to represent an entry that cascades to the left or right.
$horizontalspacing Horizontal spacing used when laying out entries.
$hotcloseboxiconid The icon id of the close box for cascaded menus, used when $openwhenmouseover is kFalse, and the mouse is over the close box.
$verticalcascadeiconid The id of the icon used to represent an entry that cascades to the top or bottom.
$verticalspacing Vertical spacing used when laying out entries.
$font… properties Used to control the font and colour of entry text: $font, $fontsize, $fontstyle, $textcolor, $hotfontstyle, $hottextcolor
$descriptionfont… properties Used to control the font and colour of description text: $descriptionfont, $descriptionfontsize, $descriptionfontstyle, $descriptiontextcolor
$headingfont… properties Used to control the font and colour of heading text: $headingfont, $headingfontsize, $headingfontstyle, $headingtextcolor, $hotheadingfontstyle, $hotheadingtextcolor
$openwhenmouseover If true, cascaded menus open when the mouse is over the relevant part of the control. Otherwise, the user needs to click in order to open a cascaded menu. On a mobile device, the value of this property is ignored and treated as kFalse, because there is no mouse.

When an entry is selected in the Nav Menu an event is triggered, one of the the following events:

Event Description
evLoadCascade The control sends this event when it needs to populate a cascaded menu (i.e. kNavMenuCascadeFlagUseEventToPopulate is set for the menu). The application code processing this event builds a list for the cascaded menu, and assigns it to the runtime-only property $cascadecontents.
evMenuEntryClicked The control sends this event when the user clicks on a menu entry.
evEmptySpaceClicked The user has clicked in empty space to the right or bottom of the menu (generated for top-level menu page only).

evLoadCascade and evMenuEntryClicked have 2 event parameters, pLineIdent and pLineTag, which are the ident and tag of the menu list line for which the event was generated. These events and their parameters can be trapped in the $event method for the control.

Scrolling

If the initial menu (set with the list content in $dataname) is too wide to fit the control, the control uses scroll arrows at the left and right to allow its content to be scrolled – ideally you should fit your content to the width of the control so no scroll arrows are required. The scroll arrows are displayed in this case to support the breadcrumb mode which uses a single row of entries for the initial page.

On a touch device, the scroll arrows are not displayed but you can scroll the control horizontally by touch-dragging. The scroll arrows are the same ones used for the tab control which are specified in omnis.css and the images folder, so you can change their appearance if required.

The following methods define the Nav Menu for a fictional online shop (they are contained in an object class and called via an object variable in the remote form). An example containing a similar Nav menu is available in the JavaScript Components Gallery on the Omnis website, and in the Hub.

First the content list for the Nav Menu is defined (with seven columns), then the second-level items are created, in this case the shop departments, and the top-level for the menu is added. The list built here is added to the list specified in $dataname for the Nav Menu object in a remote form.

Do method defineMenuList (lDepartmentList)
Do lDepartmentList.$add(kNavMenuTypeCascade"Books""", 0, 100, "books")
Do lDepartmentList.$add(kNavMenuTypeCascade"CDs""", 0, 101, "cds")
Do lDepartmentList.$add(kNavMenuTypeCascade"Digital music""", 0, 102, "digimusic")
Do method defineMenuList (lOmniShop)
Do lOmniShop.$add(kNavMenuTypeCascadecon("Shop by",kCr,"Department"),"",0,1,"",
row(lDepartmentList,kNavMenuCascadeFlagOpenOnParentEdge +
kNavMenuCascadeFlagExpand,kNavMenuSideBottomkNavMenuSideTop+
kNavMenuSideBottomkNavMenuSideRight))
Quit method lOmniShop

The defineMenuList method is a generic method to define the list of the menu content:

Do pMenuList.$define(lType,lText,lDescText,lFlags,lIdent,lTag,lInfo)

The $events property for the Nav Menu object has two events specified: evLoadCascade and evMenuEntryClicked. The menu object itself has the following event method:

On evLoadCascade
  Do iNavMenuObject.$shopLoadCascade($cfield,pLineTag)
On evMenuEntryClicked
  If not(iNavMenuObject.$handleclick($cfield,pLineTag))
End If

The $shopLoadCascade method builds the content for the cascaded menu:

Do method defineMenuList (lCascadeList)
Switch pTag
  Case "books"
    Do lCascadeList.$add(
      kNavMenuTypeHeading,"Books","",kNavMenuFlagDisabled)
    Do lCascadeList.$add(
    kNavMenuTypeEntry,"Best sellers","Top 1000 books",0,200)
    Do lCascadeList.$add(
      kNavMenuTypeEntry,"eBooks","For kindle and tablets",0,201)
    Do lCascadeList.$add(
   kNavMenuTypeImage,"Pre-order","",0,202,"",row(iIcon10001))
       # this line is shown in the pic below
  Case "cds"
    Do lCascadeList.$add(
      kNavMenuTypeHeading,"CDs","",kNavMenuFlagDisabled)
    Do lCascadeList.$add(
      kNavMenuTypeEntry,"CD store","Over 3m CDs",0,300)
   Do lCascadeList.$add(
      kNavMenuTypeImage,"Rock store","",0,301,"",row(iIcon10002))
  Case "digimusic"
    Do lCascadeList.$add(
      kNavMenuTypeHeading,"Digital music","",kNavMenuFlagDisabled)
    Do lCascadeList.$add(
      kNavMenuTypeEntry,"Music store","Over 30m songs",0,400)
    Do lCascadeList.$add(
      kNavMenuTypeEntry,"Your music library","Play online",0,401)
    Do lCascadeList.$add(
      kNavMenuTypeImage,"Pre-order","this new
      album",0,402,"",row(iIcon10000,-200,-50))
  End Switch
Calculate pControl.$cascadecontents as lCascadeList

The menu will look something like this:

image78

 

Page Control

The Page Control links to a Paged pane on a remote form and allows the end user to change the current page in the linked paged pane by swiping over the page control or clicking for non-touch screens. The Page control also gives the end user a visual clue as to the current selected pane in the linked page pane object, since the highlighted dot in the control changes to reflect the current page in the linked paged pane. There is an example app in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image79

The paged pane linked to the Page control is specified in the $linkedobject property. In this case, when the page control is clicked or swiped the linked paged pane control will select the next available pane automatically.

Property Description
$::currentpage the current page number
$linkedobject the name of a paged pane object on the current remote form that links to the iPage control
$::pagecount the number of pages
$pageindicatorcolor the color for the current page indicator
$currentpageindicatorcolor the color for all the pages except the current page indicator

When the page indicator changes in the Page control an evPageChanged is triggered containing the number of the new page in pValue.

Paged Pane

The Paged Pane provides a very convenient method to show a number of fields or controls grouped together on separate panes, or to break down an entry form into more manageable parts whereby each pane contains a small number of fields. The Page Control example app in the Samples section in the Hub in the Studio Browser uses the Paged Pane; the same app is available in the JavaScript Component Gallery.

The $pagecount property specifies the number of panes, and $currentpage specifies the current pane. In design mode, you have to set $currentpage to the number of the pane you wish to add fields to, or you can right-click the background of the paged pane and select the number of the pane you want to edit. You can set $effect to select different border effects for the control (a kJSborder... constant).

You can link a paged pane to a Navigation Bar, Page Control, or Tab Bar control so when the nav bar, page or tab changes the current pane of the paged pane changes accordingly. To link a paged pane to one of these controls, set the $linkedobject property of the Nav bar, Page control or Tab bar to the name of the paged pane.

By setting $scrolltochangepage to kTrue the pages are laid out horizontally, and the end user can change the current page by scrolling horizontally (for touch devices the end user can change panes by tapping on the current pane).

Events

An evUserChangedPage event is triggered when the pane changes and the new page number reported in pPageNumber.

When a Paged Pane is linked to a Nav bar or Tab bar control, the evUserChangedPage event is triggered when the nav button or tab is clicked to change the pane.

Rounded Corners

The $borderradius property lets you add rounded corners to the Paged pane. The radius can be specified by a single value, so all corners are the same radius, or up to four hyphen-separated pixel values, in the order topleft, topright, bottomright, bottomleft, e.g. 4-4-0-0 to add rounded corners to just the top of the paged pane. If the bottomleft value is omitted the topright value is used. If bottomright is omitted the topleft value is used. If topright is omitted the topleft value is used.

Note: If a border radius is set, the rounded corners are not drawn in design mode: they are only rendered when the app is run on the client. The rounded corners are not drawn in design mode to allow the full use of the available space within the page pane control while designing the form.

Using $dataname

The Page Pane control has a $dataname property which you can use to set the value of $currentpage. When the form is opened or redrawn the numeric value of $dataname is used to set the current page. If $dataname is empty or returns an invalid page number, the control uses the page number in $currentpage.

Page Panes in Complex grids

You can use a page pane in a complex grid. You can set the value of $currentpage by assigning a column in the complex grid list to $dataname of the page pane. Therefore each row in the complex grid could display a different page in the page pane control.

In this case, controls within the page pane control will also get their data from the complex grid control, if their $dataname refers to a column in the list used to build the complex grid.

Group Boxes

A Group box component is not available in the JavaScript client components, but you can create one “on the fly” using a new method called $makegroupbox() to change a Paged pane into something that simulates the behavior and appearance of a group box. The method PagePaneName.$makegroupbox(cLabel[,cFont,cFontSize,cTextColor]) must be executed on the client, and converts a Paged pane to a Group box with the specified label, as well as the optional CSS font, font size, and text color. This method can be called from $init in the remote form.

Animated Transitions

If enabled, the $animatetransitions property ensures that the transition between pages is animated when the current page is changed. The property cannot be changed at runtime (the same as $scrolltochangepage).

If used in conjunction with $scrolltochangepage, when the user stops scrolling, the pane will smoothly animate into position, rather than jumping instantly.

The animation time is set to 500ms, which should be fine for most purposes, but if you wish to change this, you can use JavaScript to change the Paged Pane control's (or its prototype's) ANIMATION_TIME property.

Page Styling

Page panes have a default CSS classname ‘omnis-pagedpane-page’. This allows you to apply CSS styling or behavior to each page of the paged pane control.

In addition, a CSS rule (-webkit-overflow-scrolling: touch;) enables momentum scrolling on iOS, i.e. for touch iOS devices, scrolling slows down before stopping.

Picture Control

The Picture control allows you to display an image in your form: you can display an image file in a folder, an image from a database, or an icon, depending on the combination of settings of $dataname, $mediatype and $iconid. If $mediatype is empty (and $iconid is zero), the $dataname of the Picture control is a URL to the image to be displayed, relative to your html page containing the JavaScript Client. If $mediatype is specified, then $dataname is the name of a binary instance variable containing the image data: in this case, $mediatype can be set to one of the standard image types, e.g. image/png, image/jpeg or image/gif. Alternatively, $iconid can be set to a URL referencing an image file in the ‘html/icons’ folder, overriding the $dataname and $mediatype properties. For backwards compatibility, the picture control can display an icon in an icon data file (Omnispic) or #ICONS by setting $iconid to a numeric icon ID.

There is an example app that uses the Picture control in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

Image Alignment and Scaling

The $picturealign property specifies where the picture will be positioned in the control and is a kPAL... constant. The $noscale property determines whether or not the images displayed in the control are scaled. The $keepaspectratio property determines whether or not the images displayed in the control keep their aspect ratio when scaled: if true, and $noscale is false, the aspect ratio of pictures is maintained when they are scaled.

The property $keepaspectratiomode controls how the image in the Picture control is scaled and positioned when $keepaspectratio is true and $noscale is false. The value of $keepaspectratiomode is a kKAR... constant with the possible values:

  1. kKARtopLeft
    The image is scaled to fit the control and anchored at the top-left corner. This is the default value (and maintains compatibility with existing libraries)

  2. kKARcenter
    The image is scaled to fit the control and centered, so background may be visible at the top and bottom or the left and right of the image, depending on the shape of the image control and the orientation of the image

  3. kKARfill
    The image is scaled to fill the control and centered, so no margin (background) is shown. This can result in the image being cropped at the top and bottom, or the left and right, depending on the shape of the image control and the orientation of the image

Example

In the Webshop sample app, the product images are shown in a Picture control embedded in the Complex grid control on the main jsShop remote form. In this case, $mediatype is set to JPG and the $dataname of the control is iProductList.product_picture which holds the image data for each product.

Pie Chart Control

See the description for the Bar and Pie Chart Control section for information about defining the list variable structure for pie and bar charts, plus chart events, as well as information about setting the bar/segment colors for charts, including the use of theme colors and the $colorlist runtime property.

Each value (segment) in a Pie chart is shown as a percentage of the total of all the values in your list, that is, the size of each segment (angle in degrees) is calculated as the proportion of the individual value when compared to the total of all values in the list.

There is an example app in the Samples section in the Hub in the Studio Browser showing you how to set up a Pie chart, and the same app is available in the JavaScript Component Gallery.

image80

Main and Legend Titles

There are a number of properties in the Pie Chart component to allow you to add a legend title and have some control over the appearance and positioning of the legend.

$maintitle The legend title
$showlegendnames If true the legend shows the value names ( column 2 ) and not values ( column 1 ). The list data structure is same as bar chart
$legendcolumns The number of columns the legend is split into
$legendpos Changes the position of the legend: can be above, below, left or right of the pie
$flyout Enables the pie segments to move or “fly out” when the end user’s mouse hovers over the segment (kTrue by default)

image81

Two positioning constants are available for the $legendpos property (which in practice are only appropriate for mobile devices), whereby as the device is rotated and the screen orientation changes, the legend is repositioned automatically either “before” (left or above) the pie or “after” (right or below) the pie. The constant values are:

kJSPieLegendAutoBefore the legend is placed before the pie chart, either above or to the left of the chart
kJSPieLegendAutoAfter the legend is placed after the pie chart, either below or to the right of the chart

The Popup menu is a menu that pops up when the user clicks on the header of the control, or when $hotwhenmouseover is true the menu will pop up when the end user’s pointer hovers over the control. The contents of the popup menu can be:

  1. a list variable specified in $::listname

  2. a remote menu class specified in the $::menuname property, or

When specifying one of these properties, the other property must be empty; the properties are on the Data tab in the Property Manager.

There are two example apps that use the Popup menu in the Samples section in the Hub in the Studio Browser: the first is named JS Droplist, Combo, Popup and uses a popup built from the list; the second uses a Remote menu to display a popup menu. The same apps are available in the JavaScript Component Gallery; the following screen shows the ‘red night’ JS Theme in use.

image82

When using a list variable to populate a Popup menu, the data in the column specified in $coltext is used for the menu options. The $colenabled property is the column name for the menu line enabled state, and $colcommandid is the column name holding the menu line command id.

You can add an icon to the popup menu by setting $iconid to the ID of an icon in an icon file or #ICONS. You can place the icon before or after the menu title by setting $textbeforeicon.

The menu will normally popup when the user clicks on the control, but you can make the menu popup when the end user’s pointer passes over the control (it is “hot”) by setting $hotwhenmouseover to kTrue.

You can control the position of the popup by setting $menupos to one of the constants: kJSPopMenuPosBottom, kJSPopMenuPosRight, or kJSPopMenuPosTop.

When the menu is clicked the evClick event is triggered with the selected line reported in pLinenumber. You can use the following $event method to trap the line number:

On evClick
  If pLineNumber>0 ## a line was selected
    ## Do something
  End If

You can use an HTML <select> tag for the user interface by setting $usehtmlselect to kTrue.

The $menulineheight remote form property allows you to set the line height for all the menus in a remote form, including Popup menus and any Context menus for the form, as well as menus belonging to Tab strip and Splitbutton controls.

For pre-Studio 10.2 converted applications, the value of $menulineheight will be zero, meaning the font size will determine the line height, as previous versions. For new applications, this will be a touch-friendly value to give enough space for each menu option.

Progress Bar Control

The Progress Bar control lets you display a progress bar in your remote form, to show the progress of some process in your application. The current value of the progress bar is reported in the $::value property which is a value between 0 and the value of $max inclusive. The color of the bar representing the completed amount can be set in $progresscolor, which only applies when the standard HTML5 progress control is not available. The following screen is when $usesystemappearance is kTrue on Windows:

image83

The $sendcarryon property provides a mechanism to send an evCarryOn event to the progress control. To generate an evCarryOn event, assign kTrue to $sendcarryon. The event processing code for evCarryOn can assign $sendcarryon to kTrue again, to generate the next evCarryOn.

You can add a Cancel button to your form to allow the end user to break a long process, but the Cancel button itself must be named in the $alwaysenabledobject remote form property so it remains enabled during the long process.

System Appearance

When set to true (the default), the $usesystemappearance forces the progress control to use the <progress> HTML5 element (if it’s supported by the browser). If $usesystemappearance is set to false, the progress control uses two <div> elements, and the following additional properties apply: $secondarycolor sets the color of the stripes of the progress bar, and $progressanimation (true by default) animates the progress bar. The following progress bar has $usesystemappearance set to false (and using the ‘red night’ JS Theme):

image84

Example

The following example assumes the progress control has been added to a remote form and a button is used to initiate some process and send a carryon event to the progress itself; note the ‘lockui’ client command is used to stop any clicks on the UI once the progress is initiated (except for the Cancel button). The initial values for $::value and $::max of the progress control are 0 and 100 respectively. The following code could be behind a button:

On evClick
  Do $cinst.$clientcommand("lockui",row(kTrue))
  Calculate iCancelled as kFalse
  Calculate iValue as 1
  Do $cinst.$objs.ProgressBar.$sendcarryon.$assign(kTrue)

The evCarryOn event is sent to the progress bar which has the following event method:

On evCarryOn
  If not(iCancelled)
    Calculate iValue as iValue+5
    Do $cinst.$objs.ProgressBar.$::value.$assign(iValue)
    If iValue<100
      Do $cinst.$objs.ProgressBar.$sendcarryon.$assign(kTrue)
    Else
      Do $cinst.$clientcommand("lockui",row()) ## unlock ui
    End If
  End If

This example is in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

RadioGroup Control

A Radio Group presents a number of mutually exclusive buttons that can be either on or off: selecting one of the radio buttons deselects all other buttons in that group. The variable you assign to a radio group should be numeric (e.g. Integer). Its value is within the range $minvalue and $maxvalue inclusive and directly corresponds to which button in the group is selected, that is, the first button selects the first value in the range, the second button the second value, and so on. The labels for the buttons are assigned in $text which is a comma-separated list (e.g. All,Female,Male). The Radio group has the following properties:

Property Description
$dataname a numeric variable
$::horizontal If true, the radio column order is horizontal
$columncount The number of columns shown for the radio group
$minvalue The minimum value for the radio group
$maxvalue The maximum value for the radio group
$text Comma-separated list of labels assigned to the buttons
$radiobuttoncolor The color for the Radio group control

When a button in the group is clicked the evClick event is reported with pNewValue containing the value of the selected button.

Note that the Check box example app in the Samples section in the Hub in the Studio Browser also uses a Radiogroup to select Gender, and the same app is available in the JavaScript Component Gallery; the following screen shows the ‘health’ JS Theme in use.

image85

Example

The Webshop app uses a Radiogroup control to allow the end user to select a group or category of products to be shown in the main product list. (To examine this control and its properties and methods, open the webshop library and the jsShop remote form.) The $minvalue and $maxvalue of the radiogroup are set to 0 and 8, respectively (although the groups are generated dynamically in the form), and the numeric variable iRadioGroup with an initial value of 1 is assigned to $dataname. When the form is opened, the $construct() method behind the radiogroup calls a $build method.

# radiogroup control is called ‘filter’ containing
# $construct method which is run when the form opens
Do iGroupList.$definefromsqlclass($tables.T_qGroups)
Do $cfield.$build()

The $build method generates a list of product groups from the database, which is then concatenated into a single comma-separated list and assigned to the $text property of the radiogroup.

# $build method behind the radiogroup
Do iGroupList.$selectdistinct()
Do iGroupList.$fetch(kFetchAll)
For iGroupList.$line from 1 to iGroupList.$linecount() step 1 ## loop through the list
  Calculate text as con(   text,mid($prefs.$separators,3,1),iGroupList.product_group## uses the localized separator (possibly semicolon)
End For
Calculate text as mid(text,2,len(text))
Do $cfield.$minvalue.$assign(1)
Do $cfield.$maxvalue.$assign(iGroupList.$linecount())
# $maxvalue of radiogroup is set to the number of groups in list
Do $cfield.$text.$assign(text)

When the form is opened the main product list is built using a method behind the product list itself (also called $build) and the list initially contains the Appetizers only. A group of radio buttons is created, each item representing a different group or category of food or drink; the initial value of the radiogroup is set to 1 selecting the first item in the group.

image86

When the end user clicks on the radiogroup, to select another product type, the click is detected in the $event method in the radiogroup control, the number of the radio button clicked is passed in pNewVal, and the product list is rebuilt based on the selected product group; note a Where clause is created based on the selected group and sent to the $build method behind the main productList control.

# $event method for Radiogroup
On evClick
  Calculate whereClause as con(
    'WHERE product_group =
    ',kSq,iGroupList.[pNewVal].product_group,kSq)
  Do $cinst.$objs.productList.$build(whereClause)

Rich Text Editor Control

The Rich Text Editor control (jsrich) can be used instead of a regular Edit or Multi-line edit field, which adds the ability for end users to edit the text using a text editor UI and to apply “rich” formatting such as bold, italic, and simple bullets. There is an example app showing how you can use the Rich text editor in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image87

The Rich text editor control uses the Quill open source text editor which relies on modern browser technologies and, as such, some older mobile OS's (iOS < 6.0 & Android < 4.0) may have compatibility issues. For Studio 8.0.2 the control is based on Quill 1.0, which brings several new features and bug fixes, including Code Blocks with syntax highlighting, Undo/redo shortcut keys, Sub/Superscript, In/Outdent, Block Quotes, Image uploads, content tips, and so on.

The text data for the control is stored in the instance variable assigned to $dataname: see below for properties to format the data content. You can allow text editing in the control by setting $showcontrols to kTrue where upon the text content in the field will become editable: on mobile devices this places the cursor in the field and opens the soft keypad ready for typing. The text editing controls in the field will appear at the top of the control and will allow the end user to format the text, including bold, italic, underline, and so on. The text data in the control is HTML markup and can include formatted text such as ordered (numbered) and unordered lists (bullets). End users can also insert images using the Paste option.

Dynamically Loaded Resources

The control dynamically loads the necessary JavaScript & CSS files when it is used. There are several files in the Studio tree to support the text editor:

html/scripts/
    quill.js
    quill-legacy.js
    highlight.pack.js
html/css/
    quill.snow.css
    quill-legacy.snow.css
    highlight-theme.css

When deploying to a web server, you must make sure to also copy these files over. Quill 1.0 only supports IE 11+. When running on earlier IE versions, the control will fall back to Quill 0.2 - this is what the ‘-legacy’ files above are used for.

Properties

Together with the standard component properties, the Rich Text Editor Control has the following properties:

Property Description
$dataname The name of an instance variable to store the HTML formatted text, or a column in an instance row variable
$dataformat Controls the format of the document data stored in $dataname for the control, a constant: kJSRichTextDataFormatJSON, kJSRichTextDataFormatHTML, or kJSRichTextDataFormatPlain
$showcontrols Set this to kTrue to switch the control to edit mode and to display text editing toolbar controls
$plaintextname Specifies the name of a variable that automatically receives the plain text equivalent of the data stored in the variable named in $dataname (just the plain text without any HTML formatting); this property is optional
$contenttip Allows you to specify some text to be displayed in the editor when it has no content
$removedtoolbaritems A bitmask of kJSRichText… values, allowing you to specify toolbar items to hide in your Rich Text Editor instance

Setting Default Text Properties

You can specify the default value of the font, size and text color shown in the editor’s controls by assigning values to the component’s text properties, as follows:

  1. $font
    maps directly to the editor’s font droplist and will set the default value accordingly.

  2. $textcolor
    will attempt to set the default text color to one of the colors in the toolbar’s color palette. If there is not an exact match, it will add the color as another tile in the palette.

  3. $fontsize
    will set the default font size to the closest match. Set to 13 for the ‘Normal’ font size as default.

Data Format

The $dataformat property controls the format of the document data stored in $dataname for the control. It can be one of the following constants:

  1. kJSRichTextDataFormatJSON
    The document data will be stored in the $dataname as JSON, as a Quill 'Delta' object. This is the best option for restoring the data later, as it preserves all formatting.
    When setting the data, you can assign JSON (Delta), HTML or plain text: this should be detected and converted as necessary.

  2. kJSRichTextDataFormatHTML
    The document data will be stored in the $dataname as HTML. This may lose some minor formatting. This format is suitable to use if you are going to use the data elsewhere in your code, but not for storing the document data and restoring into the Rich Text Editor.
    When setting the data, you can assign HTML only.

  3. kJSRichTextDataFormatPlain
    The document data will be stored in the $dataname as Plain text. This will lose most formatting.
    When setting the data, you can assign Plain Text only.

The $dataformat property can be changed in your code to populate the $dataname with data of the specified format. Note that if you do this in a server-executed method, the $dataname won't be updated until the client next contacts the server.

Appending Data

The $appenddata(cData, bNewLine) and $prependdata(cData, bNewLine) methods allow you to append or prepend data to the content in $dataname. If you pass bNewLine as kTrue, the data will be added on a separate line. These methods can only be executed on the client.

The data format of the passed data depends on the value of the $dataformat property. If $dataformat is JSON, the data could be sent as plain text, HTML or JSON (a Quill Delta object).

Code Blocks

The updated Rich Text Editor allows you to insert Code Blocks. These allow you to insert syntax-highlighted code. The syntax highlighting is achieved using highlight.js and by default includes highlight support for several popular languages.

image88

If the language(s) you require is/are not supported out of the box, you can create a ‘Custom Package’ on the highlight.js download page, and replace the highlight.pack.js in your tree/web server with the one you download.

Similarly, if you want to change the code block’s appearance, you can take any of the theme css files from your highlight.js download, rename it highlight-theme.css and replace the supplied file with your own.

Drag and Drop

End users can drag data from a Rich Text Editor and drop it elsewhere in the form, or users can drag data and drop it into the Rich Text Editor; in the latter case the evDrop event is generated in the control. If some text is selected and dragged out of the Rich Text Editor, then only the selected text is dropped at the cursor position.

End users can also drag external content and drop it onto the Rich Text Editor, e.g. text or an image from another browser pane or a different application, but in this special case the evDrop event is not generated in the control.

Localizing the Rich Text Editor

There are various strings in the Rich Text Edit control that can be localized in the string table for the remote form containing the control. You must use the following string table ids to replace the default text for the controls in the text editor.

Tooltips for buttons

rt_backgroundcolor rt_insertorderedlist rt_print
rt_blockquote rt_insertunorderedlist rt_removeformat
rt_bold rt_italic rt_strikethrough
rt_clearformat rt_justifycenter rt_subscript
rt_codeblock rt_justifyfull rt_superscript
rt_decrease_indent rt_justifyleft rt_textalign
rt_image rt_justifyright rt_textcolor
rt_increase_indent rt_link rt_underline
rt_indent rt_outdent rt_video

Text displayed on controls

rt_fontsize rt_fontfamily rt_sansserif
rt_serif rt_monospace

Printing the Text Contents

End users can print the contents of the editor control using a print button on the editor's toolbar, which when clicked opens a window for printing. The $printcontents lets you print the contents.

  1. $printcontents(cTitle)
    Opens a new window to print the editor's current contents. cTitle is the title of the document to print.

You enable the new print button by setting $removedtoolbaritems to kJSRichTextPrint. In addition, the Omnis string table item with ID: rt_print lets you edit the tooltip of the button.

Segmented Control

The Segmented Control displays a number of segments or buttons that you can use for navigation (like a tab bar or toolbar) within your web or mobile app, or you can use it with only two segments to create a switch. You can assign an icon and text to each segment and you can detect which segment has been clicked in the $event method of the control.

The Segmented control provides a series of ‘segments’ or buttons arranged horizontally, each of which can contain an icon and/or text. You can optionally show the selected segment in a highlighted state, by setting $showselectedsegment to kTrue, which is useful if you are using the segmented control as a navigation control. You can further show the current segment by the setting the color of the current segment indicator in the $focusedsegmentindicatorcolor property.

You can use the segmented control as a toolbar, docking it to the top or bottom of its container by setting its $edgefloat property to one of the kEFposn… values, such as kEFposnMenuBar or kEFposnTopToolBar.

There is an example app in the Samples section in the Hub in the Studio Browser, showing how you can use the Segmented control as a toolbar and switch (the second image below); the same app is available in the JavaScript Component Gallery. The following images show the ‘professional’ JS Theme in use.

image89

image90

Properties

The Segmented control has the following properties, together with the standard properties for a JavaScript control.

Property Description
$currentsegment The number (1 - $segmentcount) of the current segment (this specifies the segment affected by segment specific properties).
This can also be changed in a design view by clicking on a segment of the design component. The current segment will be shown with a red outline while the component is selected.
$hidedisabledsegments Hides any disabled segments
$movesegment Lets you move a segment (in design mode only)
$segmentcount The number of segments (must be at least one).
$segmentenabled If true, the segment is enabled and generates a click event when the user presses it.
$segmenticonid The icon displayed on the current segment. Set to 0 for no icon;
$segmenttext The text displayed on the current segment.
$displaystyle A kJSSegmentStyle… controls whether the text is above or below the icon
$showselectedsegment If true, the currently selected segment will be shown in a highlighted state. See $selectedcolor & $selectedtextcolor. If false, the highlighted appearance will still be shown while segments are being clicked, to give the user feedback of the click.
$focusedsegmentindicatorcolor Specifies the color of the current segment indicator
$segmentbordercolor The colour that applies to borders / dividers of segments
$segmentborderradius Single value border radius that applies to segments. If $segmentspacing is zero, this applies to only the outer edges of the outer segments. Otherwise, it applies to all segments
$segmenteffect Determines whether borders / dividers are applied to segments, either kBorderNone or kBorderPlain
$segmentenabled Set to kFalse to disable a segment
$segmentspacing the space between the segments in pixels. The behavior can be affected by $segmentwidth (see below). If zero, dividers are drawn between segments. Otherwise, borders are drawn around the segments
$segmentwidth The width applied to all the segments in pixels. By default, this is zero, in which case the width of the segments is determined by the total width of the control and $segmentspacing. If this value is small enough, the segments will be centred in the control
$selectedsegment The number (0 - $segmentcount) of the currently selected segment. If 0 no segment will be selected.
$selectedcolor The background color of the currently selected segment, or of the segment currently being clicked.
$selectedtextcolor The text color of the currently selected segment, or of the segment currently being clicked.
$bordercolor Controls the color of the segment divider lines, as well as the control’s border.
$backcolor Controls the background color of the segments.

Segment size and spacing

If $segmentwidth and $segmentspacing are set so that the segments extend beyond the width of the control, the overflowing content will be scrollable. However, if $segmentwidth is zero (the default), the segments will always fit inside the container.

In the extreme case where $segmentspacing is very high, as long as $segmentwidth is zero, the spacing will be limited to prevent the segments becoming too small or the content overflowing.

Hiding Disabled Segments

You can set $segmentenabled for a segment to false to disable it. The new property $hidedisabledsegments allows you to hide any segments that have been disabled.

Moving Segments in Design mode

The $movesegment property lets you move a segment: you need to set it to a number corresponding to the new position (the property works in the same way as the Data Grid's $movecolumn property).

Events

An evClick event is generated when one of the segments is clicked and the pClickedSegment event parameter returns the number of the segment clicked.

Slider Control

The Slider control provides a graphical slider component with an optional custom thumb icon that the user can drag to control its numeric setting, which can be used to set the value of another component in your form, such as a volume control. As an alternative, you can use the Native Slider to control variable numeric values.

There is an example app in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image91

The current value of the slider is reported in the property $val according to where the slider is positioned. You can specify the range for the slider in the $min and $max properties, while $step is the size of each step the slider takes between the min and max values. The slider also has these properties:

Property Description
$vertical If true, the slider is a vertical slider
$sliderhorziconid The id of the icon to use for a horizontal slider handle
$sliderverticonid The id of the icon to use for a vertical slider handle
$horzmargin The horizontal drawing margin
$vertmargin The vertical drawing margin

The Slider reports three events: evStartSlider (when the control is starting to track), evEndSlider (when the control has finished tracking), and evNewValue (when the value has changed). You can detect these events in the $event method for the component. These events all pass the current value of the Slider in the pSliderValue parameter. As the user drags the Slider thumb the evNewValue event is triggered and pSliderValue is sent to the $event method for the Slider.

To use the values of the slider in your remote form you can trap the slider events in the $event method of the slider control (which must execute on the client), and transfer the current values to instance variables in your form, as follows:

On evStartSlider
  Calculate iStartValue as pSliderValue
On evEndSlider
  Calculate iEndValue as pSliderValue
On evNewValue
  Calculate iNewValue as pSliderValue

Split Button Control

The Split Button control combines a standard button with a dropdown menu, allowing you to provide multiple, alternate actions grouped together in a single button control. The Split Button is like the Send button in gmail as it provides two options in one control: a default Send option on the button and a Schedule send option via the menu.

The component is available for JavaScript remote forms as well as window classes, but there are some additional properties for the JavaScript control (the window version is an external component that must be loaded via the Component Store).

The menu for the control is specified in the $menuname property and must be a Remote Menu class for the JavaScript component, or a menu class for the Window class control.

The following example Split button has a Print option and a printer icon on the main button part, and it has options for printing to a Preview, PDF or File specified in a Remote menu class, specified in the $menuname property of the button control. In this case, a single click on the button would activate the Print to printer option, while clicking on the down arrow provides the other options (the images uses the ‘professional’ JS Theme).

image92

Properties

The following properties are available for both the JS Remote form and Window class controls.

Property Description
$hotbackcolor The background color of the control when hovered
$activebackcolor The background color of the control while pressed; active color is generated automatically if $activebackcolor is kColorDefault
$buttonborderradius The radius in pixels of the corners
$borderwidth The width (0-7) of the edges drawn as the border of the control
$arrowside The position of the dropdown button on the control
$textbeforeicon If true, and the control has both text and an icon, the text is drawn before the icon
$vertical If true, the text and icon are arranged vertically
$menuname The name of the menu class, a Remote Menu class for the JS control, or a Menu class for the Window control

The following properties are available for the JavaScript control only.

Property Description
$menubackcolor The background color of menu lines
$menuhotbackcolor The background color of menu lines when hovered
$menutextcolor The text color of menu lines
$menuhottextcolor The text color of menu lines when hovered
$menudisabledtextcolor The text color of disabled menu lines

Events

An evClick event is triggered when the main button area is pressed. In addition, for the JavaScript client only, the evOpenContextMenu and evExecuteContextMenu events are generated when the menu is pressed, and in this case, the pControlMenu event parameter is kTrue (when a Context menu is opened pControlMenu will be kFalse), and the pCommandID parameter contains the command ID of the selected menu line, e.g. 1002 for line 2.

Example

There is an example app in the Hub in the Studio Browser to show how you can use a JS Split button, and the same app is available in the JavaScript Component Gallery. The example library contains a JS remote form and remote menu class (plus a window class and menu to show the thick client split button). The following image shows the JS Split button example using the ‘default’ theme.

image93

The $event method behind the split button control traps the evClick and evCCC events corresponding to clicks on the button or the menu part of the control.

On evClick
  Do method buttonClicked
On evExecuteContextMenu
  Do method menuClicked (pCommandID)
# buttonClicked method
Do $cinst.$showmessage('Button Clicked!','Split Button')
Do $cinst.$showmessage(con('Remote Menu Clicked!//pCommandID=',pMenuLineCommandID),'Split Button')

The pCommandID parameter is passed to the menuClicked method which contains the command ID for the selected menu line ($commandid is a menu line property which stores IDs 1001, 1002, etc for successive menu lines).

Subform

The Subform control allows you to place another remote form class inside the main remote form; the concept of the subform is similar to embedding an iframe into an HTML page where you can embed another form or inside the main page. You could, for example, create a single “main” form and a number of other remote forms loaded at runtime into a subform control, to create a powerful and interactive web application with many subforms or frames. The JavaScript Component Gallery app on the Omnis website, for example, is implemented using a main gallery form and each example component is loaded in a separate form as a subform.

When you have placed the subform control on your remote form, you specify the initial remote form to appear in the subform in the $classname property. Alternatively, you can switch subforms at runtime by assigning a new remote form name to $classname to switch the current form displayed in the subform control, as follows:

# oSub is the name of the Subform control on the main Remote form
Calculate $cinst.$objs.oSub.$classname as NewFormName

Note: you can also create a group of subforms dynamically in your code using a Subform Set, which is described in the JavaScript Remote Forms chapter.

$dataname and Subforms

If the remote form class inside the subform field has only one field, you can override its dataname using the $dataname property for the subform field. For example, your subform class may contain a single headed list field that takes its data from a specific list variable. However, you can change the list assigned to the headed list by setting the subform field’s $dataname property to the name of another list. You could do this in the $construct() method of the subform field.

$construct and Subforms

Opening a remote form containing a subform field or any number of subform objects creates an instance of each form, which belong to the same task as the parent remote form instance. Omnis calls the $construct() methods of all the subform classes first in tabbing order, then the $construct() method of the parent form instance. The reverse happens on closing the parent form, with the subforms being destructed after the parent form instance.

You can send parameters to the subform’s $construct() method by including a comma-separated list of parameter values in the $parameters property when you create the subform field. The $parameters property can only be assigned in the remote form editor, and it has no effect at runtime. If you attempt to set it at runtime in your code, the error "$parameters cannot be assigned at runtime" will be displayed on the client.

$init and Subforms

When changing subform instances you can send parameters to the new target subform instance. To do this you can assign a comma-separated list of values to the $userinfo property of a subform and this can be parsed and sent as parameters to the client-executed $init method in the new subform instance. Each token in the comma-separated list will be a separate parameter, and can be a quoted string (including spaces and commas) or a numeric value. For example, when changing subform:

Calculate $cinst.$objs.subform1.$userinfo as "'Davy Jones',123,0"
Calculate $cinst.$objs.subform1.$classname as "jsSubform1"

In the $init method in the new subform jsSubform1, three parameters will be populated: p1: "Davy Jones", p2: 123, p3: 0.

The $loadfinished client-executed method allows you to check when all subforms of a form have been loaded. The method is called after all the subforms that belong to the parent remote form instance have finished loading and their $init methods have been called.

Multiple Subforms and Caching

The $multipleclasses property tells Omnis to keep a set of remote form instances open for use in the subform object, rather than constructing a new instance each time the class is changed. When you assign a new remote form name to $classname at runtime, the new remote form is downloaded to the client and displayed in the client’s browser. If the $multipleclasses property is enabled, the previous remote form is cached and hidden on the client, otherwise the remote form instance is destroyed. If any previous remote forms have been cached in this way using $multipleclasses, you can switch back to them instantaneously, otherwise they have to be reloaded each time you assign to $classname of the subform object.

Referencing Subform Instances

A subform control has the $subinst property (object) which is the instance contained within the subform control. You can use this property to get a reference to the instance in a subform object and therefore change properties within the instance. If the subform property $multipleclasses is set to kTrue, you must use $subinst(cClassName) to get a reference for the appropriate instance. For example, where a subform control has a single subform class the following code will return a reference to the form instance in the subform:

Set reference item to $cinst.$objs.subfrm.$subinst
Do item.$setcolor(kRed)

or when you may have assigned multiple classes to the subform control ($multipleclasses is set to kTrue):

Set reference item to $cinst.$objs.subfrm.$subinst("classname")
Do item.$setcolor(kRed)

Note that the item returned will be null if the instance does not exist.

Subform Container Notation

You can use $cinst.$container to obtain the instance containing a subform instance, where in the current context $cinst is a subform. The $container property returns the object containing the referenced object. This notation will work in server methods (for all clients) , and client-side methods for the JavaScript Client only. For examples:

Set reference item to $cinst.$container
Do item.$getList() Returns iList
# and
Calculate $cinst.$container().iSelected as iList.C1

Example

The Holidays sample app (in the Applets section of the Hub in the Studio Browser) uses a subform to display either the User or Admin form. When the main jsHolidays remote form is loaded, its $construct() method calls a class method to setup the initial subform to be shown which, in this case, is the User form. In addition, there are buttons on the main Holidays form to allow the end user to switch forms; for example, the code behind the User button is:

# $event method for User button on jsHolidays
On evClick
  Do method setSubForm (kUserForm)
  Calculate iAdminBtnState as kTrue
  Calculate iUserBtnState as kFalse
  Do $cinst.$objs.adminBtn.$enabled.$assign(kTrue)
  Do $cobj.$enabled.$assign(kFalse)

The setSubForm method has the following code to switch forms:

If pOption=kAdminForm ## test if Admin or User
  Do $cinst.$objs.subForm.$classname.$assign("jsAdminForm")
Else
  Do $cinst.$objs.subForm.$classname.$assign("jsUserForm")
End If

There are further subform examples in the Samples section in the Hub in the Studio Browser, and the same apps are available in the JS Component gallery on the Omnis website at: www.omnis.net.

Switch Control

The Switch control is like a check box insofar as it represents an On / Off value (1 or zero), but it can display alternative images for the On or Off states. When the end user clicks the switch the value of the control’s variable alternates between 1 and zero, so the control is useful for representing preferences which can be Enabled or Disabled.

The variable you specify in the $dataname property should be a Number or Boolean variable. The $switchon and $switchoff properties let you specify an icon ID for the images to be used when the switch is either on or off. The properties $justifyhoriz and $justifyvert allow you to justify the contents in the control horizontally or vertically.

The $switchcolor property specifies the color for the Switch control when it is switched on (set to value 1), assuming no on/off icons have been set.

You can use the Native Switch component to display on/off values.

Example

There is an example library showing the Switch control with a range of different ON/ OFF images in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

image94

Tab Control

The Tab Control or ‘Tab bar’ allows the end user to select a tab which can correspond to a specific option in your application; the tab control can also be linked to a Paged Pane by setting $linkedobject. The $tabcount property specifies the number of tabs; it can be set to zero in design mode, and the number of tabs assigned at runtime using the notation. The $currenttab property specifies which tab is highlighted and its value will change as the end user selects a tab: assigning a new value to this property at runtime will change the highlighted tab; the following screen shows the Tab control using the ‘health’ JS Theme.

image95

In design mode, you can specify the properties for a particular tab by making it the “selected tab” in the $selectedtab property, under the “Tab” tab in the Property Manager. The text for a tab is specified in the $tabtext property: you can add a line break by inserting //. The size of the tab (i.e. the width for horizontal tabs) is determined by the width of the text on the tab. However, you can set $fixedtabsize to kTrue to fix the size of the tabs, and set $maxfixedtabsize to set the tab width or height. You can hide or show a tab using the $tabvisible property, and you can disable or enable a tab using $tabenabled; for example, you can set these properties for individual tabs to kFalse in design mode and at runtime set these properties to kTrue to show and enable the tabs.

There are many properties under the Appearance tab in the Property Manager to control the general appearance of the Tab Control and the tabs themselves. The tabs have angular corners by default, but you can round the corners by setting $tabborderradius. You can create a vertical aligned set of tabs by setting the $side property: you can orient the tabs on the left or right. The $tabsjst property determines the position of the tabs within the control. The $currenttabindicatorcolor property specifies the color of the current tab indicator.

The $tabbackstyle property controls the style or color of the background of the tabs and is a kJSTabsBackStyle… constant: kJSTabsBackStyleDefault shows a default appearance for the current platform, kJSTabsBackStyleColor shows a flat background color specified in $tabbackcolor, and kJSTabsBackStyleImage displays an image specified in $tabbackiconid.

There is an example app called ‘Tab bar’ in the Samples section in the Hub in the Studio Browser showing how you can link a tab control to a paged pane, as well as using a tab control to display a menu; the same app is available in the JavaScript Component Gallery.

Tab Icons

By default, the tabs display text only, but you can add an icon to the tabs by selecting the position of the text and icon by setting $tablayout. For example, you can set $tablayout to kJSTabsLayoutIconLeft to add an icon to the left of the tab text, and then set $tabiconsize to set the width of the space allowed for the icons.

Reordering Tabs

In design mode, you can move or re-order the tabs in the control by entering a number into the $movetab property; in effect, the number of the selected tab will become the number you entered, and the other tabs are shuffled along. This is useful if you have setup multiple tabs and need to move a tab easily without having to redefine each tab again.

Linking Tabs to Panes

The Tab Control can be linked to a Paged Pane by setting $linkedobject to the name of a Paged Pane control, so when different tabs are clicked, the pane in the linked Paged Pane is changed automatically. Assigning a new value to the $currenttab tab property of the Tab control at runtime will also change the current pane in the linked Paged Pane control.

The base edge of the tab control does not normally have a border, and when the tabs are linked to a paged pane the tab control updates the paged pane border so that there is the appearance of a gap below the current tab. If you want to add a border under the tabs you need to set $baseedgewidth to 1 or more.

Tab Menus

The Tab Control can also be linked to a Remote Menu class; clicking on a tab will trigger the corresponding line in the menu. To implement this, the $trackmenus property must be kTrue, and the $tabmenu property set to the name of a remote menu class for the selected tab (the tab with number $selectedtab). If assigned at runtime, the menu instance must already be present on the client (via a $tabmenu or $contextmenu property in the class data when the form was loaded).

You can control the color of the menu lines and text using the $tabmenu… properties under the Appearance and Text tabs in the Property Manager, or in your code for the control.

Events

When the end user clicks on a tab the value of $currenttab will change and an evTabSelected event is triggered, with the new tab number reported in pTabNumber. This event needs to be enabled in the $events property for the control to be reported.

The $canclickselectedtab property can be enabled so a click on the selected tab generates evTabSelected (provided that evTabSelected is specified in $events). This allows you to detect a click on the currently selected tab (which was not possible in previous versions).

Example

The Contacts sample app users a Tab control in the main jsContacts remote form to allow the end user to switch from viewing a list of contacts to a form showing details of individual contacts. In this case, the Tab control is linked to a page pane which displays the contact list or contact details view. The $linkedobject property of the contactTabStrip control is set to ‘pagePane’ (the name of the page pane) and the $tabtext for each tab is defined as ‘Contacts’ and ‘Details’ respectively. In addition, the evTabSelected event is enabled in the $events property of the Tab control. The code for the Tab control $event method is:

# $event method for Tab control
On evTabSelected
  If pTabNumber=2
    Do method loadRecord (iContactList.$line)
    Do $cinst.$objs.saveBtn.$enabled.$assign(kTrue)
  Else If pTabNumber=1
    Calculate iNewContact as kFalse
    Do $cinst.$objs.saveBtn.$enabled.$assign(kFalse)
  End If

If the Details tab is clicked, the second tab, the second pane in the page pane is displayed and the details for the currently selected contact are loaded using the loadRecord class method.

Timer Control

The Timer is an invisible component that triggers an evTimer event after a specified time while $running is set to kTrue. You can specify a $timervalue, which is interpreted as an interval in seconds or milliseconds according to $useseconds, which should be set to kTrue for seconds or kFalse for milliseconds (the default).

There is an example app in the Samples section in the Hub in the Studio Browser, and the same app is available in the JavaScript Component Gallery.

Example

In the Webshop sample app (available under the Applets section in the Hub), it would be possible to use a Timer control to rebuild the Orders list periodically; in this case, you could use the Timer object to run a method at a given interval to rebuild the Orders list in the jsShopOwner remote form. In reality, the Orders list is rebuilt every time a new order is placed, but a Timer object could be used to regulate the rebuilding of the Orders list.

To implement a Timer in the Webshop app, you would need to enable the evTimer event in the $events property of the Timer control. The $useseconds property is set to kTrue and $timervalue is set to 2 (to give an interval of 2 seconds). The $construct() method of the Orders list (a data grid) includes a line of code to start the timer:

# $construct method for Orders list/data grid
Do iOrderList.$definefromsqlclass($tables.T_qOrders)
Do $cinst.$objs.tim.$running.$assign(kTrue## possible using a timer object
Do $cfield.$build()

The $build() method behind the Orders list builds the list when the form is opened, but when used with the Timer object it can be used to rebuild the list as well. The $event method for the Timer object is run every 2 seconds, and has the following code:

On evTimer
  Do $cinst.$objs.dat.$build()

Timer Worker Object

The timer component contains a Worker Object. This has the advantage over the other timer objects in that it can be used with remote tasks in the multi-threaded server. It has the following properties:

  1. $timervalue and $useseconds
    These work as for the current timer objects

  2. $repeat
    If true, then after calling $starttimer() the timer will fire until $stoptimer() is called or the object is deleted;otherwise the timer will fire at most once for each call to $starttimer().A change to $repeat is ignored until the timer is started again

The timer component supports the methods $starttimer() and $stoptimer(). Just like $repeat, changes to $useseconds or $timervalue do not take effect if the timer is already running.

When the timer fires (or the timer is cancelled), Omnis calls the $completed or $cancelled method in the object, just like other worker objects. This occurs in the context of the task that owns the object, and interrupts any code running for that task (after a complete method command has executed).

Toolbar Control

The Toolbar Control allows you to add a series of buttons and an optional menu at the top of a remote form that the end user can click on or tap to perform an action. Each toolbar button can be assigned an icon and text, as well as a different action. When a button is clicked, the item number is reported to the event handling method allowing you to run the appropriate code.

The toolbar is displayed horizontally, by default, but can also be displayed vertically. You can use edgefloat properties to ‘stick’ the toolbar to the top or side of the remote form. It items do not fit on the toolbar they are added to an overflow menu automatically (shown by three vertical dots on the right of the toolbar), or items can be forced to appear on the overflow menu.

A toolbar can have a “side menu”, displayed on the left of the toolbar, by setting $sidemenu to true and adding a list variable name to $dataname containing the menu items. Items in the side menu can have a 'selected' state as well as a 'focused' state. Selecting a line in the side menu sets the current line in the list. The selected line will remain highlighted until another line is selected. When the side menu is opened, the selected line will get the focus.

Example

There is an example app in the Samples section in the Hub in the Studio Browser showing a Toolbar with overflow and a side menu; the same app is available in the JavaScript Component Gallery.

The example Toolbar has four items or buttons defined, each with an icon and text, the main title ‘Toolbar’ on the left, and an overflow menu on the right.

image96

Items can be forced to always appear in the overflow, regardless of the width of the main toolbar, shown on the right of the toolbar by the three vertical dots, and shown dropped here:

image97

As the browser window is resized, or the remote form (the app) is displayed on a mobile device, the main toolbar width will shrink, and the button items are added to the overflow menu automatically, as shown (note the icons are not displayed when the item is in the overflow menu):

image98

The following image shows the same Toolbar with the side menu added and in the dropped state:

image99

The following image shows the same Toolbar but using the Themed SVG icons instead of the PNG image icons, as well as the ‘lemonade’ JS Theme:

image100

Properties

The custom properties for the Toolbar control are described below. The ‘Item’ tab in the Property Manager contains item specific properties that apply to the $currentitem.

Property Description
$itemcount The number of toolbar items/buttons
$currentitem Item specific properties are assigned to the current item
$moveitem Allows you to move an item in design mode; the current item moves to the position specified by the number entered
$itemiconid The icon for the current item (item specific property); note $showitemicons needs to be enabled to display icons
$itemtext The text for current item (item specific property); note $showitemtext needs to be enabled to display text
$itemoverflow Force the item to be appear in the overflow menu (item specific property)
$itemenabled If kTrue (the default) the item is enabled (item specific property); if kFalse the item is greyed and cannot be selected with the pointer or keyboard; applies to items whether they are on the toolbar itself or the overflow menu
$sidemenu Add a side menu to the toolbar. The $dataname must be a list containing the menu data
$dataname Name of a list variable containing the menu data, to display a menu when $sidemenu is set to true
$verticaltoolbar Display the toolbar in a vertical orientation
$menudirection A kJSToolbarMenuDirection… constant which sets the direction the menu should open. Different values are available depending on the $verticaltoolbar property: Down or Up for horizontal toolbars, Right or Left for vertical toolbars
$toolbartitle The optional title to display on the toolbar; leave this blank for no title
$titlefontsize The font size applied to the toolbar title
$itemwidth The width of items on the toolbar; without a value items have a variable width and are forced to fit the length of the toolbar
$displaystyle A kJSToolbarStyle... constant determining the position of the icon text relative to the icon: either Above, Below, Left of, or Right of the icon
$showitemicons If true, any item with an $itemiconid will display an icon on the toolbar
$showitemtext If true, any item with $itemtext will display text on the toolbar; when true, $showtooltips is disabled
$showtooltips Show tooltips on toolbar items; $showitemtext must be set to false
$showdividers If true, dividers will be shown between toolbar items
$dividercolor The color of the dividers between items if $showdividers is true
$iconcolor The color of standard icons such as the hamburger icon
$sidemenucolor The background color of the side menu
$overflowcolor The background color of the overflow menu
$toolbaractivecolor The color of toolbar items when clicked
$toolbarhovercolor Hover color for toolbar items
$sidemenuhovercolor Hover color for side menu items
$overflowhovercolor Hover color for overflow items
$selecteditem The number of the selected item
$showselecteditem If true, the item will have its background color set to $selectedcolor and its text colour set to $selectedtextcolor.
$selectedcolor The background color of the selected item
$selectedtextcolor The text color of the selected item
$selectedlinecolor The color used for the background of the selected line in the side menu
$toolbarhovertextcolor Text color of toolbar items when hovered
$sidemenutextcolor Text color of side menu items
$sidemenuhovertextcolor Text color of side menu items when hovered
$overflowtextcolor Text color of overflow menu items
$overflowhovertextcolor Text color of overflow menu items when hovered

Clicking on a toolbar item will make that item selected, and $selecteditem is set to the selected item number. If $showselecteditem is true, the item will have its background color set to $selectedcolor and its text color set to $selectedtextcolor.

Disabling Items

The $itemenabled property allows you to disable specific items. When $itemenabled is set to kFalse for an item it is greyed and cannot be selected with the pointer or keyboard. This property applies to items whether they are on the toolbar itself or the overflow menu.

Events

The Toolbar reports two events: evClick reports the toolbar item that was clicked, with pClickedItem returning the item number; and evNavigationClick reports true if an item on the side menu was clicked, with the group number reported in pClickedMenuGroup (zero if the data is ungrouped) and the item number in pClickedMenuItem. You can write event handling code in the $event for the toolbar to trap these events and branch according to the value of pClickedItem or pClickedMenuItem.

Defining the $dataname list

To enable the side menu, you need to set $sidemenu to kTrue and specify a list variable name in $dataname containing the contents of the menu. The $dataname can generate either a grouped or an ungrouped menu.

Ungrouped list columns with each row representing an item:

  1. Text (Character): The text of the menu item.

  2. IconPath (Character): A URL of an image to display. The image will be scaled to fit.

Grouped list columns with each row representing a group:

  1. SubList (List): A list with columns matching the ungrouped list above. Contains data for the group.

  2. GroupName (Character): The text displayed on the group header.

  3. Fixed (Boolean): Optional column. If true, the group is always expanded. False by default.

  4. Collapsed (Boolean): Optional column. If true, the group is collapsed by default. False by default.

TransButton Control

The TransButton control is like a standard button, but it can display a different icon and/or background color when the end user’s pointer hovers over the control, or when the button is tapped on touch devices. In all other respects the Transbutton is like a standard push button control, insofar as it generates a single evClick event when the button is clicked which can be used as confirmation or to initiate an action in your code using the $event method. Note the evClick event must be enabled in the $events property for the control for it to be reported.

There is an example app in the Samples section in the Hub in the Studio Browser showing how you can use the Trans button, and the same app is available in the JavaScript Component Gallery.

image101

Hover Action

The Transbutton has several properties prefixed “$hot” that relate to the appearance of the button for the hover action. You can specify two icons for the Transbutton: one to represent the “off” state which is specified in $iconid, and the other to represent the “over” state which is specified in $hoticonid: if no $hoticonid is specified the icon in $iconid is used which will not provide a hover effect. You can also specify a different background color for the hover action in $hotbackcolor, and an alternative border color in $hotbordercolor.

The icons used in $iconid and $hoticonid can be from an icon set, or #ICONS, or an icon datafile. You can use the standard icon sizes (16x16, 32x32, 48x48 and their 2x equivalents for hi-def support), but you can also use non standard sized images as well, but in this case they can only be sourced from an icon set (and the size should be specified in the file name according to the usual naming). The Transbutton will not draw or position icons from standalone pages in #ICONS or icon datafiles (e.g. omnispic.df1) correctly in the client, since the client cannot determine the icon size from its URL.

You can set $vertical to true to center the button’s content vertically: $align also affects the placement of the icon when $vertical is true.

HTML Button Text

You can specify a label for the button using the $text property which is a single line of plain text. When set to kTrue the $textishtml property specifies that the text in $text is treated as HTML, and therefore any HTML, including character and color attributes, can be used to style the text. For example, you can insert a line break by setting $textishtml to kTrue, and using <br> in $text for the button wherever a line break is required.

The HTML needs to be valid for it to be rendered in the form, including when used as the contents of a <p> element; so for example, you cannot use a <p> element inside another <p> element.

Tree List Control

The Tree List Control provides a graphical way of displaying a list of items in a hierarchical format. Each node can have a check box or its own icon. The $dataname property for a tree list is the name of a list variable containing the content (data) and structure of tree list. The list can contain the entire data for a tree list when the form is opened, or the content can be built as nodes are expanded when a tree list is in “dynamic” mode.

There are two example apps in the Samples section in the Hub in the Studio Browser showing how you can create a tree list with check boxes (left) and a dynamic tree structure (right); the same app is available in the JavaScript Component Gallery. The following images show the ‘vintage’ JS Theme in use.

image102

Properties

Tree lists have the following properties:

Property Description
$checkbox If true, and $multipleselect is also true, the tree control has check boxes that can be used to select nodes
$currentnodeident The current node ident for Dynamic tree lists only: see below
$datamode Controls how the list content is used to structure the tree list, a constant: kJSTreeFlatList, kJSTreeFlatListWithTags, kJSTreeFlatListOld, kJSTreeFlatListOldWithTags
$evenrowcolor Specifies the color to be used for every even row in the list of nodes. The kColorDefault setting means use the same color as odd numbered rows ($backcolor).
$extraspace Adds extra space in between the lines in the list; it is the number of pixels added to the normal font height of a row in the list, or zero for no extra space
$iconurlprefix All icons used in the tree (as a result of $showicons being true) must come from a single icon directory; the default is _icons/omnispic/
$lineborder If true, a row border is added between each node
$linebordercolor Specifies the color of the line when $lineborder is true; it uses the value of $bordercolor when set to kColorDefault
$multipleselect If kTrue allows the end user to select more than one line; should be enabled for tree lists with $checkbox enabled
$nodeaction Performs an action on the tree node, only for Dynamic mode: see below
$nodedata List for tree node when building dynamically: see below
$showicons If true, the tree control shows node icons from location in $iconurlprefix
$showlines If true, the tree control displays dotted lines connecting nodes
$twostate If true, and the tree control has checkboxes (see $checkbox), selection of each node is independent

Tree List Format

The format or mode of the data is set in the $datamode property which controls how the list content is used to structure the contents of the tree list. There are several different data modes to format a tree list, as well as the Dynamic mode, represented by the following constants:

  1. kJSTreeFlatList
    The first N columns represent a node in a tree of depth N. The last 5 columns are node properties: iconid,ident(int),expanded(bool),textcolor(zero means $textcolor),tooltip

  2. kJSTreeFlatListWithTags
    The first N columns represent a node in a tree of depth N. The last 7 columns are node properties: iconid,ident(int),expanded(bool),textcolor(zero means $textcolor), tooltip, tag(char), enterable(bool)

  3. kJSTreeFlatListOld
    A list with the same structure as the plug-in client tree kTreeDataFlatList

  4. kJSTreeFlatListOldWithTags
    A list compatible with the plug-in client kTreeDataFlatListWithTags

  5. kJSTreeDynamicLoad
    the tree list content can be built dynamically; see below

Tree Events

When the user selects a node the evClick event is reported, while a double-click reports an evDoubleClick. In both cases, the id and tag of the selected node is reported in the pNodeIdent and pNodeTag parameters. Note you cannot get click or double-click events for nodes which are enterable, as the click puts them into edit mode.

For enterable nodes, the evRenamed event is reported if the end user has renamed the node. evRenamed has node ident, node tag, old name and new name as event parameters.

The evExpandNode event is fired after the user has expanded a node, every time that node is expanded (unlike evLoadNode which is only triggered if the node has no children). This applies to both dynamic and non-dynamic tree lists; see below for dynamic tree lists.

You cannot use $nodedata to load data into the tree list with evExpandNode, it is just a notification and includes the parameters pNodeIdent and pNodeTag. If evLoadNode and evExpandNode are both active, evLoadNode will be fired first, as evExpandNode is fired after the node is expanded.

Scrolling in long lists

Tree lists scroll to view the current line in the list, and any parents opened as necessary, whenever the current line changes or the $currentnodeident property is set. In a non-multiple select tree lists, setting either the current line in the list or the $currentnodeident will select the line and scroll to it. This applies to flat list trees only.

In multiple select tree lists, setting the current line will scroll to that line but will not select it. Setting $currentnodeident notationally will set both the current line and select the node. Tree lists without checkboxes will clear any current selection, but tree lists with checkboxes will not. This behavior mimics the user behaviour of clicking a node.

In multiple select tree lists, the $currentnodeident and the current line in the list can reference different nodes; however, in single select tree lists, they will always reference the same nodes.

Dynamic Tree Lists

The content inside a Tree List Control can be built dynamically as the end user expands a node. In previous versions, the entire contents of the tree list had to be built and sent to the client, including the contents for all unexpanded nodes, which for large lists created quite an overhead. Building the tree list data and displaying content in a tree list can be optimized with the ability to build node contents “on the fly” as required (note there is an example app in the Hub and JS Component gallery).

Creating Dynamic Trees

To use a Tree Control in dynamic mode you need to set its $datamode property to kJSTreeDynamicLoad. Note that dynamic mode can only be used for ‘single-select’ trees, and attempting to assign kJSTreeDynamicLoad to $datamode will fail if $multipleselect or $checkbox for the tree control is kTrue.

As in previous versions, a dynamic tree still requires a list identified by $dataname, but the list need only contain the initial content of the tree, that is, the content for the root or parent nodes. After the list content is changed, the tree reloads its content from the list.

Dynamic trees also use lists to set the content of expanded nodes and to add nodes programmatically to the tree. The lists all have the same structure: each list represents an ordered set of nodes with the same parent (or no parent in the case of the $dataname list), and the columns are as follows:

  1. Column 1: Text. The text displayed for the node.

  2. Column 2: Icon. Only used when $showicons is set to kTrue. This is a line number in the list identified by $nodeiconlist, or zero if the node does not have an icon. $nodeiconlist is described below.

  3. Column 3: Ident. A unique positive integer that identifies the node. Cannot be the same as the ident of any other node in the tree. The tree control throws an exception (resulting in a message box displayed on the client) if you try to use a duplicate ident.

  4. Column 4: Tag. A string associated with the node. Any value that is useful to the developer. Need not be unique.

  5. Column 5: Tooltip. The tooltip string for the node, displayed when the user hovers the mouse over the node. Leave empty for no tooltip, although on some browsers nodes may inherit their tooltip from their parent node if the tooltip is empty.

  6. Column 6: Text color. The text color for the node (an integer RGB value). Zero means use the $textcolor of the tree.

  7. Column 7: Flags. Integer flags. A sum of zero or more of the following constants:

  1. kJSTreeFlagEnterable. The node text can be edited (this works with the existing evRenamed event).

  2. kJSTreeFlagHasChildren. The node has children.

  3. kJSTreeFlagExpanded. The node will be immediately expanded. If you set this flag you must supply the child nodes using a node list supplied as the children column.

  4. kJSTreeFlagDiscardOnCollapse. If set, when the user collapses the node, the tree deletes the node contents. This means that the next time the user expands the node, the tree will generate an evLoadNode event; evLoadNode is described later in this document.

  1. Column 8: Children. If the kJSTreeFlagHasChildren is present, you can pre-populate the node content by using a nested list to specify the children. If you do not supply any children using this list, then you can supply them later by using the evLoadNode event (see below). The content of this column is ignored if the kJSTreeFlagHasChildren is not present. You can nest children lists arbitrarily deep (within reason).

$nodeiconlist allows you to specify the icons to be used with the tree. These must be available when the tree is updated from the dataname list. $nodeiconlist must be the name of an instance variable list with at least one column which must be a character column containing icon URLs. You can populate each URL in the node icon list using the iconurl() function, for example:

Do iNodeIcons.$define(iNodeIcon)
Do iNodeIcons.$add(iconurl(1710))
Do iNodeIcons.$add(iconurl(1711))
Do iNodeIcons.$add(iconurl(1712))

Populating Expanded Nodes

Dynamic trees have the event evLoadNode which allows you to populate the tree on demand, by only populating node content when a node is expanded. When using the kJSTreeDynamicLoad mode for $datamode, evLoadNode is generated so that you can set the content of the node by setting the $nodedata property which is the name of a list containing the expanded node content. For other settings of $datamode, evLoadNode is generated when the user expands a tree node.

The evLoadNode event has two parameters, pNodeIdent and pNodeTag, corresponding to the node that is being expanded. In the event processing for evLoadNode, you can set a new tree property, $nodedata, to a node list representing the content of the node (with the above column format); if the event processing fails to set this property, the tree control sets the node content to empty.

The list assigned to $nodedata can specify nested children if desired.

$nodedata is a runtime-only property that can only be set.

Manipulating Tree Nodes

Dynamic trees support ‘node actions’ to allow you to manipulate the nodes in a Tree List programmatically. For example, you can expand or collapse a node, and you can add, delete or rename modes. You execute a node action by assigning a row variable to the $nodeaction property of the tree. The supported actions are as follows:

  1. kJSTreeActionExpand
    row(kJSTreeActionExpand, ident). Expands the node with the specified ident if it is not already expanded.

  2. kJSTreeActionCollapse
    row(kJSTreeActionCollapse, ident). Collapses the node with the specified ident if it is not already collapsed.

  3. kJSTreeActionRename
    row(kJSTreeActionRename, ident, newname). Renames the node with the specified ident to the new name.

  4. kJSTreeActionDelete
    row(kJSTreeActionDelete, ident). Deletes the node with the specified ident (also recursively deletes node children). If the current node is deleted, an evClick event will be generated to inform the application of the new current node.

  5. kJSTreeActionAdd
    row(kJSTreeActionAdd, ident, position, nodelist). Adds the nodes in the nodelist to the tree, where ident specifies the parent node of the nodes in nodelist; to add a new root nodes specify ident as zero. The position parameter can be one of:

  1. -1 to add the new nodes before any existing children of the node specified by ident

  2. 0 to add the new nodes after any existing children of the node specified by ident

  3. a child node ident. New nodes are added after the child node with this ident. If no such node exists, the new nodes are added after any existing children.

$nodeaction is a runtime-only property that can only be set.

Collapsing a Node

The tree control now generates evCollapseNode when the user collapses a node. This applies to all trees, not just dynamic trees.

The Current Node

The current (selected) node in the tree is no longer represented by a list line. Instead, there is a new property, $currentnodeident that applies to dynamic trees. When the user changes $currentnodeident (by clicking on a node), the control generates evClick. In addition, the developer can assign $currentnodeident (and read its value in client-executed methods). $currentnodeident is a runtime-only property.

Video Control

The Video control allows you to play a video within your remote form. The video can be hosted on YouTube or you can play a video via the HTML5 video support in the browser. There is an example app in the Samples section in the Hub in the Studio Browser showing how how you can play a YouTube video; the same app is available in the JavaScript Component Gallery.

The JS Video control has the following properties:

Property Description
$dataname

If $youtube=kFalse, this is a 2 columned list containing the location and type of the videos to be played: Column 1 is the URL of the video file; Column 2 is the media types

If $youtube=kTrue, this is a list containing the IDs of the YouTube videos to be played; only Column 1 of the list is used and contains the ID of the YouTube video

$showcontrols If true, the control displays video controls such as the Play and Pause buttons
$youtube

If true, the control will play a movie from youtube.com; column 1 of the $dataname list is the YouTube video id

If false, the control will use HTML5 video to play video files from URLs

$startposition The time (in seconds) at which the video should start when played
$currentposition (Runtime only) The current time (in seconds) of the current position in the video. Assign to this to ‘seek’ to a particular time
$duration (Runtime only) The duration of the current video (in seconds). Read-only (in a client-exec method)
$poster A URL to an image to display before the first frame of the video is ready. HTML5 video only ($youtube=kFalse)
$playing Whether the video is currently playing. Assign to this in order to play or pause the video. Note that many mobile devices prevent the playing of videos if not in direct response to a user action
$volume The volume level of the video player (0-100). Assigning 0 will mute the player
$playbackrate The video's playback speed, with 1.0 being default speed. Youtube will round down to the closest supported rate of the particular video
$requestcaptions If true, closed captions will be turned on (when available, attempting to use the client's language) for Youtube videos. Note that even if disabled, captions may be enabled through the video controls, or through the user’s account settings in Youtube (if they are signed in)

Properties relating to the current video player ($currentposition, $duration, $volume) will return -1 if queried before a video is ‘ready’ (see evVideoReady).

YouTube

If you set the $youtube property to kTrue, the $dataname for the video control should be a list containing YouTube ids: the data in the first column of the first row in the list is used to reference the video on YouTube. Note the YouTube id is not the full URL on youtube.com, but just the id on the end of the URL, e.g. 'Ff-qlTlSkc0'.

Playlists

If the list assigned to a Youtube video control ($youtube = ktrue) has more than one line, a YouTube playlist will be created, using the video IDs supplied in each line of the list. The videos in the playlist will be played successively.

If $showcontrols is true, the playlist can be accessed via the video controls in the UI. You could notationally skip to the next video by skipping to the end of the current video. For example, using the client-executed method:

Calculate $cinst.$objs.youtubeVideo.$currentposition as $cinst.$objs.youtubeVideo.$duration

HTML5

If you set $youtube to kFalse, the $dataname should be a 2 column list. The first column should contain URLs to the video files, located somewhere on the internet or the Omnis App Server, and the second column should state the media type. For example:

Do iList.$define('VideoURL','VideoType')
Do iList.$add('videos/myVideo.mp4','video/mp4')
Do iList.$add('videos/myVideo.ogv','video/ogg')
Do iList.$add('videos/myVideo.webm','video/webm')

Not all browsers are able to play all video file types, so you should provide the video in multiple formats and populate the list with the URL to each file and type. When the client connects, the browser will play the first video file it is able to play from the list.

Events

The JS Video control has the following events:

  1. evVideoReady
    Sent when the video is ready to be played, and can be interacted with.

  2. evVideoEnded
    Sent when the video has finished playing (i.e. it has played to the end).

Both events receive a pVideoURL parameter, describing the currently playing video. For HTML5 videos ($youtube = kFalse), this will be a URL to the video file. For Youtube videos ($youtube = kTrue), this will be the Youtube video ID. These should correspond to a value in the list assigned to the control’s $dataname.

External Components

iCalendar

The iCalendar external component allows you to load and manage calendar events: it is a non-visual External Component that you can use in your Remote Forms (or window classes). iCalendar allows you to read, write and modify objects based on the standard iCalendar format, which is supported by many third-party calendar products.

The iCalendar model is based on four object types:

  1. Component: A group containing Properties which represent, for example, an event. Components can contain other Components (sub-components).

  2. Property: Used to communicate information about a Component, such as a description or a location.

  3. Value: Properties have a value associated with them. For example, a DTSTART Property will have a date or datetime value.

  4. Parameter: A modifier for a Property. Properties may have more than one Parameter (or none).

There are two types of object in the Omnis iCalendar external component:

  1. Document: Represents the entire Document and its children.

  2. Component: Used to access and manipulate iCalendar Components and their associated Properties and Parameters.

To access the iCalendar objects & methods, you need to create an instance variable in your remote form (or window class), choose Object as its Type, under Subtype drop down the Select object dialog, open the ‘iCalendar Objects’ group and select ‘Document’ object.

Working with iCalendar files

iCalendar Documents can be initialised with character data, or built up with the Omnis iCalendar methods.

To load an iCalendar file into a Document object, use FileOps to read in the character data. Then use $initwithdata() to initialise the document.

 Do FileOps.$getfilename(lPath,"Select ics file","*.ics")
 Do lFileOps.$openfile(lPath,kTrue)
 Do lFileOps.$readcharacter(kUniTypeUTF8,iCalText)
 Do lFileOps.$closefile()
 Do lDoc.$initwithdata(iCalText)

To output the character data, use $getdata() on the Document or a single Component. To save the data into a file, use FileOps.

 Calculate lDocText as iNewDoc.$getdata()
 Do FileOps.$putfilename(lPath,,"*.ics")
 Do lFileOps.$createfile(lPath)
 Do lFileOps.$openfile(lPath)
 Do lFileOps.$writecharacter(kUniTypeUTF8,lDocText)
 Do lFileOps.$closefile()

Updating sub-components

The functions $getcomponent() and $getsubcomponent() return a copy of a Component. Therefore, modifying the returned Component will not affect the parent (the Component or Document that the method was called on). In order to update the parent, Component copy will need to be saved back to the parent with $replacerootcomponent() or $replacesubcomponent().

Custom Properties

As well as the standard Property types, custom Properties can be added to Components. These must be prefixed with “X-”, e.g. “X-PROPERTY”. By default, the data type of a custom Property is character. When adding a Property to a Component with $addproperty(), the optional iDataType Parameter can be used to override the default data type. Doing so will set the “VALUE” Parameter to the data type associated with the constant. The data type cannot be changed after it has been created.

Custom Parameters

Like custom Properties, custom Parameters can be applied to Properties. Similarly, they must also have “X-” as a prefix.

Error Properties

When a Document is initialised with $initwithdata(), the character data is parsed. If there are any syntactic or semantic errors in the data, such as a misspelt Property name or a Property without a value, an X-LIC- error Property will be inserted. For example, the following error is caused by misspelling the ATTENDEE Property:

X-LIC-ERROR;X-LIC-ERRORTYPE=PROPERTY-PARSE-ERROR:Parse error in property name: ATENDEE

Special Values

These values contain multiple parts and are therefore represented as rows. The static $createrow() helper method can be used to build these rows, which can be used to create a new Property or update a value.

Recur

The “RECUR” value type in the iCalendar model denotes a recurring event. It is commonly used with the “RRULE” Property. Its value may contain several parts, separated by semicolons. The parts contain key value pairs separated by the equals sign. The example shows a Recurrence Rule property.

RRULE:FREQ=MONTHLY;BYMONTHDAY=1;UNTIL=19980901T210000Z

A Component’s $propertylist will store an RRULE Property as a rows containing columns relating to each keyword. To create an RRULE Property with $addproperty(), the vValue parameter can take either a character or row argument. To create a recurrence type row, use $createrow(kICalendarRowTypeRecur).

Duration

The “DURATION” value type is represented in a component’s $propertylist as a row. The columns are: IS_NEGATIVE, DAYS, WEEKS, HOURS, MINUTES and SECONDS. To add a Property with a duration type, a row containing these column names can be used. The column values are all Integers, with the exception of IS_NEGATIVE, which is a Boolean. Alternatively, a string can passed. For example, P15DT5H0M20S denotes a duration of 15 days, 5 hours, and 20 seconds. See the RFC 5545 iCalendar specification for details on this format (https://tools.ietf.org/html/rfc5545#section-3.3.6).

Period

“PERIOD” value types have two parts: The first is the start time (date time). The second can either be the end of the period (date time), or a duration. Period is the default value type of the Free/Busy Property. In the $propertylist, period values are displayed as a row containing a START date time and either a DURATION or an END date time.

19970101T180000Z/19970102T070000Z date time “/” date time (Explicit)

19970101T180000Z/PT5H30M date time “/” duration (Start)

Geo

“GEO” Properties hold geographic coordinates, represented as two floats separated by a semicolon. The values are latitude and longitude respectively, e.g. 37.386013;-122.082932.

In the $propertylist of a Component, they are displayed as a row containing a LAT and a LONG column with float values.

Static Methods

$createcomponent()

OmnisICalendar.$createcomponent(iType)

Creates a new iCalendar Component object using one of the kICalendarComponent... constants. Returns an iCalendar component object.

  1. iType: A kICalendarComponent... constant to specify the Component type.

$createrow()

OmnisICalendar.$createrow(iType)

Returns a row which can be used to add or update certain Properties. iType can be one of the kICalendarRowType... constants.

  1. iType: A kICalendarRowType... constant to specify the type of row.

Document Object Methods

$initwithdata()

$initwithdata(cData)

Initializes the object with the Character contents of an iCalendar file. Returns true if successful.

  1. cData: The character data containing the contents of an iCalendar file.

$getdata()

$getdata() - no parameters

Returns character data representing the Document that can be saved as an iCalendar file.

$getcomponent()

$getcomponent(iComponentId)

Returns a copy of the root Component object with the specified ID.

  1. iComponentId: The ID of the root Component to find.

$addrootcomponent()

$addrootcomponent(oComponent)

Adds a Component to the root of the Document. Returns the ID of the new Component.

  1. oComponent: The Component to be added to the root.

$deleterootcomponent()

$deleterootcomponent(iComponentId)

Removes the Component with the specified ID from the root. Returns true if the Component was deleted.

  1. iComponentId: The ID of the Component to delete.

$replacerootcomponent()

$replacerootcomponent(iComponentId, oComponent)

Replaces the Component at the specified ID with oComponent. Returns true if successful.

  1. iComponentId: The ID of the Component to replace.

  2. oComponent: The new Component.

Document Object Properties

$componentlist

A list of root-level Component info for the Document. The columns for this list are: ID, Type and TypeName.

Component Object Methods

$getdata()

$getdata() - no parameters

Returns character data representing the Component and its children, that can be saved as an iCalendar file.

$isvalidcalendar()

$isvalidcalendar() - no parameters

Returns true if the VCALENDAR Component meets the RFC 5546 iCalendar specification standards.

$getsubcomponent()

$getsubcomponent(iComponentId)

Returns a copy of the sub-component object with the specified ID.

  1. iComponentId: The ID of the sub-component to find.

$addsubcomponent()

$addsubcomponent(oComponent)

Adds a sub-component to the Component. Returns the ID of the new Component.

  1. oComponent: The sub-component to be added to the Component.

$deletesubcomponent()

$deletesubcomponent(iComponentId)

Removes the sub-component with the specified ID from the component. Returns true if the sub-component was deleted.

  1. iComponentId: The ID of the Component to delete.

$replacesubcomponent()

$replacesubcomponent(iComponentId, oComponent)

Replaces the Component at the specified ID with oComponent. Returns true if successful.

  1. iComponentId: The ID of the Component to replace.

  2. oComponent: The new Component.

$addproperty()

$addproperty(cName, vValue, [wParameters, iDataType])

Adds a new Property to the Component. Returns the Property ID.

  1. cName: The name of the Property. Must be a valid Property type.

  2. vValue: The value to assign to the Property. The type can be Character, Integer, Date Time, Float, Boolean or Row.

  3. wParameters: A row of Parameters to add to the Property.

  4. iDataType: A kICalendarDataType... constant. Sets the 'VALUE' Parameter which overrides the default data type for the Property. Can be used to specify the type of a custom Property.

$deleteproperty()

$deleteproperty(iPropertyId)

Delete the Property with the specified ID. Returns true if the Property was deleted.

  1. iPropertyId: The ID of the Property to delete.

$setparameter()

$setparameter(iPropertyId, cName, cValue)

Sets the Parameter of the Property. If there is an existing Parameter with the same name, it will be overwritten. Returns true if successful.

  1. iPropertyId: The ID of the Property associated with the Parameter.

  2. cName: The name of the Parameter to set.

  3. cValue: The value to set the Parameter to.

$updateproperty()

$updateproperty(iPropertyId, vValue, [wParameters])

Updates the Property with the specified ID. Providing Parameters will overwrite any existing ones. Returns true if successful.

  1. iPropertyId: The ID of the Property to update.

  2. vValue: The new value to assign to the Property. The type can be Character, Integer, Date Time, Float, Boolean or Row.

  3. wParameters: A row of Parameters to add to the Property.

$deleteparameter()

$deleteparameter(iPropertyId, cName)

Removes the Parameter with the name cParamName from the Property. Returns true if the Parameter was deleted.

  1. iPropertyId: The ID of the Property associated with the Parameter.

  2. cName: The name of the Parameter to delete.

Component Object Properties

$componentlist

A list of sub-component info for the Component. The columns for this list are: ID, Type and TypeName.

$propertylist

A list of iCalendar Properties held by this Component. The columns for this list are: ID, PropertyName and PropertyValue. The PropertyValue column contains a row for each Property. Each row has a “_VALUE” column containing the Property value (the type of this depends on the Property), and columns for any Parameters that the Property has.

$typename

The type name of the Component.

$typenumber

The type number of the Component.