Cleaned up docs to make JSdoc generation more meaningful.

semantics-font
Frode Petterson 2015-05-05 13:13:57 +02:00
parent 467f97c11f
commit ccc03782df
5 changed files with 475 additions and 259 deletions

View File

@ -1,21 +1,26 @@
/** @namespace H5P */
var H5P = H5P || {}; var H5P = H5P || {};
/** /**
* The Event class for the EventDispatcher * The Event class for the EventDispatcher.
*
* @class * @class
* @param {string} type
* @param {*} data
* @param {Object} [extras]
* @param {boolean} [extras.bubbles] 
* @param {boolean} [extras.external]
*/ */
H5P.Event = function(type, data, extras) { H5P.Event = function(type, data, extras) {
this.type = type; this.type = type;
this.data = data; this.data = data;
var bubbles = false; var bubbles = false;
// Is this an external event? // Is this an external event?
var external = false; var external = false;
// Is this event scheduled to be sent externally? // Is this event scheduled to be sent externally?
var scheduledForExternal = false; var scheduledForExternal = false;
if (extras === undefined) { if (extras === undefined) {
extras = {}; extras = {};
} }
@ -25,31 +30,29 @@ H5P.Event = function(type, data, extras) {
if (extras.external === true) { if (extras.external === true) {
external = true; external = true;
} }
/** /**
* Prevent this event from bubbling up to parent * Prevent this event from bubbling up to parent
*
* @returns {undefined}
*/ */
this.preventBubbling = function() { this.preventBubbling = function() {
bubbles = false; bubbles = false;
}; };
/** /**
* Get bubbling status * Get bubbling status
* *
* @returns {Boolean} - true if bubbling false otherwise * @returns {boolean}
* true if bubbling false otherwise
*/ */
this.getBubbles = function() { this.getBubbles = function() {
return bubbles; return bubbles;
}; };
/** /**
* Try to schedule an event for externalDispatcher * Try to schedule an event for externalDispatcher
* *
* @returns {Boolean} * @returns {boolean}
* - true if external and not already scheduled * true if external and not already scheduled, otherwise false
* - false otherwise
*/ */
this.scheduleForExternal = function() { this.scheduleForExternal = function() {
if (external && !scheduledForExternal) { if (external && !scheduledForExternal) {
@ -60,18 +63,28 @@ H5P.Event = function(type, data, extras) {
}; };
}; };
/**
* Callback type for event listeners.
*
* @callback H5P.EventCallback
* @param {H5P.Event} event
*/
H5P.EventDispatcher = (function () { H5P.EventDispatcher = (function () {
/** /**
* The base of the event system. * The base of the event system.
* Inherit this class if you want your H5P to dispatch events. * Inherit this class if you want your H5P to dispatch events.
*
* @class * @class
* @memberof H5P
*/ */
function EventDispatcher() { function EventDispatcher() {
var self = this; var self = this;
/** /**
* Keep track of listeners for each event. * Keep track of listeners for each event.
*
* @private * @private
* @type {Object} * @type {Object}
*/ */
@ -80,11 +93,14 @@ H5P.EventDispatcher = (function () {
/** /**
* Add new event listener. * Add new event listener.
* *
* @public * @throws {TypeError}
* @throws {TypeError} listener - Must be a function * listener must be a function
* @param {String} type - Event type * @param {string} type
* @param {Function} listener - Event listener * Event type
* @param {Function} thisArg - Optionally specify the this value when calling listener. * @param {H5P.EventCallback} listener
* Event listener
* @param {function} thisArg
* Optionally specify the this value when calling listener.
*/ */
this.on = function (type, listener, thisArg) { this.on = function (type, listener, thisArg) {
if (thisArg === undefined) { if (thisArg === undefined) {
@ -110,11 +126,14 @@ H5P.EventDispatcher = (function () {
/** /**
* Add new event listener that will be fired only once. * Add new event listener that will be fired only once.
* *
* @public * @throws {TypeError}
* @throws {TypeError} listener - must be a function * listener must be a function
* @param {String} type - Event type * @param {string} type
* @param {Function} listener - Event listener * Event type
* @param {Function} thisArg - Optionally specify the this value when calling listener. * @param {H5P.EventCallback} listener
* Event listener
* @param {function} thisArg
* Optionally specify the this value when calling listener.
*/ */
this.once = function (type, listener, thisArg) { this.once = function (type, listener, thisArg) {
if (thisArg === undefined) { if (thisArg === undefined) {
@ -136,10 +155,12 @@ H5P.EventDispatcher = (function () {
* Remove event listener. * Remove event listener.
* If no listener is specified, all listeners will be removed. * If no listener is specified, all listeners will be removed.
* *
* @public * @throws {TypeError}
* @throws {TypeError} listener - must be a function * listener must be a function
* @param {String} type - Event type * @param {string} type
* @param {Function} listener - Event listener * Event type
* @param {H5P.EventCallback} listener
* Event listener
*/ */
this.off = function (type, listener) { this.off = function (type, listener) {
if (listener !== undefined && !(listener instanceof Function)) { if (listener !== undefined && !(listener instanceof Function)) {
@ -175,45 +196,48 @@ H5P.EventDispatcher = (function () {
/** /**
* Dispatch event. * Dispatch event.
* *
* @public * @param {string|H5P.Event} event
* @param {String|Function} event - Event object or event type as string * Event object or event type as string
* @param {mixed} eventData * @param {*} [eventData]
* Custom event data(used when event type as string is used as first * Custom event data(used when event type as string is used as first
* argument * argument).
* @param {Object} [extras]
* @param {boolean} [extras.bubbles] 
* @param {boolean} [extras.external]
*/ */
this.trigger = function (event, eventData, extras) { this.trigger = function (event, eventData, extras) {
if (event === undefined) { if (event === undefined) {
return; return;
} }
if (typeof event === 'string') { if (typeof event === 'string') { // TODO: Check instanceof String as well?
event = new H5P.Event(event, eventData, extras); event = new H5P.Event(event, eventData, extras);
} }
else if (eventData !== undefined) { else if (eventData !== undefined) {
event.data = eventData; event.data = eventData;
} }
// Check to see if this event should go externally after all triggering and bubbling is done // Check to see if this event should go externally after all triggering and bubbling is done
var scheduledForExternal = event.scheduleForExternal(); var scheduledForExternal = event.scheduleForExternal();
if (triggers[event.type] !== undefined) { if (triggers[event.type] !== undefined) {
// Call all listeners // Call all listeners
for (var i = 0; i < triggers[event.type].length; i++) { for (var i = 0; i < triggers[event.type].length; i++) {
triggers[event.type][i].listener.call(triggers[event.type][i].thisArg, event); triggers[event.type][i].listener.call(triggers[event.type][i].thisArg, event);
} }
} }
if (triggers['*'] !== undefined) { if (triggers['*'] !== undefined) {
// Call all * listeners // Call all * listeners
for (var i = 0; i < triggers['*'].length; i++) { for (var j = 0; j < triggers['*'].length; j++) {
triggers['*'][i].listener.call(triggers['*'][i].thisArg, event); triggers['*'][j].listener.call(triggers['*'][j].thisArg, event);
} }
} }
// Bubble // Bubble
if (event.getBubbles() && self.parent instanceof H5P.EventDispatcher && typeof self.parent.trigger === 'function') { if (event.getBubbles() && self.parent instanceof H5P.EventDispatcher && typeof self.parent.trigger === 'function') { // TODO: Check instanceof Function as well?
self.parent.trigger(event); self.parent.trigger(event);
} }
if (scheduledForExternal) { if (scheduledForExternal) {
H5P.externalDispatcher.trigger(event); H5P.externalDispatcher.trigger(event);
} }

View File

@ -1,11 +1,12 @@
var H5P = H5P || {}; var H5P = H5P || {};
/** /**
* Constructor for xAPI events * Used for xAPI events.
* *
* @class * @class
* @extends H5P.Event
*/ */
H5P.XAPIEvent = function() { H5P.XAPIEvent = function () {
H5P.Event.call(this, 'xAPI', {'statement': {}}, {bubbles: true, external: true}); H5P.Event.call(this, 'xAPI', {'statement': {}}, {bubbles: true, external: true});
}; };
@ -13,12 +14,12 @@ H5P.XAPIEvent.prototype = Object.create(H5P.Event.prototype);
H5P.XAPIEvent.prototype.constructor = H5P.XAPIEvent; H5P.XAPIEvent.prototype.constructor = H5P.XAPIEvent;
/** /**
* Helperfunction to set scored result statements * Set scored result statements.
* *
* @param {int} score * @param {number} score
* @param {int} maxScore * @param {number} maxScore
*/ */
H5P.XAPIEvent.prototype.setScoredResult = function(score, maxScore) { H5P.XAPIEvent.prototype.setScoredResult = function (score, maxScore) {
this.data.statement.result = { this.data.statement.result = {
'score': { 'score': {
'min': 0, 'min': 0,
@ -29,13 +30,14 @@ H5P.XAPIEvent.prototype.setScoredResult = function(score, maxScore) {
}; };
/** /**
* Helperfunction to set a verb. * Set a verb.
* *
* @param {string} verb * @param {string} verb
* Verb in short form, one of the verbs defined at * Verb in short form, one of the verbs defined at
* http://adlnet.gov/expapi/verbs/ * {@link http://adlnet.gov/expapi/verbs/|ADL xAPI Vocabulary}
*
*/ */
H5P.XAPIEvent.prototype.setVerb = function(verb) { H5P.XAPIEvent.prototype.setVerb = function (verb) {
if (H5P.jQuery.inArray(verb, H5P.XAPIEvent.allowedXAPIVerbs) !== -1) { if (H5P.jQuery.inArray(verb, H5P.XAPIEvent.allowedXAPIVerbs) !== -1) {
this.data.statement.verb = { this.data.statement.verb = {
'id': 'http://adlnet.gov/expapi/verbs/' + verb, 'id': 'http://adlnet.gov/expapi/verbs/' + verb,
@ -50,13 +52,15 @@ H5P.XAPIEvent.prototype.setVerb = function(verb) {
}; };
/** /**
* Helperfunction to get the statements verb id * Get the statements verb id.
* *
* @param {boolean} full * @param {boolean} full
* if true the full verb id prefixed by http://adlnet.gov/expapi/verbs/ will be returned * if true the full verb id prefixed by http://adlnet.gov/expapi/verbs/
* @returns {string} - Verb or null if no verb with an id has been defined * will be returned
* @returns {string}
* Verb or null if no verb with an id has been defined
*/ */
H5P.XAPIEvent.prototype.getVerb = function(full) { H5P.XAPIEvent.prototype.getVerb = function (full) {
var statement = this.data.statement; var statement = this.data.statement;
if ('verb' in statement) { if ('verb' in statement) {
if (full === true) { if (full === true) {
@ -70,13 +74,14 @@ H5P.XAPIEvent.prototype.getVerb = function(full) {
}; };
/** /**
* Helperfunction to set the object part of the statement. * Set the object part of the statement.
* *
* The id is found automatically (the url to the content) * The id is found automatically (the url to the content)
* *
* @param {object} instance - the H5P instance * @param {Object} instance
* The H5P instance
*/ */
H5P.XAPIEvent.prototype.setObject = function(instance) { H5P.XAPIEvent.prototype.setObject = function (instance) {
if (instance.contentId) { if (instance.contentId) {
this.data.statement.object = { this.data.statement.object = {
'id': this.getContentXAPIId(instance), 'id': this.getContentXAPIId(instance),
@ -107,11 +112,12 @@ H5P.XAPIEvent.prototype.setObject = function(instance) {
}; };
/** /**
* Helperfunction to set the context part of the statement. * Set the context part of the statement.
* *
* @param {object} instance - the H5P instance * @param {Object} instance
* The H5P instance
*/ */
H5P.XAPIEvent.prototype.setContext = function(instance) { H5P.XAPIEvent.prototype.setContext = function (instance) {
if (instance.parent && (instance.parent.contentId || instance.parent.subContentId)) { if (instance.parent && (instance.parent.contentId || instance.parent.subContentId)) {
var parentId = instance.parent.subContentId === undefined ? instance.parent.contentId : instance.parent.subContentId; var parentId = instance.parent.subContentId === undefined ? instance.parent.contentId : instance.parent.subContentId;
this.data.statement.context = { this.data.statement.context = {
@ -128,9 +134,9 @@ H5P.XAPIEvent.prototype.setContext = function(instance) {
}; };
/** /**
* Helper function to set the actor, email and name will be added automatically * Set the actor. Email and name will be added automatically.
*/ */
H5P.XAPIEvent.prototype.setActor = function() { H5P.XAPIEvent.prototype.setActor = function () {
if (H5PIntegration.user !== undefined) { if (H5PIntegration.user !== undefined) {
this.data.statement.actor = { this.data.statement.actor = {
'name': H5PIntegration.user.name, 'name': H5PIntegration.user.name,
@ -160,7 +166,8 @@ H5P.XAPIEvent.prototype.setActor = function() {
/** /**
* Get the max value of the result - score part of the statement * Get the max value of the result - score part of the statement
* *
* @returns {int} the max score, or null if not defined * @returns {number}
* The max score, or null if not defined
*/ */
H5P.XAPIEvent.prototype.getMaxScore = function() { H5P.XAPIEvent.prototype.getMaxScore = function() {
return this.getVerifiedStatementValue(['result', 'score', 'max']); return this.getVerifiedStatementValue(['result', 'score', 'max']);
@ -169,12 +176,19 @@ H5P.XAPIEvent.prototype.getMaxScore = function() {
/** /**
* Get the raw value of the result - score part of the statement * Get the raw value of the result - score part of the statement
* *
* @returns {int} the max score, or null if not defined * @returns {number}
* The score, or null if not defined
*/ */
H5P.XAPIEvent.prototype.getScore = function() { H5P.XAPIEvent.prototype.getScore = function() {
return this.getVerifiedStatementValue(['result', 'score', 'raw']); return this.getVerifiedStatementValue(['result', 'score', 'raw']);
}; };
/**
* Get content xAPI ID.
*
* @param {Object} instance
* The H5P instance
*/
H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) { H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) {
var xAPIId; var xAPIId;
if (instance.contentId && H5PIntegration && H5PIntegration.contents) { if (instance.contentId && H5PIntegration && H5PIntegration.contents) {
@ -184,15 +198,16 @@ H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) {
} }
} }
return xAPIId; return xAPIId;
} };
/** /**
* Figure out if a property exists in the statement and return it * Figure out if a property exists in the statement and return it
* *
* @param {array} keys * @param {string[]} keys
* List describing the property we're looking for. For instance * List describing the property we're looking for. For instance
* ['result', 'score', 'raw'] for result.score.raw * ['result', 'score', 'raw'] for result.score.raw
* @returns the value of the property if it is set, null otherwise * @returns {*}
* The value of the property if it is set, null otherwise.
*/ */
H5P.XAPIEvent.prototype.getVerifiedStatementValue = function(keys) { H5P.XAPIEvent.prototype.getVerifiedStatementValue = function(keys) {
var val = this.data.statement; var val = this.data.statement;
@ -206,7 +221,7 @@ H5P.XAPIEvent.prototype.getVerifiedStatementValue = function(keys) {
}; };
/** /**
* List of verbs defined at http://adlnet.gov/expapi/verbs/ * List of verbs defined at {@link http://adlnet.gov/expapi/verbs/|ADL xAPI Vocabulary}
* *
* @type Array * @type Array
*/ */

View File

@ -1,31 +1,41 @@
var H5P = H5P || {}; var H5P = H5P || {};
// Create object where external code may register and listen for H5P Events /**
* The external event dispatcher. Others, outside of H5P may register and
* listen for H5P Events here.
*
* @type {H5P.EventDispatcher}
*/
H5P.externalDispatcher = new H5P.EventDispatcher(); H5P.externalDispatcher = new H5P.EventDispatcher();
// EventDispatcher extensions // EventDispatcher extensions
/** /**
* Helper function for triggering xAPI added to the EventDispatcher * Helper function for triggering xAPI added to the EventDispatcher.
* *
* @param {string} verb - the short id of the verb we want to trigger * @param {string} verb
* @param {oject} extra - extra properties for the xAPI statement * The short id of the verb we want to trigger
* @param {Oject} [extra]
* Extra properties for the xAPI statement
*/ */
H5P.EventDispatcher.prototype.triggerXAPI = function(verb, extra) { H5P.EventDispatcher.prototype.triggerXAPI = function (verb, extra) {
this.trigger(this.createXAPIEventTemplate(verb, extra)); this.trigger(this.createXAPIEventTemplate(verb, extra));
}; };
/** /**
* Helper function to create event templates added to the EventDispatcher * Helper function to create event templates added to the EventDispatcher.
* *
* Will in the future be used to add representations of the questions to the * Will in the future be used to add representations of the questions to the
* statements. * statements.
* *
* @param {string} verb - verb id in short form * @param {string} verb
* @param {object} extra - Extra values to be added to the statement * Verb id in short form
* @returns {Function} - XAPIEvent object * @param {Object} [extra]
* Extra values to be added to the statement
* @returns {H5P.XAPIEvent}
* Instance
*/ */
H5P.EventDispatcher.prototype.createXAPIEventTemplate = function(verb, extra) { H5P.EventDispatcher.prototype.createXAPIEventTemplate = function (verb, extra) {
var event = new H5P.XAPIEvent(); var event = new H5P.XAPIEvent();
event.setActor(); event.setActor();
@ -49,22 +59,28 @@ H5P.EventDispatcher.prototype.createXAPIEventTemplate = function(verb, extra) {
* *
* DEPRECATED - USE triggerXAPIScored instead * DEPRECATED - USE triggerXAPIScored instead
* *
* @param {int} score - will be set as the 'raw' value of the score object * @deprecated
* @param {int} maxScore - will be set as the "max" value of the score object * since 1.5, use triggerXAPIScored instead.
* @param {number} score
* Will be set as the 'raw' value of the score object
* @param {number} maxScore
* will be set as the "max" value of the score object
*/ */
H5P.EventDispatcher.prototype.triggerXAPICompleted = function(score, maxScore) { H5P.EventDispatcher.prototype.triggerXAPICompleted = function (score, maxScore) {
this.triggerXAPIScored(score, maxScore, 'completed'); this.triggerXAPIScored(score, maxScore, 'completed');
}; };
/** /**
* Helper function to create scored xAPI events * Helper function to create scored xAPI events
* *
* * @param {number} score
* @param {int} score - will be set as the 'raw' value of the score object * Will be set as the 'raw' value of the score object
* @param {int} maxScore - will be set as the "max" value of the score object * @param {number} maxScore
* @param {string} verb - short form of adl verb * Will be set as the "max" value of the score object
* @param {string} verb
* Short form of adl verb
*/ */
H5P.EventDispatcher.prototype.triggerXAPIScored = function(score, maxScore, verb) { H5P.EventDispatcher.prototype.triggerXAPIScored = function (score, maxScore, verb) {
var event = this.createXAPIEventTemplate(verb); var event = this.createXAPIEventTemplate(verb);
event.setScoredResult(score, maxScore); event.setScoredResult(score, maxScore);
this.trigger(event); this.trigger(event);
@ -73,9 +89,9 @@ H5P.EventDispatcher.prototype.triggerXAPIScored = function(score, maxScore, verb
/** /**
* Internal H5P function listening for xAPI completed events and stores scores * Internal H5P function listening for xAPI completed events and stores scores
* *
* @param {function} event - xAPI event * @param {H5P.XAPIEvent} event
*/ */
H5P.xAPICompletedListener = function(event) { H5P.xAPICompletedListener = function (event) {
if (event.getVerb() === 'completed' && !event.getVerifiedStatementValue(['context', 'contextActivities', 'parent'])) { if (event.getVerb() === 'completed' && !event.getVerifiedStatementValue(['context', 'contextActivities', 'parent'])) {
var score = event.getScore(); var score = event.getScore();
var maxScore = event.getMaxScore(); var maxScore = event.getMaxScore();

485
js/h5p.js
View File

@ -1,17 +1,34 @@
/*jshint multistr: true */ /*jshint multistr: true */
// TODO: Should we split up the generic parts needed by the editor(and others), and the parts needed to "run" H5Ps? // TODO: Should we split up the generic parts needed by the editor(and others), and the parts needed to "run" H5Ps?
/** @namespace */
var H5P = H5P || {}; var H5P = H5P || {};
// Determine if we're inside an iframe. /**
* Tells us if we're inside of an iframe.
* @member {boolean}
*/
H5P.isFramed = (window.self !== window.top); H5P.isFramed = (window.self !== window.top);
// Useful jQuery object. /**
* jQuery instance of current window.
* @member {H5P.jQuery}
*/
H5P.$window = H5P.jQuery(window); H5P.$window = H5P.jQuery(window);
/**
* List over H5P instances on the current page.
* @member {Array}
*/
H5P.instances = []; H5P.instances = [];
// Detect if we support fullscreen, and what prefix to use. // Detect if we support fullscreen, and what prefix to use.
if (document.documentElement.requestFullScreen) { if (document.documentElement.requestFullScreen) {
/**
* Browser prefix to use when entering fullscreen mode.
* undefined means no fullscreen support.
* @member {string}
*/
H5P.fullScreenBrowserPrefix = ''; H5P.fullScreenBrowserPrefix = '';
} }
else if (document.documentElement.webkitRequestFullScreen) { else if (document.documentElement.webkitRequestFullScreen) {
@ -30,34 +47,36 @@ else if (document.documentElement.msRequestFullscreen) {
H5P.fullScreenBrowserPrefix = 'ms'; H5P.fullScreenBrowserPrefix = 'ms';
} }
/** @const {Number} */ /** @const {number} */
H5P.DISABLE_NONE = 0; H5P.DISABLE_NONE = 0;
/** @const {Number} */ /** @const {number} */
H5P.DISABLE_FRAME = 1; H5P.DISABLE_FRAME = 1;
/** @const {Number} */ /** @const {number} */
H5P.DISABLE_DOWNLOAD = 2; H5P.DISABLE_DOWNLOAD = 2;
/** @const {Number} */ /** @const {number} */
H5P.DISABLE_EMBED = 4; H5P.DISABLE_EMBED = 4;
/** @const {Number} */ /** @const {number} */
H5P.DISABLE_COPYRIGHT = 8; H5P.DISABLE_COPYRIGHT = 8;
/** @const {Number} */ /** @const {number} */
H5P.DISABLE_ABOUT = 16; H5P.DISABLE_ABOUT = 16;
/** /**
* Keep track of when the H5Ps where started. * Keep track of when the H5Ps where started.
* *
* @type {Array} * @type {Object[]}
*/ */
H5P.opened = {}; H5P.opened = {};
/** /**
* Initialize H5P content. * Initialize H5P content.
* Scans for ".h5p-content" in the document and initializes H5P instances where found. * Scans for ".h5p-content" in the document and initializes H5P instances where found.
*
* @param {Object} target DOM Element
*/ */
H5P.init = function (target) { H5P.init = function (target) {
// Useful jQuery object. // Useful jQuery object.
@ -67,8 +86,12 @@ H5P.init = function (target) {
// Determine if we can use full screen // Determine if we can use full screen
if (H5P.canHasFullScreen === undefined) { if (H5P.canHasFullScreen === undefined) {
// Restricts fullscreen when embedded. /**
// (embedded doesn't support semi-fullscreen solution) * Use this variable to check if fullscreen is supported. Fullscreen can be
* restricted when embedding since not all browsers support the native
* fullscreen, and the semi-fullscreen solution doesn't work when embedded.
* @type {boolean}
*/
H5P.canHasFullScreen = (H5P.isFramed && H5P.externalEmbed !== false) ? ((document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled) ? true : false) : true; H5P.canHasFullScreen = (H5P.isFramed && H5P.externalEmbed !== false) ? ((document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled) ? true : false) : true;
// We should consider document.msFullscreenEnabled when they get their // We should consider document.msFullscreenEnabled when they get their
// element sizing corrected. Ref. https://connect.microsoft.com/IE/feedback/details/838286/ie-11-incorrectly-reports-dom-element-sizes-in-fullscreen-mode-when-fullscreened-element-is-within-an-iframe // element sizing corrected. Ref. https://connect.microsoft.com/IE/feedback/details/838286/ie-11-incorrectly-reports-dom-element-sizes-in-fullscreen-mode-when-fullscreened-element-is-within-an-iframe
@ -348,9 +371,15 @@ H5P.getHeadTags = function (contentId) {
'<script>H5PIntegration = window.top.H5PIntegration; var H5P = H5P || {}; H5P.externalEmbed = false;</script>'; '<script>H5PIntegration = window.top.H5PIntegration; var H5P = H5P || {}; H5P.externalEmbed = false;</script>';
}; };
/**
* When embedded the communicator helps talk to the parent page.
*
* @type {Communicator}
*/
H5P.communicator = (function () { H5P.communicator = (function () {
/** /**
* @class * @class
* @private
*/ */
function Communicator() { function Communicator() {
var self = this; var self = this;
@ -373,9 +402,8 @@ H5P.communicator = (function () {
/** /**
* Register action listener. * Register action listener.
* *
* @public * @param {string} action What you are waiting for
* @param {String} action What you are waiting for * @param {function} handler What you want done
* @param {Function} handler What you want done
*/ */
self.on = function (action, handler) { self.on = function (action, handler) {
actionHandlers[action] = handler; actionHandlers[action] = handler;
@ -384,8 +412,7 @@ H5P.communicator = (function () {
/** /**
* Send a message to the all mighty father. * Send a message to the all mighty father.
* *
* @public * @param {string} action
* @param {String} action
* @param {Object} [data] payload * @param {Object} [data] payload
*/ */
self.send = function (action, data) { self.send = function (action, data) {
@ -404,13 +431,12 @@ H5P.communicator = (function () {
})(); })();
/** /**
* Enable full screen for the given h5p. * Enter fullscreen for the given H5P instance.
* *
* @param {jQuery} $element Content container. * @param {H5P.jQuery} $element Content container.
* @param {object} instance * @param {Object} instance
* @param {function} exitCallback Callback function called when user exits fullscreen. * @param {function} exitCallback Callback function called when user exits fullscreen.
* @param {jQuery} $body For internal use. Gives the body of the iframe. * @param {H5P.jQuery} $body For internal use. Gives the body of the iframe.
* @returns {undefined}
*/ */
H5P.fullScreen = function ($element, instance, exitCallback, body) { H5P.fullScreen = function ($element, instance, exitCallback, body) {
if (H5P.exitFullScreen !== undefined) { if (H5P.exitFullScreen !== undefined) {
@ -450,7 +476,8 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
/** /**
* Prepare for resize by setting the correct styles. * Prepare for resize by setting the correct styles.
* *
* @param {String} classes CSS * @private
* @param {string} classes CSS
*/ */
var before = function (classes) { var before = function (classes) {
$classes.addClass(classes); $classes.addClass(classes);
@ -464,6 +491,8 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
/** /**
* Gets called when fullscreen mode has been entered. * Gets called when fullscreen mode has been entered.
* Resizes and sets focus on content. * Resizes and sets focus on content.
*
* @private
*/ */
var entered = function () { var entered = function () {
// Do not rely on window resize events. // Do not rely on window resize events.
@ -476,7 +505,8 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
* Gets called when fullscreen mode has been exited. * Gets called when fullscreen mode has been exited.
* Resizes and sets focus on content. * Resizes and sets focus on content.
* *
* @param {String} classes CSS * @private
* @param {string} classes CSS
*/ */
var done = function (classes) { var done = function (classes) {
H5P.isFullscreen = false; H5P.isFullscreen = false;
@ -561,14 +591,15 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
}; };
/** /**
* Find the path to the content files based on the id of the content * Find the path to the content files based on the id of the content.
* Also identifies and returns absolute paths.
* *
* Also identifies and returns absolute paths * @param {string} path
* * Relative to content folder or absolute.
* @param string path * @param {number} contentId
* Absolute path to a file, or relative path to a file in the content folder * ID of the content requesting the path.
* @param contentId * @returns {string}
* Id of the content requesting a path * Complete URL to path.
*/ */
H5P.getPath = function (path, contentId) { H5P.getPath = function (path, contentId) {
var hasProtocol = function (path) { var hasProtocol = function (path) {
@ -601,10 +632,14 @@ H5P.getPath = function (path, contentId) {
* THIS FUNCTION IS DEPRECATED, USE getPath INSTEAD * THIS FUNCTION IS DEPRECATED, USE getPath INSTEAD
* Will be remove march 2016. * Will be remove march 2016.
* *
* Find the path to the content files folder based on the id of the content * Find the path to the content files folder based on the id of the content
* *
* @param contentId * @deprecated
* Id of the content requesting a path * Will be removed march 2016.
* @param contentId
* Id of the content requesting the path
* @returns {string}
* URL
*/ */
H5P.getContentPath = function (contentId) { H5P.getContentPath = function (contentId) {
return H5PIntegration.url + '/content/' + contentId; return H5PIntegration.url + '/content/' + contentId;
@ -613,32 +648,38 @@ H5P.getContentPath = function (contentId) {
/** /**
* Get library class constructor from H5P by classname. * Get library class constructor from H5P by classname.
* Note that this class will only work for resolve "H5P.NameWithoutDot". * Note that this class will only work for resolve "H5P.NameWithoutDot".
* Also check out: H5P.newRunnable * Also check out {@link H5P.newRunnable}
* *
* Used from libraries to construct instances of other libraries' objects by name. * Used from libraries to construct instances of other libraries' objects by name.
* *
* @param {string} name Name of library * @param {string} name Name of library
* @returns Class constructor * @returns {Object} Class constructor
*/ */
H5P.classFromName = function (name) { H5P.classFromName = function (name) {
var arr = name.split("."); var arr = name.split(".");
return this[arr[arr.length-1]]; return this[arr[arr.length - 1]];
}; };
/** /**
* A safe way of creating a new instance of a runnable H5P. * A safe way of creating a new instance of a runnable H5P.
* *
* TODO: Should we check if version matches the library? * @param {Object} library
* TODO: Dynamically try to load libraries currently not loaded? That will require a callback. * Library/action object form params.
* * @param {number} contentId
* @param {Object} library Library/action object form params. * Identifies the content.
* @param {Number} contentId * @param {H5P.jQuery} [$attachTo]
* @param {jQuery} $attachTo An optional element to attach the instance to. * Element to attach the instance to.
* @param {Boolean} skipResize Optionally skip triggering of the resize event after attaching. * @param {boolean} [skipResize]
* @param {Object} extras - extra params for the H5P content constructor * Skip triggering of the resize event after attaching.
* @return {Object} Instance. * @param {Object} [extras]
* Extra parameters for the H5P content constructor
* @returns {Object}
* Instance.
*/ */
H5P.newRunnable = function (library, contentId, $attachTo, skipResize, extras) { H5P.newRunnable = function (library, contentId, $attachTo, skipResize, extras) {
// TODO: Should we check if version matches the library?
// TODO: Dynamically try to load libraries currently not loaded? That will require a callback.
var nameSplit, versionSplit, machineName; var nameSplit, versionSplit, machineName;
try { try {
nameSplit = library.library.split(' ', 2); nameSplit = library.library.split(' ', 2);
@ -723,10 +764,9 @@ H5P.newRunnable = function (library, contentId, $attachTo, skipResize, extras) {
}; };
/** /**
* Used to print useful error messages. * Used to print useful error messages. (to JavaScript error console)
* *
* @param {mixed} err Error to print. * @param {*} err Error to print.
* @returns {undefined}
*/ */
H5P.error = function (err) { H5P.error = function (err) {
if (window.console !== undefined && console.error !== undefined) { if (window.console !== undefined && console.error !== undefined) {
@ -737,10 +777,14 @@ H5P.error = function (err) {
/** /**
* Translate text strings. * Translate text strings.
* *
* @param {String} key Translation identifier, may only contain a-zA-Z0-9. No spaces or special chars. * @param {string} key
* @param {Object} vars Data for placeholders. * Translation identifier, may only contain a-zA-Z0-9. No spaces or special chars.
* @param {String} ns Translation namespace. Defaults to H5P. * @param {Object} vars
* @returns {String} Text * Data for placeholders.
* @param {string} ns
* Translation namespace. Defaults to H5P.
* @returns {string}
* Translated text
*/ */
H5P.t = function (key, vars, ns) { H5P.t = function (key, vars, ns) {
if (ns === undefined) { if (ns === undefined) {
@ -767,6 +811,19 @@ H5P.t = function (key, vars, ns) {
return translation; return translation;
}; };
/**
* Creates a new popup dialog over the H5P content.
*
* @class
* @param {string} name
* Used for html class.
* @param {string} title
* Used for header.
* @param {string} content
* Displayed inside the dialog.
* @param {H5P.jQuery} $element
* Which DOM element the dialog should be inserted after.
*/
H5P.Dialog = function (name, title, content, $element) { H5P.Dialog = function (name, title, content, $element) {
var self = this; var self = this;
var $dialog = H5P.jQuery('<div class="h5p-popup-dialog h5p-' + name + '-dialog">\ var $dialog = H5P.jQuery('<div class="h5p-popup-dialog h5p-' + name + '-dialog">\
@ -810,9 +867,14 @@ H5P.Dialog = function (name, title, content, $element) {
/** /**
* Gather copyright information and display in a dialog over the content. * Gather copyright information and display in a dialog over the content.
* *
* @param {jQuery} $element to insert dialog after. * @param {H5P.jQuery} $element
* @param {object} instance to get copyright information from. * DOM Element to insert dialog after.
* @returns {undefined} * @param {Object} instance
* H5P instance to get copyright information for.
* @param {Object} parameters
* Parameters of the content instance.
* @param {number} contentId
* Identifies the H5P content
*/ */
H5P.openCopyrightsDialog = function ($element, instance, parameters, contentId) { H5P.openCopyrightsDialog = function ($element, instance, parameters, contentId) {
var copyrights; var copyrights;
@ -843,10 +905,12 @@ H5P.openCopyrightsDialog = function ($element, instance, parameters, contentId)
/** /**
* Gather a flat list of copyright information from the given parameters. * Gather a flat list of copyright information from the given parameters.
* *
* @param {H5P.ContentCopyrights} info Used to collect all information in. * @param {H5P.ContentCopyrights} info
* @param {(Object|Arrray)} parameters To search for file objects in. * Used to collect all information in.
* @param {Number} contentId Used to insert thumbnails for images. * @param {(Object|Array)} parameters
* @returns {undefined} * To search for file objects in.
* @param {number} contentId
* Used to insert thumbnails for images.
*/ */
H5P.findCopyrights = function (info, parameters, contentId) { H5P.findCopyrights = function (info, parameters, contentId) {
// Cycle through parameters // Cycle through parameters
@ -887,9 +951,12 @@ H5P.findCopyrights = function (info, parameters, contentId) {
/** /**
* Recursive function for checking if content has copyrights * Recursive function for checking if content has copyrights
* *
* @param {(Object|Arrray)} parameters To search for file objects in. * @param {(Object|Array)} parameters
* @param {Number} contentId Used to insert thumbnails for images. * To search for file objects in.
* @returns {boolean} Returns true if complete copyright information was found. * @param {number} contentId
* Used to insert thumbnails for images.
* @returns {boolean}
* Returns true if complete copyright information was found.
*/ */
H5P.hasCopyrights = function (parameters, contentId) { H5P.hasCopyrights = function (parameters, contentId) {
// Cycle through parameters // Cycle through parameters
@ -929,9 +996,16 @@ H5P.hasCopyrights = function (parameters, contentId) {
/** /**
* Display a dialog containing the embed code. * Display a dialog containing the embed code.
* *
* @param {jQuery} $element to insert dialog after. * @param {H5P.jQuery} $element
* @param {string} embed code. * Element to insert dialog after.
* @returns {undefined} * @param {string} embedCode
* The embed code.
* @param {string} resizeCode
* The advanced resize code
* @param {Object} size
* The content's size.
* @param {number} size.width
* @param {number} size.height
*/ */
H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size) { H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size) {
var fullEmbedCode = embedCode + resizeCode; var fullEmbedCode = embedCode + resizeCode;
@ -1010,6 +1084,8 @@ H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size) {
/** /**
* Copyrights for a H5P Content Library. * Copyrights for a H5P Content Library.
*
* @class
*/ */
H5P.ContentCopyrights = function () { H5P.ContentCopyrights = function () {
var label; var label;
@ -1017,16 +1093,16 @@ H5P.ContentCopyrights = function () {
var content = []; var content = [];
/** /**
* Public. Set label. * Set label.
* *
* @param {String} newLabel * @param {string} newLabel
*/ */
this.setLabel = function (newLabel) { this.setLabel = function (newLabel) {
label = newLabel; label = newLabel;
}; };
/** /**
* Public. Add sub content. * Add sub content.
* *
* @param {H5P.MediaCopyright} newMedia * @param {H5P.MediaCopyright} newMedia
*/ */
@ -1037,7 +1113,7 @@ H5P.ContentCopyrights = function () {
}; };
/** /**
* Public. Add sub content. * Add sub content.
* *
* @param {H5P.ContentCopyrights} newContent * @param {H5P.ContentCopyrights} newContent
*/ */
@ -1048,9 +1124,9 @@ H5P.ContentCopyrights = function () {
}; };
/** /**
* Public. Print content copyright. * Print content copyright.
* *
* @returns {String} HTML. * @returns {string} HTML.
*/ */
this.toString = function () { this.toString = function () {
var html = ''; var html = '';
@ -1083,20 +1159,26 @@ H5P.ContentCopyrights = function () {
/** /**
* A ordered list of copyright fields for media. * A ordered list of copyright fields for media.
* *
* @param {Object} copyright information fields. * @class
* @param {Object} labels translation. Optional. * @param {Object} copyright
* @param {Array} order of fields. Optional. * Copyright information fields.
* @param {Object} extraFields for copyright. Optional. * @param {Object} [labels]
* Translation of labels.
* @param {Array} [order]
* Order of the fields.
* @param {Object} [extraFields]
* Add extra copyright fields.
*/ */
H5P.MediaCopyright = function (copyright, labels, order, extraFields) { H5P.MediaCopyright = function (copyright, labels, order, extraFields) {
var thumbnail; var thumbnail;
var list = new H5P.DefinitionList(); var list = new H5P.DefinitionList();
/** /**
* Private. Get translated label for field. * Get translated label for field.
* *
* @param {String} fieldName * @private
* @return {String} * @param {string} fieldName
* @returns {string}
*/ */
var getLabel = function (fieldName) { var getLabel = function (fieldName) {
if (labels === undefined || labels[fieldName] === undefined) { if (labels === undefined || labels[fieldName] === undefined) {
@ -1107,10 +1189,12 @@ H5P.MediaCopyright = function (copyright, labels, order, extraFields) {
}; };
/** /**
* Private. Get humanized value for field. * Get humanized value for field.
* *
* @param {String} fieldName * @private
* @return {String} * @param {string} fieldName
* @param {string} value
* @returns {string}
*/ */
var humanizeValue = function (fieldName, value) { var humanizeValue = function (fieldName, value) {
if (fieldName === 'license') { if (fieldName === 'license') {
@ -1142,7 +1226,7 @@ H5P.MediaCopyright = function (copyright, labels, order, extraFields) {
} }
/** /**
* Public. Set thumbnail. * Set thumbnail.
* *
* @param {H5P.Thumbnail} newThumbnail * @param {H5P.Thumbnail} newThumbnail
*/ */
@ -1151,10 +1235,10 @@ H5P.MediaCopyright = function (copyright, labels, order, extraFields) {
}; };
/** /**
* Public. Checks if this copyright is undisclosed. * Checks if this copyright is undisclosed.
* I.e. only has the license attribute set, and it's undisclosed. * I.e. only has the license attribute set, and it's undisclosed.
* *
* @returns {Boolean} * @returns {boolean}
*/ */
this.undisclosed = function () { this.undisclosed = function () {
if (list.size() === 1) { if (list.size() === 1) {
@ -1167,9 +1251,9 @@ H5P.MediaCopyright = function (copyright, labels, order, extraFields) {
}; };
/** /**
* Public. Print media copyright. * Print media copyright.
* *
* @returns {String} HTML. * @returns {string} HTML.
*/ */
this.toString = function () { this.toString = function () {
var html = ''; var html = '';
@ -1191,7 +1275,11 @@ H5P.MediaCopyright = function (copyright, labels, order, extraFields) {
}; };
}; };
// Translate table for copyright license codes. /**
* Maps copyright license codes to their human readable counterpart.
*
* @type {Object}
*/
H5P.copyrightLicenses = { H5P.copyrightLicenses = {
'U': 'Undisclosed', 'U': 'Undisclosed',
'CC BY': 'Attribution', 'CC BY': 'Attribution',
@ -1208,11 +1296,12 @@ H5P.copyrightLicenses = {
}; };
/** /**
* Simple class for creating thumbnails for images. * A simple and elegant class for creating thumbnails of images.
* *
* @param {String} source * @class
* @param {Number} width * @param {string} source
* @param {Number} height * @param {number} width
* @param {number} height
*/ */
H5P.Thumbnail = function (source, width, height) { H5P.Thumbnail = function (source, width, height) {
var thumbWidth, thumbHeight = 100; var thumbWidth, thumbHeight = 100;
@ -1221,9 +1310,9 @@ H5P.Thumbnail = function (source, width, height) {
} }
/** /**
* Public. Print thumbnail. * Print thumbnail.
* *
* @returns {String} HTML. * @returns {string} HTML.
*/ */
this.toString = function () { this.toString = function () {
return '<img src="' + source + '" alt="' + H5P.t('thumbnail') + '" class="h5p-thumbnail" height="' + thumbHeight + '"' + (thumbWidth === undefined ? '' : ' width="' + thumbWidth + '"') + '/>'; return '<img src="' + source + '" alt="' + H5P.t('thumbnail') + '" class="h5p-thumbnail" height="' + thumbHeight + '"' + (thumbWidth === undefined ? '' : ' width="' + thumbWidth + '"') + '/>';
@ -1231,7 +1320,11 @@ H5P.Thumbnail = function (source, width, height) {
}; };
/** /**
* Simple data class for storing a single field. * Simple data structure class for storing a single field.
*
* @class
* @param {string} label
* @param {string} value
*/ */
H5P.Field = function (label, value) { H5P.Field = function (label, value) {
/** /**
@ -1255,12 +1348,14 @@ H5P.Field = function (label, value) {
/** /**
* Simple class for creating a definition list. * Simple class for creating a definition list.
*
* @class
*/ */
H5P.DefinitionList = function () { H5P.DefinitionList = function () {
var fields = []; var fields = [];
/** /**
* Public. Add field to list. * Add field to list.
* *
* @param {H5P.Field} field * @param {H5P.Field} field
*/ */
@ -1269,28 +1364,28 @@ H5P.DefinitionList = function () {
}; };
/** /**
* Public. Get Number of fields. * Get Number of fields.
* *
* @returns {Number} * @returns {number}
*/ */
this.size = function () { this.size = function () {
return fields.length; return fields.length;
}; };
/** /**
* Public. Get field at given index. * Get field at given index.
* *
* @param {Number} index * @param {number} index
* @returns {Object} * @returns {H5P.Field}
*/ */
this.get = function (index) { this.get = function (index) {
return fields[index]; return fields[index];
}; };
/** /**
* Public. Print definition list. * Print definition list.
* *
* @returns {String} HTML. * @returns {string} HTML.
*/ */
this.toString = function () { this.toString = function () {
var html = ''; var html = '';
@ -1306,14 +1401,26 @@ H5P.DefinitionList = function () {
* THIS FUNCTION/CLASS IS DEPRECATED AND WILL BE REMOVED. * THIS FUNCTION/CLASS IS DEPRECATED AND WILL BE REMOVED.
* *
* Helper object for keeping coordinates in the same format all over. * Helper object for keeping coordinates in the same format all over.
*
* @deprecated
* Will be removed march 2016.
* @class
* @param {number} x
* @param {number} y
* @param {number} w
* @param {number} h
*/ */
H5P.Coords = function (x, y, w, h) { H5P.Coords = function (x, y, w, h) {
if ( !(this instanceof H5P.Coords) ) if ( !(this instanceof H5P.Coords) )
return new H5P.Coords(x, y, w, h); return new H5P.Coords(x, y, w, h);
/** @member {number} */
this.x = 0; this.x = 0;
/** @member {number} */
this.y = 0; this.y = 0;
/** @member {number} */
this.w = 1; this.w = 1;
/** @member {number} */
this.h = 1; this.h = 1;
if (typeof(x) === 'object') { if (typeof(x) === 'object') {
@ -1342,10 +1449,10 @@ H5P.Coords = function (x, y, w, h) {
* Parse library string into values. * Parse library string into values.
* *
* @param {string} library * @param {string} library
* library in the format "machineName majorVersion.minorVersion" * library in the format "machineName majorVersion.minorVersion"
* @returns * @returns {Object}
* library as an object with machineName, majorVersion and minorVersion properties * library as an object with machineName, majorVersion and minorVersion properties
* return false if the library parameter is invalid * return false if the library parameter is invalid
*/ */
H5P.libraryFromString = function (library) { H5P.libraryFromString = function (library) {
var regExp = /(.+)\s(\d)+\.(\d)$/g; var regExp = /(.+)\s(\d)+\.(\d)$/g;
@ -1365,9 +1472,10 @@ H5P.libraryFromString = function (library) {
/** /**
* Get the path to the library * Get the path to the library
* *
* @param {String} library * @param {string} library
* The library identifier in the format "machineName-majorVersion.minorVersion". * The library identifier in the format "machineName-majorVersion.minorVersion".
* @returns {String} The full path to the library. * @returns {string}
* The full path to the library.
*/ */
H5P.getLibraryPath = function (library) { H5P.getLibraryPath = function (library) {
return H5PIntegration.url + '/libraries/' + library; return H5PIntegration.url + '/libraries/' + library;
@ -1375,13 +1483,15 @@ H5P.getLibraryPath = function (library) {
/** /**
* Recursivly clone the given object. * Recursivly clone the given object.
* TODO: Consider if this needs to be in core. Doesn't $.extend do the same?
* *
* @param {object} object Object to clone. * @param {Object|Array} object
* @param {type} recursive * Object to clone.
* @returns {object} A clone of object. * @param {boolean} [recursive]
* @returns {Object|Array}
* A clone of object.
*/ */
H5P.cloneObject = function (object, recursive) { H5P.cloneObject = function (object, recursive) {
// TODO: Consider if this needs to be in core. Doesn't $.extend do the same?
var clone = object instanceof Array ? [] : {}; var clone = object instanceof Array ? [] : {};
for (var i in object) { for (var i in object) {
@ -1400,22 +1510,23 @@ H5P.cloneObject = function (object, recursive) {
/** /**
* Remove all empty spaces before and after the value. * Remove all empty spaces before and after the value.
* TODO: Only include this or String.trim(). What is best?
* I'm leaning towards implementing the missing ones: http://kangax.github.io/compat-table/es5/
* So should we make this function deprecated?
* *
* @param {String} value * @param {string} value
* @returns {@exp;value@call;replace} * @returns {string}
*/ */
H5P.trim = function (value) { H5P.trim = function (value) {
return value.replace(/^\s+|\s+$/g, ''); return value.replace(/^\s+|\s+$/g, '');
// TODO: Only include this or String.trim(). What is best?
// I'm leaning towards implementing the missing ones: http://kangax.github.io/compat-table/es5/
// So should we make this function deprecated?
}; };
/** /**
* Check if javascript path/key is loaded. * Check if JavaScript path/key is loaded.
* *
* @param {String} path * @param {string} path
* @returns {Boolean} * @returns {boolean}
*/ */
H5P.jsLoaded = function (path) { H5P.jsLoaded = function (path) {
H5PIntegration.loadedJs = H5PIntegration.loadedJs || []; H5PIntegration.loadedJs = H5PIntegration.loadedJs || [];
@ -1425,8 +1536,8 @@ H5P.jsLoaded = function (path) {
/** /**
* Check if styles path/key is loaded. * Check if styles path/key is loaded.
* *
* @param {String} path * @param {string} path
* @returns {Boolean} * @returns {boolean}
*/ */
H5P.cssLoaded = function (path) { H5P.cssLoaded = function (path) {
H5PIntegration.loadedCss = H5PIntegration.loadedCss || []; H5PIntegration.loadedCss = H5PIntegration.loadedCss || [];
@ -1435,12 +1546,14 @@ H5P.cssLoaded = function (path) {
/** /**
* Shuffle an array in place. * Shuffle an array in place.
* TODO: Consider if this should be a part of core. I'm guessing very few libraries are going to use it.
* *
* @param {array} array Array to shuffle * @param {Array} array
* @returns {array} The passed array is returned for chaining. * Array to shuffle
* @returns {Array}
* The passed array is returned for chaining.
*/ */
H5P.shuffleArray = function (array) { H5P.shuffleArray = function (array) {
// TODO: Consider if this should be a part of core. I'm guessing very few libraries are going to use it.
if (!(array instanceof Array)) { if (!(array instanceof Array)) {
return; return;
} }
@ -1458,21 +1571,26 @@ H5P.shuffleArray = function (array) {
}; };
/** /**
* DEPRECATED! Do not use this function directly, trigger the finish event
* instead.
*
* Post finished results for user. * Post finished results for user.
* *
* @param {Number} contentId * @deprecated
* @param {Number} score achieved * Do not use this function directly, trigger the finish event instead.
* @param {Number} maxScore that can be achieved * Will be removed march 2016
* @param {Number} time optional reported time usage * @param {number} contentId
* Identifies the content
* @param {number} score
* Achieved score/points
* @param {number} maxScore
* The maximum score/points that can be achieved
* @param {number} [time]
* Reported time consumption/usage
*/ */
H5P.setFinished = function (contentId, score, maxScore, time) { H5P.setFinished = function (contentId, score, maxScore, time) {
if (H5PIntegration.postUserStatistics === true) { if (H5PIntegration.postUserStatistics === true) {
/** /**
* Return unix timestamp for the given JS Date. * Return unix timestamp for the given JS Date.
* *
* @private
* @param {Date} date * @param {Date} date
* @returns {Number} * @returns {Number}
*/ */
@ -1518,12 +1636,14 @@ if (String.prototype.trim === undefined) {
* *
* Helper function that triggers an event if the instance supports event handling * Helper function that triggers an event if the instance supports event handling
* *
* @param {function} instance * @param {Object} instance
* An H5P instance * Instance of H5P content
* @param {string} eventType * @param {string} eventType
* The event type * Type of event to trigger
* @param {*} data
* @param {Object} extras
*/ */
H5P.trigger = function(instance, eventType, data, extras) { H5P.trigger = function (instance, eventType, data, extras) {
// Try new event system first // Try new event system first
if (instance.trigger !== undefined) { if (instance.trigger !== undefined) {
instance.trigger(eventType, data, extras); instance.trigger(eventType, data, extras);
@ -1540,14 +1660,14 @@ H5P.trigger = function(instance, eventType, data, extras) {
* Helper function that registers an event handler for an event type if * Helper function that registers an event handler for an event type if
* the instance supports event handling * the instance supports event handling
* *
* @param {function} instance * @param {Object} instance
* An h5p instance * Instance of H5P content
* @param {string} eventType * @param {string} eventType
* The event type * Type of event to listen for
* @param {function} handler * @param {H5P.EventCallback} handler
* Callback that gets triggered for events of the specified type * Callback that gets triggered for events of the specified type
*/ */
H5P.on = function(instance, eventType, handler) { H5P.on = function (instance, eventType, handler) {
// Try new event system first // Try new event system first
if (instance.on !== undefined) { if (instance.on !== undefined) {
instance.on(eventType, handler); instance.on(eventType, handler);
@ -1559,18 +1679,25 @@ H5P.on = function(instance, eventType, handler) {
}; };
/** /**
* Create UUID * Generate random UUID
* *
* @returns {String} UUID * @returns {string} UUID
*/ */
H5P.createUUID = function() { H5P.createUUID = function () {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(char) { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(char) {
var random = Math.random()*16|0, newChar = char === 'x' ? random : (random&0x3|0x8); var random = Math.random()*16|0, newChar = char === 'x' ? random : (random&0x3|0x8);
return newChar.toString(16); return newChar.toString(16);
}); });
}; };
H5P.createTitle = function(rawTitle, maxLength) { /**
* Create title
*
* @param {string} rawTitle
* @param {number} maxLength
* @returns {string}
*/
H5P.createTitle = function (rawTitle, maxLength) {
if (!rawTitle) { if (!rawTitle) {
return ''; return '';
} }
@ -1648,11 +1775,14 @@ H5P.createTitle = function(rawTitle, maxLength) {
/** /**
* Get user data for given content. * Get user data for given content.
* *
* @public * @param {number} contentId
* @param {number} contentId What content to get data for. * What content to get data for.
* @param {string} dataId Identifies the set of data for this content. * @param {string} dataId
* @param {function} done Callback with error and data parameters. * Identifies the set of data for this content.
* @param {string} [subContentId] Identifies which data belongs to sub content. * @param {function} done
* Callback with error and data parameters.
* @param {string} [subContentId]
* Identifies which data belongs to sub content.
*/ */
H5P.getUserData = function (contentId, dataId, done, subContentId) { H5P.getUserData = function (contentId, dataId, done, subContentId) {
if (!subContentId) { if (!subContentId) {
@ -1700,19 +1830,33 @@ H5P.createTitle = function(rawTitle, maxLength) {
} }
}; };
/**
* Async error handling.
*
* @callback H5P.ErrorCallback
* @param {*} error
*/
/** /**
* Set user data for given content. * Set user data for given content.
* *
* @public * @param {number} contentId
* @param {number} contentId What content to get data for. * What content to get data for.
* @param {string} dataId Identifies the set of data for this content. * @param {string} dataId
* @param {object} data The data that is to be stored. * Identifies the set of data for this content.
* @param {object} extras - object holding the following properties: * @param {Object} data
* - {string} [subContentId] Identifies which data belongs to sub content. * The data that is to be stored.
* - {boolean} [preloaded=true] If the data should be loaded when content is loaded. * @param {Object} [extras]
* - {boolean} [deleteOnChange=false] If the data should be invalidated when the content changes. * Extra properties
* - {function} [errorCallback] Callback with error as parameters. * @param {string} [extras.subContentId]
* - {boolean} [async=true] * Identifies which data belongs to sub content.
* @param {boolean} [extras.preloaded=true]
* If the data should be loaded when content is loaded.
* @param {boolean} [extras.deleteOnChange=false]
* If the data should be invalidated when the content changes.
* @param {H5P.ErrorCallback} [extras.errorCallback]
* Callback with error as parameters.
* @param {boolean} [extras.async=true]
*/ */
H5P.setUserData = function (contentId, dataId, data, extras) { H5P.setUserData = function (contentId, dataId, data, extras) {
var options = H5P.jQuery.extend(true, {}, { var options = H5P.jQuery.extend(true, {}, {
@ -1755,10 +1899,12 @@ H5P.createTitle = function(rawTitle, maxLength) {
/** /**
* Delete user data for given content. * Delete user data for given content.
* *
* @public * @param {number} contentId
* @param {number} contentId What content to remove data for. * What content to remove data for.
* @param {string} dataId Identifies the set of data for this content. * @param {string} dataId
* @param {string} [subContentId] Identifies which data belongs to sub content. * Identifies the set of data for this content.
* @param {string} [subContentId]
* Identifies which data belongs to sub content.
*/ */
H5P.deleteUserData = function (contentId, dataId, subContentId) { H5P.deleteUserData = function (contentId, dataId, subContentId) {
if (!subContentId) { if (!subContentId) {
@ -1776,6 +1922,10 @@ H5P.createTitle = function(rawTitle, maxLength) {
// Init H5P when page is fully loadded // Init H5P when page is fully loadded
$(document).ready(function () { $(document).ready(function () {
/**
* Prevent H5P Core from initializing. Must be overriden before document ready.
* @member {boolean} H5P.preventInit
*/
if (!H5P.preventInit) { if (!H5P.preventInit) {
// Note that this start script has to be an external resource for it to // Note that this start script has to be an external resource for it to
// load in correct order in IE9. // load in correct order in IE9.
@ -1799,6 +1949,11 @@ H5P.createTitle = function(rawTitle, maxLength) {
}); });
} }
/**
* Indicates if H5P is embedded on an external page using iframe.
* @member {boolean} H5P.externalEmbed
*/
// Relay events to top window. // Relay events to top window.
if (H5P.isFramed && H5P.externalEmbed === false) { if (H5P.isFramed && H5P.externalEmbed === false) {
H5P.externalDispatcher.on('*', window.top.H5P.externalDispatcher.trigger); H5P.externalDispatcher.on('*', window.top.H5P.externalDispatcher.trigger);

6
js/jquery.js vendored
View File

@ -6,4 +6,10 @@ return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,a
// Snap this specific version of jQuery into H5P. jQuery.noConflict will // Snap this specific version of jQuery into H5P. jQuery.noConflict will
// revert the globals to what they were before this file was loaded. // revert the globals to what they were before this file was loaded.
var H5P = H5P || {}; var H5P = H5P || {};
/**
* jQuery v1.9.1
*
* @member
*/
H5P.jQuery = jQuery.noConflict(true); H5P.jQuery = jQuery.noConflict(true);