This repository is a collection of everything needed to create a Versal gadget. It contains:
- versal-player-api.js: Convenience library for talking to the Versal Player. It essentially wraps the postMessage API.
- versal-gadget-theme.css: Some (very) basic styles. We will expand on this the future, to provide a consistent look across gadgets.
To install all the APIs at once, you can use the new HTML Imports API. We recommend using Webcomponentsjs library as a lightweight polyfill for HTML imports.
In your gadget directory, run bower install --save versal-gadget-api webcomponentsjs
.
Then add the following to the <head>
of your your gadget's versal.html
:
<script src="bower_components/webcomponentsjs/webcomponentsjs-lite.min.js"></script>
<link rel="import" href="bower_components/versal-gadget-api/versal-gadget-api.html">
You can also install the different APIs in this repo manually. This is recommended if you're not planning on using Web Components, or want to keep the gadget's footprint as small as possible. See the documentation for the different APIs below for installation instructions.
- We have a tutorial to get you started, Gadget development tutorial, which is a nicer version of this file
- Use our SDK to create, preview, and upload your gadget: Versal/sdk
- Check out our example gadgets: Versal/hello-world-gadget, Versal/highlightr-iframe, Versal/codepen-gadget, Versal/chess-gadget
In you gadget directory, run bower install --save versal-gadget-api
Add the following to the <head>
of your gadget's versal.html
:
<script src="bower_components/versal-gadget-api/versal-player-api.js"></script>
Then instantiate the player API object:
var playerApi = new VersalPlayerAPI()
All supported messages from gadget to player are exposed as methods on the player API object.
Indicates that the gadget has subscribed to the necessary messages and is ready to start receiving them. This would be typically the first message sent by the gadget to the player.
Example: playerApi.startListening()
Assign height (in pixels) to the gadget's container.
Example: playerApi.setHeight(420)
Assign height to the gadget's container according to the current height of the gadget's body
element. It uses document.body.offsetHeight
: "For the document body object, the measurement includes total linear content height [..] Floated elements extending below other linear content are ignored."
Example: playerApi.setHeightToBodyHeight()
Create a watching timer that will refresh the gadget container's height according to the current height of the gadget's body
element. The value of the timer interval is given in milliseconds; the default value is 32.
Example: playerApi.watchBodyHeight({interval: 200})
Stop dynamically adjusting the gadget container's height.
Example: playerApi.unwatchBodyHeight()
Persist a single attribute in the gadget configuration. This function can only be called while authoring.
Example: playerApi.setAttribute('myColor', '#202020')
Persist an object containing the changed attributes in the gadget configuration. Each key/value pair at the top level of the object will be persisted. Existing persisted keys will remain untouched so only the changed attributes need to be specified (not the entire gadget configuration). This function can only be called while authoring.
Example: playerApi.setAttributes({ myColor: '#202020', myFont: 'Courier' })
Persist an object containing the gadget's current learner state. Each key/value pair at the top level of the object will be persisted. Existing persisted keys will remain untouched so only the the changed attributes need to be specified (not the entire learner state).
Example: playerApi.setLearnerState({ lastOpened: 12, lastSelected: true })
Define the gadget's property sheet.
Usage: playerApi.setPropertySheetAttributes(descriptionObject)
The argument is a object describing the attributes appearing in the property sheet.
For each attribute, we describe the attribute's name, the attribute's data type, and options specific to that data type. Example:
playerApi.setPropertySheetAttributes({
numberOfWords: { type: 'Range', min: 100, max: 500, step: 20 },
chosenAuthor: { type: 'Select',
options: ['Shakespeare', 'Hegel', 'Dickens', 'Lao Tzu']
}
})
Presently the player supports the following data types in property sheets:
Text
,Number
,TextArea
,Checkbox
,Color
,SectionHeader
: these types need no options.
Example: { type: 'TextArea' }
SectionHeader
, adds a read-only header to display the relevance of adjacent options
Example: { type: 'SectionHeader', title: 'Specific options' }
Checkboxes
,Radio
,Select
: these types take an array ofoptions
, representing the possible selection items. TheSelect
type is a drop-down listbox.
Example: { type: 'Radio', options : ['Green', 'Yellow', 'Red' ] }
-
`Date`, a date picker
Example: { type: 'Date', yearStart: 1990, yearEnd : 2038 }
-
`DateTime`, a date/time picker
Example: { type: 'Datetime', 'yearStart : 1990, yearEnd : 2038, minsInterval : 60 }
-
`Range`, a slider with a given range and step
Example: { type: 'Range', min: 100, max: 200, step: 10 }
-
`Tags`, a selection of user-supplied tags
Example of using Tags
:
{ type : 'Tags',
options: ['music', 'movies', 'study', 'family', 'pets'],
lowercase: true,
duplicates: false,
minLength: 3,
maxLength: 20,
updateAutoComplete: true
}
Update current "router state" in player.
Example: playerApi.patchRouterState({ courseId: 'course_id', lessonId: 'lesson_id', sectionId: 'section_id' })
A "router state" object describing where to send learners when they finish taking a course. The learner will be sent to the "routing state" described when they click "finish course" on the last lesson of current course.
Example: playerApi.updateFinishCourseActionRouterState({ courseId: 'course_id', lessonId: 'lesson_id', sectionId: 'section_id' })
Tell the player to show a placeholder that indicates an error.
Example: playerApi.error(new Error('Something bad happened to my gadget'))
Track events generated by the gadget. These events can be, for example, learner's progress, or statistical information about the gadget's performance.
Example: playerApi.track(name, data)
The name
specifies the kind of progress event. The data
is an object describing that progress event.
Obtain the URL for an asset held by the Versal platform.
Example: playerApi.assetUrl(assetId)
The argument is the asset's ID string.
Ask the player to show a standard dialog for uploading an asset.
Usage: playerApi.requestAsset({type: assetType, attribute: attrName}, function(assetData){...})
Possible asset types are image
and video
.
attribute
is the name of the gadget attribute in which the new asset's metadata will be stored after a successful upload. It is optional and defaults to __asset__
. This is useful if you want to store the image data or URL yourself in an attribute that is an object or array.
The callback is optional. It will be invoked after a successful upload, and is called with the same assetData
as is stored in the attribute.
Each newly uploaded asset is processed and stored on the Versal platform. The asset is described by the data structure of the form
{ id: 'xxxx',
representations: [
{
id: 'yyyy',
original: false,
contentType: 'image/png',
scale: '800x600'
},
{
id: 'zzzz',
original: true,
contentType: 'image/png',
scale: '1024x768'
},
...
]
}
This data structure will be set as the value of the gadget's configuration attribute named attrName
(which is given as a parameter in the requestAsset
call). The gadget code should select a desired representation and use its ID in the playerApi.assetUrl()
method in order to obtain the corresponding URL of the asset.
Since a successful upload will assign a new value for a gadget attribute, the gadget should expect an attributesChanged
message after the user completes the upload. If the callback argument was given in the requestAsset
call, the callback function will be also invoked with the new asset data structure as its argument.
Subscribe to messages by using the on
and off
methods, for example:
playerApi.on('message name', callback)
playerApi.off('message name', callback)
Supported message names are attributesChanged
, learnerStateChanged
, and editableChanged
.
This message indicates to the gadget that some attributes have changed their values. This message is also sent to the gadget at initialization time, that is, shortly after the gadget sends startListening
to the player. After initialization the event is fired again with the current gadget state:
- after each call to
setAttributes
- whenever the author changes an attribute via a property sheet
Example: playerApi.on('attributesChanged', function(attrs){...})
The callback receives an object containing the new attributes for the gadget. The gadget should update its visual state accordingly.
This message indicates to the gadget that some learner's state has changed. This message is also sent to the gadget at initialization time, that is, shortly after the gadget sends startListening
to the player. After initialization the event is fired again with the current learner state after each call to setLearnerState
.
Example: playerApi.on('learnerStateChanged', function(learnerState){...})
The callback receives an object containing the new learner state for the gadget. The gadget should update its visual state accordingly.
This message indicates to the gadget whether its configuration is currently being edited.
Example: playerApi.on('editableChanged', function(attrs){...})
The callback receives an object of the form {editable: true/false}
. The value of editable
describes the new editable state for the gadget. Accordingly, the gadget should switch its visual state to editing (the author's view) or to the learner's view.
Add to the <head>
of your gadget's versal.html
:
<link rel="stylesheet" href="bower_components/versal-gadget-api/versal-gadget-theme.css">
See styleguide.html for some basic examples. Note that this is very much work in progress.
To work on the CSS, just open styleguide.html locally in a web browser.
The JS APIs are developed using test-driven development. First run npm install
, and then run karma start
. Karma will run the tests whenever a file changes. You can also run the tests just once, using npm test
.
npm run build
git commit -am'Build for release'
bower version patch
git push origin master --tags