Labs.js JavaScript API for Office Mix - Preview

Labs.js is an API that allows applications (also known as labs) to integrate with an Office Mix lesson. By writing against the API an application can easily be run within the PowerPoint authoring tool as well as in the online lesson player. It is designed to be a lightweight API that is simple and can easily be plugged in to existing applications. The underlying core is also designed to be run across multiple platforms. All a platform needs is to implement the underlying driver interfaces and any app targeted towards Labs.js will run on it.

This guide is divided into the following sections:

Files in the SDK

There are a handfull of files included in the SDK for labs.js development

Examples

The following provides a brief list of existing labs created for Office Mix using labs.js.

Getting help

For help, feature requests, comments, issues, etc... don't hesitate to send mail to labsjs@microsoft.com

Data Sharing

You can configure the Labs.js JavaScript API for Office Mix to share information with Microsoft about how a user interacts with your app, such as whether the app loaded successfully, any content that is displayed to the user in your app, and any information the user enters in your app. Microsoft may combine this information with other information to provide the Office Mix service in accordance with the statement on Privacy & Cookies for Office Mix. If you configure the API in this way, we require (and you agree) that you will include a notice to this effect in the privacy terms for your app as follows:

This app for Office will share information with Microsoft about how you interact with it, such as whether the app loaded successfully, any content that is displayed to you in the app, and any information you enter in the app. Microsoft may combine this information with other information to provide the Office Mix service in accordance with the statement on Privacy & Cookies for Office Mix. By using this app, you consent to the app sharing information with Microsoft for this purpose.

The following sections describes the steps necessary for doing Labs.js development.

Office Mix utilizes Apps for Office in order to integrate interactive content within a PowerPoint slide deck. To lab developers the details of Office.js, the API for Apps for Office, are abstracted behind the labs.js API. But in order to develop an Office Mix application you will need to set yourself up as an Apps for Office developer.

Register for an Office 365 Developer Site

The first step is to register for an Office 365 developer site. This will give you a place where you can host your applications prior to submitting them to the store for approval. Also, hosting on a developer site will allow you to publish any of these apps to Office Mix and try it out in our live environment.

Instructions on how to do this can be found by visiting this link: http://msdn.microsoft.com/library/office/fp179924(v=office.15)

You only need to follow the first two steps. Making use of "Napa" is optional. Once you create your site it will be provisioned. Once SharePoint has been provisioned you can move on to the next step. Note that it can take a bit of time to fully provision your developer site.

Set up an app catalog on SharePoint Online

The next step is to set up an app catalog on SharePoint Online. An app catalog is used to host apps specific to an individual organization. For Office Mix we make use of an app catalog to be able to insert pre-production apps into a lesson and test it out end to end prior to submitting the app to the store.

Instructions on this process can be found here: http://msdn.microsoft.com/en-us/library/1d50a571-6e02-4bc0-a3d6-6ef1eca3c2ce(Office.1501401)

Create your application manifest

The application manifest is an XML document that describes your lab app. It contains a URL reference to where the app is hosted as well as various details about it. These include display name, description, icons, default starting size, etc... A sample manifest is contained below.

The SDK also comes with a sample manifest: SampleManifest.xml. You can also navigate to http://msdn.microsoft.com/en-us/library/office/fp161044(v=office.15).aspx to find more detailed information about the schema as well as a link to the schema definition.

Sample manifest

<?xml version="1.0" encoding="utf-8"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ContentApp">
  <Id>[GUID in the form EDA37F5A-13F1-4CB6-BA6A-4B2D2ED0A783]</Id>
  <Version>[Version in the form 1.0.0.0]</Version>
  <ProviderName>[Provider Name]</ProviderName>
  <DefaultLocale>en-US</DefaultLocale>
  <DisplayName DefaultValue="[Display Name]">
  </DisplayName>
  <Description DefaultValue="[Description]">
  </Description>
  <IconUrl DefaultValue="[32x32px icon URL]">
  </IconUrl>
  <HighResolutionIconUrl DefaultValue="[96x96px icon URL]">
  </HighResolutionIconUrl>
  <SupportUrl DefaultValue="[Support URL]"></SupportUrl>
  <Hosts>
    <Host Name="Presentation"/>
  </Hosts>  
  <DefaultSettings>
    <SourceLocation DefaultValue="[URL to application]"></SourceLocation>
    <!-- Max values for the below is 1000px -->
    <RequestedWidth>960</RequestedWidth> 
    <RequestedHeight>540</RequestedHeight>
  </DefaultSettings>
  <Permissions>Restricted</Permissions>
  <!-- Whether to take an application snapshot as a preview. Need to be careful if this could expose information that should be no shown (i.e. the answer) -->
  <AllowSnapshot>true</AllowSnapshot>
