diff --git a/h5p.classes.php b/h5p.classes.php index 681cb23..62f3011 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1606,7 +1606,7 @@ class H5PCore { public static $coreApi = array( 'majorVersion' => 1, - 'minorVersion' => 4 + 'minorVersion' => 5 ); public static $styles = array( 'styles/h5p.css', @@ -2749,13 +2749,13 @@ class H5PContentValidator { 'type' => 'group', 'fields' => $library['semantics'], ), FALSE); - $validkeys = array('library', 'params', 'uuid'); + $validkeys = array('library', 'params', 'subContentId'); if (isset($semantics->extraAttributes)) { $validkeys = array_merge($validkeys, $semantics->extraAttributes); } $this->filterParams($value, $validkeys); - 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); + if (isset($value->subContentId) && ! preg_match('/^\{?[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\}?$/', $value->subContentId)) { + unset($value->subContentId); } // Find all dependencies for this library diff --git a/js/h5p-event-dispatcher.js b/js/h5p-event-dispatcher.js index d67ee10..1d52ef7 100644 --- a/js/h5p-event-dispatcher.js +++ b/js/h5p-event-dispatcher.js @@ -9,18 +9,55 @@ H5P.Event = function(type, data, extras) { this.type = type; this.data = data; var bubbles = false; + + // Is this an external event? + var external = false; + + // Is this event scheduled to be sent externally? + var scheduledForExternal = false; + if (extras === undefined) { extras = {}; } if (extras.bubbles === true) { bubbles = true; } + if (extras.external === true) { + external = true; + } + + /** + * Prevent this event from bubbling up to parent + * + * @returns {undefined} + */ this.preventBubbling = function() { bubbles = false; }; + + /** + * Get bubbling status + * + * @returns {Boolean} - true if bubbling false otherwise + */ this.getBubbles = function() { return bubbles; }; + + /** + * Try to schedule an event for externalDispatcher + * + * @returns {Boolean} + * - true if external and not already scheduled + * - false otherwise + */ + this.scheduleForExternal = function() { + if (external && !scheduledForExternal) { + scheduledForExternal = true; + return true; + } + return false; + }; }; H5P.EventDispatcher = (function () { @@ -144,27 +181,42 @@ H5P.EventDispatcher = (function () { * Custom event data(used when event type as string is used as first * argument */ - this.trigger = function (event, eventData) { + this.trigger = function (event, eventData, extras) { if (event === undefined) { return; } if (typeof event === 'string') { - event = new H5P.Event(event, eventData); + event = new H5P.Event(event, eventData, extras); } else if (eventData !== undefined) { event.data = eventData; } - if (triggers[event.type] === undefined) { - return; + + // Check to see if this event should go externally after all triggering and bubbling is done + var scheduledForExternal = event.scheduleForExternal(); + + if (triggers[event.type] !== undefined) { + // Call all listeners + for (var i = 0; i < triggers[event.type].length; i++) { + triggers[event.type][i].listener.call(triggers[event.type][i].thisArg, event); + } } - // Call all listeners - for (var i = 0; i < triggers[event.type].length; i++) { - triggers[event.type][i].listener.call(triggers[event.type][i].thisArg, event); + + if (triggers['*'] !== undefined) { + // Call all * listeners + for (var i = 0; i < triggers['*'].length; i++) { + triggers['*'][i].listener.call(triggers['*'][i].thisArg, event); + } } + // Bubble if (event.getBubbles() && self.parent instanceof H5P.EventDispatcher && typeof self.parent.trigger === 'function') { self.parent.trigger(event); - } + } + + if (scheduledForExternal) { + H5P.externalDispatcher.trigger(event); + } }; } diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 9b30675..a8513a4 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': {}}, {bubbles: true}); + H5P.Event.call(this, 'xAPI', {'statement': {}}, {bubbles: true, external: true}); }; H5P.XAPIEvent.prototype = Object.create(H5P.Event.prototype); @@ -87,8 +87,8 @@ H5P.XAPIEvent.prototype.setObject = function(instance) { } } }; - if (instance.uuid) { - this.data.statement.object.definition.extensions['http://h5p.org/x-api/h5p-uuid'] = instance.uuid; + if (instance.subContentId) { + this.data.statement.object.definition.extensions['http://h5p.org/x-api/h5p-subContentId'] = instance.subContentId; // Don't set titles on main content, title should come from publishing platform if (typeof instance.getH5PTitle === 'function') { this.data.statement.object.definition.name = { @@ -112,8 +112,8 @@ 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)) { - var parentId = instance.parent.uuid === undefined ? instance.parent.contentId : instance.parent.uuid; + if (instance.parent && (instance.parent.contentId || instance.parent.subContentId)) { + var parentId = instance.parent.subContentId === undefined ? instance.parent.contentId : instance.parent.subContentId; this.data.statement.context = { "contextActivities": { "parent": [ @@ -179,8 +179,8 @@ H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) { var xAPIId; if (instance.contentId && H5PIntegration && H5PIntegration.contents) { xAPIId = H5PIntegration.contents['cid-' + instance.contentId].url; - if (instance.uuid) { - xAPIId += '?uuid=' + instance.uuid; + if (instance.subContentId) { + xAPIId += '?subContentId=' + instance.subContentId; } } return xAPIId; diff --git a/js/h5p-x-api.js b/js/h5p-x-api.js index 9d0e7cd..fa5e51a 100644 --- a/js/h5p-x-api.js +++ b/js/h5p-x-api.js @@ -4,7 +4,7 @@ var H5P = H5P || {}; H5P.externalDispatcher = new H5P.EventDispatcher(); if (H5P.isFramed && H5P.externalEmbed !== true) { - H5P.externalDispatcher.on('xAPI', window.top.H5P.externalDispatcher.trigger); + H5P.externalDispatcher.on('*', window.top.H5P.externalDispatcher.trigger); } // EventDispatcher extensions