How to Create Add-in Controls

Description

Custom controls can be created and added to the Alpha Anywhere environment or the UX Component.

Discussion

Add-in controls are defined by entries in the 'uxCustomControls' folder in the executable folder. To add an add-in control to your UX component, click the More... item in the UX toolbox and select the control to insert into the component.

You can create your own add-in controls and add them to the dialog by placing the definition files for the control int he 'uxCustomControls' folder in the executable folder.

All of the definition files for the add-in control must be placed inside a folder in the 'uxCustomControls' directory. The folder name is the name of the add-in control shown in the More... dialog. Inside the sub-folder there should be three files:

define.xbasic

Xbasic script the defines the 'builder' for the custom control.

generate.xbasic

Xbasic script that generates the settings for the custom control based on properties defined in the builder.

info.json

A settings object that defines the icon and help text for the control that are shown in the dialog where the user selects the control.

define.xbasic

The define.xbasic file contains the definition for an Xbasic function called define used to dislpay a property sheet for configuring the control. The Xbasic function must return a JSON object of the control's properties

The function takes 3 parameters:

Parameter
Description
json

A string containing a JSON definition of existing (if any) settings. These settings should be used to populate the value of the properties for defining the control. json will be an empty string if properties have not been defined for the control (such as when inserting the control into the UX for the first time.)

wf

A dot variable used with other builder functions (such as a5wcb_editJavascript) to provide context about the environment.

flagSilent

If not specified,this property should default to .f.. Silent mode is used to generate a default definition in case the user tries to preview before defining control properties

Here's an example of the define function. This is the define function for the StepIndicator control:

function define as c (json as c, wf as p, flagSilent = .f.)
dim clicktoedit as c = "<Click Button to Edit>"
dim v as p
if json <> "" then
	v = json_parse(json)
end if

dim v.steps.labels as c = default "One,Two,Three,Four"
dim v.steps.colorDone as c = default "#007cdb"
dim v.steps.colorNotDone as c = default "#ddd"
dim v.textOffset as c = default "14px"
dim v.lineWidth as c = default "4px"
dim v.dotSize as c = default "10px"
dim v.borderRadius as c = default "2px"
dim v.showIndicatorsAsCircles as l = default .t.



dim pg as p

dim pg as p
dim pg.settings as p
dim pg.def as c
pg.def = <<%str%
^^Step Indicator
	state=opened

	++Specify the labels for each step
		var=v.steps.labels
		help=Specify the label for each step in the process.
		type=smart
		readonly = .t.
		data = v.steps.labels = getSteps(v.steps.labels)

	++Color (completed steps)
		var=v.steps.colorDone
		help=Specify the color of the indicator for each step that has been completed.
		type=smart
		data = v.steps.colorDone =  a5_color_picker("HEX",v.steps.colorDone)

	++Color (steps to be completed)
		var=v.steps.colorNotDone
		help=Specify the color of the indicator for each step that has not yet been completed
		type=smart
		data = v.steps.colorNotDone =  a5_color_picker("HEX",v.steps.colorNotDone)

	++Text offset
		var=v.textOffset
		help=Distance between the text labels and the step indicators

	++Line width
		var=v.lineWidth

	++Dot size
		var=v.dotSize

	++Show step indicators as circles
		var=v.showIndicatorsAsCircles
		help=Show the step indicators as circles.

	++Border radius
		var=v.borderRadius
		show=v.showIndicatorsAsCircles = .f.

^^Events
	state=opened
	show_category = .f.

%str%

dim dlg_title as c
dim dlg_body as c
dim dlg_event as c
dlg_title = "Step Indicator"
dlg_body = <<%dlg%
{propgrid=100,40pg};
{justify=right}
{lf};
<10&OK!ok><10&Cancel>
%dlg%
dlg_event = <<%code%
if a_dlg_button ="ok" then
	flagOK = .t.
end if
%code%

dim flagOK as l = .f.
dim flagOK as l = .f.
if flagSilent = .f. then
	ui_dlg_box(dlg_title,dlg_body,dlg_event)
else
	'silent mode is used to generate a default definition in case the user tries to preview before defining control properties
	flagOK = .t.
end if

if flagOK = .t. then
	define = vartojson(v)
else
	define = json
end if

end function

generate.xbasic

The generate.xbasic file is responsible for computing the settings, CSS, data, and javascript for the control. The file must contain an Xbasic function called generate that takes the followin parameters:

generate must return an object with the following properties:

Property
Description
settings

A JSON object that contains the settings for the object. The settings property contains the HTML template used to display the control.

css

CSS definitions for the control.

data

A string containing a JavaScript array of data values. An empty object can be used "{}" to specify no data value.

javascript

JavaScript that is executed when the control is rendered.

For example, the below Xbasic is the generate function for the StepIndicator control:

function generate as p (v as p)

dim v.steps.labels as c = default "One,Two,Three,Four"
dim v.steps.colorDone as c = default "#007cdb"
dim v.steps.colorNotDone as c = default "#ddd"

dim v.textOffset as c = default "14px"
dim v.lineWidth as c = default "4px"
dim v.dotSize as c = default "10px"
dim v.showIndicatorsAsCircles as l = default .t.
dim v.borderRadius as c = default "10px"

dim htmlTemplate as c
htmlTemplate = <<%html%
<div style="white-space:nowrap;">{*root}<div class="step {*if [temp].value >= [count] || [count] == 0}stepDone{*endif}" style="width: {Math.floor(100/[root].length)}%;">{[value]}<div class="stepBar"></div><div class="stepDot"></div></div>{/*root}</div>%html%

dim p as p
p.inputId = "{variablename}"
p.variableName = "{variablenameUPPERCASE}"
p.theme = "{dialog.style}"
p.multiple = .f.
p.separator = "\n"
p.loopNavigate = .f.
p.loopNavigateNullSelection = .t.
p.allowNullSelecttion = .f.
p.allowNullDeselection = .f.
p.allowAnyValue = .t.
p.autoRefresh = .t.
p.scroll = .f.
p.layout = "default"
dim p.layouts as p
p.layouts.default.type = "template"
p.layouts.default.template = htmlTemplate
p._onInitialize = "{javascript}function() { $acn(this.contId,'{dialog.ComponentName}_' + this.variableName); }"
generateJavascript(p,v)

dim e as p
e.settings = vartojson(p,.t.)

e.css =  <<%str%

$doneColor: v.steps.colorDone;
$notDoneColor: v.steps.colorNotDone;

$textOffset: v.textOffset;
$lineWidth: v.lineWidth;
$dotSize: v.dotSize;
$borderRadius: v.radiusSetting;

.step {
	position: relative;
	display: inline-block;
	text-align: center;
	padding-bottom: $dotSize + $textOffset;
}

.stepBar {
	position: absolute;
	height: $lineWidth;
	background: $notDoneColor;
	border-radius: 2px;
	width: 100%;
	left: -50%;
	bottom: ($dotSize - $lineWidth)/2;
	z-index: 4;
}
.stepDot {
	position: absolute;
	height: $dotSize;
	width: $dotSize;
	background: $notDoneColor;
	border-radius: $borderRadius;
	left: 50%;
	bottom: 0px;
	margin-left: 0-($dotSize/2);
	z-index: 5;
}
.stepDone .stepBar, .stepDone .stepDot {
	background:$doneColor;
}
.step:first-child .stepBar, .stepDone:first-child .stepBar {
	background: transparent;
	width: 50%;
	left: 0px;
}

%str%

dim v.radiusSetting as c
if v.showIndicatorsAsCircles then
	v.radiusSetting = "($dotSize/2);"
else
	v.radiusSetting = v.borderRadius
end if

e.css = replace_variables_in_string(e.css,v,"v")

e.data = "__data__"
e.data = stritran(e.data,"__data__", js_list_to_array(comma_to_crlf(v.steps.labels)))
e.data =  js_list_to_array(comma_to_crlf(v.steps.labels))
e.javascript = ""


generate = e

end function

function generateJavascript as v (p as p, v as p)

dim v.javascriptEvents as p
dim eventNames as c
eventNames = properties_enum(v.javascriptEvents)
dim js_i as c
for each en in eventNames
	js_i = v.javascriptEvents.data(en.value)
	js_i = a5wcb_removeJavascriptComments(js_i)
	if js_i <> "" then
		p.set(en.value,"{javascript}function() {"  + js_i + "}")
	end if
next

end function

info.json

The info.json file defines the icon and help text for the add-in control shown in the dialog when choosing an add-in control to insert into the UX Component. The JSON must define the following properties:

Property
Description
icon

The icon shown in the Select control type dialog. It can reference built-in Alpha Anywhere images. For example, "$$window.menu".

description

A description of the control.

version

A number defining the current version of the control.

For example, the JSON shown below defines the icon, description, and version information for the StepIndicator control:

{

	"icon": "$$generic.orb.blue",
	"description" : "Display a Step Indicator control to show what step you are on in a multi-step operation.",
	"version" : 1
}

For examples of how to define the contents of these three files, please refer to any of the sample controls that are shipped with Alpha Anywhere. They can be found in the installation directory inside the uxCustomControls folder.

Videos

Add-in Controls

The UX Builder allows you to define add-in data bound controls. These are control that are defined externally and are available in the UX Builder just like any of the built-in controls.

2016-03-15