From 228915e93b0aad6c84942a1179a79d627eeb91cb Mon Sep 17 00:00:00 2001 From: Ernesto Serrano Date: Fri, 20 Jun 2025 13:36:01 +0100 Subject: [PATCH 01/12] Add initial H5P export support --- .../workarea/menus/navbar/items/navbarFile.js | 46 ++++++++++ .../exelearning/Command/ElpExportCommand.php | 3 +- .../Command/ElpExportH5pCommand.php | 15 ++++ src/Constants.php | 3 + .../Service/Api/OdeExportService.php | 11 +++ .../Service/Export/ExportH5PService.php | 89 +++++++++++++++++++ templates/workarea/menus/menuNavbar.html.twig | 1 + translations/messages.ca.xlf | 4 + translations/messages.en.xlf | 4 + translations/messages.eo.xlf | 4 + translations/messages.es.xlf | 4 + translations/messages.eu.xlf | 4 + translations/messages.gl.xlf | 4 + translations/messages.va.xlf | 4 + 14 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/Command/net/exelearning/Command/ElpExportH5pCommand.php create mode 100644 src/Service/net/exelearning/Service/Export/ExportH5PService.php diff --git a/public/app/workarea/menus/navbar/items/navbarFile.js b/public/app/workarea/menus/navbar/items/navbarFile.js index 07be5116c..9331245fc 100644 --- a/public/app/workarea/menus/navbar/items/navbarFile.js +++ b/public/app/workarea/menus/navbar/items/navbarFile.js @@ -46,6 +46,9 @@ export default class NavbarFile { this.exportEPUB3Button = this.menu.navbar.querySelector( '#navbar-button-export-epub3', ); + this.exportH5PButton = this.menu.navbar.querySelector( + '#navbar-button-export-h5p', + ); this.exportXmlPropertiesButton = this.menu.navbar.querySelector( '#navbar-button-export-xml-properties', ); @@ -79,6 +82,7 @@ export default class NavbarFile { this.setExportSCORM2004Event(); this.setExportIMSEvent(); this.setExportEPUB3Event(); + this.setExportH5PEvent(); this.setExportXmlPropertiesEvent(); this.setImportXmlPropertiesEvent(); this.setLeftPanelsTogglerEvents(); @@ -274,6 +278,13 @@ export default class NavbarFile { }); } + setExportH5PEvent() { + this.exportH5PButton.addEventListener('click', () => { + if (eXeLearning.app.project.checkOpenIdevice()) return; + this.exportH5PEvent(); + }); + } + /** * Download the project to ePub3 * File -> Export as -> Xml properties @@ -1086,6 +1097,41 @@ export default class NavbarFile { eXeLearning.app.interface.connectionTime.loadLasUpdatedInInterface(); } + async exportH5PEvent() { + let toastData = { + title: _('Export'), + body: _('Generating export files...'), + icon: 'downloading', + }; + let toast = eXeLearning.app.toasts.createToast(toastData); + let odeSessionId = eXeLearning.app.project.odeSession; + let response = await eXeLearning.app.api.getOdeExportDownload( + odeSessionId, + 'h5p', + ); + if (response['responseMessage'] == 'OK') { + this.downloadLink( + response['urlZipFile'], + response['exportProjectName'], + ); + toast.toastBody.innerHTML = _('The project has been exported.'); + } else { + toast.toastBody.innerHTML = _('An error occurred while exporting the project.'); + toast.toastBody.classList.add('error'); + eXeLearning.app.modals.alert.show({ + title: _('Error'), + body: response['responseMessage'] ? response['responseMessage'] : _('Unknown error.'), + contentId: 'error', + }); + } + + setTimeout(() => { + toast.remove(); + }, 1000); + + eXeLearning.app.interface.connectionTime.loadLasUpdatedInInterface(); + } + /** * Export the properties as xml and download it * diff --git a/src/Command/net/exelearning/Command/ElpExportCommand.php b/src/Command/net/exelearning/Command/ElpExportCommand.php index a40c1ce98..de9732c74 100644 --- a/src/Command/net/exelearning/Command/ElpExportCommand.php +++ b/src/Command/net/exelearning/Command/ElpExportCommand.php @@ -41,7 +41,7 @@ protected function configure(): void $this ->addArgument('input', InputArgument::REQUIRED, 'Input ELP file path (use "-" for stdin)') ->addArgument('output', InputArgument::REQUIRED, 'Output directory') - ->addArgument('format', InputArgument::OPTIONAL, 'Export format (elp, html5, html5-sp, scorm12, scorm2004, ims, epub3)', $this->defaultFormat) + ->addArgument('format', InputArgument::OPTIONAL, 'Export format (elp, html5, html5-sp, scorm12, scorm2004, ims, epub3, h5p)', $this->defaultFormat) ->addOption('debug', 'd', InputOption::VALUE_NONE, 'Enable debug mode') ->addOption('base-url', 'b', InputOption::VALUE_OPTIONAL, 'Base URL for links', false); } @@ -63,6 +63,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int Constants::EXPORT_TYPE_SCORM2004, Constants::EXPORT_TYPE_IMS, Constants::EXPORT_TYPE_EPUB3, + Constants::EXPORT_TYPE_H5P, ]; if (!in_array($format, $validFormats, true)) { diff --git a/src/Command/net/exelearning/Command/ElpExportH5pCommand.php b/src/Command/net/exelearning/Command/ElpExportH5pCommand.php new file mode 100644 index 000000000..abeb0468e --- /dev/null +++ b/src/Command/net/exelearning/Command/ElpExportH5pCommand.php @@ -0,0 +1,15 @@ +entityManager = $entityManager; @@ -86,6 +89,7 @@ public function __construct( $this->exportSCORM2004Service = $exportSCORM2004Service; $this->exportIMSService = $exportIMSService; $this->exportEPUB3Service = $exportEPUB3Service; + $this->exportH5PService = $exportH5PService; $this->slugger = $slugger; } @@ -306,6 +310,10 @@ public function export( $ext = Constants::FILE_EXTENSION_ZIP; $typeSuffix = Constants::SUFFIX_TYPE_IMS; break; + case Constants::EXPORT_TYPE_H5P: + $ext = Constants::FILE_EXTENSION_H5P; + $typeSuffix = Constants::SUFFIX_TYPE_H5P; + break; default: $ext = Constants::FILE_EXTENSION_ZIP; break; @@ -814,6 +822,9 @@ private function generateExportContentByExportType( case Constants::EXPORT_TYPE_EPUB3: $exportService = $this->exportEPUB3Service; break; + case Constants::EXPORT_TYPE_H5P: + $exportService = $this->exportH5PService; + break; case Constants::EXPORT_TYPE_HTML5_SP: $exportService = $this->exportHTML5SPService; break; diff --git a/src/Service/net/exelearning/Service/Export/ExportH5PService.php b/src/Service/net/exelearning/Service/Export/ExportH5PService.php new file mode 100644 index 000000000..4e58f0b17 --- /dev/null +++ b/src/Service/net/exelearning/Service/Export/ExportH5PService.php @@ -0,0 +1,89 @@ +exportType = Constants::EXPORT_TYPE_H5P; + $this->fileHelper = $fileHelper; + $this->currentOdeUsersService = $currentOdeUsersService; + $this->translator = $translator; + } + + public function generateExportFiles( + $user, + $odeSessionId, + $odeNavStructureSyncs, + $pagesFileData, + $odeProperties, + $libsResourcesPath, + $odeComponentsSyncCloneArray, + $idevicesMapping, + $idevicesByPage, + $idevicesTypesData, + $userPreferencesDtos, + $theme, + $elpFileName, + $resourcesPrefix, + $isPreview, + $translator, + ) { + $exportDirPath = $this->fileHelper->getOdeSessionUserTmpExportDir($odeSessionId, $user); + $contentDir = $exportDirPath.'content'.DIRECTORY_SEPARATOR; + if (!is_dir($contentDir)) { + mkdir($contentDir, 0775, true); + } + + $projectTitle = isset($odeProperties['pp_title']) ? $odeProperties['pp_title']->getValue() : 'eXeLearning project'; + $language = isset($odeProperties['pp_lang']) ? $odeProperties['pp_lang']->getValue() : 'en'; + + $html = ''; + foreach ($odeNavStructureSyncs as $page) { + $pageId = $page->getOdePageId(); + $pageData = $pagesFileData[$pageId]; + $html .= '

'.htmlspecialchars($pageData['name']).'

'; + foreach ($pageData['blocks'] as $block) { + foreach ($block['idevices'] as $idevice) { + if (!empty($idevice['htmlView'])) { + $html .= $idevice['htmlView']; + } + } + } + } + + $content = ['text' => $html]; + file_put_contents($contentDir.'content.json', json_encode($content, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + + $h5pJson = [ + 'title' => $projectTitle, + 'language' => $language, + 'mainLibrary' => 'H5P.Text', + 'embedTypes' => ['iframe'], + 'preloadedDependencies' => [ + [ + 'machineName' => 'H5P.Text', + 'majorVersion' => 1, + 'minorVersion' => 1, + ], + ], + ]; + file_put_contents($exportDirPath.'h5p.json', json_encode($h5pJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + + return true; + } +} diff --git a/templates/workarea/menus/menuNavbar.html.twig b/templates/workarea/menus/menuNavbar.html.twig index 255c05609..3ccca102c 100644 --- a/templates/workarea/menus/menuNavbar.html.twig +++ b/templates/workarea/menus/menuNavbar.html.twig @@ -33,6 +33,7 @@
  • {{ "SCORM 2004" | trans }}
  • {{ "IMS CP" | trans }}
  • {{ "ePub3" | trans }}
  • +
  • {{ "H5P" | trans }}
  • {#