From ee02f08bdb54d2882b4b97e99979aa070a4aed93 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Wed, 14 Oct 2015 14:43:03 +0200 Subject: [PATCH 1/8] Prevent warnings when reading the directory fails (There will still be error messages) --- h5p.classes.php | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 06cd47c..1682a76 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1578,16 +1578,19 @@ Class H5PExport { */ private static function populateFileList($dir, &$files, $relative = '') { $strip = strlen($dir) + 1; - foreach (glob($dir . DIRECTORY_SEPARATOR . '*') as $file) { - $rel = $relative . substr($file, $strip); - if (is_dir($file)) { - self::populateFileList($file, $files, $rel . '/'); - } - else { - $files[] = (object) array( - 'absolutePath' => $file, - 'relativePath' => $rel - ); + $contents = glob($dir . DIRECTORY_SEPARATOR . '*'); + if (!empty($contents)) { + foreach ($contents as $file) { + $rel = $relative . substr($file, $strip); + if (is_dir($file)) { + self::populateFileList($file, $files, $rel . '/'); + } + else { + $files[] = (object) array( + 'absolutePath' => $file, + 'relativePath' => $rel + ); + } } } } From f9ea9adb1ba634b074304cbe2830b478c2507f45 Mon Sep 17 00:00:00 2001 From: Andrew Downes Date: Tue, 20 Oct 2015 11:13:08 +0100 Subject: [PATCH 2/8] Add support for result.success & completion --- js/h5p-x-api-event.js | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 98b287a..1653b0c 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -18,18 +18,40 @@ H5P.XAPIEvent.prototype.constructor = H5P.XAPIEvent; * * @param {number} score * @param {number} maxScore + * @param {object} instance + * @param {boolean} completion + * @param {boolean} success */ -H5P.XAPIEvent.prototype.setScoredResult = function (score, maxScore, instance) { - this.data.statement.result = { - 'score': { - 'min': 0, - 'max': maxScore, - 'raw': score +H5P.XAPIEvent.prototype.setScoredResult = function (score, maxScore, instance, completion, success) { + this.data.statement.result = {}; + + if (typeof score !== 'undefined') { + if (typeof maxScore === 'undefined') { + this.data.statement.result.score = {'raw': score}; + } + else { + this.data.statement.result.score = { + 'min': 0, + 'max': maxScore, + 'raw': score + }; + if (maxScore > 0) { + this.data.statement.result.score.scaled = Math.round(score / maxScore * 10000) / 10000; + } } - }; - if (maxScore > 0) { - this.data.statement.result.score.scaled = Math.round(score / maxScore * 10000) / 10000; } + + if (typeof completion === 'undefined') { + this.data.statement.result.completion = true; + } + else { + this.data.statement.result.completion = completion; + } + + if (typeof success !== 'undefined') { + this.data.statement.result.success = success; + } + if (instance && instance.activityStartTime) { var duration = Math.round((Date.now() - instance.activityStartTime ) / 10) / 100; // xAPI spec allows a precision of 0.01 seconds From 76a02867aa9a26acd0a0cb83086d6da4a32b4de3 Mon Sep 17 00:00:00 2001 From: Andrew Downes Date: Tue, 20 Oct 2015 11:29:01 +0100 Subject: [PATCH 3/8] Update triggerXAPICompleted and triggerXAPIScored Added support for completion and success. --- js/h5p-x-api.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/js/h5p-x-api.js b/js/h5p-x-api.js index e287c1a..aeec7b6 100644 --- a/js/h5p-x-api.js +++ b/js/h5p-x-api.js @@ -65,9 +65,16 @@ H5P.EventDispatcher.prototype.createXAPIEventTemplate = function (verb, extra) { * 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 {boolean} success + * will be set as the "success" value of the result object */ -H5P.EventDispatcher.prototype.triggerXAPICompleted = function (score, maxScore) { - this.triggerXAPIScored(score, maxScore, 'completed'); +H5P.EventDispatcher.prototype.triggerXAPICompleted = function (score, maxScore, success) { + var verb = 'completed'; + if (typeof success !== 'undefined') { + if (success) {verb = "passed";} + else {verb = "failed";} + } + this.triggerXAPIScored(score, maxScore, verb, true, success); }; /** @@ -80,9 +87,9 @@ H5P.EventDispatcher.prototype.triggerXAPICompleted = function (score, maxScore) * @param {string} verb * Short form of adl verb */ -H5P.EventDispatcher.prototype.triggerXAPIScored = function (score, maxScore, verb) { +H5P.EventDispatcher.prototype.triggerXAPIScored = function (score, maxScore, verb, completion, success) { var event = this.createXAPIEventTemplate(verb); - event.setScoredResult(score, maxScore, this); + event.setScoredResult(score, maxScore, this, completion, success); this.trigger(event); }; From 876135436c77a5a6576f12cf5b3a2c84d197a698 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 26 Oct 2015 14:13:21 +0100 Subject: [PATCH 4/8] Made resize script smarter to avoid flickering. --- js/h5p-resizer.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/js/h5p-resizer.js b/js/h5p-resizer.js index ab35e19..228cc72 100644 --- a/js/h5p-resizer.js +++ b/js/h5p-resizer.js @@ -19,6 +19,7 @@ actionHandlers.hello = function (iframe, data, respond) { // Make iframe responsive iframe.style.width = '100%'; + iframe.contentDocument.body.style.height = 'auto'; // Tell iframe that it needs to resize when our window resizes var resize = function (event) { @@ -46,16 +47,6 @@ * @param {Function} respond Send a response to the iframe */ actionHandlers.prepareResize = function (iframe, data, respond) { - responseData = {}; - - // Create spaceholder and insert after iframe. - var spaceholder = document.createElement('div'); - spaceholder.style.height = (iframe.clientHeight - 1) + 'px'; - iframe.parentNode.insertBefore(spaceholder, iframe.nextSibling); - - // Reset iframe height, in case content has shrinked. - iframe.style.height = '1px'; - respond('resizePrepared'); }; @@ -68,14 +59,21 @@ * @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'; - iframe.parentNode.removeChild(iframe.nextSibling); + if (iframe.clientHeight === iframe.contentDocument.body.scrollHeight && + iframe.contentDocument.body.scrollHeight === iframe.contentWindow.document.body.clientHeight) { + return; // Do not resize unless page and scrolling differs + } + + // Reset iframe height, in case content has shrinked. + iframe.style.height = iframe.contentWindow.document.body.clientHeight + 'px'; + + // Resize iframe so all content is visible. Use scrollHeight to make sure we get everything + iframe.style.height = iframe.contentDocument.body.scrollHeight + 'px'; }; /** * Keyup event handler. Exits full screen on escape. - * + * * @param {Event} event */ var escape = function (event) { From f0530957ad11cb4da00e2654e3bfbf27d700f99e Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Tue, 27 Oct 2015 16:57:28 +0100 Subject: [PATCH 5/8] Improved semi-fullscreen for iPad. --- js/h5p.js | 29 ++++++++++++++++++++++++++++- styles/h5p.css | 8 +++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/js/h5p.js b/js/h5p.js index a55a87c..504d8d0 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -539,7 +539,13 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) { before('h5p-semi-fullscreen'); var $disable = H5P.jQuery('
').appendTo($container.find('.h5p-content-controls')); - var keyup, disableSemiFullscreen = function () { + var keyup, disableSemiFullscreen = H5P.exitFullScreen = function () { + if (lastViewport) { + metaTags[i].content = lastViewport; + } + else { + head.removeChild(metaTag); + } $disable.remove(); $body.unbind('keyup', keyup); done('h5p-semi-fullscreen'); @@ -551,6 +557,27 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) { }; $disable.click(disableSemiFullscreen); $body.keyup(keyup); + + // Disable zoom + var lastViewport; + var metaTags = document.getElementsByTagName('meta'); + for (var i = 0; i < metaTags.length; i++) { + if (metaTags[i].name === 'viewport') { + lastViewport = metaTags[i].content; + break; + } + } + if (!lastViewport) { + // Create tag + metaTags[i] = document.createElement('meta'); + metaTags[i].name = 'viewport'; + } + metaTags[i].content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0'; + if (!lastViewport) { + var head = document.getElementsByTagName('head')[0]; + head.appendChild(metaTag); + } + entered(); } else { diff --git a/styles/h5p.css b/styles/h5p.css index 3fca24e..4586952 100644 --- a/styles/h5p.css +++ b/styles/h5p.css @@ -130,13 +130,15 @@ div.h5p-fullscreen { } .h5p-iframe-wrapper.h5p-semi-fullscreen { - width: 100%; - height: 100%; + width: auto; + height: auto; background: black; position: fixed; top: 0; left: 0; - z-index: 1000; + right: 0; + bottom: 0; + z-index: 100001; } .h5p-iframe-wrapper.h5p-semi-fullscreen .buttons { position: absolute; From cc6521c4a1d11f10d7c63b9cae2b50ecb8e1ac31 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 1 Nov 2015 00:19:56 +0100 Subject: [PATCH 6/8] completed default value depends on verb --- js/h5p-x-api-event.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index 1653b0c..c5ce2e3 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -42,7 +42,7 @@ H5P.XAPIEvent.prototype.setScoredResult = function (score, maxScore, instance, c } if (typeof completion === 'undefined') { - this.data.statement.result.completion = true; + this.data.statement.result.completion = (this.getVerb() === 'completed' || this.getVerb() === 'answered'); } else { this.data.statement.result.completion = completion; From 844883a1cff662558daf2eb7c1544319a0b1c6e4 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 1 Nov 2015 00:23:10 +0100 Subject: [PATCH 7/8] triggerXAPICompleted is deprecated so we don't change it. Also fixes doc --- js/h5p-x-api.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/js/h5p-x-api.js b/js/h5p-x-api.js index aeec7b6..735161c 100644 --- a/js/h5p-x-api.js +++ b/js/h5p-x-api.js @@ -69,12 +69,7 @@ H5P.EventDispatcher.prototype.createXAPIEventTemplate = function (verb, extra) { * will be set as the "success" value of the result object */ H5P.EventDispatcher.prototype.triggerXAPICompleted = function (score, maxScore, success) { - var verb = 'completed'; - if (typeof success !== 'undefined') { - if (success) {verb = "passed";} - else {verb = "failed";} - } - this.triggerXAPIScored(score, maxScore, verb, true, success); + this.triggerXAPIScored(score, maxScore, 'completed', true, success); }; /** @@ -86,6 +81,10 @@ H5P.EventDispatcher.prototype.triggerXAPICompleted = function (score, maxScore, * Will be set as the "max" value of the score object * @param {string} verb * Short form of adl verb + * @param {boolean} completion + * Is this a statement from a completed activity? + * @param {boolean} success + * Is this a statement from an activity that was done successfully? */ H5P.EventDispatcher.prototype.triggerXAPIScored = function (score, maxScore, verb, completion, success) { var event = this.createXAPIEventTemplate(verb); From ccfa2d516fda6411acc7d2f00083172969aaf1d4 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Sun, 1 Nov 2015 00:30:45 +0100 Subject: [PATCH 8/8] Make sure we get answered statements in the result log --- js/h5p-x-api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/h5p-x-api.js b/js/h5p-x-api.js index e287c1a..2b2e36a 100644 --- a/js/h5p-x-api.js +++ b/js/h5p-x-api.js @@ -96,7 +96,7 @@ H5P.EventDispatcher.prototype.setActivityStarted = function() { * @param {H5P.XAPIEvent} event */ H5P.xAPICompletedListener = function (event) { - if (event.getVerb() === 'completed' && !event.getVerifiedStatementValue(['context', 'contextActivities', 'parent'])) { + if ((event.getVerb() === 'completed' || event.getVerb() === 'answered') && !event.getVerifiedStatementValue(['context', 'contextActivities', 'parent'])) { var score = event.getScore(); var maxScore = event.getMaxScore(); var contentId = event.getVerifiedStatementValue(['object', 'definition', 'extensions', 'http://h5p.org/x-api/h5p-local-content-id']);