Merge branch 'master' of ssh://stash.amendor.com:7999/h5p/h5p-core-php
commit
f60bc3939b
143
h5p.classes.php
143
h5p.classes.php
|
@ -219,6 +219,34 @@ interface H5PFrameworkInterface {
|
||||||
* Library Id
|
* Library Id
|
||||||
*/
|
*/
|
||||||
public function deleteLibraryDependencies($libraryId);
|
public function deleteLibraryDependencies($libraryId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the data we need to export H5P
|
||||||
|
*
|
||||||
|
* @param int $contentId
|
||||||
|
* ContentID of the node we are going to export
|
||||||
|
* @param string $title
|
||||||
|
* Title of the node to export
|
||||||
|
* @param string $language
|
||||||
|
* Language of the node to export
|
||||||
|
* @return array
|
||||||
|
* An array with all the data needed to export the h5p in the following format:
|
||||||
|
* 'title' => string,
|
||||||
|
* 'contentId' => string/int,
|
||||||
|
* 'mainLibrary' => string (machine name for main library),
|
||||||
|
* 'embedType' => string,
|
||||||
|
* 'libraries' => array(
|
||||||
|
* 'machineName' => string,
|
||||||
|
* 'majorVersion' => int,
|
||||||
|
* 'minorVersion' => int,
|
||||||
|
* 'preloaded' => int(0|1),
|
||||||
|
* 'language' => string,
|
||||||
|
*/
|
||||||
|
public function getExportData($contentId, $title, $language);
|
||||||
|
/**
|
||||||
|
* Check if export is enabled.
|
||||||
|
*/
|
||||||
|
public function isExportEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -244,7 +272,7 @@ class H5PValidator {
|
||||||
private $h5pOptional = array(
|
private $h5pOptional = array(
|
||||||
'contentType' => '/^.{1,255}$/',
|
'contentType' => '/^.{1,255}$/',
|
||||||
'author' => '/^.{1,255}$/',
|
'author' => '/^.{1,255}$/',
|
||||||
'license' => '/^(cc-by|cc-by-sa|cc-by-nd|cc-by-nc|cc-by-nc-sa|cc-by-nc-nd|pd|cr|MIT)$/',
|
'license' => '/^(cc-by|cc-by-sa|cc-by-nd|cc-by-nc|cc-by-nc-sa|cc-by-nc-nd|pd|cr|MIT|GPL1|GPL2|GPL3|MPL|MPL2)$/',
|
||||||
'dynamicDependencies' => array(
|
'dynamicDependencies' => array(
|
||||||
'machineName' => '/^[\w0-9\-\.]{1,255}$/i',
|
'machineName' => '/^[\w0-9\-\.]{1,255}$/i',
|
||||||
'majorVersion' => '/^[0-9]{1,5}$/',
|
'majorVersion' => '/^[0-9]{1,5}$/',
|
||||||
|
@ -268,7 +296,7 @@ class H5PValidator {
|
||||||
|
|
||||||
private $libraryOptional = array(
|
private $libraryOptional = array(
|
||||||
'author' => '/^.{1,255}$/',
|
'author' => '/^.{1,255}$/',
|
||||||
'license' => '/^(cc-by|cc-by-sa|cc-by-nd|cc-by-nc|cc-by-nc-sa|cc-by-nc-nd|pd|cr|MIT|GPL1|GPL2|GPL3)$/',
|
'license' => '/^(cc-by|cc-by-sa|cc-by-nd|cc-by-nc|cc-by-nc-sa|cc-by-nc-nd|pd|cr|MIT|GPL1|GPL2|GPL3|MPL|MPL2)$/',
|
||||||
'description' => '/^.{1,}$/',
|
'description' => '/^.{1,}$/',
|
||||||
'dynamicDependencies' => array(
|
'dynamicDependencies' => array(
|
||||||
'machineName' => '/^[\w0-9\-\.]{1,255}$/i',
|
'machineName' => '/^[\w0-9\-\.]{1,255}$/i',
|
||||||
|
@ -1003,6 +1031,110 @@ class H5PStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used for exporting zips
|
||||||
|
*/
|
||||||
|
Class H5PExport {
|
||||||
|
public $h5pF;
|
||||||
|
public $h5pC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the H5PExport
|
||||||
|
*
|
||||||
|
* @param object $H5PFramework
|
||||||
|
* The frameworks implementation of the H5PFrameworkInterface
|
||||||
|
* @param H5PCore
|
||||||
|
* Reference to an insance of H5PCore
|
||||||
|
*/
|
||||||
|
public function __construct($H5PFramework, $H5PCore) {
|
||||||
|
$this->h5pF = $H5PFramework;
|
||||||
|
$this->h5pC = $H5PCore;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create the H5P package
|
||||||
|
*
|
||||||
|
* @param object $exportData
|
||||||
|
* The data to be exported.
|
||||||
|
* @return H5P package.
|
||||||
|
*/
|
||||||
|
public function exportToZip($exportData) {
|
||||||
|
$h5pDir = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR;
|
||||||
|
$tempPath = $h5pDir . 'temp' . DIRECTORY_SEPARATOR . $exportData['contentId'];
|
||||||
|
$zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $exportData['contentId'] . '.h5p';
|
||||||
|
// Check if h5p-package already exists.
|
||||||
|
if (!file_exists($zipPath) == true) {
|
||||||
|
// Temp dir to put the h5p files in
|
||||||
|
@mkdir($tempPath);
|
||||||
|
$this->h5pC->copyTree($h5pDir . 'content' . DIRECTORY_SEPARATOR . $exportData['contentId'], $tempPath . DIRECTORY_SEPARATOR . 'content');
|
||||||
|
// Copies libraries to temp dir and create mention in h5p.json
|
||||||
|
foreach($exportData['libraries'] as $library) {
|
||||||
|
$source = $h5pDir . 'libraries' . DIRECTORY_SEPARATOR . $library['machineName'] . '-' . $library['majorVersion'] . '.' . $library['minorVersion'];
|
||||||
|
$destination = $tempPath . DIRECTORY_SEPARATOR . $library['machineName'];
|
||||||
|
$this->h5pC->copyTree($source, $destination);
|
||||||
|
|
||||||
|
// Set preloaded and dynamic dependencies
|
||||||
|
if ($library['preloaded']) {
|
||||||
|
$preloadedDependencies[] = array(
|
||||||
|
'machineName' => $library['machineName'],
|
||||||
|
'majorVersion' => $library['majorVersion'],
|
||||||
|
'minorVersion' => $library['minorVersion'],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$dynamicDependencies[] = array(
|
||||||
|
'machineName' => $library['machineName'],
|
||||||
|
'majorVersion' => $library['majorVersion'],
|
||||||
|
'minorVersion' => $library['minorVersion'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make embedTypes into an array
|
||||||
|
$embedTypes = explode(', ', $exportData['embedType']);
|
||||||
|
|
||||||
|
// Build h5p.json
|
||||||
|
$h5pJson = array (
|
||||||
|
'title' => $exportData['title'],
|
||||||
|
'language' => $exportData['language'],
|
||||||
|
'mainLibrary' => $exportData['mainLibrary'],
|
||||||
|
'embedTypes' => $embedTypes,
|
||||||
|
);
|
||||||
|
// Add preloaded and dynamic dependencies if they exist
|
||||||
|
if ($preloadedDependencies) { $h5pJson['preloadedDependencies'] = $preloadedDependencies; }
|
||||||
|
if ($dynamicDependencies) { $h5pJson['dynamicDependencies'] = $dynamicDependencies; }
|
||||||
|
|
||||||
|
// Save h5p.json
|
||||||
|
$results = print_r(json_encode($h5pJson), true);
|
||||||
|
file_put_contents($tempPath . DIRECTORY_SEPARATOR . 'h5p.json', $results);
|
||||||
|
|
||||||
|
// Create new zip instance.
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
$zip->open($zipPath, ZIPARCHIVE::CREATE);
|
||||||
|
|
||||||
|
// Get all files and folders in $tempPath
|
||||||
|
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tempPath . DIRECTORY_SEPARATOR));
|
||||||
|
// Add files to zip
|
||||||
|
foreach ($iterator as $key=>$value) {
|
||||||
|
$test = '.';
|
||||||
|
// Do not add the folders '.' and '..' to the zip. This will make zip invalid.
|
||||||
|
if (substr_compare($key, $test, -strlen($test), strlen($test)) !== 0) {
|
||||||
|
// Get files path in $tempPath
|
||||||
|
$filePath = explode($tempPath . DIRECTORY_SEPARATOR, $key);
|
||||||
|
// Add files to the zip with the intended file-structure
|
||||||
|
$zip->addFile($key, $filePath[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Close zip and remove temp dir
|
||||||
|
$zip->close();
|
||||||
|
@rmdir($tempPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set headers for automagic download!!
|
||||||
|
header('Content-Description: File Transfer');
|
||||||
|
header('Content-Type: application/zip');
|
||||||
|
header('Content-Disposition: attachment; filename="' . $exportData['title'] . '.h5p"');
|
||||||
|
readfile ($zipPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions and storage shared by the other H5P classes
|
* Functions and storage shared by the other H5P classes
|
||||||
*/
|
*/
|
||||||
|
@ -1225,6 +1357,9 @@ class H5PContentValidator {
|
||||||
if (in_array('ul', $tags) || in_array('ol', $tags) && ! in_array('li', $tags)) {
|
if (in_array('ul', $tags) || in_array('ol', $tags) && ! in_array('li', $tags)) {
|
||||||
$tags[] = 'li';
|
$tags[] = 'li';
|
||||||
}
|
}
|
||||||
|
if (in_array('del', $tags) || in_array('strike', $tags) && ! in_array('s', $tags)) {
|
||||||
|
$tags[] = 's';
|
||||||
|
}
|
||||||
// Strip invalid HTML tags.
|
// Strip invalid HTML tags.
|
||||||
$text = $this->filter_xss($text, $tags);
|
$text = $this->filter_xss($text, $tags);
|
||||||
}
|
}
|
||||||
|
@ -1240,7 +1375,9 @@ class H5PContentValidator {
|
||||||
|
|
||||||
// Check if string is according to optional regexp in semantics
|
// Check if string is according to optional regexp in semantics
|
||||||
if (isset($semantics->regexp)) {
|
if (isset($semantics->regexp)) {
|
||||||
$pattern = '|' . $semantics->regexp->pattern . '|';
|
// Note: '|' used as regexp fence, to allow / in actual patterns.
|
||||||
|
// But also escaping '|' found in patterns, so that is valid too.
|
||||||
|
$pattern = '|' . str_replace('|', '\\|', $semantics->regexp->pattern) . '|';
|
||||||
$pattern .= isset($semantics->regexp->modifiers) ? $semantics->regexp->modifiers : '';
|
$pattern .= isset($semantics->regexp->modifiers) ? $semantics->regexp->modifiers : '';
|
||||||
if (preg_match($pattern, $text) === 0) {
|
if (preg_match($pattern, $text) === 0) {
|
||||||
// Note: explicitly ignore return value FALSE, to avoid removing text
|
// Note: explicitly ignore return value FALSE, to avoid removing text
|
||||||
|
|
29
js/h5p.js
29
js/h5p.js
|
@ -1,7 +1,7 @@
|
||||||
var H5P = H5P || {};
|
var H5P = H5P || {};
|
||||||
|
|
||||||
// This needs to be determined before init is run.
|
// This needs to be determined before init is run.
|
||||||
H5P.isFramed = (window.parent !== window);
|
H5P.isFramed = (window.self !== window.top); // (window.parent !== window);
|
||||||
|
|
||||||
// Initialize H5P content
|
// Initialize H5P content
|
||||||
// Scans for ".h5p-content"
|
// Scans for ".h5p-content"
|
||||||
|
@ -62,36 +62,35 @@ H5P.init = function () {
|
||||||
H5P.fullScreen($el, obj);
|
H5P.fullScreen($el, obj);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// H5Ps living in iframes. Note: Fullscreen button will be added
|
// H5Ps living in iframes. Note: Fullscreen button will be added
|
||||||
// inside iFrame if relevant
|
// inside iFrame if relevant
|
||||||
var $h5pIframes = H5P.jQuery(".h5p-iframe");
|
var $h5pIframes = H5P.jQuery(".h5p-iframe");
|
||||||
|
if ($h5pIframes.length !== 0) {
|
||||||
$h5pIframes.each(function (idx, iframe) {
|
$h5pIframes.each(function (idx, iframe) {
|
||||||
var $iframe = H5P.jQuery(iframe),
|
var $iframe = H5P.jQuery(iframe),
|
||||||
contentId = $iframe.data('content-id'),
|
contentId = $iframe.data('content-id'),
|
||||||
mainLibrary = $iframe.data('class');
|
mainLibrary = $iframe.data('class');
|
||||||
|
|
||||||
// Get iFrame body, and reset it to contain only the normal H5P DIV.
|
iframe.contentDocument.open();
|
||||||
$iframe.contents().find('body')
|
iframe.contentDocument.write('<!doctype html><html><head>' + H5PIntegration.getHeadTags(contentId) + '</head><body><div class="h5p-content" data-class="' + mainLibrary + '" data-content-id="' + contentId + '"/></body></html>');
|
||||||
.html('<div class="h5p-content" data-class="' + mainLibrary + '" data-content-id="' + contentId + '"/>');
|
iframe.contentDocument.close();
|
||||||
|
|
||||||
// Add scripts required for this iFrame from settings
|
|
||||||
H5PIntegration.addFilesToIframe($iframe, contentId);
|
|
||||||
});
|
});
|
||||||
if ($h5pIframes.length > 0) {
|
|
||||||
// TODO: This seems very hacky... why can't we just use the resize event? What happens if we ain't done before the next interval starts?
|
// TODO: This seems very hacky... why can't we just use the resize event? What happens if we ain't done before the next interval starts?
|
||||||
setInterval(function h5pIframeResizer() {
|
setInterval(function () {
|
||||||
$h5pIframes.each(function (idx, iframe) {
|
$h5pIframes.each(function (idx, iframe) {
|
||||||
var contentHeight = iframe.contentDocument.body.offsetHeight;
|
var $iframe = H5P.jQuery(iframe);
|
||||||
var frameHeight = H5P.jQuery(iframe).innerHeight();
|
var contentHeight = $iframe.contents().height();
|
||||||
|
var frameHeight = $iframe.innerHeight();
|
||||||
|
|
||||||
if (frameHeight !== contentHeight) {
|
if (frameHeight !== contentHeight) {
|
||||||
H5P.resizeIframe(H5P.jQuery(iframe).data('content-id'), contentHeight);
|
H5P.resizeIframe($iframe.data('content-id'), contentHeight);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 250);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -429,7 +428,7 @@ if (String.prototype.trim === undefined) {
|
||||||
|
|
||||||
// Finally, we want to run init when document is ready. But not if we're
|
// Finally, we want to run init when document is ready. But not if we're
|
||||||
// in an iFrame. Then we wait for parent to start init().
|
// in an iFrame. Then we wait for parent to start init().
|
||||||
if (H5P.jQuery && !H5P.isFramed) {
|
if (H5P.jQuery) {
|
||||||
H5P.jQuery(document).ready(function () {
|
H5P.jQuery(document).ready(function () {
|
||||||
if (!H5P.initialized) {
|
if (!H5P.initialized) {
|
||||||
H5P.initialized = true;
|
H5P.initialized = true;
|
||||||
|
|
|
@ -60,7 +60,8 @@ div.h5p-semi-fullscreen {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.h5p-iframe-wrapper {
|
.h5p-iframe-wrapper {
|
||||||
width: auto; height: auto;
|
width: auto;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.h5p-fullscreen .h5p-iframe-wrapper,
|
.h5p-fullscreen .h5p-iframe-wrapper,
|
||||||
|
@ -91,6 +92,8 @@ div.h5p-semi-fullscreen {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
.h5p-iframe-wrapper.h5p-semi-fullscreen .buttons button:before {
|
.h5p-iframe-wrapper.h5p-semi-fullscreen .buttons button:before {
|
||||||
content: 'Exit ';
|
content: 'Exit ';
|
||||||
|
|
Loading…
Reference in New Issue