From 2720ec5f1614ef513bf361c74f4434db96f48be9 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Fri, 25 Oct 2013 15:10:50 +0200 Subject: [PATCH 1/2] Added iframe support (by: Frank Ronny Larsen). --- h5p.classes.php | 2 +- js/h5p.js | 133 +++++++++++++++++++++++++++++++++++++++++------- styles/h5p.css | 90 +++++++++++++++++++++++++++++++- 3 files changed, 204 insertions(+), 21 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 0068902..51380ff 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1870,4 +1870,4 @@ class H5PContentValidator { } } -?> \ No newline at end of file +?> diff --git a/js/h5p.js b/js/h5p.js index 3dca4ea..d8b040f 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -1,6 +1,8 @@ var H5P = H5P || {}; -// +// This needs to be determined before init is run. +H5P.isFramed = (window.parent !== window); + // Initialize H5P content // Scans for ".h5p-content" H5P.init = function () { @@ -11,11 +13,18 @@ H5P.init = function () { H5P.$body = H5P.jQuery('body'); } + // Is this H5P being run in a frame? + if (H5P.isFramed) { + H5P.$body.addClass('h5p-iframe-content'); + } + if (H5P.fullScreenBrowserPrefix === undefined) { if (document.documentElement.requestFullScreen) { H5P.fullScreenBrowserPrefix = ''; } - else if (document.documentElement.webkitRequestFullScreen && navigator.userAgent.indexOf('Android') === -1) { // Skip Android + else if (document.documentElement.webkitRequestFullScreen + && navigator.userAgent.indexOf('Android') === -1 // Skip Android + ) { // Safari has stopped working as of v6.0.3. (Specifying keyboard input // makes webkitRequestFullScreen silently fail.) The following code // assumes that the Safari developers figure out how to properly handle @@ -37,12 +46,17 @@ H5P.init = function () { } } + // H5Ps added in normal DIV. H5P.jQuery(".h5p-content").each(function (idx, el) { - var $el = H5P.jQuery(el); - var contentId = $el.data('content-id'); - var obj = new (H5P.classFromName($el.data('class')))(H5P.jQuery.parseJSON(H5PIntegration.getJsonContent(contentId)), contentId); + var $el = H5P.jQuery(el), + contentId = $el.data('content-id'), + mainLibrary = $el.data('class'), + obj = new (H5P.classFromName(mainLibrary))(H5P.jQuery.parseJSON(H5PIntegration.getJsonContent(contentId)), contentId); + + // Render H5P in container. obj.attach($el); + // Add Fullscreen button if relevant. if (H5PIntegration.getFullscreen(contentId)) { H5P.jQuery('
' + H5PIntegration.fullscreenText + '
').insertBefore($el).children().click(function () { H5P.fullScreen($el, obj); @@ -50,6 +64,48 @@ H5P.init = function () { }); } }); + + // H5Ps living in iframes. Note: Fullscreen button will be added + // inside iFrame if relevant + var $h5pIframes = H5P.jQuery(".h5p-iframe"); + $h5pIframes.each(function (idx, iframe) { + var $iframe = H5P.jQuery(iframe), + contentId = $iframe.data('content-id'), + mainLibrary = $iframe.data('class'); + + // Get iFrame body, and reset it to contain only the normal H5P DIV. + $iframe.contents().find('body') + .html('
'); + + // Add scripts required for this iFrame from settings + H5PIntegration.addFilesToIframe($iframe, contentId); + }); + if ($h5pIframes.length > 0) { + // TODO: This seems very hacky... why can't we just use the resize event? What happens if we ain't done before the next interval starts? + setInterval(function h5pIframeResizer() { + $h5pIframes.each(function (idx, iframe) { + var contentHeight = iframe.contentDocument.body.offsetHeight; + var frameHeight = H5P.jQuery(iframe).innerHeight(); + + if (frameHeight !== contentHeight) { + H5P.resizeIframe(H5P.jQuery(iframe).data('content-id'), contentHeight); + } + }); + }, 100); + } +}; + +H5P.fullScreenIframe = function (contentId, obj, exitCallback) { + H5P.fullScreen(H5P.jQuery('#iframe-wrapper-' + contentId), obj, exitCallback); +}; + +H5P.resizeIframe = function (contentId, height) { + var iframe = document.getElementById('iframe-' + contentId); + // Don't allow iFrame to grow beyond window height; + if (height > window.innerHeight) { + height = window.innerHeight; + } + iframe.style.height = (H5P.isFullscreen) ? '100%' : height + 'px'; }; /** @@ -59,22 +115,44 @@ H5P.init = function () { * @param {object} obj H5P * @returns {undefined} */ -H5P.fullScreen = function ($el, obj) { +H5P.fullScreen = function ($el, obj, exitCallback) { + if (H5P.isFramed) { + var $classes = H5P.jQuery('html').add(H5P.$body).add($el); + $classes.addClass('h5p-fullscreen'); + window.parent.H5P.fullScreenIframe($el.data('content-id'), obj, function () { + $classes.removeClass('h5p-fullscreen'); + }); + + return; + } + if (H5P.fullScreenBrowserPrefix === undefined) { // Create semi fullscreen. $el.add(H5P.$body).addClass('h5p-semi-fullscreen'); // Move H5P content to top of body to make sure it is above other page // content. Insert placeholder in original position to be able to move it // back. - $el.after('
').prependTo(H5P.$body); + // THIS DOES NOT WORK WITH IFRAMED CONTENT, iframe will reload/fail. + // $el.after('
').prependTo(H5P.$body); + + H5P.isFullscreen = true; var $disable = H5P.jQuery('Disable fullscreen').appendTo($el); var keyup, disableSemiFullscreen = function () { $el.add(H5P.$body).removeClass('h5p-semi-fullscreen'); - $('#h5pfullscreenreplacementplaceholder').before($el).remove(); + // H5P.jQuery('#h5pfullscreenreplacementplaceholder').before($el).remove(); $disable.remove(); + H5P.isFullscreen = false; H5P.$body.unbind('keyup', keyup); + H5P.jQuery(".h5p-iframe").each(function (idx, el) { + H5P.resizeIframe(H5P.jQuery(el).data('content-id'), 0); + }); + + if (exitCallback) { + exitCallback(); + } + if (obj.resize !== undefined) { obj.resize(false); } @@ -91,12 +169,23 @@ H5P.fullScreen = function ($el, obj) { } else { var first, eventName = H5P.fullScreenBrowserPrefix + 'fullscreenchange'; + H5P.isFullscreen = true; document.addEventListener(eventName, function () { if (first === undefined) { first = false; return; } + H5P.isFullscreen = false; $el.add(H5P.$body).removeClass('h5p-fullscreen'); + + H5P.jQuery(".h5p-iframe").each(function (idx, el) { + H5P.resizeIframe(H5P.jQuery(el).data('content-id'), 0); + }); + + if (exitCallback) { + exitCallback(); + } + if (obj.resize !== undefined) { obj.resize(false); } @@ -112,7 +201,9 @@ H5P.fullScreen = function ($el, obj) { $el.add(H5P.$body).addClass('h5p-fullscreen'); } - + H5P.jQuery(".h5p-iframe").each(function (idx, el) { + H5P.resizeIframe(H5P.jQuery(el).data('content-id'), 0); + }); if (obj.resize !== undefined) { obj.resize(true); } @@ -317,10 +408,10 @@ H5P.setFinished = function (contentId, points, maxPoints) { }; // Add indexOf to browsers that lack them. (IEs) -if(!Array.prototype.indexOf) { - Array.prototype.indexOf = function(needle) { - for(var i = 0; i < this.length; i++) { - if(this[i] === needle) { +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (needle) { + for (var i = 0; i < this.length; i++) { + if (this[i] === needle) { return i; } } @@ -330,13 +421,19 @@ if(!Array.prototype.indexOf) { // Need to define trim() since this is not available on older IEs, // and trim is used in several libs -if(String.prototype.trim === undefined) { +if (String.prototype.trim === undefined) { String.prototype.trim = function () { return H5P.trim(this); }; } -// Finally, we want to run init when document is ready. -H5P.jQuery(document).ready(function(){ - H5P.init(); -}); \ No newline at end of file +// Finally, we want to run init when document is ready. But not if we're +// in an iFrame. Then we wait for parent to start init(). +if (H5P.jQuery && !H5P.isFramed) { + H5P.jQuery(document).ready(function () { + if (!H5P.initialized) { + H5P.initialized = true; + H5P.init(); + } + }); +} diff --git a/styles/h5p.css b/styles/h5p.css index 4b2b265..8330945 100644 --- a/styles/h5p.css +++ b/styles/h5p.css @@ -1,9 +1,15 @@ +body.h5p-iframe-content { + font-family: Arial, Helvetica, sans-serif; + margin: 0; +} + body.h5p-semi-fullscreen { overflow: hidden; } .h5p-content { - width: 100%; - height: 100%; + display: block; + width: auto; + height: auto; background: #fefefe; font-size: 16px; } @@ -48,4 +54,84 @@ div.h5p-semi-fullscreen { text-decoration: none; opacity: 0.9; filter: alpha(opacity = 90); +} +.h5p-iframe-wrapper.h5p-fullscreen { + width: 100%; + height: 100%; +} +.h5p-iframe-wrapper { + width: auto; height: auto; +} + +.h5p-fullscreen .h5p-iframe-wrapper, +.h5p-semi-fullscreen .h5p-iframe-wrapper { + width: 100%; + height: 100%; +} + +.h5p-iframe-wrapper.h5p-semi-fullscreen { + width: 100%; + height: 100%; + background: black; + position: fixed; + top: 0; + left: 0; + z-index: 100; +} +.h5p-iframe-wrapper .buttons { + text-align: right; +} +.h5p-iframe-wrapper.h5p-semi-fullscreen .buttons { + position: absolute; + top: 0; + right: 0; + z-index: 20; +} +.h5p-iframe-wrapper .h5p-iframe { + width: 100%; + height: 100%; + z-index: 10; +} +.h5p-iframe-wrapper.h5p-semi-fullscreen .buttons button:before { + content: 'Exit '; +} +.h5p-iframe-wrapper button.fullscreen { + color: #e5eef6; + text-decoration: none; + padding: 6px 12px; + background: #539ad7; + background-image: -webkit-linear-gradient(top,#4584ba,#539ad7); + background-image: -moz-linear-gradient(top,#4584ba,#539ad7); + background-image: -o-linear-gradient(top,#4584ba,#539ad7); + background-image: -ms-linear-gradient(top,#4584ba,#539ad7); + background-image: linear-gradient(to bottom,#4584ba,#539ad7); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4584ba',endColorstr='#539ad7',GradientType=0); + box-shadow: 0 0 8px #bebebe; + border: none; + opacity: 0.8; +} +.h5p-iframe-wrapper button.fullscreen:hover { + opacity: 1; + background: #539ad7; + background-image: -webkit-linear-gradient(top,#539ad7,#4584ba); + background-image: -moz-linear-gradient(top,#539ad7,#4584ba); + background-image: -o-linear-gradient(top,#539ad7,#4584ba); + background-image: -ms-linear-gradient(top,#539ad7,#4584ba); + background-image: linear-gradient(to bottom,#539ad7,#4584ba); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#539ad7',endColorstr='#4584ba',GradientType=0); + cursor: pointer; +} + +html.h5p-fullscreen, body.h5p-fullscreen { + height: 100%; + overflow: hidden; +} +.h5p-fullscreen .h5p-content-controls { + display: none; +} +body.h5p-iframe-content div.h5p-content { + overflow: hidden; +} +body.h5p-iframe-content.h5p-fullscreen div.h5p-content { + height: 100%; } \ No newline at end of file From 44b5d8997020f3e17fc363834a4af4f57b30f377 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 28 Oct 2013 14:08:59 +0100 Subject: [PATCH 2/2] Fixed iframe solution in IE8. --- js/h5p.js | 15 ++++++++------- styles/h5p.css | 5 ++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/js/h5p.js b/js/h5p.js index d8b040f..75e42ee 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -1,7 +1,7 @@ var H5P = H5P || {}; // This needs to be determined before init is run. -H5P.isFramed = (window.parent !== window); +H5P.isFramed = (window.self !== window.top); // (window.parent !== window); // Initialize H5P content // Scans for ".h5p-content" @@ -80,18 +80,19 @@ H5P.init = function () { // Add scripts required for this iFrame from settings H5PIntegration.addFilesToIframe($iframe, contentId); }); - if ($h5pIframes.length > 0) { + if ($h5pIframes.length !== 0) { // TODO: This seems very hacky... why can't we just use the resize event? What happens if we ain't done before the next interval starts? - setInterval(function h5pIframeResizer() { + setInterval(function () { $h5pIframes.each(function (idx, iframe) { - var contentHeight = iframe.contentDocument.body.offsetHeight; - var frameHeight = H5P.jQuery(iframe).innerHeight(); + var $iframe = H5P.jQuery(iframe); + var contentHeight = $iframe.contents().height(); + var frameHeight = $iframe.innerHeight(); if (frameHeight !== contentHeight) { - H5P.resizeIframe(H5P.jQuery(iframe).data('content-id'), contentHeight); + H5P.resizeIframe($iframe.data('content-id'), contentHeight); } }); - }, 100); + }, 250); } }; diff --git a/styles/h5p.css b/styles/h5p.css index 8330945..96d7b41 100644 --- a/styles/h5p.css +++ b/styles/h5p.css @@ -60,7 +60,8 @@ div.h5p-semi-fullscreen { height: 100%; } .h5p-iframe-wrapper { - width: auto; height: auto; + width: auto; + height: auto; } .h5p-fullscreen .h5p-iframe-wrapper, @@ -91,6 +92,8 @@ div.h5p-semi-fullscreen { width: 100%; height: 100%; z-index: 10; + overflow: hidden; + border: 0; } .h5p-iframe-wrapper.h5p-semi-fullscreen .buttons button:before { content: 'Exit ';