JavaScript API version 12
- Changelog
- Usage
- Methods
- getVersion
- getUserInfo
- getDeviceInfo
- hasFeature
- trackEvent
- share
- getAssetPreviewUrl
- getAssetsByTags
- getAssetsInFolder
- getAssetsByQuery
- getAssetFileUrl
- getCollections
- openCollection
- createCollection
- addAssetsToCollection
- addAssetsToCollections
- addAssetsToCollectionWithId
- clearCollection
- addAssetsToSharedSpace
- addAssetsToSharedSpaces
- getShowpadApi
- refreshShowpadApi
- getSalesforceApi
- refreshSalesforceApi
- upload
- displayModal
- displayToast
- getCoursesByIds
- AppsDB
Changelog
Added: - Retrieve a summary for one or more courses ShowpadLib.getCoursesByIds()
.
Usage
The methods listed below are all available on the window.ShowpadLib
object after page load.
Simply call the desired method with the correct parameters.
When window.ShowpadLib
is created and ready to go, the method window.onShowpadLibLoaded()
will be called (if it exists).
Have a look at the examples to get some more context.
Methods
All methods returning a boolean
will return true
when the call was executed successfully and return false
when something went wrong.
The method returns false
when a required parameter was not set or when the method was called again before the previous method was completed.
Some methods return full objects or single values like getUserInfo()
, upload()
or getVersion()
getVersion
Returns the version of the integration. If this function does not exist, we can assume that version 2 is available.
let version = null;
if (typeof window.ShowpadLib.getVersion === 'function') {
version = window.ShowpadLib.getVersion();
}
else {
version = 2;
}
getUserInfo
Returns the information of the active user.
const userInfo = window.ShowpadLib.getUserInfo();
// userInfo will look like this:
const userInfo = {
email: 'user@company.com',
id: '123',
user_name: 'user@company.com',
full_name: 'Firstname Lastname'
};
getDeviceInfo
Returns the information of the current device.
The locale
value is a 2-letter code following the ISO 639-1 standard.
The app
is one of the following values: web
, ios
, android
, windows
. It represents the app where this HTML Content is currently being viewed.
The version
is a version code for the app where this HTML content is being viewed.
const deviceInfo = window.ShowpadLib.getDeviceInfo();
// deviceInfo will look like this:
const deviceInfo = {
locale: 'en', // language of the device, following ISO 639-1
app: 'web', // the app,
version: '2' // the app version
};
hasFeature
Use this method to know if a specific feature is supported on the app your content is running in.
This method will (synchronously) return:
true
if the feature is supported.false
if the feature is known to the app but not supported.null
if the feature is unknown to this version of the application.
The list of features can be found in the table below.
Key | Description |
---|---|
shareEmail | Share content by sending an email. Useful in combination with the share() method |
shareLink | Share content by generating a link. Useful in combination with the share() method |
collections | Add content to a Collection. Useful in combination with the addAssetsToCollection() method |
collections | Add content to multiple Collections. Useful in combination with the addAssetsToCollections() method |
sharedSpaces | Add content to a Shared Space. Useful in combination with the addAssetsToSharedSpace() method |
sharedSpaces | Add content to multiple Shared Space. Useful in combination with the addAssetsToSharedSpaces() method |
if (window.ShowpadLib.hasFeature('shareLink')) {
// The feature "shareLink" is supported on this platform.
}
trackEvent
Track an event in your Experience App. This is used to track how conversations are happening within the experience. The events currently aren’t visualized in the Online-Platform but can be exported through Showpad’s Export API.
The method accepts a single event or an array of events. The order of the array is the order they are tracked in. In principle there are no constraints on the event format, but we recommend to adhere to the formats as shown in the example below, for compatibility with potential future reporting:
type
is the type of the item that is touched by the user. This is probably different per experience.- For the Atom, an example is
node-node
. - For custom experiences we recommend following 2 types:
pageview
for tracking navigation (jumping from page X to Y) andevent
for tracking interactions not related with navigation (i.e. a slider or input field).
- For the Atom, an example is
touchpoint.id
is the unique id for this touch point. This should never change, not even across versions.touchpoint.name
is the current name of this touch point. This can change over time. The last send name will be shown in the analytics.touchpoint.sourceId
is the id of the page the user is currently on.touchpoint.sourceName
is the name of the page the user is currently on.touchpoint.destinationId
is the id of the page this touch point is linking to. Omit if not used.touchpoint.destinationName
is the current name of the page this touch point is linking to. Omit if not used.touchpoint.fields.pageviewDepth
is a path representing the depth of the page.touchpoint.fields.pageviewType
is an indication of how the page is displayed.touchpoint.fields.eventCategory
is a reference to the type of object that was interacted with, i.e. a video.touchpoint.fields.eventAction
is a reference to the action on the object i.e. play a video.touchpoint.fields.eventLabel
is useful for categorizing events.touchpoint.fields.eventValue
: is a numeric value associated with the event.
// PAGEVIEW
const pageview = {
"type": "pageview",
"touchpoint": {
"id": "eventID",
"name": "Event name",
"sourceId": "pageID",
"sourceName": "Page name",
"destinationId": "pageID",
"destinationName": "Page name",
"fields": {
"pageviewDepth": "category A/item B/detail C", // Path representing the depth of the page (in this example, you could compare on category level, item level and detail level)
"pageviewType": "tab" // How the page is displayed (page, tab, slide, ...)
}
}
};
// EVENT
const event = {
"type": "event",
"touchpoint": {
"id": "eventID",
"name": "Event name",
"sourceId": "pageID",
"sourceName": "Page name",
"fields": {
"eventCategory": "Video", // The object that was interacted with
"eventAction": "play", // The type of interaction
"eventLabel": "Fall Campaign", // Useful for categorizing events
"eventValue": 42 // A numeric value associated with the event
}
}
};
ShowpadLib.trackEvent(event); // Track a single event
ShowpadLib.trackEvent([event, pageview]); // Track multiple events
share
Shows a modal view to share contents. The provided assets will be added so they can be shared.
The type of the modal is either email
or link
.
If some of the assets are not shareable (expired, deleted, unshareable, …), the modal will still be shown, but the callback function will be called with result partial
. In this case, the Showpad client will show a warning message to the user that some content cannot be shared.
If none of the provided assets can be shared, a warning will be shown, but no sharing modal will be displayed and the result will be error
const assetSlugs = ['asset1-slug','asset2-slug'];
const type = 'email'; // Can be 'email' or 'link'.
if (window.ShowpadLib.share(type, assetSlugs, callbackFn)) {
// Call went through, callbackFn will be called.
}
else {
// Something went wrong or the given type is not supported on this app.
}
function callbackFn (result) {
if (result == 'success') {
// all assets were added to the share dialog and the dialog is shown
}
else if (result == 'partial') {
// some assets were not added to the share dialog, because they could be expired, unshareable, deleted, ...
// the share-dialog is shown
}
else if (result == 'error') {
// no assets were added and the dialog is NOT shown
}
else {
// null was returned, something went wrong
}
}
getAssetPreviewUrl
Returns the url with which the asset preview image can be loaded. The assetId is always required. The assetSlug is also required on mobile.
assetId
is the actual asset-id, eg. “74d51a49c063fdf8a4ef6c5be4c032fc”assetSlug
is the last part of theappLink
, eg. ‘18c6236ced7d’ in ‘showpad://file/18c6236ced7d’. You can find this in the Online-Platform or retrieve it via our API.size
is the maximum dimension for the width or height.
const assetId = 'asset1-id';
const assetSlug = 'asset1-slug';
const size = 400;
const imageEl = document.getElementById('image');
imageEl.src = ShowpadLib.getAssetPreviewUrl(assetId, assetSlug, size);
// The asset preview image should now be loaded in the image element.
Sizes
From and including: iOS 6.5, Windows v1.6.12
-
When there’s a custom icon, the original custom icon image will be returned
-
When no size is given => a small preview image suitable for icons will be returned (max size 480px)
-
When a size parameter is given:
- if the size is larger than 500px AND the file is an image, the full-size image will be returned, otherwise the same preview will be returned as if size is not passed
For all Android versions and before iOS 6.5, Windows v1.6.12
- The small preview image is always returned. (max size 480px)
getAssetsByTags
Invokes the callback function with a list of assets that have all the given tags. This function works offline.
tags
is an array of case-sensitive tag names you want to search for. The resulting assets should have all of the tags.
const tags = ['Tag 1','screen-15','nl'];
if (ShowpadLib.getAssetsByTags(tags, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (assets) {
if (assets) {
// Assets might look like this:
const assets = [
{
"id": "abc123", // Local id to the device
"slug": "bdfklje739v930g0d",
"name": "my_brochure.pdf",
"displayName": "My Brochure fo 2017.pdf",
"type": "document",
"description": "A description", // Can be null
"permissions": {
"share": true, // File can be shared
"annotate": true, // File can be annotated
"download": true // File can be downloaded
},
"tags": ["Tag 1","screen-15","nl"],
"previewUrl" : "https://endpoint/asset/abc123/preview", // Same as response from getAssetPreviewUrl
},
...
];
}
else {
// null was returned, something went wrong
}
}
getAssetsInFolder
Invokes the callback function with a list of assets that can be found in the given folder. This function works offline.
folder
is a string that is the last part of the folder app link, eg.xyz2250
inshowpad://folder/xyz2250
.
Note: this will not work recursively and will only return actual assets. So it doesn’t return values from deeper levels nor will it return folders.
const folder = 'xyz2250'; // last part from showpad://folder/xyz2250, this can be the id or slug.
if (ShowpadLib.getAssetsInFolder(folder, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (assets) {
if (assets) {
// Assets might look like this:
const assets = [
{
"id": "abc123", // Local id to the device
"slug": "bdfklje739v930g0d",
"name": "my_brochure.pdf",
"displayName": "My Brochure fo 2017.pdf",
"type": "document",
"description": "A description", // Can be null
"permissions": {
"share": true, // File can be shared
"annotate": true, // File can be annotated
"download": true // File can be downloaded
},
"tags": ["Tag 1","screen-13"],
"previewUrl" : "https://endpoint/asset/abc123/preview", // Same as response from getAssetPreviewUrl
},
...
];
}
else {
// null was returned, something went wrong
}
}
getAssetsByQuery
Invokes the callback function with a list of assets that match with the given query. This function works offline and thus cannot search within documents.
query
is a string that we’ll look for in the assets. This would translate to something like “… WHERE displayName LIKE ‘%{query}%’”.
const query = 'onepager';
if (ShowpadLib.getAssetsByQuery(query, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (assets) {
if (assets) {
// Assets might look like this:
const assets = [
{
"id": "abc123", // Local id to the device
"slug": "bdfklje739v930g0d",
"name": "featured_product_onepager.pdf",
"displayName": "My Brochure fo 2017.pdf",
"type": "document",
"description": "A description", // Can be null
"permissions": {
"share": true, // File can be shared
"annotate": true, // File can be annotated
"download": true // File can be downloaded
},
"tags": ["Tag 1","screen-15","nl"],
"previewUrl" : "https://endpoint/asset/abc123/preview", // Same as response from getAssetPreviewUrl
},
...
];
}
else {
// null was returned, something went wrong
}
}
getAssetFileUrl
Returns the url with which the asset file (the video, image, pdf,…) can be fetched. The assetId is always required. The assetSlug is also required on mobile.
assetId
is the actual asset-id, eg. “74d51a49c063fdf8a4ef6c5be4c032fc”assetSlug
is the last part of theappLink
, eg. ‘18c6236ced7d’ in ‘showpad://file/18c6236ced7d’. You can find this in the Online-Platform or retrieve it via our API.
const assetId = 'asset1-id';
const assetSlug = 'asset1-slug';
const videoEl = document.getElementById('video');
videoEl.src = ShowpadLib.getAssetFileUrl(assetId, assetSlug);
// The asset data should now be loaded in the video element.
getCollections
Invokes the callback function with a list of Collection data ([{ id, name }]
) or null
when something went wrong.
if (window.ShowpadLib.getCollections(callbackFn)) {
// Call went through, callbackFn will be called.
}
else {
// Something went wrong
}
function callbackFn (collections) {
if (collections) {
// Collections might look like this:
const collections = [
{
id: '1',
name: 'Collection Name 1',
},
{
id: '2',
name: 'Collection Name 2'
}
];
}
else {
// null was returned, something went wrong
}
}
openCollection
Shows a modal view with the contents of the Collection. This view allows for the Collection to be shared
const collectionId = '...' ;
if (window.ShowpadLib.openCollection(collectionId)) {
// Modal will be opened
}
else {
// Something went wrong
}
createCollection
Creates a new Collection with the specified name, will invoke the callback function with the id of the new Collection or null
when an error occured
const name = 'My Collection Name';
if (window.ShowpadLib.createCollection(name, callbackFn)) {
// Call went through, callbackFn will be called.
}
else {
// Something went wrong
}
function callbackFn (collectionId: string | null) {
if (collectionId) {
// Do something with collection id
}
else {
// Something went wrong
}
}
addAssetsToCollection
Shows the modal which prompts the user the select the Collection to add the assets to.
Will call the callback method with the id of the Collection the assets were added to or null
if the flow was canceled or an error occured
const assetSlugs = [];
assetSlugs.push('asset1-slug');
assetSlugs.push('asset2-slug');
if (window.ShowpadLib.addAssetsToCollection(assetSlugs, callbackFn)) {
// Call went through, modal will be shown.
// callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (collectionId: string | null) {
if (collectionId) {
// Assets were added to the collection with provided collectionId
}
else {
// Something went wrong or the user canceled the flow or
// none of the given asset-slugs were found.
}
}
addAssetsToCollections
Shows the modal which prompts the user the select Collections to add the assets to.
The provided callback method accepts 2 parameters. The first parameter is an error if something occured or null
in case of success. The second paramter is a list of ids of the Collections that assets where added to.
const assetSlugs = [];
assetSlugs.push("asset1-slug");
assetSlugs.push("asset2-slug");
if (window.ShowpadLib.addAssetsToCollections(assetSlugs, callbackFn)) {
// Call went through, modal will be shown.
// callbackFn will be called
} else {
// Something went wrong
}
function callbackFn(error: Error | null, collectionIds?: string[]) {
if (error === null) {
// Assets were added to the Collections with provided collectionIds
} else {
// Something went wrong or the user canceled the flow or none of the given asset-slugs were found.
// error will contain an error with more information.
}
}
addAssetsToCollectionWithId
Will add the given assets to the Collection with the given id. If the Collection does not exist, nothing will happen.
const collectionId = '...';
const assetSlugs = ['asset1-slug', 'asset2-slug'];
if (window.ShowpadLib.addAssetsToCollectionWithId(collectionId, assetSlugs, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (collectionId: string | null) {
if (collectionId) {
// Assets were added to the collection with provided collectionId
}
else {
// Something went wrong or the user canceled the flow
}
}
clearCollection
Removes all the items from the given Collection
const collectionId = '...';
if (window.ShowpadLib.clearCollection(collectionId)) {
// Call went through, items will be cleared
}
else {
// Something went wrong
}
addAssetsToSharedSpace
Shows the modal which prompts the user to select the Shared Space to add the assets to.
Will call the callback method with the id of the Shared Space the assets were added to or null
if the flow was canceled or an error occured
const assetSlugs = [];
assetSlugs.push('asset1-slug');
assetSlugs.push('asset2-slug');
if (window.ShowpadLib.addAssetsToSharedSpace(assetSlugs, callbackFn)) {
// Call went through, modal will be shown.
// callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (sharedSpaceId: string | null) {
if (sharedSpaceId) {
// Assets were added to the Shared Space with provided sharedSpaceId
}
else {
// Something went wrong or the user canceled the flow or
// none of the given asset-slugs were found.
}
}
addAssetsToSharedSpaces
Shows the modal which prompts the user to select multiple Shared Space to add the assets to.
The provided callback method accepts 2 parameters. The first parameter is an error if something occured or null
in case of success. The second paramter is a list of ids of the Shared Spaces that assets where added to.
const assetSlugs = [];
assetSlugs.push('asset1-slug');
assetSlugs.push('asset2-slug');
if (window.ShowpadLib.addAssetsToSharedSpaces(assetSlugs, callbackFn)) {
// Call went through, modal will be shown.
// callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (error: Error | null, sharedSpaceIds?: string[]) {
if (error === null) {
// Assets were added to the Shared Spaces with provided sharedSpaceIds
}
else {
// Something went wrong or the user canceled the flow or none of the given asset-slugs were found.
// error will contain an error with more information.
}
}
getShowpadApi
Invokes the callback function with an object with the required information to do an HTTP request to the Showpad API.
If the Showpad API returns a 401, it means your access token has expired, and you’ll need to request a new one.
Do this using the refreshShowpadApi()
method.
if (window.ShowpadLib.getShowpadApi(callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (apiConfig) {
if (apiConfig) {
// apiConfig can look like this:
const apiConfig = {
accessToken: 'xyz',
url: 'https://subdomain.showpad.biz', // no trailing slash
error: null // or a string with the actual error
};
if (apiConfig.accessToken && apiConfig.url) {
// Do an api-call
}
else if (apiConfig.error) {
if (apiConfig.error === 'unavailable') {
// no api key available
}
else {
// something else went wrong
}
}
else {
// Something went wrong
}
}
else {
// Something went wrong or the user canceled the flow
}
}
refreshShowpadApi
This method will refresh the Showpad access token and call the callback function with the same object as the getShowpadApi
call
function doApiCall (url, config) {
fetch(url, config)
.then(response => {
if (response.status < 200 || response.status >= 400) {
const error = new Error();
error.statusCode = response.status;
throw error;
}
})
.catch(onApiCallFailed);
}
function onApiCallFailed (error) {
if (error.statusCode === 401) {
// Unauthorized, let's refresh the token
refreshToken(url, config);
}
}
function refreshToken (url, config) {
if (window.ShowpadLib.refreshShowpadApi(apiConfig => {})) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (apiConfig) {
if (apiConfig) {
// apiConfig can look like this:
const apiConfig = {
accessToken: 'xyz',
url: 'https://subdomain.showpad.biz', // no trailing slash
error: null // or a string with the actual error
};
if (apiConfig.accessToken && apiConfig.url) {
// Refresh succeeded, retry the failed call.
config.headers['Authorization'] = `Bearer ${apiConfig.accessToken}`;
doApiCall(url, config);
}
else if (apiConfig.error) {
if (apiConfig.error === 'unavailable') {
// no api key available
}
else if (apiConfig.error === 'expired') {
// Refresh Token has expired, no further calls can be made.
}
else {
// Something went wrong
}
}
else {
// Something went wrong
}
}
else {
// Something went wrong
}
}
}
getSalesforceApi
Invokes the callback function with an object with the required information to do an HTTP request to the Salesforce API.
If the Salesforce API returns a 401, it means your access token has expired, and you’ll need to request a new one.
Do this using the refreshSalesforceApi()
method.
if (window.ShowpadLib.getSalesforceApi(callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (apiConfig) {
if (apiConfig) {
// apiConfig can look like this:
const apiConfig = {
accessToken: 'xyz',
url: 'https://login.salesforce.com', // no trailing slash
error: null // or a string with the actual error
};
if (apiConfig.accessToken && apiConfig.url) {
// Do an api-call to Salesforce
}
else if (apiConfig.error) {
if (apiConfig.error === 'unavailable') {
// no Salesforce access token available
// Possibly, the user is not connected to Salesforce.
}
else {
// something else went wrong
}
}
else {
// Something went wrong
}
}
else {
// Something went wrong or the user canceled the flow
}
}
Particularities with the Salesforce API and HTML Content
To call an api on a different domain (eg. “https://login.salesforce.com”), that service needs to have CORS enabled. More info about CORS or (Cross-Origin Resource Sharing) can be found here .
Salesforce has a specific settings-page to enable specific domains for your Salesforce instance. Salesforce requires this to be an “https://”-url. The problem is that your HTML Content is also rendered in our mobile apps, and they don’t use an “https://”-scheme, but something specific for the platform (eg. “ms-appx-package://” on Windows).
So calling the Salesforce API directly from your HTML Content, will probably result in a CORS error by Salesforce.
To circumvent this, we suggest to proxy all api-calls to Salesforce through an iframe. This iframe would link to a webpage hosted on a CORS-enabled domain. The javascript in the HTML Content would just call some javascript in that iframe, which would send it through to Salesforce and send the response back. The communication between the HTML Content and the iframe needs to happen with “postMessage” https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage.
The diagram below might make things more clear.
refreshSalesforceApi
This method will refresh the Salesforce access token and call the callback function with the same object as the getSalesforceApi
call.
function doSalesforceApiCall (url, config) {
fetch(url, config)
.then(response => {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error();
error.statusCode = response.status;
throw error;
})
.catch(onSalesforceApiCallFailed);
}
function onSalesforceApiCallFailed (error) {
if (error.statusCode === 401) {
// Unauthorized, let's refresh the token
refreshSalesforceToken(url, config);
}
}
function refreshSalesforceToken (url, config) {
if (window.ShowpadLib.refreshSalesforceApi(apiConfig => {})) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (apiConfig) {
if (apiConfig) {
// apiConfig can look like this:
const apiConfig = {
accessToken: 'xyz',
url: 'https://login.salesforce.com', // no trailing slash
error: null // or a string with the actual error
};
if (apiConfig.accessToken && apiConfig.url) {
// Refresh succeeded, retry the failed call.
config.headers['Authorization'] = `Bearer ${apiConfig.accessToken}`;
doApiCall(url, config);
}
else if (apiConfig.error) {
if (apiConfig.error === 'unavailable') {
// no Salesforce access token available
}
else if (apiConfig.error === 'expired') {
// Salesforce Refresh Token has expired, no further calls can be made.
}
else {
// Something went wrong
}
}
else {
// Something went wrong
}
}
else {
// Something went wrong
}
}
}
upload
Uploads a single file to “My files”. Returns an EventEmitter which emits the upload status.
A file can be a File
object or an ArrayBuffer
object.
const filename = 'filename.txt';
const file = new File(['file contents'], filename);
const upload = {
file: file,
filename: filename
};
const statusEmitter = window.ShowpadLib.upload(upload);
The EventEmitter will emit seperate events for each specific type of progress the upload goes through.
Events
queued
Emitted when the host received the upload but has not yet started the upload.
Fires once
statusEmitter.on('queued', () => {
// Do something when the upload is queued
});
uploading
Emitted when the upload has progressed and reports on the amount of bytes sent.
Can fire multiple times
statusEmitter.on('uploading', (data) => {
// Do something when uploading
});
with the data object containing
data = {
bytesTotal: 1000, // The total number of bytes to upload
bytesSent: 500 // The number of bytes uploaded
}
processing
The upload is succesfully transferred to the server and the file is now being processed.
Fires once
statusEmitter.on('processing', () => {
// Do something when processing
});
success
The upload has been successfully uploaded and is processed.
Fires once
statusEmitter.on('success', (data) => {
// Do something when the upload succeeded
});
With the object containing
data = {
asset: {
"id": "abc123",
"slug": "bdfklje739v930g0d",
"name": "my_brochure.pdf",
"displayName": "My Brochure fo 2017.pdf",
"type": "document",
"description": "A description",
"permissions": {
"share": true,
"annotate": true,
"download": true
},
"tags": ["Tag 1","screen-15","nl"],
"previewUrl" : "https://endpoint/asset/abc123/preview"
}
}
failed
At some point the upload failed.
Fires once
statusEmitter.on('failed', (error) => {
// Do something when upload failed
});
with the error object containing
error = {
reason: "A wrong filetype was submitted"
}
displayModal
displays a native modal with a title, text and clickable buttons.
title
to specify a title for the modal
text
the text contents displayed in the modal
buttons
an array of buttons to display
A button must have 2 fields named reason
and text
and possibly one optional field called tinted
reason
is a text field that is passed back in the callback whenever a buttons is clicked.
text
is the text to display on the button
tinted
is an optional parameter. When set to true the button has a distinctive seperate color
window.ShowpadLib.displayModal({
title: "The modal title",
text: "The modal text",
buttons: [
{reason: 'cancel', text: 'Cancel'},
{reason: 'ok', text: 'OK', tinted: true}
...
]
}, (reason) => {
// Modal closed with reason
});
displayToast
Display a native toast
text
is the text to be displayed in the toast
actionText
the text to be used on the action button
type
must be one of info|success|error
.
Depending on the type the toast color will be blue|green|red
.
window.ShowpadLib.displayToast({
type: "info",
text: "The text displayed in the toast",
actionText: "click me",
}, (reason) => {
// Toast has been closed with reason
});
reason can be timeout
or clicked
depending if the user clicked before a timeout occured.
getCoursesByIds
Invokes the callback function with a list of course summaries that match with the given courseIds.
const courseIds = [
"A943324A8E9A405CA95C5DF55E4BD71A",
"182D49E57B534C84B7431D55483400C4"
];
ShowpadLib.getCoursesByIds(courseIds, callbackFn);
function callbackFn (error, courseSummaries) {
if (error) {
// Error occured, handle it
}
else {
// Response might look like this:
const courses = [
{
"assignment": {
"assignedAt": "2020-01-01T01:01:01.001Z",
"dueAt": "2020-01-01T01:01:01.001Z",
"status": "REQUIRED"
},
"course": {
"description": "asfadsf",
"id": "0A5098512C5042CDB794BF1D1E6053AC",
"owner": {
"firstName": "Ruth",
"id": "15b582a012674557a1f69d455f69bb17",
"lastName": "Elliott"
},
"thumbnail": {
"assetId": "9069c2760c08efecef3eaf799a610cb5",
"checksum": "159657c3ecd1c01a8af41cda9b03384b",
"offsetX": 0.5,
"offsetY": 0.5,
"url": "https://example.showpad.biz/api/v3/assets/2d5d23fc8cef6da5ffea2613a8382c29/preview/v1"
},
"title": "Example Course"
},
"courseLinkUrl": "/webapp2/courses/0A5098512C5042CDB794BF1D1E6053AC",
"isBookmarked": true,
"prerequisite": {
"assignment": {
"assignedAt": "2022-10-11T20:42:32.000Z"
},
"course": {
"id": "F4B00C314A914267A04E648F8144F4BA",
"title": "An Example Pre"
},
"progress": {
"completedAt": "2022-10-12T10:35:28.000Z"
}
},
"progress": {
"completedAt": "2020-01-01T01:01:01.001Z",
"lastActivityAt": "2020-01-01T01:01:01.001Z",
"isOptedIn": true,
"remainingAttempts": 3,
"startedAt": "2020-01-01T01:01:01.001Z",
"timeRemainingInSeconds": 80
}
},
...
];
}
}
AppsDB
Prerequisites
Create a store
Before being able to use an AppsDB store you first have to create it using our REST API. You can find the documentation on how to do that here.
Device Time
Syncing data to our mobile apps relies on a correct device time. If the device time does not match the actual time, data might be synced out of order or be blocked. When this occurs, the apps will try to sync again at a later point in time.
getStoreEntryValue
Retrieve a value from a store entry.
const store = 'my-store';
const entryId = 'my-key';
if (ShowpadLib.getStoreEntryValue(store, entryId, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (value) {
if (value) {
console.log(value);
}
else {
// null was returned, something went wrong
}
}
getGlobalStoreEntryValue
Retrieve a value from a global store entry.
const store = 'my-store';
const entryId = 'my-key';
if (ShowpadLib.getGlobalStoreEntryValue(store, entryId, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (value) {
if (value) {
console.log(value);
}
else {
// null was returned, something went wrong
}
}
setStoreEntryValue
Set a value on a store entry. The callback is optional.
const store = 'my-store';
const entryId = 'my-key';
const value = 'entry-value';
if (ShowpadLib.setStoreEntryValue(store, entryId, value, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (value) {
if (value) {
console.log(value);
}
else {
// null was returned, something went wrong.
}
}
deleteStoreEntry
Delete store entry. The callback is optional.
const store = 'my-store';
const entryId = 'my-key';
if (ShowpadLib.deleteStoreEntry(store, entryId, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (success) {
if (success) {
console.log("Delete succeeded");
}
else {
// null was returned, something went wrong.
}
}
getStoreEntries
Get all entries from a store. The results from this call are paginated.
const store = 'store-name';
if (ShowpadLib.getStoreEntries(store, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (paginatedEntries) {
if (paginatedEntries) {
console.log(paginatedEntries);
}
else {
// null was returned, something went wrong.
}
}
With an entry list returned of following structure
{
cursor: "optional-cursor-string", // See the "getStoreEntries and getGlobalStoreEntries pagination" section for more information about this.
entries: [
{
id: "entry-key-1",
storeId: "my-store-id",
value: "entry-value-1"
},
{
id: "entry-key-2",
storeId: "my-store-id",
value: "entry-value-2"
},
...
]
}
getGlobalStoreEntries
Get all global entries from a store. The results from this call are paginated.
const store = 'store-name';
if (ShowpadLib.getGlobalStoreEntries(store, callbackFn)) {
// Call went through, callbackFn will be called
}
else {
// Something went wrong
}
function callbackFn (paginatedEntries) {
if (paginatedEntries) {
console.log(paginatedEntries);
}
else {
// null was returned, something went wrong.
}
}
With an entry list returned of following structure
{
cursor: "optional-cursor-string", // See the "getStoreEntries and getGlobalStoreEntries pagination" section for more information about this.
entries: [
{
id: "entry-key-1",
storeId: "my-store-id",
value: "entry-value-1"
},
{
id: "entry-key-2",
storeId: "my-store-id",
value: "entry-value-2"
},
...
]
}
getStoreEntries and getGlobalStoreEntries pagination
Both getStoreEntries() and getGlobalStoreEntries() calls are paginated.
Meaning whenever the requested entry-list has too many entries(limit) or is too large(>1MB) to be returned in one go, the function will return a cursor-string that can be passed to a subsequent call to get the remainder of the entries.
Example: paginated getStoreEntries() call with cursor
// entryList returned in a previous getStoreEntries() request
entryList = {
cursor: 'example-cursor-string',
entries: [...]
};
// Pagination object
const pagination = {
cursor: entryList.cursor
};
ShowpadLib.getStoreEntries(store, pagination, callbackFn)
In the above example the entryList
represents the entry-list returned in a previous call that had more entries than could be returned in one go.
To get the next page of entries we do a second call passing in the cursor to indicate we want all entries after the already retrieved entry-list;
When dealing with very large entry-lists (multiple MB or thousands of entries) it is possible multiple calls are needed to get all the data in store.
Inversely when dealing with a large amount of small entries, you can set a limit on the maximum entries to be returned at once.
// Pagination object
const pagination = {
limit: 100
};
ShowpadLib.getStoreEntries(store, pagination, callbackFn)
In the above example we limit our output to a maximum of 100 entries.
When there are more than 100 entries to be returned or if the dataset is too large(>1MB), a cursor will be returned that can be used to fetch the next 100 entries.
Helper function to retrieve all entries from a store
When you simply want to fetch all entries from a store, you can make use of the following helper function.
function getAllStoreEntries(storeId, callbackFn, cursor) {
const pagination = { cursor: cursor };
ShowpadLib.getStoreEntries(storeId, pagination,
function getStoreEntriesCallback(entryList) {
let allEntries = entryList.entries;
if (entryList.cursor) {
getAllStoreEntries(storeId, function (entries) {
allEntries = allEntries.concat(entries);
callbackFn(allEntries);
}, entryList.cursor)
} else {
callbackFn(allEntries);
}
}
);
}
const store = 'store-name';
getAllStoreEntries(store, function (entries) {
console.log('all entries', entries);
});