This commit is contained in:
Xes
2025-08-14 22:39:38 +02:00
parent 3641e93527
commit 5403f346e3
3370 changed files with 327179 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
import H5P from 'imports-loader?H5PIntegration=>window.parent.H5PIntegration!H5P';
import 'H5PEventDispatcher';
import 'H5PxAPI';
import 'H5PxAPIEvent';
import 'H5PContentType';
import 'H5PConfirmationDialog';
import 'H5PRequestQueue';
import 'H5PActionBar';
H5P.getLibraryPath = function (library) {
if (H5PIntegration.pathIncludesVersion) {
return this.librariesPath + '/' + library;
}
return this.librariesPath + '/' + library.split('-')[0];
};
H5P.getPath = function (path, contentId) {
var hasProtocol = function (path) {
return path.match(/^[a-z0-9]+:\/\//i);
};
if (hasProtocol(path)) {
return path;
}
var prefix;
if (contentId !== undefined) {
prefix = H5PIntegration.url + '/content';
}
else if (window.H5PEditor !== undefined) {
prefix = H5PEditor.filesPath;
}
else {
return;
}
return prefix + '/' + path;
};

View File

@@ -0,0 +1,75 @@
const H5PIntegration = {};
H5PIntegration.l10n = {
H5P: {
"fullscreen": "Fullscreen",
"disableFullscreen": "Disable fullscreen",
"download": "Download",
"copyrights": "Rights of use",
"embed": "Embed",
"size": "Size",
"showAdvanced": "Show advanced",
"hideAdvanced": "Hide advanced",
"advancedHelp": "Include this script on your website if you want dynamic sizing of the embedded content:",
"copyrightInformation": "Rights of use",
"close": "Close",
"title": "Title",
"author": "Author",
"year": "Year",
"source": "Source",
"license": "License",
"thumbnail": "Thumbnail",
"noCopyrights": "No copyright information available for this content.",
"reuse": "Reuse",
"reuseContent": "Reuse Content",
"reuseDescription": "Reuse this content.",
"downloadDescription": "Download this content as a H5P file.",
"copyrightsDescription": "View copyright information for this content.",
"embedDescription": "View the embed code for this content.",
"h5pDescription": "Visit H5P.org to check out more cool content.",
"contentChanged": "This content has changed since you last used it.",
"startingOver": "You'll be starting over.",
"by": "by",
"showMore": "Show more",
"showLess": "Show less",
"subLevel": "Sublevel",
"confirmDialogHeader": "Confirm action",
"confirmDialogBody": "Please confirm that you wish to proceed. This action is not reversible.",
"cancelLabel": "Cancel",
"confirmLabel": "Confirm",
"licenseU": "Undisclosed",
"licenseCCBY": "Attribution",
"licenseCCBYSA": "Attribution-ShareAlike",
"licenseCCBYND": "Attribution-NoDerivs",
"licenseCCBYNC": "Attribution-NonCommercial",
"licenseCCBYNCSA": "Attribution-NonCommercial-ShareAlike",
"licenseCCBYNCND": "Attribution-NonCommercial-NoDerivs",
"licenseCC40": "4.0 International",
"licenseCC30": "3.0 Unported",
"licenseCC25": "2.5 Generic",
"licenseCC20": "2.0 Generic",
"licenseCC10": "1.0 Generic",
"licenseGPL": "General Public License",
"licenseV3": "Version 3",
"licenseV2": "Version 2",
"licenseV1": "Version 1",
"licensePD": "Public Domain",
"licenseCC010": "CC0 1.0 Universal (CC0 1.0) Public Domain Dedication",
"licensePDM": "Public Domain Mark",
"licenseC": "Copyright",
"contentType": "Content Type",
"licenseExtras": "License Extras",
"changes": "Changelog",
"contentCopied": "Content is copied to the clipboard",
"connectionLost": "Connection lost. Results will be stored and sent when you regain connection.",
"connectionReestablished": "Connection reestablished.",
"resubmitScores": "Attempting to submit stored results.",
"offlineDialogHeader": "Your connection to the server was lost",
"offlineDialogBody": "We were unable to send information about your completion of this task. Please check your internet connection.",
"offlineDialogRetryMessage": "Retrying in :num....",
"offlineDialogRetryButtonLabel": "Retry now",
"offlineSuccessfulSubmit": "Successfully submitted results."
}
};
window.H5PIntegration = H5PIntegration;

View File

@@ -0,0 +1,208 @@
import Toposort from 'toposort-class';
import H5P from 'imports-loader?H5PIntegration=>window.H5PIntegration!H5P';
H5PIntegration = window.H5PIntegration;
export default class H5PStandalone {
constructor(el, pathToContent = 'workspace', options = {}, displayOptions = {}, librariesPath = {}) {
this.id = options.id || Math.random().toString(36).substr(2, 9);
this.path = pathToContent;
if (librariesPath == {}) {
this.librariesPath = this.path;
} else {
this.librariesPath = librariesPath;
}
console.log('This.librariesPath = '+this.librariesPath);
this.initElement(el);
return this.initH5P(options.frameCss, options.frameJs, displayOptions, options.preventH5PInit);
}
initElement(el) {
if (!(el instanceof HTMLElement)) {
throw new Error('createH5P must be passed an element');
}
el.innerHTML = `<div class="h5p-iframe-wrapper" style="background-color:#DDD;">
<iframe id="h5p-iframe-${this.id}" class="h5p-iframe" data-content-id="${this.id}" style="width: 100%; height: 100%; border: none; display: block;" src="about:blank" frameBorder="0"></iframe>
</div>`;
}
async initH5P(frameCss = './styles/h5p.css', frameJs = './frame.bundle.js', displayOptions, preventH5PInit) {
this.h5p = await this.getJSON(`${this.path}/h5p.json`);
const content = await this.getJSON(`${this.path}/content/content.json`);
H5PIntegration.pathIncludesVersion = this.pathIncludesVersion = await this.checkIfPathIncludesVersion();
this.mainLibrary = await this.findMainLibrary();
const dependencies = await this.findAllDependencies();
const { styles, scripts } = this.sortDependencies(dependencies);
H5PIntegration.url = this.path;
H5PIntegration.contents = H5PIntegration.contents ? H5PIntegration.contents : {};
H5PIntegration.core = {
styles: [frameCss],
scripts: [frameJs]
};
H5PIntegration.contents[`cid-${this.id}`] = {
library: `${this.mainLibrary.machineName} ${this.mainLibrary.majorVersion}.${this.mainLibrary.minorVersion}`,
jsonContent: JSON.stringify(content),
styles: styles,
scripts: scripts,
displayOptions: displayOptions
};
// if (!preventH5PInit) {
H5P.init();
// }
}
getJSON(url) {
return fetch(url).then(res => res.json());
}
/**
* Check if the library folder include the version or not
* This was changed at some point in H5P and we need to be backwards compatible
*
* @return {boolean}
*/
async checkIfPathIncludesVersion() {
let dependency = this.h5p.preloadedDependencies[0];
let machinePath = dependency.machineName + "-" + dependency.majorVersion + "." + dependency.minorVersion;
let pathIncludesVersion;
try {
await this.getJSON(`${this.librariesPath}/${machinePath}/library.json`);
pathIncludesVersion = true;
} catch (e) {
pathIncludesVersion = false;
}
return pathIncludesVersion;
}
/**
* return the path to a library
* @param {object} library
* @return {string}
*/
libraryPath(library) {
return library.machineName + (this.pathIncludesVersion ? "-" + library.majorVersion + "." + library.minorVersion : '');
}
/**
* FInd the main library for this H5P
* @return {Promise}
*/
findMainLibrary() {
const mainLibraryInfo = this.h5p.preloadedDependencies.find(dep => dep.machineName === this.h5p.mainLibrary);
this.mainLibraryPath = this.h5p.mainLibrary + (this.pathIncludesVersion ? "-" + mainLibraryInfo.majorVersion + "." + mainLibraryInfo.minorVersion : '');
return this.getJSON(`${this.librariesPath}/${this.mainLibraryPath}/library.json`);
}
/**
* find all the libraries used in this H5P
* @return {Promise}
*/
findAllDependencies() {
const directDependencyNames = this.h5p.preloadedDependencies.map(dependency => this.libraryPath(dependency));
return this.loadDependencies(directDependencyNames, []);
}
/**
* searches through all supplied libraries for dependencies, this is recursive and repeats until all deep dependencies have been found
* @param {string[]} toFind list of libraries to find the dependencies of
* @param {string[]} alreadyFound the dependencies that have already been found
*/
async loadDependencies(toFind, alreadyFound) {
// console.log(`loading dependency level: ${dependencyDepth}`);
// dependencyDepth++;
let dependencies = alreadyFound;
let findNext = [];
let newDependencies = await Promise.all(toFind.map((libraryName) => this.findLibraryDependencies(libraryName)));
// loop over newly found libraries
newDependencies.forEach((library) => {
// push into found list
dependencies.push(library);
// check if any dependencies haven't been found yet
library.dependencies.forEach((dependency) => {
if (!dependencies.find((foundLibrary) => foundLibrary.libraryPath === dependency) && !newDependencies.find((foundLibrary) => foundLibrary.libraryPath === dependency)) {
findNext.push(dependency);
}
});
});
if (findNext.length > 0) {
return this.loadDependencies(findNext, dependencies);
}
return dependencies;
}
/**
* Loads a dependencies library.json and finds the libraries it dependson as well ass the JS and CSS it needs
* @param {string} libraryName
*/
async findLibraryDependencies(libraryName) {
const library = await this.getJSON(`${this.librariesPath}/${libraryName}/library.json`);
const libraryPath = this.libraryPath(library);
let dependencies = [];
if (library.preloadedDependencies) {
dependencies = library.preloadedDependencies.map(dependency => this.libraryPath(dependency));
}
return { libraryPath, dependencies, preloadedCss: library.preloadedCss, preloadedJs: library.preloadedJs };
}
/**
* Resolves the library dependency tree and sorts the JS and CSS files into order
* @param {object[]} dependencies
* @return {object}
*/
sortDependencies(dependencies) {
const dependencySorter = new Toposort();
let CSSDependencies = {};
let JSDependencies = {};
dependencies.forEach(dependency => {
dependencySorter.add(dependency.libraryPath, dependency.dependencies);
if (dependency.preloadedCss) {
CSSDependencies[dependency.libraryPath] = CSSDependencies[dependency.libraryPath] ? CSSDependencies[dependency.libraryPath] : [];
dependency.preloadedCss.forEach(style => {
CSSDependencies[dependency.libraryPath].push(`${this.librariesPath}/${dependency.libraryPath}/${style.path}`);
});
}
if (dependency.preloadedJs) {
JSDependencies[dependency.libraryPath] = JSDependencies[dependency.libraryPath] ? JSDependencies[dependency.libraryPath] : [];
dependency.preloadedJs.forEach(script => {
JSDependencies[dependency.libraryPath].push(`${this.librariesPath}/${dependency.libraryPath}/${script.path}`);
});
}
});
let styles = [];
let scripts = [];
dependencySorter.sort().reverse().forEach(function (dependencyName) {
Array.prototype.push.apply(styles, CSSDependencies[dependencyName]);
Array.prototype.push.apply(scripts, JSDependencies[dependencyName]);
});
if (this.mainLibrary.preloadedCss) {
Array.prototype.push.apply(styles, this.mainLibrary.preloadedCss.map(style => `${this.librariesPath}/${this.mainLibraryPath}/${style.path}`));
}
if (this.mainLibrary.preloadedJs) {
Array.prototype.push.apply(scripts, this.mainLibrary.preloadedJs.map(script => `${this.librariesPath}/${this.mainLibraryPath}/${script.path}`));
}
return { styles, scripts };
}
}

View File

@@ -0,0 +1,10 @@
import './h5p-integration';
import H5PStandalone from './h5p-standalone.class';
import 'H5PEventDispatcher';
import 'H5PxAPI';
import 'H5PxAPIEvent';
import 'H5PContentType';
window.H5P.preventInit = true;
export default { H5P: H5PStandalone };