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

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 onPageChange 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 onPageChange 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:

  1. If the component has a property named property that is dynamic, then the property is updated with the new value.
  2. Otherwise, if the component has a bind property with that name, then that bound property is updated.
  3. 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.