</OfficeApp>

Upload your application manifest to your SharePoint site

Once you have an app catalog created and have your first manifest you are now ready to submit your application to your catalog. Navigate to your application catalog (usually https://[your site]/sites/AppCatalog). Then click on the "new app" button and follow the steps to upload your application manifest. Once this succeeds your catalog now contains your newly submitted app.

Update your PowerPoint app catalog and log in with your developer account

These instructions can also be found at the beginning of the document referenced above about setting up an app catalog (http://msdn.microsoft.com/en-us/library/1d50a571-6e02-4bc0-a3d6-6ef1eca3c2ce(Office.1501401))

Open up PowerPoint and then navigate to: File > Options > Trust Center > Trust Center Settings > Trusted App Catalogs.

From here add a reference to your app catalog. Click OK and PowerPoint will ask you to sign out for the changes to take place. Do this.

The last step then is to log in under the developer account. In the upper-right corner of PowerPoint you will see your login name. Click on this and log in under your developer account. You are now all ready to insert your app.

Insert your app

After you've changed the app catalog, restarted PowerPoint for the change to take affect, and changed your login name you are now ready to insert an application.

To do so click on the Insert ribbon item. Then find Store in the Apps section. Click on this button to open the "Apps for Office" dialog. Now click on My Organization and you should see the apps in your app catalog. Now simply click on whichever one you want, choose insert, and your app will be inserted within the PowerPoint document.

Publish and View

You can now make use of all the usual Office Mix functionality to publish your lesson with your new app.

Note however when you go to view the application you will need to log in to your SharePoint catalog with the same browser that you view your lesson from. SharePoint catalogs only allow access from authenticated users and so in order to see your application you need to log in first. That way when the app attempts to contact the catalog to determine its manifest it can load.

Submit to Office Store

Publishing instructions are available here: http://msdn.microsoft.com/en-US/office/dn448457#publish. You will need to follow the instructions in the "Publish your app to the Office Store" section.

Note that a current limitation of the store is that only one login account be used to submit apps. For cases when access needs to be shared amongst multiple people the recomendation is to create a shared account.

Scripts

Office.js

Office.js is required for connecting with both PowerPoint as well as when within the Office Mix. It needs to be included in addition to labs.js.

<script src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js" type="text/javascript"></script>

Labs.js

Contained within the SDK this file needs to be included in order to make use of the API described in this document. This file will soon be hosted on a CDN as well.

<script src="https://az592748.vo.msecnd.net/sdk/LabsJS-1.0.4/labs-1.0.4.min.js" type="text/javascript"></script>

Error handling and Callbacks

Many methods in the labs.js API operate asynchronously. For these operations the API adopts a standard callback interface.

function(err, result) {
}

If there is an error the err field will be non-null. If the operation was successful err will be null and result will contain the result of the operation. The callback will never be fired immediately even if the result is available. It will always execute on a separate execution of the JavaScript event loop (via a setTimeout call).

By adoping this callback definition it is easy and possible to integrate labs.js in with your promise API of choice. For example, jQuery promises can be substituted for these callbacks with a simple translation method.

function createCallback<T>(deferred: JQueryDeferred<T>): Labs.Core.ILabCallback<T> {
    return (err, data) => {
        if (err) {
            deferred.reject(err);
        }
        else {
            deferred.resolve(data);
        }
    };
}            

Times

All timestamps stored in lab.js store the number of milliseconds since 1 January, 1970 UTC, matching the JavaScript Date object.

Lab host and DefaultLabHost

The lab host is the underlying driver used in lab development. By default this is set to a host that integrates with Office.js. For testing, and to run the app within the labshost.html, this needs to be swapped with a host that works within the simulation environment. An example of doing this via a query parameter is shown below. Changing the DefaultHostBuilder can also be used to integrate in a lab app to a different platform.

Labs.DefaultHostBuilder = function () {
    if (window.location.href.indexOf("PostMessageLabHost") !== -1) {
        return new Labs.PostMessageLabHost("test", parent, "*");
    } else {
        return new Labs.OfficeJSLabHost();
    }
};

Initialization

Initialiation is responsible for setting up communication between the lab and the host of the lab. Once initialization is complete the other API methods can be called.

Labs.connect((err, connectionResponse) => {    
});

The connectionResponse parameter contains information about the host, user and other connection related information. See the documentation for details on the values returned.

Lab Configuration and Editing

Office Mix provides API methods for lab developers to get and set their lab configuration. The configuration is used to indicate to Office Mix what type of lab is being created as well as what type of data the lab will send back. This information is used in the collection and visualization of analytics.

Getting the lab editor

The LabEditor provies the ability to edit and configure the lab. With it you can set the configuration for the lab and get the configuration for the lab. Only one labEditor can be open at any given time. When done editing the lab you need to call the done method. Done is not required to be called. But must be called before either taking the lab or opening another lab editor.

Labs.editLab((err, labEditor) => {
    if (err) {
        handleError();
        return;
    }
    _labEditor = labEditor;
});

Configuration and Components

The get and set configuration methods allow you to store the configuration for the lab. The configuration indicates to Office Mix what data will be collected and processed by the lab. A configuration contains general information about a lab including the name, version, and other configuration options. The major part is it's definition of components.

Components are the building blocks of a lab. Examples of a component are a multiple choice problem, a free response problem, or an activity like viewing a web page. Certain components, such as the DynamicComponent, allow for the creation of groups of components or quiz banks at run time.

Office Mix currently supports the following types of components.

Set and get configuration

To set the configuration simply create the configuration object and then call the setConfiguration method.

var activityComponent: Labs.Components.IActivityComponent = {
    type: Labs.Components.ActivityComponentType,
    name: uri,
    values: {},
    data: {
        uri: uri
    },
    secure: false
};
var configuration = {
    appVersion: { major: 1, minor: 1 },
    components: [activityComponent],
    name: configurationName,
    timeline: null,
    analytics: null
};
this._labEditor.setConfiguration(configuration, (err, unused) => { })

To then retrieve the configuration call the getConfiguration method on the lab editor.

labEditor.getConfiguration((err, configuration) => {
});

Closing the editor

Once done editing the lab the done method can be called on the editor to indicate that editing is complete. Only one instance of the editor can be open at any given time. And you cannot both take and edit a lab. Calling done indicates that the lab can be edited again or taken again.

labEditor.done((err) => {    
});

Interacting with a Lab

Once a lab configuration has been set the lab can now be interacted with. When running within PowerPoint these interactions are simulated. When running within the Office Mix lesson player the data is sent to the Office Mix back end for storage and use in analytics.

Getting the lab instance

The LabInstance is used for all interactions with a lab. It is an instance of the configured lab for the current user. It is used to record and retrieve per user lab data. To take the lab simply call the takeLab method that exists on the Labs object.

Labs.takeLab((err, labInstance) => {
    this._labInstance = labInstance;
    var activityComponentInstance = <Labs.Components.ActivityComponentInstance> this._labInstance.components[0];
    // populate the UI based on the instance    
});

Once retieved the instance contains an array of component instances that map to the components specified in the configuration. An instance is simply a transformed version of the configuration. The transformation is used to attach server side IDs to objects as well as to hide certain fields from the user when applicable (hints, answers, etc...). The API also provides a higher level set of functions on top of the raw instance data to aid in performance and usability.

State

State is temporary storage associated with a user taking the lab. It is a scratch space for developers to use to store information they would like to retrieve between loads of the lab. As an example a programming lab could store the user's current work in the scratch space. Changes to state do not cause any analytic computations to take place. It is always interpreted as a black box.

Setting State

labInstance.setState(this._labState(), (err, unused) => { 
    // If no error state has successfully been stored by the host
});

Getting State

labInstance.getState((err, state) => {
    // If no error the state parameter contains the set state
});

Component Instances and Results

The following provides an overview of the component instances that exist for the various types of components and short examples of the methods contained on them. The API guide provides more detailed descriptions of the methods and properties of these objects.

Common Concepts

This section outlines concepts that are common across component types.

Attempts

An attempt is a distinct attempt at the problem posed by a component. Creating a new attempt indicates the user is starting a new attempt at a particular exercise. As an example, if the exercise is a multiple choice question, beginning a new attempt should place the lab in its regular initial state. The Office Mix analytics will then aggregate how the user does for that particular exercise at the attempt level.

A component allows for the retrieval of all attempts associated with it via the getAttempts method. From these the user can then decide to either create a new attempt with the createAttempt method or use one of the existing attempts. Prior to making use of a retrieved attempt it must first be resumed via the resume method. The following provides an example of this process.

var attemptsDeferred = $.Deferred();
activityComponentInstance.getAttempts(createCallback(attemptsDeferred));
var attemptP = attemptsDeferred.promise().then((attempts) => {
    var currentAttemptDeferred = $.Deferred();
    if (attempts.length > 0) {
        currentAttemptDeferred.resolve(attempts[attempts.length - 1]);
    } else {
        activityComponentInstance.createAttempt(createCallback(currentAttemptDeferred));
    }
    return currentAttemptDeferred.then((currentAttempt: Labs.Components.ActivityComponentAttempt) => {
        var resumeDeferred = $.Deferred();
        currentAttempt.resume(createCallback(resumeDeferred));
        return resumeDeferred.promise().then(() => {
            return currentAttempt;
        });
    });
});

This concept exists for all component types except for the dynamic component.

Values

All components contain a dictionary that maps from a key to an array of values that can be used to store hints, feedback, or any other common list of values associated with the component. The component instance provides access to these values and the data they represent. Querying for a hint value causes the analytics to mark that the user took a hint. And for a secure quiz (not yet implemented) the value in the instance will be hidden from the user until they explicitly request access to it. Values are tracked on a per-attempt basis.

// Take a hint
var hints = attempt.getValues("hints");
hints[0].getValue((err, hint) => {
    // If no error hint will contain the hint data
});

ActivityComponentInstance

An ActivityComponentInstance is used to track a user's interaction with an activity component. It allows for attempts at the activity to be tracked. Within an ActivityComponentAttempt the primary method to be called is complete. The complete method indicates that the user has finished the activity. This could happen upon finishing the task assigned in the simulation or after viewing a given reading.

attempt.complete((err, unused) => { 
    // Called once the host has stored the completion
});

ChoiceComponentInstance

A ChoiceComponentInstance is used to track a user's interaction with a choice component. The ChoiceComponentAttempt is used to track attempts at the component. The primary methods contained within this class are getSubmissions and submit. The former retrieves any previous submissions while the latter allows for a new one to be stored.

Get Submissions
var submissions = this._attempt.getSubmissions();
Submit

The ChoiceComponentAnswer indicates the submitted answer and the ChoiceComponentResult contains the result. The result is optional and if not specified the API will grade the submission (this is not currently supported but will be in a future release). The return value is a ChoiceComponentSubmission which contains the answer, result and also the timestamp indicating when the result was submitted.

this._attempt.submit(
    new Labs.Components.ChoiceComponentAnswer(submission), 
    new Labs.Components.ChoiceComponentResult(correct, complete), 
    (err, submission) => {
        // Called once the server has processed the submission
    });

InputComponentInstance

An InputComponentInstance is used to track a user's interaction with an input component. The InputComponentAttempt is used to track attempts at the component. The primary methods contained within this class are getSubmissions and submit. The former retrieves any previous submissions while the latter allows for a new one to be stored.

Get Submissions
var submissions = this._attempt.getSubmissions();
Submit

The InputComponentAnswer indicates the submitted answer and the InputComponentResult contains the result. The result is optional and if not specified the API will grade the submission (this is not currently supported but will be in a future release). The return value is a InputComponentSubmission which contains the answer, result and also the timestamp indicating when the result was submitted.

this._attempt.submit(
    new Labs.Components.InputComponentAnswer(submission), 
    new Labs.Components.InputComponentResult(correct, complete), 
    (err, submission) => {
        // Called once the server has processed the submission
    });

DynamicComponentInstance

A DynamicComponentInstance is used to track a user's interaction with a dynamic component. A dynamic component allows for the creation of new components at runtime. The primary methods for a dynamic component are getComponents, createComponent, and close. All of which are explained below.

Get Components

Retrieves the list of previously created component instances

dynamicComponentInstance.getComponents((err, components) => {
    // Upon success components contains a list of previously created component instances
});
Create component

Constructs a new component, returning the instance that component creates.

var inputComponentHints = [];
for (var i = 0; i < data.hints.length; i++) {
    inputComponentHints.push({
        isHint: true,
        value: data.hints[i]        
    });
}
var inputComponent = {
    maxScore: 1,
    timeLimit: 0,
    hasAnswer: true,
    answer: data.answerData.solution,
    type: Labs.Components.InputComponentType,
    name: data.name,
    values: { hints: inputComponentHints },
    secure: false
};
var currentAttemptDeferred = $.Deferred();
var dynamicComponent = labInstance.components[0];
dynamicComponent.createComponent(inputComponent, function(err, inputComponentInstance) {
    // Create will return the instance for the specified component
})
Close

The close method is used to indicate no more components will be created by the dynamic component. The instance also has a isClosed method to see if the attempt was previously closed.

dynamicComponentInstance.close((err, unused) => {
    // Called once the server has processed the close attempt
});

Events

The events API tracks lab specific events and allows the application developer to add handlers to deal with them. Events include things like the mode changing from edit to view while within PowerPoint. Or activation methods coming from the lesson player indicating the app is now displayed on the current slide or is no longer contained on the active slide.

Mode change

The mode changed event is fired when the lab changes from "edit" to "view" mode. Edit mode is shown when in the editor mode in PowerPoint. View mode is shown when in slide show mode in PowerPoint or when being displayed within the Office Mix lesson player. The view mode should display what hte user will see when taking the lab. The edit lab should allow the user to configure the lab. The ModeChangedEventData data passed to the callback contains information on the current mode.

Labs.on(Labs.Core.EventTypes.ModeChanged, (data) => {
    var modeChangedEvent = <Labs.Core.ModeChangedEventData> data;
    this.switchToMode(modeChangedEvent.mode);
});

Activate

The activate event is sent when when the slide the application is contained on becomes active within the lesson player.

Labs.on(Labs.Core.EventTypes.Activate, (data) => {
    // App is now on the active slide
});

Deactivate

The deactivate event is sent when when the slide the application is contained on is no longe the active slide.

Labs.on(Labs.Core.EventTypes.Deactivate, (data) => {                
    // App is no longer on the active slide
});

Timeline

The lab also has the ability to interact with the player timeline. Using the timeline allows the lab to tell the player to advance to te next slide. The timeline object is found by calling the Labs.getTimeline() method.

Labs.getTimeline().next({}, (err, unused) => { });

These methods are currently only supported within the Office Mix lesson player. PowerPoint support is planned for the future.

The following provides links to the API documentation for the components of Labs.js

Labs.js and related files are Previews that are provided on the terms of the Microsoft Developer Services Agreement at http://msdn.microsoft.com/en-US/cc300389 (or a successor site).

We may provide a hash-encrypted user ID through the "id" field in the IUserInfo structure or otherwise ("ID Hash") that does not provide any personally identifiable information to you, but can be used by you to identify repeat users of your app. If you request or use the ID Hash you agree, in addition to the applicable terms of the Microsoft Developer Services Agreement, that: