From 76b0fc04f8c9f3d33ba9c95f38e9bb2fa6d5751d Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sat, 21 Mar 2015 14:16:31 +0100 Subject: [PATCH 01/21] Make UUID creator available for everyone --- js/h5p-x-api-event.js | 5 +---- js/h5p.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 141e232..abc7cca 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -111,10 +111,7 @@ H5P.XAPIEvent.prototype.setActor = function() { uuid = localStorage.H5PUserUUID; } else { - uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(char) { - var random = Math.random()*16|0, newChar = char === 'x' ? random : (random&0x3|0x8); - return newChar.toString(16); - }); + uuid = H5P.createUUID(); localStorage.H5PUserUUID = uuid; } this.data.statement.actor = { diff --git a/js/h5p.js b/js/h5p.js index a9c2617..c80d2a5 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -1391,6 +1391,18 @@ H5P.on = function(instance, eventType, handler) { } }; +/** + * Create UUID + * + * @returns {String} UUID + */ +H5P.createUUID = function() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(char) { + var random = Math.random()*16|0, newChar = char === 'x' ? random : (random&0x3|0x8); + return newChar.toString(16); + }); +}; + H5P.jQuery(document).ready(function () { if (!H5P.preventInit) { From 313bb757ba77246ea63820533d6d3944e2999b8d Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sat, 21 Mar 2015 16:45:38 +0100 Subject: [PATCH 02/21] Add bubble system and xAPI context --- h5p.classes.php | 5 ++++- js/h5p-event-dispatcher.js | 11 +++++++++++ js/h5p-x-api-event.js | 40 +++++++++++++++++++++++++++++++++++++- js/h5p.js | 22 +++++++++++++++++++-- 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index b6df5af..c4c703d 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2731,11 +2731,14 @@ class H5PContentValidator { 'type' => 'group', 'fields' => $library['semantics'], ), FALSE); - $validkeys = array('library', 'params'); + $validkeys = array('library', 'params', 'uuid'); if (isset($semantics->extraAttributes)) { $validkeys = array_merge($validkeys, $semantics->extraAttributes); } $this->filterParams($value, $validkeys); + if (isset($value->uuid) && ! preg_match('/^\{?[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}\}?$/', $value->uuid)) { + unset($value->uuid); + } // Find all dependencies for this library $depkey = 'preloaded-' . $library['machineName']; diff --git a/js/h5p-event-dispatcher.js b/js/h5p-event-dispatcher.js index cb40cd6..e164564 100644 --- a/js/h5p-event-dispatcher.js +++ b/js/h5p-event-dispatcher.js @@ -8,6 +8,13 @@ var H5P = H5P || {}; H5P.Event = function(type, data) { this.type = type; this.data = data; + var bubbles = true; + this.preventBubbling = function() { + bubbles = false; + }; + this.getBubbles = function() { + return bubbles; + }; }; H5P.EventDispatcher = (function () { @@ -132,6 +139,7 @@ H5P.EventDispatcher = (function () { * argument */ this.trigger = function (event, eventData) { + console.log(event); if (event === undefined) { return; } @@ -148,6 +156,9 @@ H5P.EventDispatcher = (function () { for (var i = 0; i < triggers[event.type].length; i++) { triggers[event.type][i].listener.call(triggers[event.type][i].thisArg, event); } + if (event.getBubbles() && typeof self.parent === 'function' && typeof self.parent.trigger === 'function') { + self.parent.trigger(event); + } }; } diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index abc7cca..0d18d84 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -79,12 +79,20 @@ H5P.XAPIEvent.prototype.getVerb = function(full) { H5P.XAPIEvent.prototype.setObject = function(instance) { if (instance.contentId) { this.data.statement.object = { - 'id': H5PIntegration.contents['cid-' + instance.contentId].url, + 'id': this.getContentXAPIId(instance), 'objectType': 'Activity', 'extensions': { 'http://h5p.org/x-api/h5p-local-content-id': instance.contentId } }; + if (instance.h5pUUID) { + this.data.statement.object.extensions['http://h5p.org/x-api/h5p-uuid'] = instance.h5pUUID; + } + if (typeof instance.getH5PTitle === 'function') { + this.data.statement.object.description = { + "en-US": instance.getH5PTitle() + }; + } } else { // Not triggered by an H5P content type... @@ -94,6 +102,25 @@ H5P.XAPIEvent.prototype.setObject = function(instance) { } }; +/** + * Helperfunction to set the context part of the statement. + * + * @param {object} instance - the H5P instance + */ +H5P.XAPIEvent.prototype.setContext = function(instance) { + if (instance.parent && instance.parent.contentId || instance.parent.uuid) { + var parentId = instance.parent.uuid === undefined ? instance.parent.contentId : instance.parent.uuid; + this.data.statement.context = { + "parent": [ + { + "id": getContentXAPIId(instance.parent), + "objectType": "Activity" + } + ] + }; + } +}; + /** * Helper function to set the actor, email and name will be added automatically */ @@ -142,6 +169,17 @@ H5P.XAPIEvent.prototype.getScore = function() { return this.getVerifiedStatementValue(['result', 'score', 'raw']); }; +H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) { + var xAPIId; + if (instance.contentId) { + xAPIId = H5PIntegration.contents['cid-' + instance.contentId].url; + if (instance.h5pUUID) { + xAPIId += '?uuid=' + instance.h5pUUID; + } + } + return xAPIId; +} + /** * Figure out if a property exists in the statement and return it * diff --git a/js/h5p.js b/js/h5p.js index c80d2a5..0370476 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -544,7 +544,7 @@ H5P.classFromName = function (name) { * @param {Object} The parent of this H5P * @return {Object} Instance. */ -H5P.newRunnable = function (library, contentId, $attachTo, skipResize) { +H5P.newRunnable = function (library, contentId, $attachTo, skipResize, parent) { var nameSplit, versionSplit; try { nameSplit = library.library.split(' ', 2); @@ -575,7 +575,16 @@ H5P.newRunnable = function (library, contentId, $attachTo, skipResize) { return H5P.error('Unable to find constructor for: ' + library.library); } - var instance = new constructor(library.params, contentId); + var extras = {}; + + if (library.uuid) { + extras.uuid = library.uuid; + } + if (parent) { + extras.parent = parent; + } + + var instance = new constructor(library.params, contentId, extras); if (instance.$ === undefined) { instance.$ = H5P.jQuery(instance); @@ -584,6 +593,12 @@ H5P.newRunnable = function (library, contentId, $attachTo, skipResize) { if (instance.contentId === undefined) { instance.contentId = contentId; } + if (instance.uuid === undefined && library.uuid) { + instance.uuid = library.uuid; + } + if (instance.parent === undefined && parent) { + instance.parent = parent; + } if ($attachTo !== undefined) { instance.attach($attachTo); @@ -1403,6 +1418,9 @@ H5P.createUUID = function() { }); }; +H5P.createH5PTitle = function(rawTitle) { + return H5P.jQuery('
').text(rawTitle).text().substr(0, 60); +}; H5P.jQuery(document).ready(function () { if (!H5P.preventInit) { From 3da0de46264895c946db1b0955618e6dc230cfd3 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 11:17:58 +0100 Subject: [PATCH 03/21] Fix bubble system --- js/h5p-event-dispatcher.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/h5p-event-dispatcher.js b/js/h5p-event-dispatcher.js index e164564..31043f9 100644 --- a/js/h5p-event-dispatcher.js +++ b/js/h5p-event-dispatcher.js @@ -5,10 +5,16 @@ var H5P = H5P || {}; * The Event class for the EventDispatcher * @class */ -H5P.Event = function(type, data) { +H5P.Event = function(type, data, extras) { this.type = type; this.data = data; var bubbles = true; + if (extras === undefined) { + extras = {}; + } + if (extras.bubbles === false) { + bubbles = false; + } this.preventBubbling = function() { bubbles = false; }; @@ -139,7 +145,6 @@ H5P.EventDispatcher = (function () { * argument */ this.trigger = function (event, eventData) { - console.log(event); if (event === undefined) { return; } @@ -156,7 +161,7 @@ H5P.EventDispatcher = (function () { for (var i = 0; i < triggers[event.type].length; i++) { triggers[event.type][i].listener.call(triggers[event.type][i].thisArg, event); } - if (event.getBubbles() && typeof self.parent === 'function' && typeof self.parent.trigger === 'function') { + if (event.getBubbles() && self.parent instanceof H5P.EventDispatcher && typeof self.parent.trigger === 'function') { self.parent.trigger(event); } }; From b79a5b61b83d28faf425a0b080fac7bbeb2d85bf Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 12:42:07 +0100 Subject: [PATCH 04/21] uuid consists of lowercase letters --- h5p.classes.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index c4c703d..2fba0f2 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2736,8 +2736,8 @@ class H5PContentValidator { $validkeys = array_merge($validkeys, $semantics->extraAttributes); } $this->filterParams($value, $validkeys); - if (isset($value->uuid) && ! preg_match('/^\{?[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}\}?$/', $value->uuid)) { - unset($value->uuid); + if (isset($value->uuid) && ! preg_match('/^\{?[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\}?$/', $value->uuid)) { + unset($value->uuid); } // Find all dependencies for this library From e14c24cc070a1c197fecefa14ccecdcf49f8a076 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 12:43:07 +0100 Subject: [PATCH 05/21] Fix xAPI statement structure to follow the standard better --- js/h5p-x-api-event.js | 28 +++++++++++++--------------- js/h5p-x-api.js | 5 ++++- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 0d18d84..837b219 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -81,25 +81,21 @@ H5P.XAPIEvent.prototype.setObject = function(instance) { this.data.statement.object = { 'id': this.getContentXAPIId(instance), 'objectType': 'Activity', - 'extensions': { - 'http://h5p.org/x-api/h5p-local-content-id': instance.contentId + 'definition': { + 'extensions': { + 'http://h5p.org/x-api/h5p-local-content-id': instance.contentId + } } }; if (instance.h5pUUID) { this.data.statement.object.extensions['http://h5p.org/x-api/h5p-uuid'] = instance.h5pUUID; } if (typeof instance.getH5PTitle === 'function') { - this.data.statement.object.description = { + this.data.statement.object.definition.name = { "en-US": instance.getH5PTitle() }; } } - else { - // Not triggered by an H5P content type... - this.data.statement.object = { - 'objectType': 'Activity' - }; - } }; /** @@ -111,12 +107,14 @@ H5P.XAPIEvent.prototype.setContext = function(instance) { if (instance.parent && instance.parent.contentId || instance.parent.uuid) { var parentId = instance.parent.uuid === undefined ? instance.parent.contentId : instance.parent.uuid; this.data.statement.context = { - "parent": [ - { - "id": getContentXAPIId(instance.parent), - "objectType": "Activity" - } - ] + "contextActivities": { + "parent": [ + { + "id": this.getContentXAPIId(instance.parent), + "objectType": "Activity" + } + ] + } }; } }; diff --git a/js/h5p-x-api.js b/js/h5p-x-api.js index e4f4edb..f18cfd3 100644 --- a/js/h5p-x-api.js +++ b/js/h5p-x-api.js @@ -39,9 +39,12 @@ H5P.EventDispatcher.prototype.createXAPIEventTemplate = function(verb, extra) { event.data.statement[i] = extra[i]; } } - if (!('object' in event)) { + if (!('object' in event.data.statement)) { event.setObject(this); } + if (!('context' in event.data.statement)) { + event.setContext(this); + } return event; }; From 93f2bcc01a1c06ee6ac30477d17b9f71a5193e32 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 12:44:55 +0100 Subject: [PATCH 06/21] Use uuid instead of h5pUUID --- js/h5p-x-api-event.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 837b219..12bfb36 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -171,8 +171,8 @@ H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) { var xAPIId; if (instance.contentId) { xAPIId = H5PIntegration.contents['cid-' + instance.contentId].url; - if (instance.h5pUUID) { - xAPIId += '?uuid=' + instance.h5pUUID; + if (instance.uuid) { + xAPIId += '?uuid=' + instance.uuid; } } return xAPIId; From 5a882e4d55cc85bfec06bf80039a5fe022e997c6 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 12:45:03 +0100 Subject: [PATCH 07/21] Improve title generator --- js/h5p.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/js/h5p.js b/js/h5p.js index 0370476..5123091 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -576,7 +576,6 @@ H5P.newRunnable = function (library, contentId, $attachTo, skipResize, parent) { } var extras = {}; - if (library.uuid) { extras.uuid = library.uuid; } @@ -1418,8 +1417,20 @@ H5P.createUUID = function() { }); }; -H5P.createH5PTitle = function(rawTitle) { - return H5P.jQuery('
').text(rawTitle).text().substr(0, 60); +H5P.createH5PTitle = function(rawTitle, maxLength) { + if (maxLength === undefined) { + maxLength = 60; + } + var title = H5P.jQuery('
') + .text( + // Strip tags + rawTitle.replace(/(<([^>]+)>)/ig,"") + // Escape + ).text(); + if (title.length > maxLength) { + title = title.substr(0, maxLength - 3) + '...'; + } + return title; }; H5P.jQuery(document).ready(function () { From 1c4a5e014b11cb957d2f2e4e5e564dedc2c82fb8 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 13:12:44 +0100 Subject: [PATCH 08/21] Comment out prefixing that isn't working --- h5p.classes.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 955dab0..4073c71 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1785,10 +1785,9 @@ class H5PCore { if ($type === 'preloadedCss' && (isset($dependency['dropCss']) && $dependency['dropCss'] === '1')) { return; } - foreach ($dependency[$type] as $file) { $assets[] = (object) array( - 'path' => $prefix . $dependency['path'] . '/' . trim(is_array($file) ? $file['path'] : $file), + 'path' => /*$prefix . */$dependency['path'] . '/' . trim(is_array($file) ? $file['path'] : $file), 'version' => $dependency['version'] ); } @@ -1808,7 +1807,7 @@ class H5PCore { // Add URL prefix if not external if (strpos($asset->path, '://') === FALSE) { - $url = $this->url . $url; + $url = /*$this->url .*/ $url; } // Add version/cache buster if set From c4e488f9c8a4c1c58f0c36da40cd5d54480307e5 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 13:27:40 +0100 Subject: [PATCH 09/21] Get contentId from the right place in the statement --- js/h5p-x-api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/h5p-x-api.js b/js/h5p-x-api.js index f18cfd3..cc18943 100644 --- a/js/h5p-x-api.js +++ b/js/h5p-x-api.js @@ -71,7 +71,7 @@ H5P.xAPICompletedListener = function(event) { if (statement.verb.id === 'http://adlnet.gov/expapi/verbs/completed') { var score = statement.result.score.raw; var maxScore = statement.result.score.max; - var contentId = statement.object.extensions['http://h5p.org/x-api/h5p-local-content-id']; + var contentId = statement.object.definition.extensions['http://h5p.org/x-api/h5p-local-content-id']; H5P.setFinished(contentId, score, maxScore); } } From 9a204b3d8f7dceaa80c71224401e93c0a8de37a0 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 15:14:28 +0100 Subject: [PATCH 10/21] Make sure title are added --- js/h5p-x-api-event.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 12bfb36..3ef34e6 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -87,13 +87,21 @@ H5P.XAPIEvent.prototype.setObject = function(instance) { } } }; - if (instance.h5pUUID) { - this.data.statement.object.extensions['http://h5p.org/x-api/h5p-uuid'] = instance.h5pUUID; + if (instance.uuid) { + this.data.statement.object.definition.extensions['http://h5p.org/x-api/h5p-uuid'] = instance.uuid; + // Don't set titles on main content, title should come from publishing platform + if (typeof instance.getH5PTitle === 'function') { + this.data.statement.object.definition.name = { + "en-US": instance.getH5PTitle() + }; + } } - if (typeof instance.getH5PTitle === 'function') { - this.data.statement.object.definition.name = { - "en-US": instance.getH5PTitle() - }; + else { + if (H5PIntegration.contents['cid-' + instance.contentId].title) { + this.data.statement.object.definition.name = { + "en-US": H5P.createH5PTitle(H5PIntegration.contents['cid-' + instance.contentId].title) + }; + } } } }; From 6b3e550a48287a980caad57b0d314b1985541f22 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 20:37:10 +0100 Subject: [PATCH 11/21] Don't bubble by default --- js/h5p-event-dispatcher.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/js/h5p-event-dispatcher.js b/js/h5p-event-dispatcher.js index 31043f9..d67ee10 100644 --- a/js/h5p-event-dispatcher.js +++ b/js/h5p-event-dispatcher.js @@ -8,12 +8,12 @@ var H5P = H5P || {}; H5P.Event = function(type, data, extras) { this.type = type; this.data = data; - var bubbles = true; + var bubbles = false; if (extras === undefined) { extras = {}; } - if (extras.bubbles === false) { - bubbles = false; + if (extras.bubbles === true) { + bubbles = true; } this.preventBubbling = function() { bubbles = false; @@ -161,6 +161,7 @@ H5P.EventDispatcher = (function () { for (var i = 0; i < triggers[event.type].length; i++) { triggers[event.type][i].listener.call(triggers[event.type][i].thisArg, event); } + // Bubble if (event.getBubbles() && self.parent instanceof H5P.EventDispatcher && typeof self.parent.trigger === 'function') { self.parent.trigger(event); } From 46c92607550ace97f50160f5c609991c8a575cd0 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 20:37:28 +0100 Subject: [PATCH 12/21] Don't bubble by default --- js/h5p-x-api-event.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 3ef34e6..7d85d90 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -6,7 +6,7 @@ var H5P = H5P || {}; * @class */ H5P.XAPIEvent = function() { - H5P.Event.call(this, 'xAPI', {'statement': {}}); + H5P.Event.call(this, 'xAPI', {'statement': {}}, {bubbles: true}); }; H5P.XAPIEvent.prototype = Object.create(H5P.Event.prototype); From 5d6d22a13fc65a10129b20ed3016e97aea33b731 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 20:37:48 +0100 Subject: [PATCH 13/21] Accept other verbs than the adl verbs --- js/h5p-x-api-event.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 7d85d90..79504f0 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -44,8 +44,8 @@ H5P.XAPIEvent.prototype.setVerb = function(verb) { } }; } - else { - H5P.error('illegal verb'); + else if (verb.id !== undefined) { + this.data.statement.verb = verb; } }; From d3453b86375e56a053af15b446225ba059e961b0 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 20:38:17 +0100 Subject: [PATCH 14/21] Context bug fix --- js/h5p-x-api-event.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 79504f0..19bc211 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -112,7 +112,7 @@ H5P.XAPIEvent.prototype.setObject = function(instance) { * @param {object} instance - the H5P instance */ H5P.XAPIEvent.prototype.setContext = function(instance) { - if (instance.parent && instance.parent.contentId || instance.parent.uuid) { + if (instance.parent && (instance.parent.contentId || instance.parent.uuid)) { var parentId = instance.parent.uuid === undefined ? instance.parent.contentId : instance.parent.uuid; this.data.statement.context = { "contextActivities": { From eb02a5942d8d9da697ab1f04abf5dd17c7df4822 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 20:38:33 +0100 Subject: [PATCH 15/21] Make externalDispatcher from framed content work again --- js/h5p-x-api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/h5p-x-api.js b/js/h5p-x-api.js index cc18943..c3efcf2 100644 --- a/js/h5p-x-api.js +++ b/js/h5p-x-api.js @@ -3,7 +3,7 @@ var H5P = H5P || {}; // Create object where external code may register and listen for H5P Events H5P.externalDispatcher = new H5P.EventDispatcher(); -if (H5P.isFramed && H5P.externalEmbed === false) { +if (H5P.isFramed && H5P.externalEmbed !== true) { H5P.externalDispatcher.on('xAPI', window.top.H5P.externalDispatcher.trigger); } From 9d38f838867c31edc6da1223abf27ffe6e7b923b Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 20:38:57 +0100 Subject: [PATCH 16/21] Refactor completed listener to use more of the new xAPI api functions --- js/h5p-x-api.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/js/h5p-x-api.js b/js/h5p-x-api.js index c3efcf2..9d0e7cd 100644 --- a/js/h5p-x-api.js +++ b/js/h5p-x-api.js @@ -66,13 +66,10 @@ H5P.EventDispatcher.prototype.triggerXAPICompleted = function(score, maxScore) { * @param {function} event - xAPI event */ H5P.xAPICompletedListener = function(event) { - var statement = event.data.statement; - if ('verb' in statement) { - if (statement.verb.id === 'http://adlnet.gov/expapi/verbs/completed') { - var score = statement.result.score.raw; - var maxScore = statement.result.score.max; - var contentId = statement.object.definition.extensions['http://h5p.org/x-api/h5p-local-content-id']; - H5P.setFinished(contentId, score, maxScore); - } + if (event.getVerb() === 'completed' && !event.getVerifiedStatementValue(['context', 'contextActivities', 'parent'])) { + var score = event.getScore(); + var maxScore = event.getMaxScore(); + var contentId = event.getVerifiedStatementValue(['object', 'definition', 'extensions', 'http://h5p.org/x-api/h5p-local-content-id']); + H5P.setFinished(contentId, score, maxScore); } }; From 8e113ff792f7cc82d1b51605ec8527141432584e Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 22 Mar 2015 20:39:16 +0100 Subject: [PATCH 17/21] Add parameter set as parameter 5 to new runnable, and blacklist libraries that already have a custom third parameter for their constructor --- js/h5p.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/js/h5p.js b/js/h5p.js index 5123091..7ac82d0 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -541,10 +541,10 @@ H5P.classFromName = function (name) { * @param {Number} contentId * @param {jQuery} $attachTo An optional element to attach the instance to. * @param {Boolean} skipResize Optionally skip triggering of the resize event after attaching. - * @param {Object} The parent of this H5P + * @param {Object} extras - extra params for the H5P content constructor * @return {Object} Instance. */ -H5P.newRunnable = function (library, contentId, $attachTo, skipResize, parent) { +H5P.newRunnable = function (library, contentId, $attachTo, skipResize, extras) { var nameSplit, versionSplit; try { nameSplit = library.library.split(' ', 2); @@ -575,15 +575,20 @@ H5P.newRunnable = function (library, contentId, $attachTo, skipResize, parent) { return H5P.error('Unable to find constructor for: ' + library.library); } - var extras = {}; + if (extras === undefined) { + extras = {}; + } if (library.uuid) { extras.uuid = library.uuid; } - if (parent) { - extras.parent = parent; + + // Some old library versions have their own custom third parameter. Make sure we don't send them the extras. They'll interpret it as something else + if (H5P.jQuery.inArray(library.library, ['H5P.CoursePresentation 1.0', 'H5P.CoursePresentation 1.1', 'H5P.CoursePresentation 1.2', 'H5P.CoursePresentation 1.3']) > -1) { + var instance = new constructor(library.params, contentId); + } + else { + var instance = new constructor(library.params, contentId, extras); } - - var instance = new constructor(library.params, contentId, extras); if (instance.$ === undefined) { instance.$ = H5P.jQuery(instance); @@ -595,8 +600,8 @@ H5P.newRunnable = function (library, contentId, $attachTo, skipResize, parent) { if (instance.uuid === undefined && library.uuid) { instance.uuid = library.uuid; } - if (instance.parent === undefined && parent) { - instance.parent = parent; + if (instance.parent === undefined && extras && extras.parent) { + instance.parent = extras.parent; } if ($attachTo !== undefined) { From c746457a872b1ccc20af7e464e27b8d45a50bf7e Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Tue, 24 Mar 2015 18:24:07 +0100 Subject: [PATCH 18/21] Make xAPI work in editor --- js/h5p-x-api-event.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 19bc211..0d0290b 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -97,7 +97,7 @@ H5P.XAPIEvent.prototype.setObject = function(instance) { } } else { - if (H5PIntegration.contents['cid-' + instance.contentId].title) { + if (H5PIntegration && H5PIntegration.contents && H5PIntegration.contents['cid-' + instance.contentId].title) { this.data.statement.object.definition.name = { "en-US": H5P.createH5PTitle(H5PIntegration.contents['cid-' + instance.contentId].title) }; @@ -177,7 +177,7 @@ H5P.XAPIEvent.prototype.getScore = function() { H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) { var xAPIId; - if (instance.contentId) { + if (instance.contentId && H5PIntegration && H5PIntegration.contents) { xAPIId = H5PIntegration.contents['cid-' + instance.contentId].url; if (instance.uuid) { xAPIId += '?uuid=' + instance.uuid; From ef7a31d2e16bd8d667b50d495668e80d23c0859b Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Tue, 24 Mar 2015 18:55:13 +0100 Subject: [PATCH 19/21] Try to get back the no url branch --- h5p.classes.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index daa6ead..3bc78d1 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1785,9 +1785,11 @@ class H5PCore { if ($type === 'preloadedCss' && (isset($dependency['dropCss']) && $dependency['dropCss'] === '1')) { return; } + dpm($prefix); + dpm($dependency['path']); foreach ($dependency[$type] as $file) { $assets[] = (object) array( - 'path' => /*$prefix . */$dependency['path'] . '/' . trim(is_array($file) ? $file['path'] : $file), + 'path' => $prefix . $dependency['path'] . '/' . trim(is_array($file) ? $file['path'] : $file), 'version' => $dependency['version'] ); } @@ -1807,7 +1809,7 @@ class H5PCore { // Add URL prefix if not external if (strpos($asset->path, '://') === FALSE) { - $url = /*$this->url .*/ $url; + $url = $this->url . $url; } // Add version/cache buster if set @@ -1839,7 +1841,6 @@ class H5PCore { $dependency['preloadedJs'] = explode(',', $dependency['preloadedJs']); $dependency['preloadedCss'] = explode(',', $dependency['preloadedCss']); } - $dependency['version'] = "?ver={$dependency['majorVersion']}.{$dependency['minorVersion']}.{$dependency['patchVersion']}"; $this->getDependencyAssets($dependency, 'preloadedJs', $files['scripts'], $prefix); $this->getDependencyAssets($dependency, 'preloadedCss', $files['styles'], $prefix); From 065ee4e8a2bdeb63554dd59c9287f185319d29ef Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Tue, 24 Mar 2015 19:29:28 +0100 Subject: [PATCH 20/21] Make editor work again --- h5p-development.class.php | 3 +-- h5p.classes.php | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/h5p-development.class.php b/h5p-development.class.php index 7f33689..491c456 100644 --- a/h5p-development.class.php +++ b/h5p-development.class.php @@ -86,7 +86,7 @@ class H5PDevelopment { $library['libraryId'] = $this->h5pF->getLibraryId($library['machineName'], $library['majorVersion'], $library['minorVersion']); $this->h5pF->saveLibraryData($library, $library['libraryId'] === FALSE); - $library['path'] = $libraryPath; + $library['path'] = $path . '/' . $contents[$i]; $this->libraries[H5PDevelopment::libraryToString($library['machineName'], $library['majorVersion'], $library['minorVersion'])] = $library; } @@ -139,7 +139,6 @@ class H5PDevelopment { */ public function getSemantics($name, $majorVersion, $minorVersion) { $library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion); - if (isset($this->libraries[$library]) === FALSE) { return NULL; } diff --git a/h5p.classes.php b/h5p.classes.php index 3bc78d1..6a2795e 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1785,8 +1785,6 @@ class H5PCore { if ($type === 'preloadedCss' && (isset($dependency['dropCss']) && $dependency['dropCss'] === '1')) { return; } - dpm($prefix); - dpm($dependency['path']); foreach ($dependency[$type] as $file) { $assets[] = (object) array( 'path' => $prefix . $dependency['path'] . '/' . trim(is_array($file) ? $file['path'] : $file), From 61a8e7e9e935d128bf977be8dac19eb3d1e558ba Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Tue, 24 Mar 2015 19:36:13 +0100 Subject: [PATCH 21/21] Make view work again as well --- h5p.classes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index 6a2795e..1bef34d 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1787,7 +1787,7 @@ class H5PCore { } foreach ($dependency[$type] as $file) { $assets[] = (object) array( - 'path' => $prefix . $dependency['path'] . '/' . trim(is_array($file) ? $file['path'] : $file), + 'path' => /*$prefix .*/ $dependency['path'] . '/' . trim(is_array($file) ? $file['path'] : $file), 'version' => $dependency['version'] ); }