From acaccea977f1331f5ca0324f8c93ed45423fea36 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Tue, 3 May 2016 12:47:16 +0200 Subject: [PATCH 01/22] Allow pagination widget to handle empty pages --- js/h5p-data-view.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/js/h5p-data-view.js b/js/h5p-data-view.js index 860625f..0edfc56 100644 --- a/js/h5p-data-view.js +++ b/js/h5p-data-view.js @@ -108,11 +108,11 @@ var H5PDataView = (function ($) { else { // Update table data self.updateTable(data.rows); - - // Update pagination widget - self.updatePagination(data.num); } + // Update pagination widget + self.updatePagination(data.num); + if (self.loaded !== undefined) { self.loaded(); } @@ -255,7 +255,6 @@ var H5PDataView = (function ($) { var remove = function () { self.facets[col].$tag.remove(); delete self.facets[col]; - self.offset = 0; // Reset to page 1 self.loadData(); }; @@ -276,9 +275,6 @@ var H5PDataView = (function ($) { } }); - // Reset to page 1 - self.offset = 0; - // Load data with new filter self.loadData(); }; From cc121b2f5345db6ba7e5510a84361b128747efb8 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Thu, 12 May 2016 15:52:37 +0200 Subject: [PATCH 02/22] Bugfix: Must be able to run from CLI --- h5p.classes.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index 93c4213..7f87f7c 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2469,7 +2469,9 @@ class H5PCore { // Determine remote/visitor origin if ($type === 'network' || - ($type === 'local' && !preg_match('/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/i', $_SERVER['REMOTE_ADDR']))) { + ($type === 'local' && + isset($_SERVER['REMOTE_ADDR']) && + !preg_match('/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/i', $_SERVER['REMOTE_ADDR']))) { if (isset($_SERVER['REMOTE_ADDR']) && filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) { // Internet $this->h5pF->setOption('site_type', 'internet'); From 27bc1587082df55ffaec7571855e998bc9948f04 Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Mon, 23 May 2016 14:34:56 +0200 Subject: [PATCH 03/22] Use buttons instead of anchors in Confirmation Dialog. HFJ-1930 --- js/h5p-confirmation-dialog.js | 71 ++++++++++++------------------ styles/h5p-confirmation-dialog.css | 10 ++--- styles/h5p-core-button.css | 25 ++++++----- 3 files changed, 47 insertions(+), 59 deletions(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index a8d4ac2..11047b2 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -24,6 +24,26 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { options.cancelText = options.cancelText || H5P.t('cancelLabel'); options.confirmText = options.confirmText || H5P.t('confirmLabel'); + /** + * Handle confirming event + * @param {Event} e + */ + function dialogConfirmed(e) { + self.hide(); + self.trigger('confirmed'); + e.preventDefault(); + } + + /** + * Handle dialog canceled + * @param {Event} e + */ + function dialogCanceled(e) { + self.hide(); + self.trigger('canceled'); + e.preventDefault(); + } + // Offset of exit button var exitButtonOffset = 2 * 16; var shadowOffset = 8; @@ -69,70 +89,37 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { body.appendChild(buttons); // Cancel button - var cancelButton = document.createElement('a'); + var cancelButton = document.createElement('button'); cancelButton.classList.add('h5p-core-cancel-button'); - cancelButton.href = '#'; cancelButton.textContent = options.cancelText; - cancelButton.onclick = function (e) { - self.hide(); - self.trigger('canceled'); - e.preventDefault(); - }; + cancelButton.onclick = dialogCanceled; cancelButton.onkeydown = function (e) { if (e.which === 32) { // Space - // Prevent jumping - e.preventDefault(); - } - else if (e.which === 13) { // Enter - self.hide(); - self.trigger('canceled'); - e.preventDefault(); + dialogCanceled(e); } }; buttons.appendChild(cancelButton); // Confirm button - var confirmButton = document.createElement('a'); + var confirmButton = document.createElement('button'); confirmButton.classList.add('h5p-core-button', 'h5p-confirmation-dialog-confirm-button'); - confirmButton.href = '#'; confirmButton.textContent = options.confirmText; - confirmButton.onclick = function (e) { - self.hide(); - self.trigger('confirmed'); - e.preventDefault(); - }; + confirmButton.onclick = dialogConfirmed; confirmButton.onkeydown = function (e) { if (e.which === 32) { // Space - // Prevent jumping - e.preventDefault(); - } - else if (e.which === 13) { // Enter - self.hide(); - self.trigger('confirmed'); - e.preventDefault(); + dialogConfirmed(e); } }; buttons.appendChild(confirmButton); // Exit button - var exitButton = document.createElement('a'); - exitButton.href = '#'; + var exitButton = document.createElement('button'); exitButton.classList.add('h5p-confirmation-dialog-exit'); - exitButton.onclick = function (e) { - self.hide(); - self.trigger('canceled'); - e.preventDefault(); - }; + exitButton.onclick = dialogCanceled; exitButton.onkeydown = function (e) { if (e.which === 32) { // Space - // Prevent jumping - e.preventDefault(); - } - else if (e.which === 13) { // Enter - self.hide(); - self.trigger('canceled'); - e.preventDefault(); + dialogCanceled(e); } }; popup.appendChild(exitButton); diff --git a/styles/h5p-confirmation-dialog.css b/styles/h5p-confirmation-dialog.css index 093a6ad..2923b17 100644 --- a/styles/h5p-confirmation-dialog.css +++ b/styles/h5p-confirmation-dialog.css @@ -81,9 +81,9 @@ float: right; } -a.h5p-confirmation-dialog-exit:visited, -a.h5p-confirmation-dialog-exit:link, -a.h5p-confirmation-dialog-exit { +button.h5p-confirmation-dialog-exit:visited, +button.h5p-confirmation-dialog-exit:link, +button.h5p-confirmation-dialog-exit { position: absolute; background: none; border: none; @@ -95,8 +95,8 @@ a.h5p-confirmation-dialog-exit { text-decoration: none; } -a.h5p-confirmation-dialog-exit:focus, -a.h5p-confirmation-dialog-exit:hover { +button.h5p-confirmation-dialog-exit:focus, +button.h5p-confirmation-dialog-exit:hover { color: #555; } diff --git a/styles/h5p-core-button.css b/styles/h5p-core-button.css index b05c423..04f33a3 100644 --- a/styles/h5p-core-button.css +++ b/styles/h5p-core-button.css @@ -1,6 +1,6 @@ -a.h5p-core-button:visited, -a.h5p-core-button:link, -a.h5p-core-button { +button.h5p-core-button:visited, +button.h5p-core-button:link, +button.h5p-core-button { font-size: 1em; line-height: 1.2; padding: 0.5em 1.25em; @@ -20,15 +20,15 @@ a.h5p-core-button { vertical-align: baseline; text-decoration: none; } -a.h5p-core-button:hover, -a.h5p-core-button:focus { +button.h5p-core-button:hover, +button.h5p-core-button:focus { background: #1356a3; color: #fff; text-decoration: none; -webkit-transition: initial; transition: initial; } -a.h5p-core-button:active { +button.h5p-core-button:active { position: relative; background: #104888; @@ -37,7 +37,7 @@ a.h5p-core-button:active { box-shadow: inset 0 4px 0 #0e407a; } -a.h5p-core-button:before { +button.h5p-core-button:before { font-family: 'H5P'; padding-right: 0.15em; font-size: 1.5em; @@ -45,9 +45,10 @@ a.h5p-core-button:before { line-height: 0.7; } -a.h5p-core-cancel-button:visited, -a.h5p-core-cancel-button:link, -a.h5p-core-cancel-button { +button.h5p-core-cancel-button:visited, +button.h5p-core-cancel-button:link, +button.h5p-core-cancel-button { + border: none; background: none; color: #a00; margin-right: 1em; @@ -55,8 +56,8 @@ a.h5p-core-cancel-button { text-decoration: none; } -a.h5p-core-cancel-button:hover, -a.h5p-core-cancel-button:focus { +button.h5p-core-cancel-button:hover, +button.h5p-core-cancel-button:focus { background: none; border: none; color: #e40000; From c6b3b06a97f3e30b8cbc0d16ef31fcb7559e95bd Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Tue, 24 May 2016 11:18:42 +0200 Subject: [PATCH 04/22] Added pointer cursor for core cancel button. HFJ-1930 --- styles/h5p-core-button.css | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/h5p-core-button.css b/styles/h5p-core-button.css index 04f33a3..3ba392e 100644 --- a/styles/h5p-core-button.css +++ b/styles/h5p-core-button.css @@ -54,6 +54,7 @@ button.h5p-core-cancel-button { margin-right: 1em; font-size: 1em; text-decoration: none; + cursor: pointer; } button.h5p-core-cancel-button:hover, From 0a63d123cf6e3865d6c72fefa819084cdcd21fbc Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Tue, 31 May 2016 10:19:07 +0200 Subject: [PATCH 05/22] Prevent DOM pollution when having many confirmation dialogs. Append confirmation dialog on show and detach it on hide. HFJ-1969 --- js/h5p-confirmation-dialog.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index 11047b2..c948192 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -128,14 +128,12 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { var wrapperElement; /** - * Append confirmation dialog + * Set parent of confirmation dialog * @param {HTMLElement} wrapper * @returns {H5P.ConfirmationDialog} */ this.appendTo = function (wrapper) { - wrapper.appendChild(popupBackground); wrapperElement = wrapper; - return this; }; @@ -169,6 +167,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { * @returns {H5P.ConfirmationDialog} */ this.show = function (offsetTop) { + wrapperElement.appendChild(popupBackground); popupBackground.classList.remove('hidden'); fitToContainer(offsetTop); setTimeout(function () { @@ -202,6 +201,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { popup.classList.add('hidden'); setTimeout(function () { popupBackground.classList.add('hidden'); + wrapperElement.removeChild(popupBackground); }, 100); return this; From c2f5feaae5ae8450baa7b451801319786473cc6e Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Tue, 31 May 2016 10:51:59 +0200 Subject: [PATCH 06/22] Improved error message for req core version HFJ-1959 --- h5p.classes.php | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 93c4213..5e19639 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1055,24 +1055,27 @@ class H5PValidator { $valid = $this->isValidRequiredH5pData($h5pData, $required, $library_name); $valid = $this->isValidOptionalH5pData($h5pData, $optional, $library_name) && $valid; - // Test library core version requirement. If no requirement is set, - // this implicitly means 1.0, which shall work on newer versions - // too. + // Check the library's required API version of Core. + // If no requirement is set this implicitly means 1.0. if (isset($h5pData['coreApi']) && !empty($h5pData['coreApi'])) { if (($h5pData['coreApi']['majorVersion'] > H5PCore::$coreApi['majorVersion']) || - (($h5pData['coreApi']['majorVersion'] == H5PCore::$coreApi['majorVersion']) && - ($h5pData['coreApi']['minorVersion'] > H5PCore::$coreApi['minorVersion']))) - { + ( ($h5pData['coreApi']['majorVersion'] == H5PCore::$coreApi['majorVersion']) && + ($h5pData['coreApi']['minorVersion'] > H5PCore::$coreApi['minorVersion']) )) { + $this->h5pF->setErrorMessage( - $this->h5pF->t('The library "%libraryName" requires H5P %requiredVersion, but only H5P %coreApi is installed.', - array( - '%libraryName' => $library_name, - '%requiredVersion' => $h5pData['coreApi']['majorVersion'] . '.' . $h5pData['coreApi']['minorVersion'], - '%coreApi' => H5PCore::$coreApi['majorVersion'] . '.' . H5PCore::$coreApi['minorVersion'] - ))); + $this->h5pF->t('The system was unable to install the %component component from the package, it requires a newer version of the H5P plugin. This site is currently running version %current, whereas the required version is %required or higher. You should consider upgrading and then try again.', + array( + '%component' => (isset($h5pData['title']) ? $h5pData['title'] : $library_name), + '%current' => H5PCore::$coreApi['majorVersion'] . '.' . H5PCore::$coreApi['minorVersion'], + '%required' => $h5pData['coreApi']['majorVersion'] . '.' . $h5pData['coreApi']['minorVersion'] + ) + ) + ); + $valid = false; } } + return $valid; } From eba774c86389f808c2d6ec54fa3179bb85b6328d Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Tue, 31 May 2016 10:19:07 +0200 Subject: [PATCH 07/22] Prevent DOM pollution when having many confirmation dialogs. Append confirmation dialog on show and detach it on hide. HFJ-1969 (cherry picked from commit 0a63d12) --- js/h5p-confirmation-dialog.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index a8d4ac2..84c8827 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -141,14 +141,12 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { var wrapperElement; /** - * Append confirmation dialog + * Set parent of confirmation dialog * @param {HTMLElement} wrapper * @returns {H5P.ConfirmationDialog} */ this.appendTo = function (wrapper) { - wrapper.appendChild(popupBackground); wrapperElement = wrapper; - return this; }; @@ -182,6 +180,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { * @returns {H5P.ConfirmationDialog} */ this.show = function (offsetTop) { + wrapperElement.appendChild(popupBackground); popupBackground.classList.remove('hidden'); fitToContainer(offsetTop); setTimeout(function () { @@ -215,6 +214,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { popup.classList.add('hidden'); setTimeout(function () { popupBackground.classList.add('hidden'); + wrapperElement.removeChild(popupBackground); }, 100); return this; From ed13203254d162036e05e83d540cfaa9347b78d1 Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Mon, 23 May 2016 14:34:56 +0200 Subject: [PATCH 08/22] Use buttons instead of anchors in Confirmation Dialog. HFJ-1930 (cherry picked from commit 27bc158) --- js/h5p-confirmation-dialog.js | 71 ++++++++++++------------------ styles/h5p-confirmation-dialog.css | 10 ++--- styles/h5p-core-button.css | 25 ++++++----- 3 files changed, 47 insertions(+), 59 deletions(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index 84c8827..c948192 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -24,6 +24,26 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { options.cancelText = options.cancelText || H5P.t('cancelLabel'); options.confirmText = options.confirmText || H5P.t('confirmLabel'); + /** + * Handle confirming event + * @param {Event} e + */ + function dialogConfirmed(e) { + self.hide(); + self.trigger('confirmed'); + e.preventDefault(); + } + + /** + * Handle dialog canceled + * @param {Event} e + */ + function dialogCanceled(e) { + self.hide(); + self.trigger('canceled'); + e.preventDefault(); + } + // Offset of exit button var exitButtonOffset = 2 * 16; var shadowOffset = 8; @@ -69,70 +89,37 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { body.appendChild(buttons); // Cancel button - var cancelButton = document.createElement('a'); + var cancelButton = document.createElement('button'); cancelButton.classList.add('h5p-core-cancel-button'); - cancelButton.href = '#'; cancelButton.textContent = options.cancelText; - cancelButton.onclick = function (e) { - self.hide(); - self.trigger('canceled'); - e.preventDefault(); - }; + cancelButton.onclick = dialogCanceled; cancelButton.onkeydown = function (e) { if (e.which === 32) { // Space - // Prevent jumping - e.preventDefault(); - } - else if (e.which === 13) { // Enter - self.hide(); - self.trigger('canceled'); - e.preventDefault(); + dialogCanceled(e); } }; buttons.appendChild(cancelButton); // Confirm button - var confirmButton = document.createElement('a'); + var confirmButton = document.createElement('button'); confirmButton.classList.add('h5p-core-button', 'h5p-confirmation-dialog-confirm-button'); - confirmButton.href = '#'; confirmButton.textContent = options.confirmText; - confirmButton.onclick = function (e) { - self.hide(); - self.trigger('confirmed'); - e.preventDefault(); - }; + confirmButton.onclick = dialogConfirmed; confirmButton.onkeydown = function (e) { if (e.which === 32) { // Space - // Prevent jumping - e.preventDefault(); - } - else if (e.which === 13) { // Enter - self.hide(); - self.trigger('confirmed'); - e.preventDefault(); + dialogConfirmed(e); } }; buttons.appendChild(confirmButton); // Exit button - var exitButton = document.createElement('a'); - exitButton.href = '#'; + var exitButton = document.createElement('button'); exitButton.classList.add('h5p-confirmation-dialog-exit'); - exitButton.onclick = function (e) { - self.hide(); - self.trigger('canceled'); - e.preventDefault(); - }; + exitButton.onclick = dialogCanceled; exitButton.onkeydown = function (e) { if (e.which === 32) { // Space - // Prevent jumping - e.preventDefault(); - } - else if (e.which === 13) { // Enter - self.hide(); - self.trigger('canceled'); - e.preventDefault(); + dialogCanceled(e); } }; popup.appendChild(exitButton); diff --git a/styles/h5p-confirmation-dialog.css b/styles/h5p-confirmation-dialog.css index 093a6ad..2923b17 100644 --- a/styles/h5p-confirmation-dialog.css +++ b/styles/h5p-confirmation-dialog.css @@ -81,9 +81,9 @@ float: right; } -a.h5p-confirmation-dialog-exit:visited, -a.h5p-confirmation-dialog-exit:link, -a.h5p-confirmation-dialog-exit { +button.h5p-confirmation-dialog-exit:visited, +button.h5p-confirmation-dialog-exit:link, +button.h5p-confirmation-dialog-exit { position: absolute; background: none; border: none; @@ -95,8 +95,8 @@ a.h5p-confirmation-dialog-exit { text-decoration: none; } -a.h5p-confirmation-dialog-exit:focus, -a.h5p-confirmation-dialog-exit:hover { +button.h5p-confirmation-dialog-exit:focus, +button.h5p-confirmation-dialog-exit:hover { color: #555; } diff --git a/styles/h5p-core-button.css b/styles/h5p-core-button.css index b05c423..04f33a3 100644 --- a/styles/h5p-core-button.css +++ b/styles/h5p-core-button.css @@ -1,6 +1,6 @@ -a.h5p-core-button:visited, -a.h5p-core-button:link, -a.h5p-core-button { +button.h5p-core-button:visited, +button.h5p-core-button:link, +button.h5p-core-button { font-size: 1em; line-height: 1.2; padding: 0.5em 1.25em; @@ -20,15 +20,15 @@ a.h5p-core-button { vertical-align: baseline; text-decoration: none; } -a.h5p-core-button:hover, -a.h5p-core-button:focus { +button.h5p-core-button:hover, +button.h5p-core-button:focus { background: #1356a3; color: #fff; text-decoration: none; -webkit-transition: initial; transition: initial; } -a.h5p-core-button:active { +button.h5p-core-button:active { position: relative; background: #104888; @@ -37,7 +37,7 @@ a.h5p-core-button:active { box-shadow: inset 0 4px 0 #0e407a; } -a.h5p-core-button:before { +button.h5p-core-button:before { font-family: 'H5P'; padding-right: 0.15em; font-size: 1.5em; @@ -45,9 +45,10 @@ a.h5p-core-button:before { line-height: 0.7; } -a.h5p-core-cancel-button:visited, -a.h5p-core-cancel-button:link, -a.h5p-core-cancel-button { +button.h5p-core-cancel-button:visited, +button.h5p-core-cancel-button:link, +button.h5p-core-cancel-button { + border: none; background: none; color: #a00; margin-right: 1em; @@ -55,8 +56,8 @@ a.h5p-core-cancel-button { text-decoration: none; } -a.h5p-core-cancel-button:hover, -a.h5p-core-cancel-button:focus { +button.h5p-core-cancel-button:hover, +button.h5p-core-cancel-button:focus { background: none; border: none; color: #e40000; From f6ce5dff74ae5ebf19e72fb0868a599e446b3205 Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Tue, 24 May 2016 11:18:42 +0200 Subject: [PATCH 09/22] Added pointer cursor for core cancel button. HFJ-1930 (cherry picked from commit c6b3b06) --- styles/h5p-core-button.css | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/h5p-core-button.css b/styles/h5p-core-button.css index 04f33a3..3ba392e 100644 --- a/styles/h5p-core-button.css +++ b/styles/h5p-core-button.css @@ -54,6 +54,7 @@ button.h5p-core-cancel-button { margin-right: 1em; font-size: 1em; text-decoration: none; + cursor: pointer; } button.h5p-core-cancel-button:hover, From e3b29a21999f1bc915ebc4f10b84257dffa3da51 Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Mon, 6 Jun 2016 14:57:51 +0200 Subject: [PATCH 10/22] Accessibility - reads confirmation dialog text on show. HFJ-1992 --- js/h5p-confirmation-dialog.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index c948192..9badb8e 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -80,6 +80,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { // Popup text var text = document.createElement('div'); text.classList.add('h5p-confirmation-dialog-text'); + text.setAttribute('role', 'alert'); text.innerHTML = options.dialogText; body.appendChild(text); @@ -116,6 +117,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { // Exit button var exitButton = document.createElement('button'); exitButton.classList.add('h5p-confirmation-dialog-exit'); + exitButton.title = options.cancelText; exitButton.onclick = dialogCanceled; exitButton.onkeydown = function (e) { if (e.which === 32) { // Space From 7807b8af68a1dfabe8e7c71d238ac139e3c96a39 Mon Sep 17 00:00:00 2001 From: Paal Joergensen Date: Mon, 6 Jun 2016 16:09:35 +0200 Subject: [PATCH 11/22] Making sure reset dialog is only shown once [HFJ-1989] --- js/h5p.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/h5p.js b/js/h5p.js index 5a1c9e1..1511ee8 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -103,6 +103,7 @@ H5P.init = function (target) { var $container = H5P.jQuery('
').appendTo($element); var contentId = $element.data('content-id'); var contentData = H5PIntegration.contents['cid-' + contentId]; + var resetUserState = false; if (contentData === undefined) { return H5P.error('No data for content id ' + contentId + '. Perhaps the library is gone?'); } @@ -118,6 +119,7 @@ H5P.init = function (target) { }; } else if (previousState === null && H5PIntegration.saveFreq) { + resetUserState = true; // Content has been reset. Display dialog. delete contentData.contentUserData; var dialog = new H5P.Dialog('content-user-data-reset', 'Data Reset', '

' + H5P.t('contentChanged') + '

' + H5P.t('startingOver') + '

OK
', $container); @@ -137,6 +139,10 @@ H5P.init = function (target) { // Create new instance. var instance = H5P.newRunnable(library, contentId, $container, true, {standalone: true}); + if (resetUserState) { + H5P.deleteUserData(contentId, 'state', instance.subContentId); + } + // Check if we should add and display a fullscreen button for this H5P. if (contentData.fullScreen == 1 && H5P.canHasFullScreen) { H5P.jQuery('
').prependTo($container).children().click(function () { From 87658ed42b786d214fed222c667986ecdc1051ca Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Tue, 7 Jun 2016 11:04:21 +0200 Subject: [PATCH 12/22] Accessibility - reads confirmation dialog text on show. HFJ-1992 --- js/h5p-confirmation-dialog.js | 51 +++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index 9badb8e..f2b6c61 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -44,6 +44,16 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { e.preventDefault(); } + /** + * Flow focus to element + * @param {HTMLElement} element Next element to be focused + * @param {Event} e Original tab event + */ + function flowTo(element, e) { + element.focus(); + e.preventDefault(); + } + // Offset of exit button var exitButtonOffset = 2 * 16; var shadowOffset = 8; @@ -59,7 +69,14 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { // Create outer popup var popup = document.createElement('div'); popup.classList.add('h5p-confirmation-dialog-popup', 'hidden'); + popup.setAttribute('role', 'dialog'); popupBackground.appendChild(popup); + popup.onkeydown = function (e) { + if (e.which === 27) {// Esc key + // Exit dialog + dialogCanceled(e); + } + }; // Popup header var header = document.createElement('div'); @@ -93,19 +110,31 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { var cancelButton = document.createElement('button'); cancelButton.classList.add('h5p-core-cancel-button'); cancelButton.textContent = options.cancelText; - cancelButton.onclick = dialogCanceled; - cancelButton.onkeydown = function (e) { - if (e.which === 32) { // Space - dialogCanceled(e); - } - }; - buttons.appendChild(cancelButton); // Confirm button var confirmButton = document.createElement('button'); confirmButton.classList.add('h5p-core-button', 'h5p-confirmation-dialog-confirm-button'); confirmButton.textContent = options.confirmText; + + // Exit button + var exitButton = document.createElement('button'); + exitButton.classList.add('h5p-confirmation-dialog-exit'); + exitButton.title = options.cancelText; + + // Cancel handler + cancelButton.onclick = dialogCanceled; + cancelButton.onkeydown = function (e) { + if (e.which === 32) { // Space + dialogCanceled(e); + } + else if (e.which === 9 && e.shiftKey) { // Shift-tab + flowTo(exitButton, e); + } + }; + buttons.appendChild(cancelButton); + + // Confirm handler confirmButton.onclick = dialogConfirmed; confirmButton.onkeydown = function (e) { if (e.which === 32) { // Space @@ -114,15 +143,15 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { }; buttons.appendChild(confirmButton); - // Exit button - var exitButton = document.createElement('button'); - exitButton.classList.add('h5p-confirmation-dialog-exit'); - exitButton.title = options.cancelText; + // Exit handler exitButton.onclick = dialogCanceled; exitButton.onkeydown = function (e) { if (e.which === 32) { // Space dialogCanceled(e); } + else if (e.which === 9 && !e.shiftKey) { // Tab + flowTo(cancelButton, e); + } }; popup.appendChild(exitButton); From f4cee6e2847a8c48ff1c3063825a62f588d38cd8 Mon Sep 17 00:00:00 2001 From: Paal Joergensen Date: Tue, 7 Jun 2016 11:09:42 +0200 Subject: [PATCH 13/22] Moved deletion of content user data to after dialog is closed [HFJ-1989] --- js/h5p.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/js/h5p.js b/js/h5p.js index 1511ee8..5de66e2 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -103,7 +103,6 @@ H5P.init = function (target) { var $container = H5P.jQuery('
').appendTo($element); var contentId = $element.data('content-id'); var contentData = H5PIntegration.contents['cid-' + contentId]; - var resetUserState = false; if (contentData === undefined) { return H5P.error('No data for content id ' + contentId + '. Perhaps the library is gone?'); } @@ -119,18 +118,19 @@ H5P.init = function (target) { }; } else if (previousState === null && H5PIntegration.saveFreq) { - resetUserState = true; // Content has been reset. Display dialog. delete contentData.contentUserData; var dialog = new H5P.Dialog('content-user-data-reset', 'Data Reset', '

' + H5P.t('contentChanged') + '

' + H5P.t('startingOver') + '

OK
', $container); H5P.jQuery(dialog).on('dialog-opened', function (event, $dialog) { - $dialog.find('.h5p-dialog-ok-button').click(function () { - dialog.close(); - }).keypress(function (event) { - if (event.which === 32) { + + var closeDialog = function (event) { + if (event.type === 'click' || event.which === 32) { dialog.close(); + H5P.deleteUserData(contentId, 'state', 0); } - }); + }; + + $dialog.find('.h5p-dialog-ok-button').click(closeDialog).keypress(closeDialog); }); dialog.open(); } @@ -139,10 +139,6 @@ H5P.init = function (target) { // Create new instance. var instance = H5P.newRunnable(library, contentId, $container, true, {standalone: true}); - if (resetUserState) { - H5P.deleteUserData(contentId, 'state', instance.subContentId); - } - // Check if we should add and display a fullscreen button for this H5P. if (contentData.fullScreen == 1 && H5P.canHasFullScreen) { H5P.jQuery('
').prependTo($container).children().click(function () { From 77fb832221f8ac3a7c66b1aca582b9bf17c00a99 Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Tue, 7 Jun 2016 14:31:41 +0200 Subject: [PATCH 14/22] Added focus capturing, redirecting it to the open confirmation dialog HFJ-1995 --- js/h5p-confirmation-dialog.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index f2b6c61..cb326c6 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -158,6 +158,9 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { // Wrapper element var wrapperElement; + // Focus capturing + var focusPredator; + /** * Set parent of confirmation dialog * @param {HTMLElement} wrapper @@ -168,6 +171,32 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { return this; }; + /** + * Capture the focus element, send it to confirmation button + * @param {Event} e Original focus event + */ + var captureFocus = function (e) { + if (!popupBackground.contains(e.target)) { + e.preventDefault(); + confirmButton.focus(); + } + }; + + /** + * Start capturing focus of parent and send it to dialog + */ + var startCapturingFocus = function () { + focusPredator = wrapperElement.parentNode || wrapperElement; + focusPredator.addEventListener('focus', captureFocus, true); + }; + + /** + * Clean up event listener for capturing focus + */ + var stopCapturingFocus = function () { + focusPredator.removeEventListener('focus', captureFocus, true); + }; + /** * Fit popup to container. Makes sure it doesn't overflow. * @params {number} [offsetTop] Offset of popup @@ -199,6 +228,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { */ this.show = function (offsetTop) { wrapperElement.appendChild(popupBackground); + startCapturingFocus(); popupBackground.classList.remove('hidden'); fitToContainer(offsetTop); setTimeout(function () { @@ -232,6 +262,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { popup.classList.add('hidden'); setTimeout(function () { popupBackground.classList.add('hidden'); + stopCapturingFocus(); wrapperElement.removeChild(popupBackground); }, 100); From 10e1a7ba65957792a71030b1917d79ecb1f41e26 Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Tue, 7 Jun 2016 15:09:59 +0200 Subject: [PATCH 15/22] Use DOM Level 2 events. HFJ-1999 --- js/h5p-confirmation-dialog.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index cb326c6..3c16214 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -71,12 +71,12 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { popup.classList.add('h5p-confirmation-dialog-popup', 'hidden'); popup.setAttribute('role', 'dialog'); popupBackground.appendChild(popup); - popup.onkeydown = function (e) { + popup.addEventListener('keydown', function (e) { if (e.which === 27) {// Esc key // Exit dialog dialogCanceled(e); } - }; + }); // Popup header var header = document.createElement('div'); @@ -123,36 +123,36 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { exitButton.title = options.cancelText; // Cancel handler - cancelButton.onclick = dialogCanceled; - cancelButton.onkeydown = function (e) { + cancelButton.addEventListener('click', dialogCanceled); + cancelButton.addEventListener('keydown', function (e) { if (e.which === 32) { // Space dialogCanceled(e); } else if (e.which === 9 && e.shiftKey) { // Shift-tab flowTo(exitButton, e); } - }; + }); buttons.appendChild(cancelButton); // Confirm handler - confirmButton.onclick = dialogConfirmed; - confirmButton.onkeydown = function (e) { + confirmButton.addEventListener('click', dialogConfirmed); + confirmButton.addEventListener('keydown', function (e) { if (e.which === 32) { // Space dialogConfirmed(e); } - }; + }); buttons.appendChild(confirmButton); // Exit handler - exitButton.onclick = dialogCanceled; - exitButton.onkeydown = function (e) { + exitButton.addEventListener('click', dialogCanceled); + exitButton.addEventListener('keydown', function (e) { if (e.which === 32) { // Space dialogCanceled(e); } else if (e.which === 9 && !e.shiftKey) { // Tab flowTo(cancelButton, e); } - }; + }); popup.appendChild(exitButton); // Wrapper element From 8615deb23b8021cba4c29a55387ede2fc79f26e5 Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Wed, 8 Jun 2016 11:06:03 +0200 Subject: [PATCH 16/22] Hide elements that confirmation dialog covers from assistive technologies. HFJ-1995 --- js/h5p-confirmation-dialog.js | 71 ++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index 3c16214..ab551dd 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -161,6 +161,13 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { // Focus capturing var focusPredator; + // Maintains hidden state of elements + var wrapperSiblingsHidden = []; + var popupSiblingsHidden = []; + + // Element with focus before dialog + var previouslyFocused; + /** * Set parent of confirmation dialog * @param {HTMLElement} wrapper @@ -182,6 +189,44 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { } }; + /** + * Hide siblings of element from assistive technology + * + * @param {HTMLElement} element + * @returns {Array} The previous hidden state of all siblings + */ + var hideSiblings = function (element) { + var hiddenSiblings = []; + var siblings = element.parentNode.children; + var i; + for (i = 0; i < siblings.length; i += 1) { + // Preserve hidden state + hiddenSiblings[i] = siblings[i].getAttribute('aria-hidden') ? + true : false; + + if (siblings[i] !== element) { + siblings[i].setAttribute('aria-hidden', true); + } + } + return hiddenSiblings; + }; + + /** + * Restores assistive technology state of element's siblings + * + * @param {HTMLElement} element + * @param {Array} hiddenSiblings Hidden state of all siblings + */ + var restoreSiblings = function (element, hiddenSiblings) { + var siblings = element.parentNode.children; + var i; + for (i = 0; i < siblings.length; i += 1) { + if (siblings[i] !== element && !hiddenSiblings[i]) { + siblings[i].removeAttribute('aria-hidden'); + } + } + }; + /** * Start capturing focus of parent and send it to dialog */ @@ -194,9 +239,26 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { * Clean up event listener for capturing focus */ var stopCapturingFocus = function () { + focusPredator.removeAttribute('aria-hidden'); focusPredator.removeEventListener('focus', captureFocus, true); }; + /** + * Hide siblings in underlay from assistive technologies + */ + var disableUnderlay = function () { + wrapperSiblingsHidden = hideSiblings(wrapperElement); + popupSiblingsHidden = hideSiblings(popupBackground); + }; + + /** + * Restore state of underlay for assistive technologies + */ + var restoreUnderlay = function () { + restoreSiblings(wrapperElement, wrapperSiblingsHidden); + restoreSiblings(popupBackground, popupSiblingsHidden); + }; + /** * Fit popup to container. Makes sure it doesn't overflow. * @params {number} [offsetTop] Offset of popup @@ -227,8 +289,11 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { * @returns {H5P.ConfirmationDialog} */ this.show = function (offsetTop) { + // Capture focused item + previouslyFocused = document.activeElement; wrapperElement.appendChild(popupBackground); startCapturingFocus(); + disableUnderlay(); popupBackground.classList.remove('hidden'); fitToContainer(offsetTop); setTimeout(function () { @@ -260,9 +325,13 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { this.hide = function () { popupBackground.classList.add('hiding'); popup.classList.add('hidden'); + + // Restore focus + stopCapturingFocus(); + previouslyFocused.focus(); + restoreUnderlay(); setTimeout(function () { popupBackground.classList.add('hidden'); - stopCapturingFocus(); wrapperElement.removeChild(popupBackground); }, 100); From 6caf44e54b69edd98f55733f522f5763e8304e76 Mon Sep 17 00:00:00 2001 From: Paal Joergensen Date: Wed, 8 Jun 2016 11:28:07 +0200 Subject: [PATCH 17/22] Added checks for mbstring PHP extension [HFJ-1996] --- h5p.classes.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 71e95c4..851515f 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2898,7 +2898,12 @@ class H5PContentValidator { // Check if string is within allowed length if (isset($semantics->maxLength)) { - $text = mb_substr($text, 0, $semantics->maxLength); + if (!extension_loaded('mbstring')) { + $this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'error'); + } + else { + $text = mb_substr($text, 0, $semantics->maxLength); + } } // Check if string is according to optional regexp in semantics @@ -2948,7 +2953,11 @@ class H5PContentValidator { // file name, 2. testing against a returned error array that could // never be more than 1 element long anyway, 3. recreating the regex // for every file. - if (!preg_match($wl_regex, mb_strtolower($file))) { + if (!extension_loaded('mbstring')) { + $this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'error'); + $valid = FALSE; + } + else if (!preg_match($wl_regex, mb_strtolower($file))) { $this->h5pF->setErrorMessage($this->h5pF->t('File "%filename" not allowed. Only files with the following extensions are allowed: %files-allowed.', array('%filename' => $file, '%files-allowed' => $whitelist)), 'error'); $valid = FALSE; } From e10594fb495d3c525a6ba5f9a55223fb9572c17c Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Thu, 9 Jun 2016 11:26:11 +0200 Subject: [PATCH 18/22] Hide redundant confirmation dialog exit button for assistive technologies. HFJ-2004 --- js/h5p-confirmation-dialog.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index ab551dd..b6ff15f 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -120,6 +120,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { // Exit button var exitButton = document.createElement('button'); exitButton.classList.add('h5p-confirmation-dialog-exit'); + exitButton.setAttribute('aria-hidden', 'true'); exitButton.title = options.cancelText; // Cancel handler @@ -167,7 +168,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { // Element with focus before dialog var previouslyFocused; - + /** * Set parent of confirmation dialog * @param {HTMLElement} wrapper @@ -191,7 +192,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { /** * Hide siblings of element from assistive technology - * + * * @param {HTMLElement} element * @returns {Array} The previous hidden state of all siblings */ @@ -213,7 +214,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { /** * Restores assistive technology state of element's siblings - * + * * @param {HTMLElement} element * @param {Array} hiddenSiblings Hidden state of all siblings */ From 51851f14c340165f7e76779d21090942ad36a4f6 Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Thu, 9 Jun 2016 13:18:09 +0200 Subject: [PATCH 19/22] Use aria-labelledby to describe dialog, instead of alert. HFJ-2003 --- js/h5p-confirmation-dialog.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index b6ff15f..481429f 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -16,6 +16,10 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { function ConfirmationDialog(options) { EventDispatcher.call(this); var self = this; + + // Make sure confirmation dialogs have unique id + H5P.ConfirmationDialog.uniqueId += 1; + var uniqueId = H5P.ConfirmationDialog.uniqueId; // Default options options = options || {}; @@ -70,6 +74,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { var popup = document.createElement('div'); popup.classList.add('h5p-confirmation-dialog-popup', 'hidden'); popup.setAttribute('role', 'dialog'); + popup.setAttribute('aria-labelledby', 'h5p-confirmation-dialog-dialog-text-' + uniqueId); popupBackground.appendChild(popup); popup.addEventListener('keydown', function (e) { if (e.which === 27) {// Esc key @@ -97,8 +102,8 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { // Popup text var text = document.createElement('div'); text.classList.add('h5p-confirmation-dialog-text'); - text.setAttribute('role', 'alert'); text.innerHTML = options.dialogText; + text.id = 'h5p-confirmation-dialog-dialog-text-' + uniqueId; body.appendChild(text); // Popup buttons @@ -346,3 +351,5 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { return ConfirmationDialog; }(H5P.EventDispatcher)); + +H5P.ConfirmationDialog.uniqueId = -1; From b3c55928e375a75f098be6be1344d61e1675663b Mon Sep 17 00:00:00 2001 From: Thomas Marstrander Date: Thu, 9 Jun 2016 15:26:15 +0200 Subject: [PATCH 20/22] Remove tabindex of exitButton in confirmation dialog. Trapped focus between confirm and cancel button. HFJ-2004 --- js/h5p-confirmation-dialog.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/js/h5p-confirmation-dialog.js b/js/h5p-confirmation-dialog.js index 481429f..a06166b 100644 --- a/js/h5p-confirmation-dialog.js +++ b/js/h5p-confirmation-dialog.js @@ -16,7 +16,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { function ConfirmationDialog(options) { EventDispatcher.call(this); var self = this; - + // Make sure confirmation dialogs have unique id H5P.ConfirmationDialog.uniqueId += 1; var uniqueId = H5P.ConfirmationDialog.uniqueId; @@ -126,6 +126,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { var exitButton = document.createElement('button'); exitButton.classList.add('h5p-confirmation-dialog-exit'); exitButton.setAttribute('aria-hidden', 'true'); + exitButton.tabIndex = -1; exitButton.title = options.cancelText; // Cancel handler @@ -135,7 +136,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { dialogCanceled(e); } else if (e.which === 9 && e.shiftKey) { // Shift-tab - flowTo(exitButton, e); + flowTo(confirmButton, e); } }); buttons.appendChild(cancelButton); @@ -146,6 +147,9 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { if (e.which === 32) { // Space dialogConfirmed(e); } + else if (e.which === 9 && !e.shiftKey) { // Tab + flowTo(cancelButton, e); + } }); buttons.appendChild(confirmButton); @@ -155,9 +159,6 @@ H5P.ConfirmationDialog = (function (EventDispatcher) { if (e.which === 32) { // Space dialogCanceled(e); } - else if (e.which === 9 && !e.shiftKey) { // Tab - flowTo(cancelButton, e); - } }); popup.appendChild(exitButton); From ec2e0fbb71e90b5c664724d3bbcbcb00546cdd5d Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 13 Jun 2016 14:46:15 +0200 Subject: [PATCH 21/22] Removed JS error on empty results --- js/h5p-data-view.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/h5p-data-view.js b/js/h5p-data-view.js index 0edfc56..89080e0 100644 --- a/js/h5p-data-view.js +++ b/js/h5p-data-view.js @@ -288,6 +288,11 @@ var H5PDataView = (function ($) { var self = this; if (self.pagination === undefined) { + if (self.table === undefined) { + // No table, no pagination + return; + } + // Create new widget var $pagerContainer = $('
', {'class': 'h5p-pagination'}); self.pagination = new H5PUtils.Pagination(num, self.limit, function (offset) { From a6656c2e6ffb14c4083c058065ff8fb2d4426365 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 20 Jun 2016 14:57:14 +0200 Subject: [PATCH 22/22] Support for when cookies are disabled HFJ-1915 --- js/h5p-x-api-event.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/js/h5p-x-api-event.js b/js/h5p-x-api-event.js index c5ce2e3..212fe0b 100644 --- a/js/h5p-x-api-event.js +++ b/js/h5p-x-api-event.js @@ -24,7 +24,7 @@ H5P.XAPIEvent.prototype.constructor = H5P.XAPIEvent; */ 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}; @@ -40,22 +40,22 @@ H5P.XAPIEvent.prototype.setScoredResult = function (score, maxScore, instance, c } } } - + if (typeof completion === 'undefined') { this.data.statement.result.completion = (this.getVerb() === 'completed' || this.getVerb() === 'answered'); } 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 - + this.data.statement.result.duration = 'PT' + duration + 'S'; } }; @@ -188,12 +188,18 @@ H5P.XAPIEvent.prototype.setActor = function () { } else { var uuid; - if (localStorage.H5PUserUUID) { - uuid = localStorage.H5PUserUUID; + try { + if (localStorage.H5PUserUUID) { + uuid = localStorage.H5PUserUUID; + } + else { + uuid = H5P.createUUID(); + localStorage.H5PUserUUID = uuid; + } } - else { - uuid = H5P.createUUID(); - localStorage.H5PUserUUID = uuid; + catch (err) { + // LocalStorage and Cookies are probably disabled. Do not track the user. + uuid = 'not-trackable-' + H5P.createUUID(); } this.data.statement.actor = { 'account': {