Add functionality to store user state in localStorage

pull/81/head
otacke 2020-03-12 18:45:45 +01:00
parent 743147698f
commit a2849c8367
2 changed files with 88 additions and 2 deletions

View File

@ -1981,6 +1981,13 @@ abstract class H5PDisplayOptionBehaviour {
const CONTROLLED_BY_PERMISSIONS = 4; const CONTROLLED_BY_PERMISSIONS = 4;
} }
abstract class H5PSaveContentStorages {
const NONE = 0;
const DATABASE = 1;
const LOCALSTORAGE = 2;
const DATABASE_LOCALSTORAGE = 3;
}
abstract class H5PHubEndpoints { abstract class H5PHubEndpoints {
const CONTENT_TYPES = 'api.h5p.org/v1/content-types/'; const CONTENT_TYPES = 'api.h5p.org/v1/content-types/';
const SITES = 'api.h5p.org/v1/sites'; const SITES = 'api.h5p.org/v1/sites';

View File

@ -80,6 +80,16 @@ H5P.init = function (target) {
// Update: Seems to be no need as they've moved on to Webkit // Update: Seems to be no need as they've moved on to Webkit
} }
// Determine if we can use local storage
if (H5P.localStorageSupported === undefined) {
try {
H5P.localStorageSupported = (window.localStorage) ? true : false;
}
catch (error) {
H5P.localStorageSupported = false;
}
}
// Deprecated variable, kept to maintain backwards compatability // Deprecated variable, kept to maintain backwards compatability
if (H5P.canHasFullScreen === undefined) { if (H5P.canHasFullScreen === undefined) {
/** /**
@ -2319,7 +2329,7 @@ H5P.createTitle = function (rawTitle, maxLength) {
function contentUserDataAjax(contentId, dataType, subContentId, done, data, preload, invalidate, async) { function contentUserDataAjax(contentId, dataType, subContentId, done, data, preload, invalidate, async) {
if (H5PIntegration.user === undefined) { if (H5PIntegration.user === undefined) {
// Not logged in, no use in saving. // Not logged in, no use in saving.
done('Not signed in.'); done('Not signed in.'); // Return value used when storing state in localStorage
return; return;
} }
@ -2381,6 +2391,44 @@ H5P.createTitle = function (rawTitle, maxLength) {
H5PIntegration.contents = H5PIntegration.contents || {}; H5PIntegration.contents = H5PIntegration.contents || {};
var content = H5PIntegration.contents['cid-' + contentId] || {}; var content = H5PIntegration.contents['cid-' + contentId] || {};
var preloadedData = content.contentUserData; var preloadedData = content.contentUserData;
/*
* If previous state in DB is empty (user might not be logged in),
* alternatively try to preload state from localStorage
*/
if (preloadedData && preloadedData[subContentId] && preloadedData[subContentId][dataId] === '{}') {
if (H5PIntegration.saveContentStorages && H5PIntegration.saveContentStorages.localStorage && H5P.localStorageSupported) {
const localStorageData = window.localStorage.getItem('H5P-cid-' + contentId + '-sid-' + subContentId);
if (localStorageData) {
let data = {};
try {
data = JSON.parse(localStorageData);
}
catch (err) {
console.error('Unable to parse JSON from state in localStorage.', err);
}
if (data.state && data.checksum) {
// Detect whether content parameters changed meanwhile
if (data.checksum === H5P.getNumericalHash(content.jsonContent)) {
try {
data = JSON.stringify(data.state);
preloadedData[subContentId][dataId] = data;
}
catch (err) {
console.error('Unable to stringify JSON for state in localStorage.', err);
}
}
else {
// Content has been changed
preloadedData[subContentId][dataId] = 'RESET';
}
}
}
}
}
if (preloadedData && preloadedData[subContentId] && preloadedData[subContentId][dataId] !== undefined) { if (preloadedData && preloadedData[subContentId] && preloadedData[subContentId][dataId] !== undefined) {
if (preloadedData[subContentId][dataId] === 'RESET') { if (preloadedData[subContentId][dataId] === 'RESET') {
done(undefined, null); done(undefined, null);
@ -2486,6 +2534,18 @@ H5P.createTitle = function (rawTitle, maxLength) {
if (options.errorCallback && error) { if (options.errorCallback && error) {
options.errorCallback(error); options.errorCallback(error);
} }
// Additionally store state in localStorage if requested
if ((!error || error === 'Not signed in.') &&
H5PIntegration.saveContentStorages && H5PIntegration.saveContentStorages.localStorage && H5P.localStorageSupported
) {
// Add checksum of params to detect changes for resetting localStorage
window.localStorage.setItem(
'H5P-cid-' + contentId + '-sid-' + options.subContentId,
'{"checksum":' + H5P.getNumericalHash(content.jsonContent) + ',"state":' + data + '}'
);
}
}, data, options.preloaded, options.deleteOnChange, options.async); }, data, options.preloaded, options.deleteOnChange, options.async);
}; };
@ -2510,7 +2570,12 @@ H5P.createTitle = function (rawTitle, maxLength) {
delete preloadedData[subContentId][dataId]; delete preloadedData[subContentId][dataId];
} }
contentUserDataAjax(contentId, dataId, subContentId, undefined, null); contentUserDataAjax(contentId, dataId, subContentId, function (error) {
// When done deleting user data in DB, delete in localStorage
if ((!error || error === 'Not signed in.') && H5P.localStorageSupported) {
window.localStorage.removeItem('H5P-cid-' + contentId + '-sid-' + subContentId);
}
}, null);
}; };
/** /**
@ -2616,6 +2681,20 @@ H5P.createTitle = function (rawTitle, maxLength) {
H5P.externalDispatcher.trigger('datainclipboard', {reset: false}); H5P.externalDispatcher.trigger('datainclipboard', {reset: false});
}; };
/**
* Get numerical hash for a text.
*
* @param {string} text - Text to be hashed.
*/
H5P.getNumericalHash = function (text) {
text = text || '';
return text
.split('')
.reduce(function (result, current) {
return (((result << 5) - result) + current.charCodeAt(0)) | 0;
}, 0);
};
/** /**
* Get config for a library * Get config for a library
* *