Simplified integration code to avoid to much duplication.
Added resizing script for new embed code. Added iframe communicator when embedding.d6
parent
e12ba70b95
commit
18a3ed4a8f
|
@ -0,0 +1,155 @@
|
|||
// H5P iframe Resizer
|
||||
(function () {
|
||||
if (!window.postMessage || !window.addEventListener) {
|
||||
return; // Not supported
|
||||
}
|
||||
|
||||
// Map actions to handlers
|
||||
var actionHandlers = {};
|
||||
|
||||
/**
|
||||
* Prepare iframe resize.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} iframe Element
|
||||
* @param {Object} data Payload
|
||||
* @param {Function} respond Send a response to the iframe
|
||||
*/
|
||||
actionHandlers.hello = function (iframe, data, respond) {
|
||||
// Make iframe responsive
|
||||
iframe.style.width = '100%';
|
||||
|
||||
// Tell iframe that it needs to resize when our window resizes
|
||||
var resize = function (event) {
|
||||
if (iframe.contentWindow) {
|
||||
// Limit resize calls to avoid flickering
|
||||
respond('resize');
|
||||
}
|
||||
else {
|
||||
// Frame is gone, unregister.
|
||||
window.removeEventListener('resize', resize);
|
||||
}
|
||||
};
|
||||
window.addEventListener('resize', resize, false);
|
||||
|
||||
// Respond to let the iframe know we can resize it
|
||||
respond('hello');
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepare iframe resize.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} iframe Element
|
||||
* @param {Object} data Payload
|
||||
* @param {Function} respond Send a response to the iframe
|
||||
*/
|
||||
actionHandlers.prepareResize = function (iframe, data, respond) {
|
||||
responseData = {};
|
||||
|
||||
// Retain parent size to avoid jumping/scrolling
|
||||
responseData.parentHeight = iframe.parentElement.style.height;
|
||||
//iframe.parentElement.style.height = iframe.parentElement.clientHeight + 'px';
|
||||
|
||||
// Reset iframe height, in case content has shrinked.
|
||||
iframe.style.height = '1px';
|
||||
|
||||
respond('resizePrepared', responseData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Resize parent and iframe to desired height.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} iframe Element
|
||||
* @param {Object} data Payload
|
||||
* @param {Function} respond Send a response to the iframe
|
||||
*/
|
||||
actionHandlers.resize = function (iframe, data, respond) {
|
||||
// Resize iframe so all content is visible.
|
||||
iframe.style.height = data.height + 'px';
|
||||
|
||||
// Free parent
|
||||
//iframe.parentElement.style.height = data.parentHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* Keyup event handler. Exits full screen on escape.
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
var escape = function (event) {
|
||||
if (event.keyCode === 27) {
|
||||
exitFullScreen();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Enter semi full screen.
|
||||
* Expands the iframe so that it covers the whole page.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} iframe Element
|
||||
* @param {Object} data Payload
|
||||
* @param {Function} respond Send a response to the iframe
|
||||
*/
|
||||
actionHandlers.fullScreen = function (iframe, data, respond) {
|
||||
iframe.style.position = 'fixed';
|
||||
iframe.style.top = iframe.style.left = 0;
|
||||
iframe.style.zIndex = 101;
|
||||
iframe.style.width = iframe.style.height = '100%';
|
||||
document.body.addEventListener('keyup', escape, false);
|
||||
respond('fullScreen');
|
||||
};
|
||||
|
||||
/**
|
||||
* Exit semi full screen.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} iframe Element
|
||||
* @param {Object} data Payload
|
||||
* @param {Function} respond Send a response to the iframe
|
||||
*/
|
||||
actionHandlers.exitFullScreen = function (iframe, data, respond) {
|
||||
iframe.style.position = '';
|
||||
iframe.style.top = iframe.style.left = '';
|
||||
iframe.style.zIndex = '';
|
||||
iframe.style.width = '100%';
|
||||
iframe.style.height = '';
|
||||
document.body.removeEventListener('keyup', escape, false);
|
||||
respond('exitFullScreen');
|
||||
};
|
||||
|
||||
|
||||
// Listen for messages from iframes
|
||||
window.addEventListener('message', function receiveMessage(event) {
|
||||
if (event.data.context !== 'h5p') {
|
||||
return; // Only handle h5p requests.
|
||||
}
|
||||
|
||||
// Find out who sent the message
|
||||
var iframe, iframes = document.getElementsByTagName('iframe');
|
||||
for (var i = 0; i < iframes.length; i++) {
|
||||
if (iframes[i].contentWindow === event.source) {
|
||||
iframe = iframes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iframe) {
|
||||
return; // Cannot find sender
|
||||
}
|
||||
|
||||
// Find action handler handler
|
||||
if (actionHandlers[event.data.action]) {
|
||||
actionHandlers[event.data.action](iframe, event.data, function (action, data) {
|
||||
if (data === undefined) {
|
||||
data = {};
|
||||
}
|
||||
data.action = action;
|
||||
data.context = 'h5p';
|
||||
event.source.postMessage(data, event.origin);
|
||||
});
|
||||
}
|
||||
}, false);
|
||||
})();
|
190
js/h5p.js
190
js/h5p.js
|
@ -31,6 +31,8 @@ else if (document.documentElement.msRequestFullscreen) {
|
|||
// Keep track of when the H5Ps where started
|
||||
H5P.opened = {};
|
||||
|
||||
H5P.canHasFullScreen = (H5P.isFramed && H5P.externalEmbed !== false) ? (document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled) : true;
|
||||
|
||||
/**
|
||||
* Initialize H5P content.
|
||||
* Scans for ".h5p-content" in the document and initializes H5P instances where found.
|
||||
|
@ -39,15 +41,12 @@ H5P.init = function () {
|
|||
// Useful jQuery object.
|
||||
H5P.$body = H5P.jQuery(document.body);
|
||||
|
||||
// Prepare internal resizer for content.
|
||||
var $window = H5P.jQuery(window.parent);
|
||||
|
||||
// H5Ps added in normal DIV.
|
||||
var $containers = H5P.jQuery(".h5p-content").each(function () {
|
||||
var $element = H5P.jQuery(this);
|
||||
var $container = H5P.jQuery('<div class="h5p-container"></div>').appendTo($element);
|
||||
var contentId = $element.data('content-id');
|
||||
var contentData = H5PIntegration.getContentData(contentId);
|
||||
var contentData = H5P.contentDatas['cid-' + contentId];
|
||||
if (contentData === undefined) {
|
||||
return H5P.error('No data for content id ' + contentId + '. Perhaps the library is gone?');
|
||||
}
|
||||
|
@ -85,7 +84,7 @@ H5P.init = function () {
|
|||
H5P.openEmbedDialog($actions, contentData.embedCode);
|
||||
});
|
||||
}
|
||||
if (H5PIntegration.showH5PIconInActionBar()) {
|
||||
if (contentData.showH5PIconInActionBar) {
|
||||
H5P.jQuery('<li><a class="h5p-link" href="http://h5p.org" target="_blank" title="' + H5P.t('h5pDescription') + '"></a></li>').appendTo($actions);
|
||||
}
|
||||
$actions.insertAfter($container);
|
||||
|
@ -100,7 +99,10 @@ H5P.init = function () {
|
|||
}
|
||||
});
|
||||
|
||||
if (H5P.isFramed) {
|
||||
if (H5P.isFramed)
|
||||
var resizeDelay;{
|
||||
if (H5P.externalEmbed === false) {
|
||||
// Internal embed
|
||||
// Make it possible to resize the iframe when the content changes size. This way we get no scrollbars.
|
||||
var iframe = window.parent.document.getElementById('h5p-iframe-' + contentId);
|
||||
var resizeIframe = function () {
|
||||
|
@ -122,7 +124,6 @@ H5P.init = function () {
|
|||
iframe.parentElement.style.height = parentHeight;
|
||||
};
|
||||
|
||||
var resizeDelay;
|
||||
instance.$.on('resize', function () {
|
||||
// Use a delay to make sure iframe is resized to the correct size.
|
||||
clearTimeout(resizeDelay);
|
||||
|
@ -131,9 +132,56 @@ H5P.init = function () {
|
|||
}, 1);
|
||||
});
|
||||
}
|
||||
else if (H5P.communicator) {
|
||||
// External embed
|
||||
var parentIsFriendly = false;
|
||||
|
||||
// Handle hello message from our parent window
|
||||
H5P.communicator.on('hello', function () {
|
||||
// Initial setup/handshake is done
|
||||
parentIsFriendly = true;
|
||||
|
||||
// Hide scrollbars for correct size
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
H5P.communicator.send('prepareResize');
|
||||
});
|
||||
|
||||
// When resize has been prepared tell parent window to resize
|
||||
H5P.communicator.on('resizePrepared', function (data) {
|
||||
H5P.communicator.send('resize', {
|
||||
height: document.body.scrollHeight,
|
||||
parentHeight: data.parentHeight
|
||||
});
|
||||
});
|
||||
|
||||
H5P.communicator.on('resize', function () {
|
||||
instance.$.trigger('resize');
|
||||
});
|
||||
|
||||
instance.$.on('resize', function () {
|
||||
if (H5P.isFullscreen) {
|
||||
return; // Skip iframe resize
|
||||
}
|
||||
|
||||
// Use a delay to make sure iframe is resized to the correct size.
|
||||
clearTimeout(resizeDelay);
|
||||
resizeDelay = setTimeout(function () {
|
||||
// Only resize if the iframe can be resized
|
||||
if (parentIsFriendly) {
|
||||
H5P.communicator.send('prepareResize');
|
||||
}
|
||||
else {
|
||||
H5P.communicator.send('hello');
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!H5P.isFramed || H5P.externalEmbed === false) {
|
||||
// Resize everything when window is resized.
|
||||
$window.resize(function () {
|
||||
H5P.jQuery(window.top).resize(function () {
|
||||
if (window.parent.H5P.isFullscreen) {
|
||||
// Use timeout to avoid bug in certain browsers when exiting fullscreen. Some browser will trigger resize before the fullscreenchange event.
|
||||
instance.$.trigger('resize');
|
||||
|
@ -142,6 +190,7 @@ H5P.init = function () {
|
|||
instance.$.trigger('resize');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Resize content.
|
||||
instance.$.trigger('resize');
|
||||
|
@ -151,11 +200,69 @@ H5P.init = function () {
|
|||
H5P.jQuery("iframe.h5p-iframe").each(function () {
|
||||
var contentId = H5P.jQuery(this).data('content-id');
|
||||
this.contentDocument.open();
|
||||
this.contentDocument.write('<!doctype html><html class="h5p-iframe"><head>' + H5PIntegration.getHeadTags(contentId) + '</head><body><div class="h5p-content" data-content-id="' + contentId + '"/></body></html>');
|
||||
this.contentDocument.write('<!doctype html><html class="h5p-iframe"><head>' + H5P.getHeadTags(contentId) + '</head><body><div class="h5p-content" data-content-id="' + contentId + '"/></body></html>');
|
||||
this.contentDocument.close();
|
||||
this.contentWindow.H5P = {
|
||||
externalEmbed: false
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
H5P.communicator = (function () {
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
function Communicator() {
|
||||
var self = this;
|
||||
|
||||
// Maps actions to functions
|
||||
var actionHandlers = {};
|
||||
|
||||
// Register message listener
|
||||
window.addEventListener('message', function receiveMessage(event) {
|
||||
if (window.parent !== event.source || event.data.context !== 'h5p') {
|
||||
return; // Only handle messages from parent and in the correct context
|
||||
}
|
||||
|
||||
if (actionHandlers[event.data.action] !== undefined) {
|
||||
actionHandlers[event.data.action](event.data);
|
||||
}
|
||||
} , false);
|
||||
|
||||
|
||||
/**
|
||||
* Register action listener.
|
||||
*
|
||||
* @public
|
||||
* @param {String} action What you are waiting for
|
||||
* @param {Function} handler What you want done
|
||||
*/
|
||||
self.on = function (action, handler) {
|
||||
actionHandlers[action] = handler;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a message to the all mighty father.
|
||||
*
|
||||
* @public
|
||||
* @param {String} action
|
||||
* @param {Object} [data] payload
|
||||
*/
|
||||
self.send = function (action, data) {
|
||||
if (data === undefined) {
|
||||
data = {};
|
||||
}
|
||||
data.context = 'h5p';
|
||||
data.action = action;
|
||||
|
||||
// Parent origin can be anything
|
||||
window.parent.postMessage(data, '*');
|
||||
};
|
||||
}
|
||||
|
||||
return (window.postMessage && window.addEventListener ? new Communicator() : undefined);
|
||||
})();
|
||||
|
||||
/**
|
||||
* Enable full screen for the given h5p.
|
||||
*
|
||||
|
@ -166,9 +273,19 @@ H5P.init = function () {
|
|||
* @returns {undefined}
|
||||
*/
|
||||
H5P.fullScreen = function ($element, instance, exitCallback, body) {
|
||||
if (H5P.isFramed) {
|
||||
if (H5P.exitFullScreen !== undefined) {
|
||||
return; // Cannot enter new fullscreen until previous is over
|
||||
}
|
||||
|
||||
if (H5P.isFramed && H5P.externalEmbed === false) {
|
||||
// Trigger resize on wrapper in parent window.
|
||||
window.parent.H5P.fullScreen($element, instance, exitCallback, H5P.$body.get());
|
||||
window.top.H5P.fullScreen($element, instance, exitCallback, H5P.$body.get());
|
||||
H5P.isFullscreen = true;
|
||||
H5P.exitFullScreen = function () {
|
||||
window.top.H5P.exitFullScreen();
|
||||
H5P.isFullscreen = false;
|
||||
H5P.exitFullScreen = undefined;
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -226,6 +343,7 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
|
|||
instance.$.trigger('resize');
|
||||
instance.$.trigger('focus');
|
||||
|
||||
H5P.exitFullScreen = undefined;
|
||||
if (exitCallback !== undefined) {
|
||||
exitCallback();
|
||||
}
|
||||
|
@ -235,6 +353,10 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
|
|||
if (H5P.fullScreenBrowserPrefix === undefined) {
|
||||
// Create semi fullscreen.
|
||||
|
||||
if (H5P.isFramed) {
|
||||
return; // TODO: Ask parent for iframe
|
||||
}
|
||||
|
||||
before('h5p-semi-fullscreen');
|
||||
var $disable = H5P.jQuery('<div role="button" tabindex="1" class="h5p-disable-fullscreen" title="' + H5P.t('disableFullscreen') + '"></div>').appendTo($container.find('.h5p-content-controls'));
|
||||
var keyup, disableSemiFullscreen = function () {
|
||||
|
@ -277,6 +399,19 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
|
|||
var params = (H5P.fullScreenBrowserPrefix === 'webkit' && H5P.safariBrowser === 0 ? Element.ALLOW_KEYBOARD_INPUT : undefined);
|
||||
$element[0][method](params);
|
||||
}
|
||||
|
||||
// Allows everone to exit
|
||||
H5P.exitFullScreen = function () {
|
||||
if (H5P.fullScreenBrowserPrefix === '') {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
else if (H5P.fullScreenBrowserPrefix === 'moz') {
|
||||
document.mozCancelFullScreen();
|
||||
}
|
||||
else {
|
||||
document[H5P.fullScreenBrowserPrefix + 'ExitFullscreen']();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -300,7 +435,7 @@ H5P.getPath = function (path, contentId) {
|
|||
}
|
||||
|
||||
if (contentId !== undefined) {
|
||||
prefix = H5PIntegration.getContentPath(contentId);
|
||||
prefix = H5P.url + '/content/' + contentId;
|
||||
}
|
||||
else if (window.H5PEditor !== undefined) {
|
||||
prefix = H5PEditor.filesPath;
|
||||
|
@ -316,18 +451,6 @@ H5P.getPath = function (path, contentId) {
|
|||
return prefix + '/' + path;
|
||||
};
|
||||
|
||||
/**
|
||||
* THIS FUNCTION IS DEPRECATED, USE getPath INSTEAD
|
||||
*
|
||||
* Find the path to the content files folder based on the id of the content
|
||||
*
|
||||
* @param contentId
|
||||
* Id of the content requesting a path
|
||||
*/
|
||||
H5P.getContentPath = function (contentId) {
|
||||
return H5PIntegration.getContentPath(contentId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get library class constructor from H5P by classname.
|
||||
* Note that this class will only work for resolve "H5P.NameWithoutDot".
|
||||
|
@ -428,15 +551,15 @@ H5P.t = function (key, vars, ns) {
|
|||
ns = 'H5P';
|
||||
}
|
||||
|
||||
if (H5PIntegration.i18n[ns] === undefined) {
|
||||
if (H5P.l10n[ns] === undefined) {
|
||||
return '[Missing translation namespace "' + ns + '"]';
|
||||
}
|
||||
|
||||
if (H5PIntegration.i18n[ns][key] === undefined) {
|
||||
if (H5P.l10n[ns][key] === undefined) {
|
||||
return '[Missing translation "' + key + '" in "' + ns + '"]';
|
||||
}
|
||||
|
||||
var translation = H5PIntegration.i18n[ns][key];
|
||||
var translation = H5P.l10n[ns][key];
|
||||
|
||||
if (vars !== undefined) {
|
||||
// Replace placeholder with variables.
|
||||
|
@ -946,7 +1069,7 @@ H5P.libraryFromString = function (library) {
|
|||
* @returns {String} The full path to the library.
|
||||
*/
|
||||
H5P.getLibraryPath = function (library) {
|
||||
return H5PIntegration.getLibraryPath(library);
|
||||
return H5P.url + '/libraries/' + library;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1088,14 +1211,3 @@ if (String.prototype.trim === undefined) {
|
|||
return H5P.trim(this);
|
||||
};
|
||||
}
|
||||
|
||||
// Finally, we want to run init when document is ready.
|
||||
// TODO: Move to integration. Systems like Moodle using YUI cannot get its translations set before this starts!
|
||||
if (H5P.jQuery) {
|
||||
H5P.jQuery(document).ready(function () {
|
||||
if (!H5P.initialized) {
|
||||
H5P.initialized = true;
|
||||
H5P.init();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue