Perseus widgets which have input boxes need to implement an API so that the mobile app can correctly interact with them.
The current widgets which have input boxes are:
- expression
- input-number
- numeric-input
- table
- matrix
- number-line
- transformer
- simulator
- unit
The main data used is the "input path", which is a list of strings uniquely identifying the specific input box. A path might look like
["matrix 3", "0", "2"]
Where "matrix-3"
is the name of the top-level widget, and "0"
and "2"
are
paths internal to the matrix
widget which identify one of the cells inside it
(in this case, the "0"
refers to the row in the matrix, and "2"
refers to
the column).
function getInputPaths()
// -> List of input paths inside the widget
Returns a list of all inputs found within the widget. The paths are relative to
the widget, so returning a []
path indicates that the widget itself is the
input box, or the matrix widget returns a list like:
[
["0", "0"],
["0", "1"],
...
]
As of this writing, there are no widgets which contain other widgets, but when that does happen, this should include the paths of the inner widgets as well.
function focus()
// -> true if an input was focused, false otherwise
This API is mainly used to focus elements at the beginning of the exercise (it's not actually called from mobile, but it's very related to the rest of the stuff here). It should either focus one of its inputs and return true, or not focus anything and return false. The return value is used by widgets (e.g. expression) which we don't want to focus at the beginning of the exercise.
function focusInputPath(inputPath)
Given an input path relative to the widget, focus that input. For example, if
the path ["0", "1"]
was passed to the matrix widget, it should focus the cell
corresponding to that path.
function blurInputPath(inputPath)
Given an input path relative to the widget, blur that input. The opposite of
focusInputPath
.
function setInputValue(inputPath, value, callback)
Set the value at the input path to the specified value, then call the callback.
The callback should probably be passed as the callback to this.props.onChange
,
and not called directly.
function getDOMNodeForPath(inputPath)
Given a path, return the DOM node for that input path. As a special case, if the single DOM node that a widget contains is the input, this function can be left un-implemented and the widget's DOM node will be used instead. (For example, input-number only has the input in it, so it doesn't need to implement this).
function getGrammarTypeForPath(inputPath)
Given a path, return the kind of grammar that should be used when taking input from the user (this should be a string). As of writing, possible values are:
"number"
"expression"
this.props.onFocus(inputPath)
Should be called whenever one of the inputs is focused with the input path of the input.
this.props.onBlur(inputPath)
Should be called whenever one of the inputs is blurred with the input path of the input.
Your widgetwill be passed an apiOptions
prop from the renderer, which you can
see the format of in src/api-options.jsx. One of the apiOptions is staticRender
,
which you'll want to examine to create inputs that interacts correctly with
mobile. When the API option apiOptions.staticRender
is set to true, you should use the
MathOutput
(a static latex-displaying input that functions with the mobile math API)
inputs instead of whatever else you were using. Alternatively, you
can pass the string "tex"
as the type to an InputWithExamples
and it will
automatically do the right thing.