JI-1059 Add offline request queue with retry dialog
Add logic for adding extra class and hiding buttons in conf dialog Update font files with throbberpull/61/head
parent
ada2f4009d
commit
39d27ab9bb
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -5,21 +5,21 @@
|
||||||
<json>
|
<json>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
{
|
{
|
||||||
"fontFamily": "h5p-core-18",
|
"fontFamily": "h5p-core-21",
|
||||||
"description": "Font generated by IcoMoon.",
|
"description": "Font generated by IcoMoon.",
|
||||||
"majorVersion": 1,
|
"majorVersion": 1,
|
||||||
"minorVersion": 1,
|
"minorVersion": 1,
|
||||||
"version": "Version 1.1",
|
"version": "Version 1.1",
|
||||||
"fontId": "h5p-core-18",
|
"fontId": "h5p-core-21",
|
||||||
"psName": "h5p-core-18",
|
"psName": "h5p-core-21",
|
||||||
"subFamily": "Regular",
|
"subFamily": "Regular",
|
||||||
"fullName": "h5p-core-18"
|
"fullName": "h5p-core-21"
|
||||||
}
|
}
|
||||||
]]>
|
]]>
|
||||||
</json>
|
</json>
|
||||||
</metadata>
|
</metadata>
|
||||||
<defs>
|
<defs>
|
||||||
<font id="h5p-core-18" horiz-adv-x="1024">
|
<font id="h5p-core-21" horiz-adv-x="1024">
|
||||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||||
<missing-glyph horiz-adv-x="1024" />
|
<missing-glyph horiz-adv-x="1024" />
|
||||||
<glyph unicode=" " horiz-adv-x="512" d="" />
|
<glyph unicode=" " horiz-adv-x="512" d="" />
|
||||||
|
@ -51,6 +51,6 @@
|
||||||
<glyph unicode="" glyph-name="info-important-description" data-tags="info-important-description" d="M512 718.701c-188.5 0-341.3-152.8-341.3-341.3s152.8-341.4 341.3-341.4 341.3 152.8 341.3 341.3-152.8 341.4-341.3 341.4v0zM512 64.601c-172.7 0-312.7 140-312.7 312.7s140 312.7 312.7 312.7c172.7 0 312.7-140 312.7-312.7-0.2-172.6-140.1-312.5-312.7-312.7v0zM512 626.901c-137.9 0-249.6-111.8-249.6-249.6s111.7-249.6 249.6-249.6 249.6 111.8 249.6 249.6-111.8 249.6-249.6 249.6v0z" />
|
<glyph unicode="" glyph-name="info-important-description" data-tags="info-important-description" d="M512 718.701c-188.5 0-341.3-152.8-341.3-341.3s152.8-341.4 341.3-341.4 341.3 152.8 341.3 341.3-152.8 341.4-341.3 341.4v0zM512 64.601c-172.7 0-312.7 140-312.7 312.7s140 312.7 312.7 312.7c172.7 0 312.7-140 312.7-312.7-0.2-172.6-140.1-312.5-312.7-312.7v0zM512 626.901c-137.9 0-249.6-111.8-249.6-249.6s111.7-249.6 249.6-249.6 249.6 111.8 249.6 249.6-111.8 249.6-249.6 249.6v0z" />
|
||||||
<glyph unicode="" glyph-name="icon-info" data-tags="icon-info" d="M467.2 480.855h87.467c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v70.385c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-87.462c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-69.959c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.715-4.373 9.2-7.159 15.338-7.245zM597.333 177.922h-22.187v209.92c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-130.128c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h22.182v-139.947h-22.187c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h174.075c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v46.065c0.043 0.527 0.067 1.141 0.067 1.761 0 5.302-1.791 10.185-4.8 14.079-3.742 4.424-9.36 7.247-15.636 7.247-0.489 0-0.975-0.017-1.456-0.051z" />
|
<glyph unicode="" glyph-name="icon-info" data-tags="icon-info" d="M467.2 480.855h87.467c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v70.385c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-87.462c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-69.959c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.715-4.373 9.2-7.159 15.338-7.245zM597.333 177.922h-22.187v209.92c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-130.128c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h22.182v-139.947h-22.187c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h174.075c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v46.065c0.043 0.527 0.067 1.141 0.067 1.761 0 5.302-1.791 10.185-4.8 14.079-3.742 4.424-9.36 7.247-15.636 7.247-0.489 0-0.975-0.017-1.456-0.051z" />
|
||||||
<glyph unicode="" glyph-name="paste" data-tags="paste" d="M394.402 723.733h-75.333c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-56.4 37.6-100.4 87.867-116v69.067c-15.733 9.467-25.067 25.067-25.067 47.067v288.4c0 31.333 25.067 56.4 56.4 56.4h131.733c0 0 0 0 3.2 3.2v0c0 31.333-28.267 59.6-59.6 59.6zM704.802 613.866c0 0-28.267 0-40.8 0-12.533 34.533-43.867 59.6-84.667 59.6s-69.067-25.067-81.6-59.6c-12.533 0-40.8 0-40.8 0-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v285.467c3.2 65.867-53.2 122.267-119.2 122.267zM582.535 626.533c22 0 40.8-18.8 40.8-40.8s-18.8-40.8-40.8-40.8c-22 0-40.8 18.8-40.8 40.8s15.733 40.8 40.8 40.8zM764.402 203.066c0-31.333-25.067-56.4-56.4-56.4h-250.933c-31.333 0-56.4 25.067-56.4 56.4v288.533c0 18.8 9.467 37.6 25.067 47.067v0c0-43.867 34.533-78.4 78.4-78.4h160c43.867 0 78.4 34.533 78.4 78.4v0c12.533-9.467 22-28.267 22-47.067v-288.533z" />
|
<glyph unicode="" glyph-name="paste" data-tags="paste" d="M394.402 723.733h-75.333c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-56.4 37.6-100.4 87.867-116v69.067c-15.733 9.467-25.067 25.067-25.067 47.067v288.4c0 31.333 25.067 56.4 56.4 56.4h131.733c0 0 0 0 3.2 3.2v0c0 31.333-28.267 59.6-59.6 59.6zM704.802 613.866c0 0-28.267 0-40.8 0-12.533 34.533-43.867 59.6-84.667 59.6s-69.067-25.067-81.6-59.6c-12.533 0-40.8 0-40.8 0-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v285.467c3.2 65.867-53.2 122.267-119.2 122.267zM582.535 626.533c22 0 40.8-18.8 40.8-40.8s-18.8-40.8-40.8-40.8c-22 0-40.8 18.8-40.8 40.8s15.733 40.8 40.8 40.8zM764.402 203.066c0-31.333-25.067-56.4-56.4-56.4h-250.933c-31.333 0-56.4 25.067-56.4 56.4v288.533c0 18.8 9.467 37.6 25.067 47.067v0c0-43.867 34.533-78.4 78.4-78.4h160c43.867 0 78.4 34.533 78.4 78.4v0c12.533-9.467 22-28.267 22-47.067v-288.533z" />
|
||||||
<glyph unicode="" glyph-name="reuse" data-tags="reuse" d="M734.975 624.754c-54.605 61.619-134.123 100.573-222.977 100.573-164.936 0-298.661-133.724-298.661-298.661h74.667c0 123.721 100.272 223.993 223.993 223.993 68.214 0 128.747-30.96 169.766-79.119l-70.213-70.213h199.109v199.109l-75.689-75.689zM512 202.674c-68.214 0-128.747 30.96-169.766 79.119l70.213 70.213h-199.109v-199.109l75.689 75.689c54.605-61.619 134.123-100.573 222.977-100.573 164.936 0 298.661 133.724 298.661 298.661h-74.667c0-123.721-100.272-223.993-223.993-223.993z" />
|
<glyph unicode="" glyph-name="reuse" data-tags="reuse" d="M734.974 646.084c-54.605 61.619-134.123 100.573-222.977 100.573-164.936 0-298.661-133.724-298.661-298.661h74.667c0 123.721 100.272 223.993 223.993 223.993 68.214 0 128.747-30.96 169.766-79.119l-70.213-70.213h199.109v199.109l-75.689-75.689zM511.999 224.004c-68.214 0-128.747 30.96-169.766 79.119l70.213 70.213h-199.109v-199.109l75.689 75.689c54.605-61.619 134.123-100.573 222.977-100.573 164.936 0 298.661 133.724 298.661 298.661h-74.667c0-123.721-100.272-223.993-223.993-223.993z" />
|
||||||
<glyph unicode="" glyph-name="info-outlined" data-tags="info-outlined" d="M467.199 202.669h89.599v268.8h-89.599v-268.8zM512 874.668c-247.296 0-448.001-200.705-448.001-448.001s200.705-448.001 448.001-448.001 448.001 200.705 448.001 448.001-200.705 448.001-448.001 448.001zM512 68.269c-197.568 0-358.398 160.83-358.398 358.398s160.83 358.398 358.398 358.398 358.398-160.83 358.398-358.398-160.83-358.398-358.398-358.398zM467.199 561.067h89.599v89.599h-89.599v-89.599z" />
|
<glyph unicode="" glyph-name="info-outlined" data-tags="info-outlined" d="M467.199 202.669h89.599v268.8h-89.599v-268.8zM512 874.668c-247.296 0-448.001-200.705-448.001-448.001s200.705-448.001 448.001-448.001 448.001 200.705 448.001 448.001-200.705 448.001-448.001 448.001zM512 68.269c-197.568 0-358.398 160.83-358.398 358.398s160.83 358.398 358.398 358.398 358.398-160.83 358.398-358.398-160.83-358.398-358.398-358.398zM467.199 561.067h89.599v89.599h-89.599v-89.599z" />
|
||||||
</font></defs></svg>
|
</font></defs></svg>
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Binary file not shown.
Binary file not shown.
|
@ -3489,6 +3489,7 @@ class H5PCore {
|
||||||
'offlineDialogBody' => $this->h5pF->t('We were unable to send information about your completion of this task. Please check your internet connection.'),
|
'offlineDialogBody' => $this->h5pF->t('We were unable to send information about your completion of this task. Please check your internet connection.'),
|
||||||
'offlineDialogRetryMessage' => $this->h5pF->t('Retrying in :num....'),
|
'offlineDialogRetryMessage' => $this->h5pF->t('Retrying in :num....'),
|
||||||
'offlineDialogRetryButtonLabel' => $this->h5pF->t('Retry now'),
|
'offlineDialogRetryButtonLabel' => $this->h5pF->t('Retry now'),
|
||||||
|
'offlineSuccessfulSubmit' => $this->h5pF->t('Successfully submitted results.'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
* @param [options.dialogText] Dialog text
|
* @param [options.dialogText] Dialog text
|
||||||
* @param [options.cancelText] Cancel dialog button text
|
* @param [options.cancelText] Cancel dialog button text
|
||||||
* @param [options.confirmText] Confirm dialog button text
|
* @param [options.confirmText] Confirm dialog button text
|
||||||
|
* @param [options.hideCancel] Hide cancel button
|
||||||
|
* @param [options.hideExit] Hide exit button
|
||||||
|
* @param [options.classes] Extra classes for popup
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ConfirmationDialog(options) {
|
function ConfirmationDialog(options) {
|
||||||
|
@ -73,6 +76,12 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
// Create outer popup
|
// Create outer popup
|
||||||
var popup = document.createElement('div');
|
var popup = document.createElement('div');
|
||||||
popup.classList.add('h5p-confirmation-dialog-popup', 'hidden');
|
popup.classList.add('h5p-confirmation-dialog-popup', 'hidden');
|
||||||
|
if (options.classes) {
|
||||||
|
options.classes.forEach(function (popupClass) {
|
||||||
|
popup.classList.add(popupClass);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
popup.setAttribute('role', 'dialog');
|
popup.setAttribute('role', 'dialog');
|
||||||
popup.setAttribute('aria-labelledby', 'h5p-confirmation-dialog-dialog-text-' + uniqueId);
|
popup.setAttribute('aria-labelledby', 'h5p-confirmation-dialog-dialog-text-' + uniqueId);
|
||||||
popupBackground.appendChild(popup);
|
popupBackground.appendChild(popup);
|
||||||
|
@ -139,7 +148,14 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
flowTo(confirmButton, e);
|
flowTo(confirmButton, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
buttons.appendChild(cancelButton);
|
|
||||||
|
if (!options.hideCancel) {
|
||||||
|
buttons.appendChild(cancelButton);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Center buttons
|
||||||
|
buttons.classList.add('center');
|
||||||
|
}
|
||||||
|
|
||||||
// Confirm handler
|
// Confirm handler
|
||||||
confirmButton.addEventListener('click', dialogConfirmed);
|
confirmButton.addEventListener('click', dialogConfirmed);
|
||||||
|
@ -148,7 +164,8 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
dialogConfirmed(e);
|
dialogConfirmed(e);
|
||||||
}
|
}
|
||||||
else if (e.which === 9 && !e.shiftKey) { // Tab
|
else if (e.which === 9 && !e.shiftKey) { // Tab
|
||||||
flowTo(cancelButton, e);
|
const nextButton = !options.hideCancel ? cancelButton : confirmButton;
|
||||||
|
flowTo(nextButton, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
buttons.appendChild(confirmButton);
|
buttons.appendChild(confirmButton);
|
||||||
|
@ -160,7 +177,9 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
dialogCanceled(e);
|
dialogCanceled(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
popup.appendChild(exitButton);
|
if (!options.hideExit) {
|
||||||
|
popup.appendChild(exitButton);
|
||||||
|
}
|
||||||
|
|
||||||
// Wrapper element
|
// Wrapper element
|
||||||
var wrapperElement;
|
var wrapperElement;
|
||||||
|
@ -346,6 +365,15 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve element
|
||||||
|
*
|
||||||
|
* @return {HTMLElement}
|
||||||
|
*/
|
||||||
|
this.getElement = function () {
|
||||||
|
return popup;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the minimum height of the view port
|
* Sets the minimum height of the view port
|
||||||
*
|
*
|
||||||
|
|
15
js/h5p.js
15
js/h5p.js
|
@ -66,20 +66,7 @@ H5P.init = function (target) {
|
||||||
H5P.$body = H5P.jQuery(document.body);
|
H5P.$body = H5P.jQuery(document.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
H5P.offlineRequestQueue = new H5P.RequestQueue();
|
H5P.offlineRequestQueue = new H5P.OfflineRequestQueue();
|
||||||
// We could handle previously failed requests here, instead we throw them away
|
|
||||||
// TODO: Add dialog
|
|
||||||
H5P.offlineRequestQueue.clear();
|
|
||||||
H5P.offlineRequestQueue.on('requestQueued', function () {
|
|
||||||
});
|
|
||||||
|
|
||||||
H5P.offlineRequestQueue.on('processingQueue', function () {
|
|
||||||
});
|
|
||||||
|
|
||||||
H5P.offlineRequestQueue.on('queueEmptied', function () {
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Determine if we can use full screen
|
// Determine if we can use full screen
|
||||||
if (H5P.fullscreenSupported === undefined) {
|
if (H5P.fullscreenSupported === undefined) {
|
||||||
|
|
|
@ -7,14 +7,15 @@ H5P.RequestQueue = (function ($, EventDispatcher) {
|
||||||
/**
|
/**
|
||||||
* A queue for requests, will be automatically processed when regaining connection
|
* A queue for requests, will be automatically processed when regaining connection
|
||||||
*
|
*
|
||||||
* @param {boolean} [options.showToast] Disable showing toast when losing or regaining connection
|
* @param {boolean} [options.showToast] Show toast when losing or regaining connection
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const RequestQueue = function (options) {
|
const RequestQueue = function (options) {
|
||||||
EventDispatcher.call(this);
|
EventDispatcher.call(this);
|
||||||
this.processingQueue = false;
|
this.processingQueue = false;
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
this.showToast = options ? options.showToast : false;
|
this.showToast = options.showToast;
|
||||||
this.itemName = 'requestQueue';
|
this.itemName = 'requestQueue';
|
||||||
|
|
||||||
// Initialize listener for when requests are added to queue
|
// Initialize listener for when requests are added to queue
|
||||||
|
@ -23,7 +24,7 @@ H5P.RequestQueue = (function ($, EventDispatcher) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add request to queue
|
* Add request to queue. Only supports posts currently.
|
||||||
*
|
*
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
* @param {Object} data
|
* @param {Object} data
|
||||||
|
@ -46,7 +47,10 @@ H5P.RequestQueue = (function ($, EventDispatcher) {
|
||||||
|
|
||||||
window.localStorage.setItem(this.itemName, JSON.stringify(storedStatements));
|
window.localStorage.setItem(this.itemName, JSON.stringify(storedStatements));
|
||||||
|
|
||||||
this.trigger('requestQueued', storedStatements);
|
this.trigger('requestQueued', {
|
||||||
|
storedStatements: storedStatements,
|
||||||
|
processingQueue: this.processingQueue,
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,7 +77,7 @@ H5P.RequestQueue = (function ($, EventDispatcher) {
|
||||||
*
|
*
|
||||||
* @returns {boolean} True if the storage was successfully cleared
|
* @returns {boolean} True if the storage was successfully cleared
|
||||||
*/
|
*/
|
||||||
RequestQueue.prototype.clear = function () {
|
RequestQueue.prototype.clearQueue = function () {
|
||||||
if (!window.localStorage) {
|
if (!window.localStorage) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -98,20 +102,16 @@ H5P.RequestQueue = (function ($, EventDispatcher) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Application is offline, re-send when we detect a connection
|
// Attempt to send queued requests
|
||||||
if (!window.navigator.onLine) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're online, attempt to send queued requests
|
|
||||||
const queue = this.getStoredRequests();
|
const queue = this.getStoredRequests();
|
||||||
const queueLength = queue.length;
|
const queueLength = queue.length;
|
||||||
|
|
||||||
// Clear storage, failed requests will be re-added
|
// Clear storage, failed requests will be re-added
|
||||||
this.clear();
|
this.clearQueue();
|
||||||
|
|
||||||
// No items left in queue
|
// No items left in queue
|
||||||
if (!queueLength) {
|
if (!queueLength) {
|
||||||
|
this.trigger('emptiedQueue', queue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,28 +169,20 @@ H5P.RequestQueue = (function ($, EventDispatcher) {
|
||||||
|
|
||||||
// Finished processing this queue
|
// Finished processing this queue
|
||||||
this.processingQueue = false;
|
this.processingQueue = false;
|
||||||
if (!window.navigator.onLine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process next queue if items were added while processing current queue
|
// Run empty queue callback with next request queue
|
||||||
const requestQueue = this.getStoredRequests();
|
const requestQueue = this.getStoredRequests();
|
||||||
if (requestQueue.length) {
|
this.trigger('queueEmptied', requestQueue);
|
||||||
this.resumeQueue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run empty queue callback
|
|
||||||
this.trigger('queueEmptied');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display toast message on the first content of current page
|
* Display toast message on the first content of current page
|
||||||
*
|
*
|
||||||
* @param {string} msg Message to display
|
* @param {string} msg Message to display
|
||||||
|
* @param {boolean} [forceShow] Force override showing the toast
|
||||||
*/
|
*/
|
||||||
RequestQueue.prototype.displayToastMessage = function (msg) {
|
RequestQueue.prototype.displayToastMessage = function (msg, forceShow) {
|
||||||
if (!this.showToast) {
|
if (!this.showToast && !forceShow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
H5P.attachToastTo(
|
H5P.attachToastTo(
|
||||||
|
@ -228,4 +220,193 @@ H5P.RequestQueue = (function ($, EventDispatcher) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return RequestQueue;
|
return RequestQueue;
|
||||||
})(H5P.jQuery, H5P.EventDispatcher);
|
})(H5P.jQuery, H5P.EventDispatcher);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request queue for retrying failing requests, will automatically retry them when you come online
|
||||||
|
*
|
||||||
|
* @type {offlineRequestQueue}
|
||||||
|
*/
|
||||||
|
H5P.OfflineRequestQueue = (function (RequestQueue, Dialog) {
|
||||||
|
return function offlineRequestQueue() {
|
||||||
|
const requestQueue = new RequestQueue();
|
||||||
|
|
||||||
|
// We could handle requests from previous pages here, but instead we throw them away
|
||||||
|
requestQueue.clearQueue();
|
||||||
|
|
||||||
|
let startTime = null;
|
||||||
|
const retryIntervals = [10, 20, 40, 60, 120, 300, 600];
|
||||||
|
let intervalIndex = -1;
|
||||||
|
let currentInterval = null;
|
||||||
|
let isAttached = false;
|
||||||
|
let isShowing = false;
|
||||||
|
let isLoading = false;
|
||||||
|
|
||||||
|
const offlineDialog = new Dialog({
|
||||||
|
headerText: H5P.t('offlineDialogHeader'),
|
||||||
|
dialogText: H5P.t('offlineDialogBody'),
|
||||||
|
confirmText: H5P.t('offlineDialogRetryButtonLabel'),
|
||||||
|
hideCancel: true,
|
||||||
|
hideExit: true,
|
||||||
|
classes: ['offline'],
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const dialog = offlineDialog.getElement();
|
||||||
|
|
||||||
|
// Add retry text to body
|
||||||
|
const countDownText = document.createElement('div');
|
||||||
|
countDownText.classList.add('count-down');
|
||||||
|
countDownText.innerHTML = H5P.t('offlineDialogRetryMessage')
|
||||||
|
.replace(':num', '<span class="count-down-num">0</span>');
|
||||||
|
|
||||||
|
dialog.querySelector('.h5p-confirmation-dialog-text').appendChild(countDownText);
|
||||||
|
const countDownNum = countDownText.querySelector('.count-down-num');
|
||||||
|
|
||||||
|
// Create throbber
|
||||||
|
const throbberWrapper = document.createElement('div');
|
||||||
|
throbberWrapper.classList.add('throbber-wrapper');
|
||||||
|
const throbber = document.createElement('div');
|
||||||
|
throbber.classList.add('sending-requests-throbber');
|
||||||
|
throbberWrapper.appendChild(throbber);
|
||||||
|
|
||||||
|
requestQueue.on('requestQueued', function (e) {
|
||||||
|
// Already processing queue, wait until queue has finished processing before showing dialog
|
||||||
|
if (e.data && e.data.processingQueue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAttached) {
|
||||||
|
const rootContent = document.body.querySelector('.h5p-content');
|
||||||
|
if (!rootContent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
offlineDialog.appendTo(rootContent);
|
||||||
|
rootContent.appendChild(throbberWrapper);
|
||||||
|
isAttached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
startCountDown();
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
requestQueue.on('queueEmptied', function (e) {
|
||||||
|
if (e.data && e.data.length) {
|
||||||
|
// New requests were added while processing queue or requests failed again. Re-queue requests.
|
||||||
|
startCountDown(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully emptied queue
|
||||||
|
clearInterval(currentInterval);
|
||||||
|
toggleThrobber(false);
|
||||||
|
intervalIndex = -1;
|
||||||
|
if (isShowing) {
|
||||||
|
offlineDialog.hide();
|
||||||
|
isShowing = false;
|
||||||
|
}
|
||||||
|
requestQueue.displayToastMessage(H5P.t('offlineSuccessfulSubmit'), true);
|
||||||
|
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
offlineDialog.on('confirmed', function () {
|
||||||
|
// Show dialog on next render in case it is being hidden by the 'confirm' button
|
||||||
|
isShowing = false;
|
||||||
|
setTimeout(function () {
|
||||||
|
retryRequests();
|
||||||
|
}, 100);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle throbber visibility
|
||||||
|
*
|
||||||
|
* @param {boolean} [forceShow] Will force throbber visibility if set
|
||||||
|
*/
|
||||||
|
const toggleThrobber = function (forceShow) {
|
||||||
|
isLoading = !isLoading;
|
||||||
|
if (forceShow !== undefined) {
|
||||||
|
isLoading = forceShow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading && isShowing) {
|
||||||
|
offlineDialog.hide();
|
||||||
|
isShowing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
throbberWrapper.classList.add('show');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throbberWrapper.classList.remove('show');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retries the failed requests
|
||||||
|
*/
|
||||||
|
const retryRequests = function () {
|
||||||
|
clearInterval(currentInterval);
|
||||||
|
toggleThrobber(true);
|
||||||
|
requestQueue.resumeQueue();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments retry interval
|
||||||
|
*/
|
||||||
|
const incrementRetryInterval = function () {
|
||||||
|
intervalIndex += 1;
|
||||||
|
if (intervalIndex >= retryIntervals.length) {
|
||||||
|
intervalIndex = retryIntervals.length - 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts counting down to retrying queued requests.
|
||||||
|
*
|
||||||
|
* @param forceDelayedShow
|
||||||
|
*/
|
||||||
|
const startCountDown = function (forceDelayedShow) {
|
||||||
|
toggleThrobber(false);
|
||||||
|
if (!isShowing) {
|
||||||
|
if (forceDelayedShow) {
|
||||||
|
// Must force delayed show since dialog may be hiding, and confirmation dialog does not
|
||||||
|
// support this.
|
||||||
|
setTimeout(function () {
|
||||||
|
offlineDialog.show();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
offlineDialog.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isShowing = true;
|
||||||
|
startTime = new Date().getTime();
|
||||||
|
incrementRetryInterval();
|
||||||
|
currentInterval = setInterval(updateCountDown, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the count down timer. Retries requests when time expires.
|
||||||
|
*/
|
||||||
|
const updateCountDown = function () {
|
||||||
|
const time = new Date().getTime();
|
||||||
|
const timeElapsed = Math.floor((time - startTime) / 1000);
|
||||||
|
const timeLeft = retryIntervals[intervalIndex] - timeElapsed;
|
||||||
|
countDownNum.textContent = timeLeft.toString();
|
||||||
|
|
||||||
|
// Retry interval reached, retry requests
|
||||||
|
if (timeLeft <= 0) {
|
||||||
|
retryRequests();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add request to offline request queue. Only supports posts for now.
|
||||||
|
*
|
||||||
|
* @param {string} url The request url
|
||||||
|
* @param {Object} data The request data
|
||||||
|
*/
|
||||||
|
this.add = function (url, data) {
|
||||||
|
requestQueue.add(url, data);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})(H5P.RequestQueue, H5P.ConfirmationDialog);
|
|
@ -116,3 +116,66 @@ button.h5p-confirmation-dialog-exit:hover {
|
||||||
margin-top: -6px;
|
margin-top: -6px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h5p-confirmation-dialog-popup.offline .h5p-confirmation-dialog-buttons {
|
||||||
|
float: none;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h5p-confirmation-dialog-popup.offline .count-down {
|
||||||
|
font-family: Arial;
|
||||||
|
margin-top: 0.15em;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h5p-confirmation-dialog-popup.offline .h5p-confirmation-dialog-confirm-button:before {
|
||||||
|
content: "\e90b";
|
||||||
|
}
|
||||||
|
|
||||||
|
.throbber-wrapper {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
background: rgba(44, 44, 44, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.throbber-wrapper.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.throbber-wrapper .throbber-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.throbber-wrapper .sending-requests-throbber{
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.throbber-wrapper .sending-requests-throbber:before {
|
||||||
|
display: block;
|
||||||
|
font-family: 'H5P';
|
||||||
|
content: "\e90b";
|
||||||
|
color: white;
|
||||||
|
font-size: 10em;
|
||||||
|
animation: request-throbber 1.5s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes request-throbber {
|
||||||
|
from {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,11 +3,11 @@
|
||||||
/* Custom H5P font to use for icons. */
|
/* Custom H5P font to use for icons. */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'h5p';
|
font-family: 'h5p';
|
||||||
src: url('../fonts/h5p-core-20.eot?cb8kvi');
|
src: url('../fonts/h5p-core-21.eot?mz1lkp');
|
||||||
src: url('../fonts/h5p-core-20.eot?cb8kvi#iefix') format('embedded-opentype'),
|
src: url('../fonts/h5p-core-21.eot?mz1lkp#iefix') format('embedded-opentype'),
|
||||||
url('../fonts/h5p-core-20.ttf?cb8kvi') format('truetype'),
|
url('../fonts/h5p-core-21.ttf?mz1lkp') format('truetype'),
|
||||||
url('../fonts/h5p-core-20.woff?cb8kvi') format('woff'),
|
url('../fonts/h5p-core-21.woff?mz1lkp') format('woff'),
|
||||||
url('../fonts/h5p-core-20.svg?cb8kvi#h5p') format('svg');
|
url('../fonts/h5p-core-21.svg?mz1lkp#h5p') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue