From b1d83fd93c750eef15169609ef11b35169a55755 Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 00:08:06 +0300 Subject: [PATCH 01/12] feat: enable user to provide user previous state data --- src/js/h5p-standalone.class.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/js/h5p-standalone.class.js b/src/js/h5p-standalone.class.js index 425196ad..8f6d03cc 100644 --- a/src/js/h5p-standalone.class.js +++ b/src/js/h5p-standalone.class.js @@ -111,6 +111,14 @@ export default class H5PStandalone { customJs: (options.customJs || []).map(script => [urlPath(script)] ), }; + if (options.contentUserData) { + contentOptions.contentUserData = options.contentUserData; + } + + if (options.saveFreq) { + H5PIntegration.saveFreq = options.saveFreq + } + this.initElement(el); return this.initH5P(generalIntegrationOptions, contentOptions, customOptions); } From 34b5428899dcf95204ea34e7838e174d513e564c Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 00:12:55 +0300 Subject: [PATCH 02/12] docs: add documentation on previous state restoration options --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8c78136e..5feb5997 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,9 @@ The standalone H5P player constructor accepts two arguments. `embedCode` |unless `embed` is true| Embed/Iframe code that user can insert on their site to view same content. Check some caveats to consider [below](#caveats-while-adding-embed-code) `customCss` | No | Path(s) to custom stylesheet file(s) `customJs` | No | Path(s) to custom script file(s) +`saveFreq` |if `contentUserData` or `ajax.*` is set| How often current user engagement content state should be saved (in seconds). Default is `false`. +`contentUserData`| No| User previous content interaction state (json string) + **Note:** - One can use absolute URL for `frameCss`, `frameJs`, and for other path options(`h5pJsonPath`,`librariesPath`, & `librariesPath`) From d943ad9a375accd3c324825e6b6ccaebdc68dd04 Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 00:16:21 +0300 Subject: [PATCH 03/12] docs: fix typos --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5feb5997..9fdfe442 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ const options = { frameJs: './frame.bundle.js', frameCss: './styles/h5p.css', h5pJsonPath: '/path/to/h5p-folder', - librariesPath: '/path/to/h5p-folder', //content is on same folder level as h5p.json + contentJsonPath: '/path/to/h5p-folder', //content is on same folder level as h5p.json librariesPath: '/path/to/shared/libaries', //shared libraries path frame: true, //required to display copyright, embed, & export buttons copyright: true, @@ -161,9 +161,9 @@ const player1 = new H5P(document.getElementById('h5p-container-1'), player1Optio player1.then(() => { return new H5P(document.getElementById('h5p-container-2'), player2Options); -}).then(( => { +}).then(() => { // do stuff -})); +}); // OR (async wrapper function removed for readability) @@ -226,7 +226,7 @@ Example that combines above points: ```js ``` From 3e9f3290d85b14e24114f122a2b817c4bafe8a81 Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 14:17:23 +0300 Subject: [PATCH 04/12] fix: save frequency should default to false --- src/js/h5p-integration.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/h5p-integration.js b/src/js/h5p-integration.js index 81e899e0..b1643443 100644 --- a/src/js/h5p-integration.js +++ b/src/js/h5p-integration.js @@ -1,4 +1,5 @@ const integration = { + saveFreq: false, l10n: { H5P: { "fullscreen": "Fullscreen", @@ -72,4 +73,4 @@ const integration = { } }; -window.H5PIntegration = window.H5PIntegration ? {...window.H5PIntegration,...integration} : integration; \ No newline at end of file +window.H5PIntegration = window.H5PIntegration ? { ...window.H5PIntegration, ...integration } : integration; \ No newline at end of file From c60456ac7b396e99cc700c4ae49e2b431b820195 Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 14:19:53 +0300 Subject: [PATCH 05/12] feat: allow user to set if to post user results --- src/js/h5p-integration.js | 1 + src/js/h5p-standalone.class.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/js/h5p-integration.js b/src/js/h5p-integration.js index b1643443..c1c7e385 100644 --- a/src/js/h5p-integration.js +++ b/src/js/h5p-integration.js @@ -1,5 +1,6 @@ const integration = { saveFreq: false, + postUserStatistics: false, l10n: { H5P: { "fullscreen": "Fullscreen", diff --git a/src/js/h5p-standalone.class.js b/src/js/h5p-standalone.class.js index 8f6d03cc..ebfc9f68 100644 --- a/src/js/h5p-standalone.class.js +++ b/src/js/h5p-standalone.class.js @@ -119,6 +119,10 @@ export default class H5PStandalone { H5PIntegration.saveFreq = options.saveFreq } + if (options.postUserStatistics) { + H5PIntegration.postUserStatistics = false + } + this.initElement(el); return this.initH5P(generalIntegrationOptions, contentOptions, customOptions); } From b247c460af8beb2350c50aaaf2c5c1fb87191fc3 Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 14:26:16 +0300 Subject: [PATCH 06/12] feat: allow user to set where post the results on finish event --- src/js/h5p-integration.js | 3 +++ src/js/h5p-standalone.class.js | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/js/h5p-integration.js b/src/js/h5p-integration.js index c1c7e385..9b9b3529 100644 --- a/src/js/h5p-integration.js +++ b/src/js/h5p-integration.js @@ -1,6 +1,9 @@ const integration = { saveFreq: false, postUserStatistics: false, + ajax: { + setFinished: undefined, + }, l10n: { H5P: { "fullscreen": "Fullscreen", diff --git a/src/js/h5p-standalone.class.js b/src/js/h5p-standalone.class.js index ebfc9f68..ea55274f 100644 --- a/src/js/h5p-standalone.class.js +++ b/src/js/h5p-standalone.class.js @@ -123,6 +123,10 @@ export default class H5PStandalone { H5PIntegration.postUserStatistics = false } + if (options.ajax && options.ajax.setFinishedUrl) { + H5PIntegration.ajax.setFinished = options.ajax.setFinishedUrl + } + this.initElement(el); return this.initH5P(generalIntegrationOptions, contentOptions, customOptions); } From 6e05abc3d5c3f0752003f6a55455575f7678fdf4 Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 14:35:31 +0300 Subject: [PATCH 07/12] feat: allow provision of xAPI actor statement user data --- src/js/h5p-standalone.class.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/js/h5p-standalone.class.js b/src/js/h5p-standalone.class.js index ea55274f..54f47e4e 100644 --- a/src/js/h5p-standalone.class.js +++ b/src/js/h5p-standalone.class.js @@ -115,6 +115,9 @@ export default class H5PStandalone { contentOptions.contentUserData = options.contentUserData; } + /** + * following options overrides global H5PIntegration. + */ if (options.saveFreq) { H5PIntegration.saveFreq = options.saveFreq } @@ -127,6 +130,10 @@ export default class H5PStandalone { H5PIntegration.ajax.setFinished = options.ajax.setFinishedUrl } + if (options.user) { + H5PIntegration['user'] = options.user; + } + this.initElement(el); return this.initH5P(generalIntegrationOptions, contentOptions, customOptions); } From 4d6d6263093774e49ee92bd19de01ad1db843e18 Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 14:45:22 +0300 Subject: [PATCH 08/12] feat: allow setting endpoint to manage current user state --- src/js/h5p-integration.js | 1 + src/js/h5p-standalone.class.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/js/h5p-integration.js b/src/js/h5p-integration.js index 9b9b3529..1de09437 100644 --- a/src/js/h5p-integration.js +++ b/src/js/h5p-integration.js @@ -3,6 +3,7 @@ const integration = { postUserStatistics: false, ajax: { setFinished: undefined, + contentUserData: undefined }, l10n: { H5P: { diff --git a/src/js/h5p-standalone.class.js b/src/js/h5p-standalone.class.js index 54f47e4e..dd07d9aa 100644 --- a/src/js/h5p-standalone.class.js +++ b/src/js/h5p-standalone.class.js @@ -134,6 +134,10 @@ export default class H5PStandalone { H5PIntegration['user'] = options.user; } + if (options.ajax && options.ajax.contentUserDataUrl) { + H5PIntegration.ajax.contentUserData = options.ajax.contentUserDataUrl + } + this.initElement(el); return this.initH5P(generalIntegrationOptions, contentOptions, customOptions); } From d9c8c7f009f070e90d15aac34740dc9c9448cca6 Mon Sep 17 00:00:00 2001 From: murage Date: Tue, 2 Nov 2021 14:58:26 +0300 Subject: [PATCH 09/12] docs: update docs to include new options & typo fixes --- README.md | 52 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9fdfe442..f2f6e647 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ Display H5P content without the need for an H5P server **Source**|**Info** -----|----- yarn | `yarn add h5p-standalone` -Release | [Donwload latest version here](https://github.com/tunapanda/h5p-standalone/releases/latest) +Release | [Download latest version here](https://github.com/tunapanda/h5p-standalone/releases/latest) ## Basic Usage -Ensure you have an extracted H5P zip file in your workspace folder first. A simple guide on how to extract an H5P zip file is provided towards the [end section of this guide ](https://github.com/tunapanda/h5p-standalone#extracting-h5p) +Ensure you have an extracted H5P zip file in your workspace folder first. A simple guide on how to extract an H5P zip file is provided [here ](https://github.com/tunapanda/h5p-standalone#extracting-h5p) -The player can be set up either by directly calling the already built scripts and styles in your `HTML` page or using `ES6` syntax. For the standalone player to work correctly on a webpage, both the assets, settings, and H5P specific files need to be set properly first. +The player can be set up either by directly calling the already built scripts and styles in your `HTML` page or using `ES6` syntax. ### Direct use 1. Download the project latest release zipped source code from [here](https://github.com/tunapanda/h5p-standalone/releases/latest) @@ -74,6 +74,8 @@ The standalone H5P player constructor accepts two arguments. 1. A HTML element where the H5P iframe will be embedded as the first argument. 2. JSON object with the following options : ### H5P Options +1) Basic options + **Option name**|**Required**|**Description** -----|-----|---- `h5pJsonPath` | Yes | Path to the H5P content folder @@ -82,19 +84,31 @@ The standalone H5P player constructor accepts two arguments. `id` | No | Player unique identifier. Randomly generated by default `librariesPath` | No| Path where the player should find the H5P content libraries. Defaults to same as `h5pJsonPath` `contentJsonPath`|No | Path where the player should find the H5P `content.json` file. Defaults to `{h5pJsonPath}/content/`, -`frame` |No| A boolean on whether to show frame and buttons below H5P +`frame` |No| A boolean on whether to show H5P player frame and buttons `copyright` |No| A boolean on whether display copyright button `export` |No| A boolean on whether display a download button. `icon` |No| A boolean on whether display H5P icon `downloadUrl` |No| A path or a url that returns zipped h5p for download. The link is used by H5P `export` button -`fullScreen` |No| A boolean on whether to enable fullscreen button if browser supports the feature. Default is `false`| -`xAPIObjectIRI`|No| An identifier for a single unique Activity ~ utilized when generating xAPI [object](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#acturi) field. Default is page host+pathname +`fullScreen` |No| A boolean on whether to enable the fullscreen button if the browser supports the feature. Default is `false`| `embed` |No| A boolean on whether display embed button. Default is `false`. N.B. Setting this option to `true` will require an `embedCode` below. `embedCode` |unless `embed` is true| Embed/Iframe code that user can insert on their site to view same content. Check some caveats to consider [below](#caveats-while-adding-embed-code) `customCss` | No | Path(s) to custom stylesheet file(s) `customJs` | No | Path(s) to custom script file(s) -`saveFreq` |if `contentUserData` or `ajax.*` is set| How often current user engagement content state should be saved (in seconds). Default is `false`. -`contentUserData`| No| User previous content interaction state (json string) +`xAPIObjectIRI`|No| An identifier for a single unique Activity ~ utilized when generating xAPI [object](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#acturi) field. Default is page host+pathname + +2) User state & data _(kindly refer to [this section](#previous-state-restoration))_ + +**Option name**|**Required**|**Description** +-----|-----|---- +`contentUserData`| No| User previous content interaction state data. The data should be in JSON string format +`saveFreq` |if `contentUserData` or `ajax.*` is set| How often current user engagement content state should be autosaved (in seconds). Default is `false`. +`postUserStatistics` | No | Indicates if H5P should post the results once a finish event is triggered. Default is `false`. **** _Requires `ajax.setFinishedUrl` property to be set_ +`ajax` | No | Object required if you need H5P to manage a learner's state +`ajax.setFinishedUrl`| No | Url where H5P should post the results once a finish event is triggered. **** _Requires `postUserStatistics` to be set to true_. +`ajax.contentUserDataUrl`| No | Endpoint where H5P can manage current user state. **** _Requires `user` property to be set_| +`user` | No | Current user data object. +`user.name` | Yes | Used as xAPI actor's name +`user.mail` | Yes | User email. Uniquely identifies the xAPI actor **Note:** @@ -134,7 +148,7 @@ new H5P(el,options) // do stuff }); -// Or using async-await syntax (async wrapper function removed for readability) : +// Or using the async-await syntax (async wrapper function removed for readability) : await new H5P(el, options); @@ -174,7 +188,7 @@ await new H5P(document.getElementById('h5p-container-2'), player2Options); ``` ## Listening to xAPI events -To listen for [xAPI events](https://h5p.org/documentation/api/H5P.XAPIEvent.html) emmitted by the player, you must wait for the player to finish loading and initializing the required content libraries. You can find more info about xAPI events here https://h5p.org/documentation/x-api +To listen for [xAPI events](https://h5p.org/documentation/api/H5P.XAPIEvent.html) emitted by the player, you must wait for the player to finish loading and initializing the required content libraries. You can find more info about xAPI events here https://h5p.org/documentation/x-api 1) Using `then()` method ```js @@ -217,11 +231,27 @@ async function myAwesomePlayer() { myAwesomePlayer(); ``` + +## Previous state restoration. +H5P provides two approaches for restoring a user's previous interaction state: +1) using data provided with `contentUserData` option. +2) automatically fetching the data if `ajax.contentUserDataUrl` is provided + +**For both cases, the `saveFreq` option must be set**. + +A summary of the previous state restoration process: + +1) If the `contentUserData` option is available, skip to the 3rd step. +2) If `contentUserData` is not available but `user.*` and `ajax.contentUserDataUrl` options were provided, request the data from `ajax.contentUserDataUrl` endpoint. +3) Process the previous state `data` as follows: + - where `data.[0].state` equals `RESET`, any previous state will be deleted + - else, parse `data.[0].state` string and pass it to the H5P player instance + ### Caveats while adding embed code - This library includes an H5P resizer by default in `main.bundle.js` at the moment. But, to allow the iframe width to resize promptly, add CSS style setting the width to 100% i.e. `style="width:100%;"` - If you want to allow users to resize the iframe width and height, set them using placeholders provided by H5P i.e., `width=":w"` and `height=":h"` -Example that combines above points: +An example that combines the above points: ```js