Standard Commands (Character Displays)
Character displays support a small set of standard commands for working with pagers and changing component property values. For more about how APL commands work in general, see APL Commands.
- Common properties
- AutoPage command
- Idle command
- Parallel command
- Sequential command
- SetPage command
- SetValue command
Common properties
A single command is encoded as a JSON object. All APL-T commands have the following common properties:
Property | Type | Default | Description |
---|---|---|---|
type | String | REQUIRED | The type of the command |
description | String | "" | Optional documentation for this command |
delay | Integer | 0 | Delay time in milliseconds before this command runs. Must be non-negative. |
screenLock | Boolean | false | If true, disable the interaction_timer . |
when | Boolean | true | Conditional expression. If this evaluates to false, the command is skipped. |
type
Specifies the particular command to run. This may be one of the predefined primitive command types or a user-defined command.
delay
The delay is the amount of time in milliseconds inserted before running this command. The delay must be a non-negative integer. If not specified, the delay defaults to 0. The delay is ignored if the command's when
property resolves to false. The delay is ignored when the command runs from within an event handler.
screenLock
The screenLock property applies to the lifecycle_section
of the APL-T document. If true, the interaction_timer
is disabled while this command runs. When a command with screenLock=true
finishes running, the interaction_timer
timer is reset to 0.
The screenLock applies to the entire extent of the command including any defined delay
. For example, the following command will hold the screen lock for 30 seconds:
{
"type": "Idle",
"delay": 30000,
"screenLock": true
}
when
If true, run the command. If false, ignore the command. Commands that are ignored also ignore the screenLock
.
AutoPage command
Automatically progress through a series of pages displayed in a Pager component. The AutoPage command finishes after the last page has been displayed for the requested time period. The AutoPage command has the following properties in addition to the regular command properties.
Property | Type | Default | Description |
---|---|---|---|
componentId | String | SELF | The id of the component. |
count | Integer | <ALL> | The number of pages to display. Defaults to all of them. |
duration | Integer | 0 | Time to wait between pages (in milliseconds). |
For example, to auto-page through a sports pager:
{
"type": "AutoPage",
"componentId": "mySportsPager",
"delay": 500,
"duration": 1000
}
The above example first pauses for 500 milliseconds (the delay property), then changes to the next page, pauses for 1000 milliseconds (the duration property), and continues changing and pausing until the final pause has completed. If the pager in this example had three pages and had started on the first page, then the AutoPage command would pause 500ms, show page #2, pause 1000 ms, show page #3, and finally pause 1000 ms.
The AutoPage command has no effect if the count is non-positive.
The AutoPage
command does the following when it stops:
- Moves the display ahead to the target page if the
AutoPage
command sequence is at least 50% complete. - Returns the display to the previous page if it is not at least 50% complete.
The onPageChanged
command runs one time with the new page if the page has changed.
The AutoPage command is ignored in fast mode.
componentId
The ID of Pager component. If omitted, the component issuing the AutoPage command is used.
count
The number of pages to display. If not specified, this defaults to the number of pages remaining. Wrapping is not supported; the count is internally clipped to fall in the range [0, pager.children.length – pager.currentIndex – 1].
duration
The amount of time to wait after advancing to the next page. Any animated transition between pages is not included in the duration and therefore increases the overall command run time.
Idle command
The idle command does nothing. It may be a placeholder or used to insert a calculated delay in a longer series of commands. For example, consider the command:
{
"type": "Sequential",
"commands": [
{
"type": "SetValue",
"componentId": "myText",
"property": "text",
"value": "Hi"
},
{
"type": "Idle",
"delay": 3000
},
{
"type": "SetValue",
"property": "myText",
"value": "you"
}
]
}
This command example shows the text "Hi" in the Text
component with id equal to "myText
" for 3 seconds and then switches the text to "you".
The type of the idle command is "Idle". The Idle
command has no properties other than the common command properties.
Parallel command
Run a series of commands in parallel. The parallel command starts running all child command simultaneously. The parallel command is considered finished when all of its child commands have finished. When the parallel command stops early, all currently running commands stop.
The type of the parallel command is "Parallel". The parallel command has the following properties in addition to the common command properties.
Property | Type | Default | Description |
---|---|---|---|
commands | Array of Commands | REQUIRED | An unordered list of commands to run in parallel. |
In fast mode, the parallel command runs all of the sub-commands in parallel, but without delays (giving a net zero duration).
commands
An un-ordered array of commands to run in parallel. Once all commands have finished running the parallel command finishes. Please note that the delay of parallel command and the delay of each command are additive. For example, given the command:
{
"type": "Parallel",
"delay": 500,
"commands": [
{
"type": "SetValue",
"delay": 1000
},
{
"type": "SetValue",
"delay": 250
}
]
}
In the above example, the first SetValue runs at 1500 milliseconds and the second at 750 milliseconds (that's before the first SetValue).
Sequential command
A sequential command runs a series of commands in order, waiting for the previous command to finish before running the next. The sequential command is finished when all of its child commands have finished.
The type of the sequential command is "Sequential". The sequential command has the following properties in addition to the common command properties.
Property | Type | Default | Description |
---|---|---|---|
catch | Array of Commands | [] | An ordered list of commands to run if this sequence stops early. |
commands | Array of Commands | REQUIRED | An ordered list of commands to run in series |
finally | Array of Commands | [] | An ordered list of commands to run after the normal commands and the catch commands |
repeatCount | Integer | 0 | Additional number of times to run these commands |
The following algorithm is followed when running a sequential command:
function runSequential(command, mode):
if mode == "normal":
for (i = 0 ; i <= repeatCount ; i++):
for cmd in command.commands:
run cmd
wait for cmd to finish
if cmd was stopped:
return doCatch()
elif mode == "fast":
for cmd in commands:
fastRun cmd
return doFinally(mode)
function doCatch():
for cmd in command.catch:
fastRun cmd
return doFinally("fast")
function doFinally(mode):
for cmd in command.finally:
if mode == "normal":
run cmd
wait for cmd to finish
if cmd was stopped: // Switch to fast mode
mode = "fast"
elif mode == "fast":
fastRun cmd
This algorithm has the following properties:
- In normal mode the commands run in order, followed by the finally commands. The repeatCount only applies to the regular commands.
- In fast mode the commands run in order without repeating, followed by the finally commands.
- If one of the commands ends early (in normal mode), the catch commands and finally commands run in fast mode.
- If one of the finally commands ends while running in normal mode, the remaining finally commands run in fast mode.
catch
The catch commands run if the sequential command stops due to another command starting. The catch commands run in "fast" mode – that is, all durations are ignored and commands jump to their final values. The catch commands are run before any finally commands.
Note that the catch commands are run only once. The repeatCount property does not apply to catch commands.
commands
An array of commands to run. The commands run in order; each command must finish before the next can begin. Please note that the delay of sequential command and the delay of the first command in the sequence are additive. For example, given the command:
{
"type": "Sequential",
"delay": 1000,
"repeatCount": 2,
"commands": [
{
"type": "SetValue",
"delay": 2000
},
{
"type": "SetValue",
"delay": 2000
}
]
}
In the above example, the first SetValue runs after 3000 milliseconds.
finally
The finally commands run after the normal sequential commands finish or after the catch commands run due to the Sequential
command stopping early. The finally commands run in normal mode unless (a) the entire Sequential command ran in fast mode or (b) the sequential command stopped early.
Note that the finally commands are run only once. The repeatCount property does not apply to finally commands.
repeatCount
The number of times to repeat this series of commands. Defaults to 0. Negative values will be ignored.
Note that the delay assigned to overall sequential command only applies the first time. For example, in the sample command sequential command (from the last section) the first SetValue fires at 3000 milliseconds, the second at 5000, the first SetValue fires again at 7000 milliseconds, and so forth.
SetPage command
Change the page displayed in a Pager component. The SetPage command finishes when the item is fully in view. The SetPage command has the following properties in addition to the regular command properties.
Property | Type | Default | Description | |
---|---|---|---|---|
componentId | String | SELF | The id of the component. | |
position | relative | absolute | absolute | Whether the value is a relative or absolute offset. |
value | Integer | REQUIRED | The distance to move. May be an absolute or relative value. |
When there are N pages in the pager, the first is index 0 and the last has index N-1. A relative position offsets from the current page. For example, to move one page forward:
{
"type": "SetPage",
"componentId": "myWeatherPager",
"position": "relative",
"value": 1
}
An absolute position sets the index of the current page. A negative absolute position is an offset from the end of the list. For example, to go to the last page:
{
"type": "SetPage",
"componentId": "myWeatherPager",
"position": "absolute",
"value": -1
}
No intermediate pages display when switch between two pages. For example, if the current page is 3 and SetPage runs with position="relative", value=-2, the current page will transition out and page 1 will transition in without showing page 2.
The SetPage command can set any page for display; it does not respect the allowed navigation direction in the Pager component. However, wrapping behavior affects page switch calculations; see the value section.
Stopping a SetPage
command jumps ahead to the target page if the SetPage
command sequence is at least 50% complete, and it returns to the previous page if it is not at least 50% complete. The onPageChanged
command runs one time when the command stops if the page has changed from the last page.
The SetPage command is ignored in fast mode.
componentId
The ID of Pager component. If omitted, the component issuing the SetPage command is used.
position
If the position is "relative", the value is a relative distance to move from the current page. If the position is "absolute", the value is the absolute page number to move to.
value
Either the distance to move or the absolute page number to move to.
The algorithm to calculate final position and direction is roughly:
if (command.position == 'absolute') { // Absolute motion
let index = command.value < 0 ? pager.children.length + command.value : command.value;
index = Math.max(0, Math.min(pager.children.length – 1, index)); // Clamp range
// Return the final index and the direction of motion
if (index == pager.currentIndex)
return NO_MOVE
return (index, index < pager.currentIndex ? "LEFT" : "RIGHT");
}
else { // Relative motion
let index = pager.currentIndex + command.value;
// If relative motion goes out of bounds and we don't support wrapping, ignore the command
if (pager.navigation != "wrap" && (index < 0 || index >= pager.children.length))
return NO_MOVE;
// Wrap appropriately
index = ((index % pager.children.length) + pager.children.length) % pager.children.length;
if (index == pager.currentIndex)
return NO_MOVE;
return (index, command.value < 0 ? "LEFT" : "RIGHT");
}
The pager animation is driven by the returned direction.
There are a couple of characteristics of this algorithm:
- Absolute values clamp within the valid range of pages. The direction is relative to the current page.
- Relative values on a wrapping pager will wrap arbitrarily. The direction is based on the commanded value; wrapping doesn't change the direction.
- Relative values on a non-wrapping pager that go out of range are ignored.
SetValue command
Changes a property or binding of a component. Each component has a defined set of dynamic properties that can be set. Each component also may have named bindings. Refer to the specifics of each component for the values that may be set.
The SetValue command has the following properties in addition to the regular command properties.
Property | Type | Default | Description |
---|---|---|---|
componentId | String | SELF | The id of the component whose value should be set. |
property | String | REQUIRED | The name of the property to set. |
value | Any | REQUIRED | The value to set on the property |
For example, to make the punchline of a joke appear:
{
"type": "SetValue",
"componentId": "jokePunchline",
"property": "text",
"value": "To get to the other side!"
}
The SetValue command changes the value of a component property or component binding. The following rules are followed:
- If the component has a property named property that is dynamic, then the property is updated with the new value.
- Otherwise, if the component has a
bind
property with that name, then that bound property is updated. - If a bound property changes value, then all dynamic properties of components that depend on that property will be updated.
An example of updating a binding value:
{
"type": "Container",
"bind": [
{
"name": "MyCounter",
"value": 0,
"type": "number"
}
],
"item": {
"type": "Text",
"text": "Ct:${MyCounter}"
},
"onMount": {
"type": "Sequential",
"repeatCount": 10,
"commands": [
{
"type": "SetValue",
"delay": 500,
"property": "MyCounter",
"value": "${value + 1}"
}
]
}
}
The above example increments the counter every 500ms until the count reaches 10.
The SetValue command runs in fast mode, but without any delay.
componentId
The ID of the component whose value will change. If this property is omitted, the component issuing the SetValue command is the recipient.
property
The name of the property to change. This may be a built-in property or a binding.
value
The value is evaluated when the command runs, so it can take advantage of existing component properties. For example:
{
"type": "SetValue",
"property": "MyCounter",
"value": "${value + 1}"
}
This command increments the value of the target component, which is the counter bound in the container.
Last updated: May 10, 2024