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 || {};
/**
* The Event class for the EventDispatcher
* The Event class for the EventDispatcher.
*
* @class
* @param {string} type
* @param {*} data
* @param {Object} [extras]
* @param {boolean} [extras.bubbles] 
* @param {boolean} [extras.external]
*/
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 = {};
}
@ -25,31 +30,29 @@ H5P.Event = function(type, data, extras) {
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
*
* @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
*
* @returns {boolean}
* true if external and not already scheduled, otherwise false
*/
this.scheduleForExternal = function() {
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 () {
/**
* The base of the event system.
* Inherit this class if you want your H5P to dispatch events.
*
* @class
* @memberof H5P
*/
function EventDispatcher() {
var self = this;
/**
* Keep track of listeners for each event.
*
* @private
* @type {Object}
*/
@ -80,11 +93,14 @@ H5P.EventDispatcher = (function () {
/**
* Add new event listener.
*
* @public
* @throws {TypeError} listener - Must be a function
* @param {String} type - Event type
* @param {Function} listener - Event listener
* @param {Function} thisArg - Optionally specify the this value when calling listener.
* @throws {TypeError}
* listener must be a function
* @param {string} type
* Event type
* @param {H5P.EventCallback} listener
* Event listener
* @param {function} thisArg
* Optionally specify the this value when calling listener.
*/
this.on = function (type, listener, thisArg) {
if (thisArg === undefined) {
@ -110,11 +126,14 @@ H5P.EventDispatcher = (function () {
/**
* Add new event listener that will be fired only once.
*
* @public
* @throws {TypeError} listener - must be a function
* @param {String} type - Event type
* @param {Function} listener - Event listener
* @param {Function} thisArg - Optionally specify the this value when calling listener.
* @throws {TypeError}
* listener must be a function
* @param {string} type
* Event type
* @param {H5P.EventCallback} listener
* Event listener
* @param {function} thisArg
* Optionally specify the this value when calling listener.
*/
this.once = function (type, listener, thisArg) {
if (thisArg === undefined) {
@ -136,10 +155,12 @@ H5P.EventDispatcher = (function () {
* Remove event listener.
* If no listener is specified, all listeners will be removed.
*
* @public
* @throws {TypeError} listener - must be a function
* @param {String} type - Event type
* @param {Function} listener - Event listener
* @throws {TypeError}
* listener must be a function
* @param {string} type
* Event type
* @param {H5P.EventCallback} listener
* Event listener
*/
this.off = function (type, listener) {
if (listener !== undefined && !(listener instanceof Function)) {
@ -175,45 +196,48 @@ H5P.EventDispatcher = (function () {
/**
* Dispatch event.
*
* @public
* @param {String|Function} event - Event object or event type as string
* @param {mixed} eventData
* Custom event data(used when event type as string is used as first
* argument
* @param {string|H5P.Event} event
* Event object or event type as string
* @param {*} [eventData]
* Custom event data(used when event type as string is used as first
* argument).
* @param {Object} [extras]
* @param {boolean} [extras.bubbles] 
* @param {boolean} [extras.external]
*/
this.trigger = function (event, eventData, extras) {
if (event === undefined) {
return;
}
if (typeof event === 'string') {
if (typeof event === 'string') { // TODO: Check instanceof String as well?
event = new H5P.Event(event, eventData, extras);
}
else if (eventData !== undefined) {
event.data = eventData;
}
// 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);
}
}
if (triggers['*'] !== undefined) {
// Call all * listeners
for (var i = 0; i < triggers['*'].length; i++) {
triggers['*'][i].listener.call(triggers['*'][i].thisArg, event);
for (var j = 0; j < triggers['*'].length; j++) {
triggers['*'][j].listener.call(triggers['*'][j].thisArg, event);
}
}
// 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);
}
if (scheduledForExternal) {
H5P.externalDispatcher.trigger(event);
}

View File

@ -1,11 +1,12 @@
var H5P = H5P || {};
/**
* Constructor for xAPI events
* Used for xAPI events.
*
* @class
* @extends H5P.Event
*/
H5P.XAPIEvent = function() {
H5P.XAPIEvent = function () {
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;
/**
* Helperfunction to set scored result statements
* Set scored result statements.
*
* @param {int} score
* @param {int} maxScore
* @param {number} score
* @param {number} maxScore
*/
H5P.XAPIEvent.prototype.setScoredResult = function(score, maxScore) {
H5P.XAPIEvent.prototype.setScoredResult = function (score, maxScore) {
this.data.statement.result = {
'score': {
'min': 0,
@ -29,13 +30,14 @@ H5P.XAPIEvent.prototype.setScoredResult = function(score, maxScore) {
};
/**
* Helperfunction to set a verb.
* Set a verb.
*
* @param {string} verb
* Verb in short form, one of the verbs defined at
* http://adlnet.gov/expapi/verbs/
* Verb in short form, one of the verbs defined at
* {@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) {
this.data.statement.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
* if true the full verb id prefixed by http://adlnet.gov/expapi/verbs/ will be returned
* @returns {string} - Verb or null if no verb with an id has been defined
* if true the full verb id prefixed by http://adlnet.gov/expapi/verbs/
* 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;
if ('verb' in statement) {
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)
*
* @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) {
this.data.statement.object = {
'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)) {
var parentId = instance.parent.subContentId === undefined ? instance.parent.contentId : instance.parent.subContentId;
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) {
this.data.statement.actor = {
'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
*
* @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() {
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
*
* @returns {int} the max score, or null if not defined
* @returns {number}
* The score, or null if not defined
*/
H5P.XAPIEvent.prototype.getScore = function() {
return this.getVerifiedStatementValue(['result', 'score', 'raw']);
};
/**
* Get content xAPI ID.
*
* @param {Object} instance
* The H5P instance
*/
H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) {
var xAPIId;
if (instance.contentId && H5PIntegration && H5PIntegration.contents) {
@ -184,15 +198,16 @@ H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) {
}
}
return xAPIId;
}
};
/**
* Figure out if a property exists in the statement and return it
*
* @param {array} keys
* List describing the property we're looking for. For instance
* ['result', 'score', 'raw'] for result.score.raw
* @returns the value of the property if it is set, null otherwise
* @param {string[]} keys
* List describing the property we're looking for. For instance
* ['result', 'score', 'raw'] for result.score.raw
* @returns {*}
* The value of the property if it is set, null otherwise.
*/
H5P.XAPIEvent.prototype.getVerifiedStatementValue = function(keys) {
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
*/

View File

@ -1,31 +1,41 @@
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();
// 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 {oject} extra - extra properties for the xAPI statement
* @param {string} verb
* 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));
};
/**
* 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
* statements.
*
* @param {string} verb - verb id in short form
* @param {object} extra - Extra values to be added to the statement
* @returns {Function} - XAPIEvent object
* @param {string} verb
* Verb id in short form
* @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();
event.setActor();
@ -49,22 +59,28 @@ H5P.EventDispatcher.prototype.createXAPIEventTemplate = function(verb, extra) {
*
* DEPRECATED - USE triggerXAPIScored instead
*
* @param {int} score - 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
* @deprecated
* 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');
};
/**
* Helper function to create scored xAPI events
*
*
* @param {int} score - 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 {string} verb - short form of adl verb
* @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
* @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);
event.setScoredResult(score, maxScore);
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
*
* @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'])) {
var score = event.getScore();
var maxScore = event.getMaxScore();

485
js/h5p.js
View File

@ -1,17 +1,34 @@
/*jshint multistr: true */
// 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 || {};
// Determine if we're inside an iframe.
/**
* Tells us if we're inside of an iframe.
* @member {boolean}
*/
H5P.isFramed = (window.self !== window.top);
// Useful jQuery object.
/**
* jQuery instance of current window.
* @member {H5P.jQuery}
*/
H5P.$window = H5P.jQuery(window);
/**
* List over H5P instances on the current page.
* @member {Array}
*/
H5P.instances = [];
// Detect if we support fullscreen, and what prefix to use.
if (document.documentElement.requestFullScreen) {
/**
* Browser prefix to use when entering fullscreen mode.
* undefined means no fullscreen support.
* @member {string}
*/
H5P.fullScreenBrowserPrefix = '';
}
else if (document.documentElement.webkitRequestFullScreen) {
@ -30,34 +47,36 @@ else if (document.documentElement.msRequestFullscreen) {
H5P.fullScreenBrowserPrefix = 'ms';
}
/** @const {Number} */
/** @const {number} */
H5P.DISABLE_NONE = 0;
/** @const {Number} */
/** @const {number} */
H5P.DISABLE_FRAME = 1;
/** @const {Number} */
/** @const {number} */
H5P.DISABLE_DOWNLOAD = 2;
/** @const {Number} */
/** @const {number} */
H5P.DISABLE_EMBED = 4;
/** @const {Number} */
/** @const {number} */
H5P.DISABLE_COPYRIGHT = 8;
/** @const {Number} */
/** @const {number} */
H5P.DISABLE_ABOUT = 16;
/**
* Keep track of when the H5Ps where started.
*
* @type {Array}
* @type {Object[]}
*/
H5P.opened = {};
/**
* Initialize H5P content.
* Scans for ".h5p-content" in the document and initializes H5P instances where found.
*
* @param {Object} target DOM Element
*/
H5P.init = function (target) {
// Useful jQuery object.
@ -67,8 +86,12 @@ H5P.init = function (target) {
// Determine if we can use full screen
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;
// 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
@ -348,9 +371,15 @@ H5P.getHeadTags = function (contentId) {
'<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 () {
/**
* @class
* @private
*/
function Communicator() {
var self = this;
@ -373,9 +402,8 @@ H5P.communicator = (function () {
/**
* Register action listener.
*
* @public
* @param {String} action What you are waiting for
* @param {Function} handler What you want done
* @param {string} action What you are waiting for
* @param {function} handler What you want done
*/
self.on = function (action, handler) {
actionHandlers[action] = handler;
@ -384,8 +412,7 @@ H5P.communicator = (function () {
/**
* Send a message to the all mighty father.
*
* @public
* @param {String} action
* @param {string} action
* @param {Object} [data] payload
*/
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 {object} instance
* @param {H5P.jQuery} $element Content container.
* @param {Object} instance
* @param {function} exitCallback Callback function called when user exits fullscreen.
* @param {jQuery} $body For internal use. Gives the body of the iframe.
* @returns {undefined}
* @param {H5P.jQuery} $body For internal use. Gives the body of the iframe.
*/
H5P.fullScreen = function ($element, instance, exitCallback, body) {
if (H5P.exitFullScreen !== undefined) {
@ -450,7 +476,8 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
/**
* Prepare for resize by setting the correct styles.
*
* @param {String} classes CSS
* @private
* @param {string} classes CSS
*/
var before = function (classes) {
$classes.addClass(classes);
@ -464,6 +491,8 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
/**
* Gets called when fullscreen mode has been entered.
* Resizes and sets focus on content.
*
* @private
*/
var entered = function () {
// 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.
* Resizes and sets focus on content.
*
* @param {String} classes CSS
* @private
* @param {string} classes CSS
*/
var done = function (classes) {
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
* Absolute path to a file, or relative path to a file in the content folder
* @param contentId
* Id of the content requesting a path
* @param {string} path
* Relative to content folder or absolute.
* @param {number} contentId
* ID of the content requesting the path.
* @returns {string}
* Complete URL to path.
*/
H5P.getPath = function (path, contentId) {
var hasProtocol = function (path) {
@ -601,10 +632,14 @@ H5P.getPath = function (path, contentId) {
* THIS FUNCTION IS DEPRECATED, USE getPath INSTEAD
* 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
* Id of the content requesting a path
* @deprecated
* Will be removed march 2016.
* @param contentId
* Id of the content requesting the path
* @returns {string}
* URL
*/
H5P.getContentPath = function (contentId) {
return H5PIntegration.url + '/content/' + contentId;
@ -613,32 +648,38 @@ H5P.getContentPath = function (contentId) {
/**
* Get library class constructor from H5P by classname.
* 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.
*
* @param {string} name Name of library
* @returns Class constructor
* @returns {Object} Class constructor
*/
H5P.classFromName = function (name) {
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.
*
* TODO: Should we check if version matches the library?
* TODO: Dynamically try to load libraries currently not loaded? That will require a callback.
*
* @param {Object} library Library/action object form params.
* @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} extras - extra params for the H5P content constructor
* @return {Object} Instance.
* @param {Object} library
* Library/action object form params.
* @param {number} contentId
* Identifies the content.
* @param {H5P.jQuery} [$attachTo]
* Element to attach the instance to.
* @param {boolean} [skipResize]
* Skip triggering of the resize event after attaching.
* @param {Object} [extras]
* Extra parameters for the H5P content constructor
* @returns {Object}
* Instance.
*/
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;
try {
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.
* @returns {undefined}
* @param {*} err Error to print.
*/
H5P.error = function (err) {
if (window.console !== undefined && console.error !== undefined) {
@ -737,10 +777,14 @@ H5P.error = function (err) {
/**
* Translate text strings.
*
* @param {String} key Translation identifier, may only contain a-zA-Z0-9. No spaces or special chars.
* @param {Object} vars Data for placeholders.
* @param {String} ns Translation namespace. Defaults to H5P.
* @returns {String} Text
* @param {string} key
* Translation identifier, may only contain a-zA-Z0-9. No spaces or special chars.
* @param {Object} vars
* Data for placeholders.
* @param {string} ns
* Translation namespace. Defaults to H5P.
* @returns {string}
* Translated text
*/
H5P.t = function (key, vars, ns) {
if (ns === undefined) {
@ -767,6 +811,19 @@ H5P.t = function (key, vars, ns) {
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) {
var self = this;
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.
*
* @param {jQuery} $element to insert dialog after.
* @param {object} instance to get copyright information from.
* @returns {undefined}
* @param {H5P.jQuery} $element
* DOM Element to insert dialog after.
* @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) {
var copyrights;
@ -843,10 +905,12 @@ H5P.openCopyrightsDialog = function ($element, instance, parameters, contentId)
/**
* Gather a flat list of copyright information from the given parameters.
*
* @param {H5P.ContentCopyrights} info Used to collect all information in.
* @param {(Object|Arrray)} parameters To search for file objects in.
* @param {Number} contentId Used to insert thumbnails for images.
* @returns {undefined}
* @param {H5P.ContentCopyrights} info
* Used to collect all information in.
* @param {(Object|Array)} parameters
* To search for file objects in.
* @param {number} contentId
* Used to insert thumbnails for images.
*/
H5P.findCopyrights = function (info, parameters, contentId) {
// Cycle through parameters
@ -887,9 +951,12 @@ H5P.findCopyrights = function (info, parameters, contentId) {
/**
* Recursive function for checking if content has copyrights
*
* @param {(Object|Arrray)} parameters To search for file objects in.
* @param {Number} contentId Used to insert thumbnails for images.
* @returns {boolean} Returns true if complete copyright information was found.
* @param {(Object|Array)} parameters
* To search for file objects in.
* @param {number} contentId
* Used to insert thumbnails for images.
* @returns {boolean}
* Returns true if complete copyright information was found.
*/
H5P.hasCopyrights = function (parameters, contentId) {
// Cycle through parameters
@ -929,9 +996,16 @@ H5P.hasCopyrights = function (parameters, contentId) {
/**
* Display a dialog containing the embed code.
*
* @param {jQuery} $element to insert dialog after.
* @param {string} embed code.
* @returns {undefined}
* @param {H5P.jQuery} $element
* Element to insert dialog after.
* @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) {
var fullEmbedCode = embedCode + resizeCode;
@ -1010,6 +1084,8 @@ H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size) {
/**
* Copyrights for a H5P Content Library.
*
* @class
*/
H5P.ContentCopyrights = function () {
var label;
@ -1017,16 +1093,16 @@ H5P.ContentCopyrights = function () {
var content = [];
/**
* Public. Set label.
* Set label.
*
* @param {String} newLabel
* @param {string} newLabel
*/
this.setLabel = function (newLabel) {
label = newLabel;
};
/**
* Public. Add sub content.
* Add sub content.
*
* @param {H5P.MediaCopyright} newMedia
*/
@ -1037,7 +1113,7 @@ H5P.ContentCopyrights = function () {
};
/**
* Public. Add sub content.
* Add sub content.
*
* @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 () {
var html = '';
@ -1083,20 +1159,26 @@ H5P.ContentCopyrights = function () {
/**
* A ordered list of copyright fields for media.
*
* @param {Object} copyright information fields.
* @param {Object} labels translation. Optional.
* @param {Array} order of fields. Optional.
* @param {Object} extraFields for copyright. Optional.
* @class
* @param {Object} copyright
* Copyright information fields.
* @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) {
var thumbnail;
var list = new H5P.DefinitionList();
/**
* Private. Get translated label for field.
* Get translated label for field.
*
* @param {String} fieldName
* @return {String}
* @private
* @param {string} fieldName
* @returns {string}
*/
var getLabel = function (fieldName) {
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
* @return {String}
* @private
* @param {string} fieldName
* @param {string} value
* @returns {string}
*/
var humanizeValue = function (fieldName, value) {
if (fieldName === 'license') {
@ -1142,7 +1226,7 @@ H5P.MediaCopyright = function (copyright, labels, order, extraFields) {
}
/**
* Public. Set thumbnail.
* Set thumbnail.
*
* @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.
*
* @returns {Boolean}
* @returns {boolean}
*/
this.undisclosed = function () {
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 () {
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 = {
'U': 'Undisclosed',
'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
* @param {Number} width
* @param {Number} height
* @class
* @param {string} source
* @param {number} width
* @param {number} height
*/
H5P.Thumbnail = function (source, width, height) {
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 () {
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) {
/**
@ -1255,12 +1348,14 @@ H5P.Field = function (label, value) {
/**
* Simple class for creating a definition list.
*
* @class
*/
H5P.DefinitionList = function () {
var fields = [];
/**
* Public. Add field to list.
* Add field to list.
*
* @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 () {
return fields.length;
};
/**
* Public. Get field at given index.
* Get field at given index.
*
* @param {Number} index
* @returns {Object}
* @param {number} index
* @returns {H5P.Field}
*/
this.get = function (index) {
return fields[index];
};
/**
* Public. Print definition list.
* Print definition list.
*
* @returns {String} HTML.
* @returns {string} HTML.
*/
this.toString = function () {
var html = '';
@ -1306,14 +1401,26 @@ H5P.DefinitionList = function () {
* THIS FUNCTION/CLASS IS DEPRECATED AND WILL BE REMOVED.
*
* 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) {
if ( !(this instanceof H5P.Coords) )
return new H5P.Coords(x, y, w, h);
/** @member {number} */
this.x = 0;
/** @member {number} */
this.y = 0;
/** @member {number} */
this.w = 1;
/** @member {number} */
this.h = 1;
if (typeof(x) === 'object') {
@ -1342,10 +1449,10 @@ H5P.Coords = function (x, y, w, h) {
* Parse library string into values.
*
* @param {string} library
* library in the format "machineName majorVersion.minorVersion"
* @returns
* library as an object with machineName, majorVersion and minorVersion properties
* return false if the library parameter is invalid
* library in the format "machineName majorVersion.minorVersion"
* @returns {Object}
* library as an object with machineName, majorVersion and minorVersion properties
* return false if the library parameter is invalid
*/
H5P.libraryFromString = function (library) {
var regExp = /(.+)\s(\d)+\.(\d)$/g;
@ -1365,9 +1472,10 @@ H5P.libraryFromString = function (library) {
/**
* Get the path to the library
*
* @param {String} library
* @param {string} library
* 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) {
return H5PIntegration.url + '/libraries/' + library;
@ -1375,13 +1483,15 @@ H5P.getLibraryPath = function (library) {
/**
* 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 {type} recursive
* @returns {object} A clone of object.
* @param {Object|Array} object
* Object to clone.
* @param {boolean} [recursive]
* @returns {Object|Array}
* A clone of object.
*/
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 ? [] : {};
for (var i in object) {
@ -1400,22 +1510,23 @@ H5P.cloneObject = function (object, recursive) {
/**
* 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
* @returns {@exp;value@call;replace}
* @param {string} value
* @returns {string}
*/
H5P.trim = function (value) {
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
* @returns {Boolean}
* @param {string} path
* @returns {boolean}
*/
H5P.jsLoaded = function (path) {
H5PIntegration.loadedJs = H5PIntegration.loadedJs || [];
@ -1425,8 +1536,8 @@ H5P.jsLoaded = function (path) {
/**
* Check if styles path/key is loaded.
*
* @param {String} path
* @returns {Boolean}
* @param {string} path
* @returns {boolean}
*/
H5P.cssLoaded = function (path) {
H5PIntegration.loadedCss = H5PIntegration.loadedCss || [];
@ -1435,12 +1546,14 @@ H5P.cssLoaded = function (path) {
/**
* 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
* @returns {array} The passed array is returned for chaining.
* @param {Array} array
* Array to shuffle
* @returns {Array}
* The passed array is returned for chaining.
*/
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)) {
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.
*
* @param {Number} contentId
* @param {Number} score achieved
* @param {Number} maxScore that can be achieved
* @param {Number} time optional reported time usage
* @deprecated
* Do not use this function directly, trigger the finish event instead.
* Will be removed march 2016
* @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) {
if (H5PIntegration.postUserStatistics === true) {
/**
* Return unix timestamp for the given JS Date.
*
* @private
* @param {Date} date
* @returns {Number}
*/
@ -1518,12 +1636,14 @@ if (String.prototype.trim === undefined) {
*
* Helper function that triggers an event if the instance supports event handling
*
* @param {function} instance
* An H5P instance
* @param {Object} instance
* Instance of H5P content
* @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
if (instance.trigger !== undefined) {
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
* the instance supports event handling
*
* @param {function} instance
* An h5p instance
* @param {Object} instance
* Instance of H5P content
* @param {string} eventType
* The event type
* @param {function} handler
* Callback that gets triggered for events of the specified type
* Type of event to listen for
* @param {H5P.EventCallback} handler
* 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
if (instance.on !== undefined) {
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) {
var random = Math.random()*16|0, newChar = char === 'x' ? random : (random&0x3|0x8);
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) {
return '';
}
@ -1648,11 +1775,14 @@ H5P.createTitle = function(rawTitle, maxLength) {
/**
* Get user data for given content.
*
* @public
* @param {number} contentId What content to get data for.
* @param {string} dataId Identifies the set of data for this content.
* @param {function} done Callback with error and data parameters.
* @param {string} [subContentId] Identifies which data belongs to sub content.
* @param {number} contentId
* What content to get data for.
* @param {string} dataId
* Identifies the set of data for this 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) {
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.
*
* @public
* @param {number} contentId What content to get data for.
* @param {string} dataId Identifies the set of data for this content.
* @param {object} data The data that is to be stored.
* @param {object} extras - object holding the following properties:
* - {string} [subContentId] Identifies which data belongs to sub content.
* - {boolean} [preloaded=true] If the data should be loaded when content is loaded.
* - {boolean} [deleteOnChange=false] If the data should be invalidated when the content changes.
* - {function} [errorCallback] Callback with error as parameters.
* - {boolean} [async=true]
* @param {number} contentId
* What content to get data for.
* @param {string} dataId
* Identifies the set of data for this content.
* @param {Object} data
* The data that is to be stored.
* @param {Object} [extras]
* Extra properties
* @param {string} [extras.subContentId]
* 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) {
var options = H5P.jQuery.extend(true, {}, {
@ -1755,10 +1899,12 @@ H5P.createTitle = function(rawTitle, maxLength) {
/**
* Delete user data for given content.
*
* @public
* @param {number} contentId What content to remove data for.
* @param {string} dataId Identifies the set of data for this content.
* @param {string} [subContentId] Identifies which data belongs to sub content.
* @param {number} contentId
* What content to remove data for.
* @param {string} dataId
* Identifies the set of data for this content.
* @param {string} [subContentId]
* Identifies which data belongs to sub content.
*/
H5P.deleteUserData = function (contentId, dataId, subContentId) {
if (!subContentId) {
@ -1776,6 +1922,10 @@ H5P.createTitle = function(rawTitle, maxLength) {
// Init H5P when page is fully loadded
$(document).ready(function () {
/**
* Prevent H5P Core from initializing. Must be overriden before document ready.
* @member {boolean} H5P.preventInit
*/
if (!H5P.preventInit) {
// Note that this start script has to be an external resource for it to
// 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.
if (H5P.isFramed && H5P.externalEmbed === false) {
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
// revert the globals to what they were before this file was loaded.
var H5P = H5P || {};
/**
* jQuery v1.9.1
*
* @member
*/
H5P.jQuery = jQuery.noConflict(true);