Merge branch 'master' into contentupgrade
commit
b81b985d5b
|
@ -311,13 +311,7 @@ class H5PDefaultStorage implements \H5PFileStorage {
|
|||
// Add filename to path
|
||||
$path .= '/' . $file->getName();
|
||||
|
||||
$fileData = $file->getData();
|
||||
if ($fileData) {
|
||||
file_put_contents($path, $fileData);
|
||||
}
|
||||
else {
|
||||
copy($_FILES['file']['tmp_name'], $path);
|
||||
}
|
||||
copy($_FILES['file']['tmp_name'], $path);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
@ -464,6 +458,24 @@ class H5PDefaultStorage implements \H5PFileStorage {
|
|||
return file_exists($filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if upgrades script exist for library.
|
||||
*
|
||||
* @param string $machineName
|
||||
* @param int $majorVersion
|
||||
* @param int $minorVersion
|
||||
* @return string Relative path
|
||||
*/
|
||||
public function getUpgradeScript($machineName, $majorVersion, $minorVersion) {
|
||||
$upgrades = "/libraries/{$machineName}-{$majorVersion}.{$minorVersion}/upgrades.js";
|
||||
if (file_exists($this->path . $upgrades)) {
|
||||
return $upgrades;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive function for copying directories.
|
||||
*
|
||||
|
|
|
@ -84,13 +84,19 @@ class H5PDevelopment {
|
|||
|
||||
// TODO: Validate props? Not really needed, is it? this is a dev site.
|
||||
|
||||
// Save/update library.
|
||||
$library['libraryId'] = $this->h5pF->getLibraryId($library['machineName'], $library['majorVersion'], $library['minorVersion']);
|
||||
if (!isset($library['metadata'])) {
|
||||
$library['metadata'] = 0;
|
||||
}
|
||||
|
||||
// Convert metadataSettings values to boolean & json_encode it before saving
|
||||
$library['metadataSettings'] = isset($library['metadataSettings']) ?
|
||||
H5PMetadata::boolifyAndEncodeSettings($library['metadataSettings']) :
|
||||
NULL;
|
||||
|
||||
// Save/update library.
|
||||
$this->h5pF->saveLibraryData($library, $library['libraryId'] === FALSE);
|
||||
|
||||
// Need to decode it again, since it is served from here.
|
||||
$library['metadataSettings'] = json_decode($library['metadataSettings']);
|
||||
|
||||
$library['path'] = 'development/' . $contents[$i];
|
||||
$this->libraries[H5PDevelopment::libraryToString($library['machineName'], $library['majorVersion'], $library['minorVersion'])] = $library;
|
||||
}
|
||||
|
|
|
@ -199,4 +199,14 @@ interface H5PFileStorage {
|
|||
* @return bool
|
||||
*/
|
||||
public function hasPresave($libraryName, $developmentPath = null);
|
||||
|
||||
/**
|
||||
* Check if upgrades script exist for library.
|
||||
*
|
||||
* @param string $machineName
|
||||
* @param int $majorVersion
|
||||
* @param int $minorVersion
|
||||
* @return string Relative path
|
||||
*/
|
||||
public function getUpgradeScript($machineName, $majorVersion, $minorVersion);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
abstract class H5PMetadata {
|
||||
|
||||
const FIELDS = array(
|
||||
private static $fields = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'maxLength' => 255
|
||||
|
@ -64,54 +64,83 @@ abstract class H5PMetadata {
|
|||
',"authorComments":' . (isset($content->author_comments) ? json_encode($content->author_comments) : 'null') . '}';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make the metadata into an associative array keyed by the property names
|
||||
* @param mixed $metadata Array or object containing metadata
|
||||
* @param bool $include_title
|
||||
* @param bool $include_missing For metadata fields not being set, skip 'em.
|
||||
* Relevant for content upgrade
|
||||
* @param array $types
|
||||
* @return array
|
||||
*/
|
||||
public static function toDBArray($metadata, $include_title = true, &$types = array()) {
|
||||
public static function toDBArray($metadata, $include_title = true, $include_missing = true, &$types = array()) {
|
||||
$fields = array();
|
||||
|
||||
if (!is_array($metadata)) {
|
||||
$metadata = (array) $metadata;
|
||||
}
|
||||
|
||||
foreach (self::FIELDS as $key => $config) {
|
||||
foreach (self::$fields as $key => $config) {
|
||||
|
||||
// Ignore title?
|
||||
if ($key === 'title' && !$include_title) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($metadata[$key])) {
|
||||
$value = $metadata[$key];
|
||||
$db_field_name = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $key));
|
||||
$exists = array_key_exists($key, $metadata);
|
||||
|
||||
switch ($config['type']) {
|
||||
case 'text':
|
||||
if (strlen($value) > $config['maxLength']) {
|
||||
$value = mb_substr($value, 0, $config['maxLength']);
|
||||
}
|
||||
$types[] = '%s';
|
||||
break;
|
||||
|
||||
case 'int':
|
||||
$value = ($value !== null) ? intval($value): null;
|
||||
$types[] = '%i';
|
||||
break;
|
||||
|
||||
case 'json':
|
||||
$value = json_encode($value);
|
||||
$types[] = '%s';
|
||||
break;
|
||||
}
|
||||
|
||||
$fields[$db_field_name] = $value;
|
||||
// Don't include missing fields
|
||||
if (!$include_missing && !$exists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $exists ? $metadata[$key] : null;
|
||||
|
||||
// lowerCamelCase to snake_case
|
||||
$db_field_name = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $key));
|
||||
|
||||
switch ($config['type']) {
|
||||
case 'text':
|
||||
if ($value !== null && strlen($value) > $config['maxLength']) {
|
||||
$value = mb_substr($value, 0, $config['maxLength']);
|
||||
}
|
||||
$types[] = '%s';
|
||||
break;
|
||||
|
||||
case 'int':
|
||||
$value = ($value !== null) ? intval($value) : null;
|
||||
$types[] = '%d';
|
||||
break;
|
||||
|
||||
case 'json':
|
||||
$value = ($value !== null) ? json_encode($value) : null;
|
||||
$types[] = '%s';
|
||||
break;
|
||||
}
|
||||
|
||||
$fields[$db_field_name] = $value;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* The metadataSettings field in libraryJson uses 1 for true and 0 for false.
|
||||
* Here we are converting these to booleans, and also doing JSON encoding.
|
||||
* This is invoked before the library data is beeing inserted/updated to DB.
|
||||
*
|
||||
* @param array $metadataSettings
|
||||
* @return string
|
||||
*/
|
||||
public static function boolifyAndEncodeSettings($metadataSettings) {
|
||||
// Convert metadataSettings values to boolean
|
||||
if (isset($metadataSettings['disable'])) {
|
||||
$metadataSettings['disable'] = $metadataSettings['disable'] === 1;
|
||||
}
|
||||
if (isset($metadataSettings['disableExtraTitleField'])) {
|
||||
$metadataSettings['disableExtraTitleField'] = $metadataSettings['disableExtraTitleField'] === 1;
|
||||
}
|
||||
|
||||
return json_encode($metadataSettings);
|
||||
}
|
||||
}
|
||||
|
|
114
h5p.classes.php
114
h5p.classes.php
|
@ -210,7 +210,9 @@ interface H5PFrameworkInterface {
|
|||
* - minorVersion: The library's minorVersion
|
||||
* - patchVersion: The library's patchVersion
|
||||
* - runnable: 1 if the library is a content type, 0 otherwise
|
||||
* - metadata: 1 if the library should support setting metadata (copyright etc)
|
||||
* - metadataSettings: Associative array containing:
|
||||
* - disable: 1 if the library should not support setting metadata (copyright etc)
|
||||
* - disableExtraTitleField: 1 if the library don't need the extra title field
|
||||
* - fullscreen(optional): 1 if the library supports fullscreen, 0 otherwise
|
||||
* - embedTypes(optional): list of supported embed types
|
||||
* - preloadedJs(optional): list of associative arrays containing:
|
||||
|
@ -535,9 +537,10 @@ interface H5PFrameworkInterface {
|
|||
* Get number of contents using library as main library.
|
||||
*
|
||||
* @param int $libraryId
|
||||
* @param array $skip
|
||||
* @return int
|
||||
*/
|
||||
public function getNumContent($libraryId);
|
||||
public function getNumContent($libraryId, $skip = NULL);
|
||||
|
||||
/**
|
||||
* Determines if content slug is used.
|
||||
|
@ -612,6 +615,14 @@ interface H5PFrameworkInterface {
|
|||
* containing the new content type cache that should replace the old one.
|
||||
*/
|
||||
public function replaceContentTypeCache($contentTypeCache);
|
||||
|
||||
/**
|
||||
* Checks if the given library has a higher version.
|
||||
*
|
||||
* @param array $library
|
||||
* @return boolean
|
||||
*/
|
||||
public function libraryHasUpgrade($library);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -648,7 +659,7 @@ class H5PValidator {
|
|||
'role' => '/^\w+$/',
|
||||
),
|
||||
'source' => '/^(http[s]?:\/\/.+)$/',
|
||||
'license' => '/^(CC BY|CC BY-SA|CC BY-ND|CC BY-NC|CC BY-NC-SA|CC BY-NC-ND|CC0 1\.0|GNU GPL|PD|ODC PDDL|CC PDM|U|C|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)$/',
|
||||
'license' => '/^(CC BY|CC BY-SA|CC BY-ND|CC BY-NC|CC BY-NC-SA|CC BY-NC-ND|CC0 1\.0|GNU GPL|PD|ODC PDDL|CC PDM|U|C)$/',
|
||||
'licenseVersion' => '/^(1\.0|2\.0|2\.5|3\.0|4\.0)$/',
|
||||
'licenseExtras' => '/^.{1,5000}$/',
|
||||
'yearsFrom' => '/^([0-9]{1,4})$/',
|
||||
|
@ -681,7 +692,10 @@ class H5PValidator {
|
|||
'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|MPL|MPL2)$/',
|
||||
'description' => '/^.{1,}$/',
|
||||
'metadata' => '/^(0|1)$/',
|
||||
'metadataSettings' => array(
|
||||
'disable' => '/^(0|1)$/',
|
||||
'disableExtraTitleField' => '/^(0|1)$/'
|
||||
),
|
||||
'dynamicDependencies' => array(
|
||||
'machineName' => '/^[\w0-9\-\.]{1,255}$/i',
|
||||
'majorVersion' => '/^[0-9]{1,5}$/',
|
||||
|
@ -914,11 +928,27 @@ class H5PValidator {
|
|||
}
|
||||
|
||||
if (!empty($missingLibraries)) {
|
||||
foreach ($missingLibraries as $libString => $library) {
|
||||
$this->h5pF->setErrorMessage($this->h5pF->t('Missing required library @library', array('@library' => $libString)), 'missing-required-library');
|
||||
// We still have missing libraries, check if our main library has an upgrade (BUT only if we has content)
|
||||
$mainDependency = NULL;
|
||||
if (!$skipContent && !empty($mainH5PData)) {
|
||||
foreach ($mainH5PData['preloadedDependencies'] as $dep) {
|
||||
if ($dep['machineName'] === $mainH5PData['mainLibrary']) {
|
||||
$mainDependency = $dep;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$this->h5pC->mayUpdateLibraries()) {
|
||||
$this->h5pF->setInfoMessage($this->h5pF->t("Note that the libraries may exist in the file you uploaded, but you're not allowed to upload new libraries. Contact the site administrator about this."));
|
||||
|
||||
if ($skipContent || !$mainDependency || !$this->h5pF->libraryHasUpgrade(array(
|
||||
'machineName' => $mainDependency['mainLibrary'],
|
||||
'majorVersion' => $mainDependency['majorVersion'],
|
||||
'minorVersion' => $mainDependency['minorVersion']
|
||||
))) {
|
||||
foreach ($missingLibraries as $libString => $library) {
|
||||
$this->h5pF->setErrorMessage($this->h5pF->t('Missing required library @library', array('@library' => $libString)), 'missing-required-library');
|
||||
}
|
||||
if (!$this->h5pC->mayUpdateLibraries()) {
|
||||
$this->h5pF->setInfoMessage($this->h5pF->t("Note that the libraries may exist in the file you uploaded, but you're not allowed to upload new libraries. Contact the site administrator about this."));
|
||||
}
|
||||
}
|
||||
}
|
||||
$valid = empty($missingLibraries) && $valid;
|
||||
|
@ -1440,10 +1470,11 @@ class H5PStorage {
|
|||
// Indicate that the dependencies of this library should be saved.
|
||||
$library['saveDependencies'] = TRUE;
|
||||
|
||||
// Save library meta data
|
||||
if (!isset($library['metadata'])) {
|
||||
$library['metadata'] = 0;
|
||||
}
|
||||
// Convert metadataSettings values to boolean & json_encode it before saving
|
||||
$library['metadataSettings'] = isset($library['metadataSettings']) ?
|
||||
H5PMetadata::boolifyAndEncodeSettings($library['metadataSettings']) :
|
||||
NULL;
|
||||
|
||||
$this->h5pF->saveLibraryData($library, $new);
|
||||
|
||||
// Save library folder
|
||||
|
@ -1592,6 +1623,16 @@ Class H5PExport {
|
|||
$this->h5pC = $H5PCore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the replace pattern used by the text editor
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
private static function revertH5PEditorTextEscape($value) {
|
||||
return str_replace('<', '<', str_replace('>', '>', str_replace(''', "'", str_replace('"', '"', $value))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return path to h5p package.
|
||||
*
|
||||
|
@ -1624,14 +1665,14 @@ Class H5PExport {
|
|||
|
||||
// Build h5p.json, the en-/de-coding will ensure proper escaping
|
||||
$h5pJson = array (
|
||||
'title' => $content['title'],
|
||||
'title' => self::revertH5PEditorTextEscape($content['title']),
|
||||
'language' => (isset($content['language']) && strlen(trim($content['language'])) !== 0) ? $content['language'] : 'und',
|
||||
'mainLibrary' => $content['library']['name'],
|
||||
'embedTypes' => $embedTypes
|
||||
);
|
||||
|
||||
foreach(array('authors', 'source', 'license', 'licenseVersion', 'licenseExtras' ,'yearFrom', 'yearTo', 'changes', 'authorComments') as $field) {
|
||||
if (isset($content['metadata'][$field])) {
|
||||
if (isset($content['metadata'][$field]) && $content['metadata'][$field] !== '') {
|
||||
if (($field !== 'authors' && $field !== 'changes') || (count($content['metadata'][$field]) > 0)) {
|
||||
$h5pJson[$field] = json_decode(json_encode($content['metadata'][$field], TRUE));
|
||||
}
|
||||
|
@ -1826,7 +1867,7 @@ class H5PCore {
|
|||
|
||||
public static $coreApi = array(
|
||||
'majorVersion' => 1,
|
||||
'minorVersion' => 19
|
||||
'minorVersion' => 20
|
||||
);
|
||||
public static $styles = array(
|
||||
'styles/h5p.css',
|
||||
|
@ -1848,7 +1889,7 @@ class H5PCore {
|
|||
'js/h5p-utils.js',
|
||||
);
|
||||
|
||||
public static $defaultContentWhitelist = 'json png jpg jpeg gif bmp tif tiff svg eot ttf woff woff2 otf webm mp4 ogg mp3 wav txt pdf rtf doc docx xls xlsx ppt pptx odt ods odp xml csv diff patch swf md textile vtt webvtt';
|
||||
public static $defaultContentWhitelist = 'json png jpg jpeg gif bmp tif tiff svg eot ttf woff woff2 otf webm mp4 ogg mp3 m4a wav txt pdf rtf doc docx xls xlsx ppt pptx odt ods odp xml csv diff patch swf md textile vtt webvtt';
|
||||
public static $defaultLibraryWhitelistExtras = 'js css';
|
||||
|
||||
public $librariesJsonData, $contentJsonData, $mainJsonData, $h5pF, $fs, $h5pD, $disableFileCheck;
|
||||
|
@ -1906,8 +1947,6 @@ class H5PCore {
|
|||
$this->relativePathRegExp = '/^((\.\.\/){1,2})(.*content\/)?(\d+|editor)\/(.+)$/';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Save content and clear cache.
|
||||
*
|
||||
|
@ -1941,7 +1980,7 @@ class H5PCore {
|
|||
if ($content !== NULL) {
|
||||
// Validate main content's metadata
|
||||
$validator = new H5PContentValidator($this->h5pF, $this);
|
||||
$validator->validateMetadata($content['metadata']);
|
||||
$content['metadata'] = $validator->validateMetadata($content['metadata']);
|
||||
|
||||
$content['library'] = array(
|
||||
'id' => $content['libraryId'],
|
||||
|
@ -1984,6 +2023,10 @@ class H5PCore {
|
|||
return $content['filtered'];
|
||||
}
|
||||
|
||||
if (!(isset($content['library']) && isset($content['params']))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Validate and filter against main library semantics.
|
||||
$validator = new H5PContentValidator($this->h5pF, $this);
|
||||
$params = (object) array(
|
||||
|
@ -3301,7 +3344,10 @@ class H5PCore {
|
|||
'licensePD' => $this->h5pF->t('Public Domain'),
|
||||
'licenseCC010' => $this->h5pF->t('CC0 1.0 Universal (CC0 1.0) Public Domain Dedication'),
|
||||
'licensePDM' => $this->h5pF->t('Public Domain Mark'),
|
||||
'licenseC' => $this->h5pF->t('Copyright')
|
||||
'licenseC' => $this->h5pF->t('Copyright'),
|
||||
'contentType' => $this->h5pF->t('Content Type'),
|
||||
'licenseExtras' => $this->h5pF->t('License Extras'),
|
||||
'changes' => $this->h5pF->t('Changelog'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3375,15 +3421,24 @@ class H5PContentValidator {
|
|||
* Validate metadata
|
||||
*
|
||||
* @param array $metadata
|
||||
* @return array Validated & filtered
|
||||
*/
|
||||
public function validateMetadata(&$metadata) {
|
||||
public function validateMetadata($metadata) {
|
||||
$semantics = $this->getMetadataSemantics();
|
||||
|
||||
$group = (object)$metadata;
|
||||
|
||||
// Stop complaining about "invalid selected option in select" for
|
||||
// old content without license chosen.
|
||||
if (!isset($group->license)) {
|
||||
$group->license = 'U';
|
||||
}
|
||||
|
||||
$this->validateGroup($group, (object) array(
|
||||
'type' => 'group',
|
||||
'fields' => $semantics,
|
||||
), FALSE);
|
||||
|
||||
return (array)$group;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3910,7 +3965,7 @@ class H5PContentValidator {
|
|||
|
||||
// Validate subcontent's metadata
|
||||
if (isset($value->metadata)) {
|
||||
$this->validateMetadata($value->metadata);
|
||||
$value->metadata = $this->validateMetadata($value->metadata);
|
||||
}
|
||||
|
||||
$validKeys = array('library', 'params', 'subContentId', 'metadata');
|
||||
|
@ -4330,7 +4385,7 @@ class H5PContentValidator {
|
|||
(object) array(
|
||||
'type' => 'optgroup',
|
||||
'label' => $this->h5pF->t('Creative Commons'),
|
||||
'options' => [
|
||||
'options' => array(
|
||||
(object) array(
|
||||
'value' => 'CC BY',
|
||||
'label' => $this->h5pF->t('Attribution (CC BY)'),
|
||||
|
@ -4369,7 +4424,7 @@ class H5PContentValidator {
|
|||
'value' => 'CC PDM',
|
||||
'label' => $this->h5pF->t('Public Domain Mark (PDM)')
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
(object) array(
|
||||
'value' => 'GNU GPL',
|
||||
|
@ -4475,7 +4530,7 @@ class H5PContentValidator {
|
|||
'field' => (object) array(
|
||||
'name' => 'change',
|
||||
'type' => 'group',
|
||||
'label' => $this->h5pF->t('Change Log'),
|
||||
'label' => $this->h5pF->t('Changelog'),
|
||||
'fields' => array(
|
||||
(object) array(
|
||||
'name' => 'date',
|
||||
|
@ -4507,7 +4562,12 @@ class H5PContentValidator {
|
|||
'label' => $this->h5pF->t('Author comments'),
|
||||
'description' => $this->h5pF->t('Comments for the editor of the content (This text will not be published as a part of copyright info)'),
|
||||
'optional' => TRUE
|
||||
)
|
||||
),
|
||||
(object) array(
|
||||
'name' => 'contentType',
|
||||
'type' => 'text',
|
||||
'widget' => 'none'
|
||||
),
|
||||
);
|
||||
|
||||
return $semantics;
|
||||
|
|
|
@ -351,7 +351,7 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
|||
*
|
||||
* @param {number|null} minHeight
|
||||
*/
|
||||
this.setViewPortMinimumHeight = function(minHeight) {
|
||||
this.setViewPortMinimumHeight = function (minHeight) {
|
||||
var container = document.querySelector('.h5p-container') || document.body;
|
||||
container.style.minHeight = (typeof minHeight === 'number') ? (minHeight + 'px') : minHeight;
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* @class
|
||||
* @augments H5P.EventDispatcher
|
||||
*/
|
||||
H5P.ContentType = function (isRootLibrary, library) {
|
||||
H5P.ContentType = function (isRootLibrary) {
|
||||
|
||||
function ContentType() {}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
|||
self.loadLibrary = loadLibrary;
|
||||
self.upgrade(name, oldVersion, newVersion, params.params, params.metadata, function (err, upgradedParams, upgradedMetadata) {
|
||||
if (err) {
|
||||
err.id = id;
|
||||
return done(err);
|
||||
}
|
||||
|
||||
|
@ -53,6 +54,12 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
|||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
if (library.semantics === null) {
|
||||
return done({
|
||||
type: 'libraryMissing',
|
||||
library: library.name + ' ' + library.version.major + '.' + library.version.minor
|
||||
});
|
||||
}
|
||||
|
||||
// Run upgrade routines on params
|
||||
self.processParams(library, oldVersion, newVersion, params, metadata, function (err, params, metadata) {
|
||||
|
@ -127,10 +134,10 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
|||
}, {metadata: metadata});
|
||||
}
|
||||
catch (err) {
|
||||
if (console && console.log) {
|
||||
console.log("Error", err.stack);
|
||||
console.log("Error", err.name);
|
||||
console.log("Error", err.message);
|
||||
if (console && console.error) {
|
||||
console.error("Error", err.stack);
|
||||
console.error("Error", err.name);
|
||||
console.error("Error", err.message);
|
||||
}
|
||||
next(err);
|
||||
}
|
||||
|
@ -176,7 +183,11 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
|||
var usedVer = new Version(usedLib[1]);
|
||||
var availableVer = new Version(availableLib[1]);
|
||||
if (usedVer.major > availableVer.major || (usedVer.major === availableVer.major && usedVer.minor >= availableVer.minor)) {
|
||||
return done(); // Larger or same version that's available
|
||||
return done({
|
||||
type: 'errorTooHighVersion',
|
||||
used: usedLib[0] + ' ' + usedVer,
|
||||
supported: availableLib[0] + ' ' + availableVer
|
||||
}); // Larger or same version that's available
|
||||
}
|
||||
|
||||
// A newer version is available, upgrade params
|
||||
|
@ -192,7 +203,12 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
|||
});
|
||||
}
|
||||
}
|
||||
done();
|
||||
|
||||
// Content type was not supporte by the higher version
|
||||
done({
|
||||
type: 'errorNotSupported',
|
||||
used: usedLib[0] + ' ' + usedVer
|
||||
});
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* global importScripts */
|
||||
var H5P = H5P || {};
|
||||
importScripts('h5p-version.js', 'h5p-content-upgrade-process.js');
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*jshint -W083 */
|
||||
/* global H5PAdminIntegration H5PUtils */
|
||||
|
||||
(function ($, Version, EventDispatcher) {
|
||||
var info, $container, librariesCache = {}, scriptsCache = {};
|
||||
var info, $log, $container, librariesCache = {}, scriptsCache = {};
|
||||
|
||||
// Initialize
|
||||
$(document).ready(function () {
|
||||
|
@ -9,7 +9,9 @@
|
|||
info = H5PAdminIntegration.libraryInfo;
|
||||
|
||||
// Get and reset container
|
||||
$container = $('#h5p-admin-container').html('<p>' + info.message + '</p>');
|
||||
const $wrapper = $('#h5p-admin-container').html('');
|
||||
$log = $('<ul class="content-upgrade-log"></ul>').appendTo($wrapper);
|
||||
$container = $('<div><p>' + info.message + '</p></div>').appendTo($wrapper);
|
||||
|
||||
// Make it possible to select version
|
||||
var $version = $(getVersionSelect(info.versions)).appendTo($container);
|
||||
|
@ -132,9 +134,7 @@
|
|||
},
|
||||
error: function (error) {
|
||||
self.printError(error.err);
|
||||
|
||||
// Stop everything
|
||||
self.terminate();
|
||||
self.workDone(error.id, null, this);
|
||||
},
|
||||
loadLibrary: function (details) {
|
||||
var worker = this;
|
||||
|
@ -196,7 +196,7 @@
|
|||
self.token = inData.token;
|
||||
|
||||
// Start processing
|
||||
self.processBatch(inData.params);
|
||||
self.processBatch(inData.params, inData.skipped);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -217,11 +217,12 @@
|
|||
*
|
||||
* @param {Object} parameters
|
||||
*/
|
||||
ContentUpgrade.prototype.processBatch = function (parameters) {
|
||||
ContentUpgrade.prototype.processBatch = function (parameters, skipped) {
|
||||
var self = this;
|
||||
|
||||
// Track upgraded params
|
||||
self.upgraded = {};
|
||||
self.skipped = skipped;
|
||||
|
||||
// Track current batch
|
||||
self.parameters = parameters;
|
||||
|
@ -300,7 +301,7 @@
|
|||
}, function done(err, result) {
|
||||
if (err) {
|
||||
self.printError(err);
|
||||
return ;
|
||||
result = null;
|
||||
}
|
||||
|
||||
self.workDone(id, result);
|
||||
|
@ -315,7 +316,12 @@
|
|||
var self = this;
|
||||
|
||||
self.working--;
|
||||
self.upgraded[id] = result;
|
||||
if (result === null) {
|
||||
self.skipped.push(id);
|
||||
}
|
||||
else {
|
||||
self.upgraded[id] = result;
|
||||
}
|
||||
|
||||
// Update progress message
|
||||
var percentComplete = Math.round((info.total - self.left + self.current) / (info.total / 100));
|
||||
|
@ -333,6 +339,7 @@
|
|||
self.nextBatch({
|
||||
libraryId: self.version.libraryId,
|
||||
token: self.token,
|
||||
skipped: JSON.stringify(self.skipped),
|
||||
params: JSON.stringify(self.upgraded)
|
||||
});
|
||||
}
|
||||
|
@ -443,11 +450,26 @@
|
|||
ContentUpgrade.prototype.printError = function (error) {
|
||||
var self = this;
|
||||
|
||||
if (error.type === 'errorParamsBroken') {
|
||||
error = info.errorContent.replace('%id', error.id) + ' ' + info.errorParamsBroken;
|
||||
}
|
||||
else if (error.type === 'scriptMissing') {
|
||||
error = info.errorScript.replace('%lib', error.library);
|
||||
switch (error.type) {
|
||||
case 'errorParamsBroken':
|
||||
error = info.errorContent.replace('%id', error.id) + ' ' + info.errorParamsBroken;
|
||||
break;
|
||||
|
||||
case 'libraryMissing':
|
||||
error = info.errorLibrary.replace('%lib', error.library);
|
||||
break;
|
||||
|
||||
case 'scriptMissing':
|
||||
error = info.errorScript.replace('%lib', error.library);
|
||||
break;
|
||||
|
||||
case 'errorTooHighVersion':
|
||||
error = info.errorContent.replace('%id', error.id) + ' ' + info.errorTooHighVersion.replace('%used', error.used).replace('%supported', error.supported);
|
||||
break;
|
||||
|
||||
case 'errorNotSupported':
|
||||
error = info.errorContent.replace('%id', error.id) + ' ' + info.errorNotSupported.replace('%used', error.used);
|
||||
break;
|
||||
}
|
||||
|
||||
self.trigger('error', {
|
||||
|
@ -455,7 +477,7 @@
|
|||
infoError: info.error,
|
||||
});
|
||||
|
||||
self.setStatus('<p>' + info.error + '<br/>' + error + '</p>');
|
||||
$('<li>' + info.error + '<br/>' + error + '</li>').appendTo($log);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* global H5PUtils */
|
||||
var H5PDataView = (function ($) {
|
||||
|
||||
/**
|
||||
|
@ -198,7 +199,6 @@ var H5PDataView = (function ($) {
|
|||
* @param number col ID of column
|
||||
*/
|
||||
H5PDataView.prototype.createFacets = function (input, col) {
|
||||
var self = this;
|
||||
var facets = '';
|
||||
|
||||
if (input instanceof Array) {
|
||||
|
|
|
@ -10,7 +10,7 @@ var H5P = window.H5P = window.H5P || {};
|
|||
* @param {boolean} [extras.bubbles]
|
||||
* @param {boolean} [extras.external]
|
||||
*/
|
||||
H5P.Event = function(type, data, extras) {
|
||||
H5P.Event = function (type, data, extras) {
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
var bubbles = false;
|
||||
|
@ -34,7 +34,7 @@ H5P.Event = function(type, data, extras) {
|
|||
/**
|
||||
* Prevent this event from bubbling up to parent
|
||||
*/
|
||||
this.preventBubbling = function() {
|
||||
this.preventBubbling = function () {
|
||||
bubbles = false;
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,7 @@ H5P.Event = function(type, data, extras) {
|
|||
* @returns {boolean}
|
||||
* true if bubbling false otherwise
|
||||
*/
|
||||
this.getBubbles = function() {
|
||||
this.getBubbles = function () {
|
||||
return bubbles;
|
||||
};
|
||||
|
||||
|
@ -54,7 +54,7 @@ H5P.Event = function(type, data, extras) {
|
|||
* @returns {boolean}
|
||||
* true if external and not already scheduled, otherwise false
|
||||
*/
|
||||
this.scheduleForExternal = function() {
|
||||
this.scheduleForExternal = function () {
|
||||
if (external && !scheduledForExternal) {
|
||||
scheduledForExternal = true;
|
||||
return true;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
var H5PLibraryDetails= H5PLibraryDetails || {};
|
||||
/* global H5PAdminIntegration H5PUtils */
|
||||
var H5PLibraryDetails = H5PLibraryDetails || {};
|
||||
|
||||
(function ($) {
|
||||
|
||||
|
@ -68,7 +69,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
*/
|
||||
H5PLibraryDetails.createContentTable = function () {
|
||||
// Remove it if it exists:
|
||||
if(H5PLibraryDetails.$contentTable) {
|
||||
if (H5PLibraryDetails.$contentTable) {
|
||||
H5PLibraryDetails.$contentTable.remove();
|
||||
}
|
||||
|
||||
|
@ -77,10 +78,10 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
var i = (H5PLibraryDetails.currentPage*H5PLibraryDetails.PAGER_SIZE);
|
||||
var lastIndex = (i+H5PLibraryDetails.PAGER_SIZE);
|
||||
|
||||
if(lastIndex > H5PLibraryDetails.currentContent.length) {
|
||||
if (lastIndex > H5PLibraryDetails.currentContent.length) {
|
||||
lastIndex = H5PLibraryDetails.currentContent.length;
|
||||
}
|
||||
for(; i<lastIndex; i++) {
|
||||
for (; i<lastIndex; i++) {
|
||||
var content = H5PLibraryDetails.currentContent[i];
|
||||
H5PLibraryDetails.$contentTable.append(H5PUtils.createTableRow(['<a href="' + content.url + '">' + content.title + '</a>']));
|
||||
}
|
||||
|
@ -97,7 +98,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
H5PLibraryDetails.$next = $('<button type="button" class="next h5p-admin">></button>');
|
||||
|
||||
H5PLibraryDetails.$previous.on('click', function () {
|
||||
if(H5PLibraryDetails.$previous.hasClass('disabled')) {
|
||||
if (H5PLibraryDetails.$previous.hasClass('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -107,7 +108,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
});
|
||||
|
||||
H5PLibraryDetails.$next.on('click', function () {
|
||||
if(H5PLibraryDetails.$next.hasClass('disabled')) {
|
||||
if (H5PLibraryDetails.$next.hasClass('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -127,7 +128,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
H5PLibraryDetails.$pagerInfo.hide();
|
||||
|
||||
// User has updated the pageNumber
|
||||
var pageNumerUpdated = function() {
|
||||
var pageNumerUpdated = function () {
|
||||
var newPageNum = $gotoInput.val()-1;
|
||||
var intRegex = /^\d+$/;
|
||||
|
||||
|
@ -135,7 +136,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
H5PLibraryDetails.$pagerInfo.css({display: 'inline-block'});
|
||||
|
||||
// Check if input value is valid, and that it has actually changed
|
||||
if(!(intRegex.test(newPageNum) && newPageNum >= 0 && newPageNum < H5PLibraryDetails.getNumPages() && newPageNum != H5PLibraryDetails.currentPage)) {
|
||||
if (!(intRegex.test(newPageNum) && newPageNum >= 0 && newPageNum < H5PLibraryDetails.getNumPages() && newPageNum != H5PLibraryDetails.currentPage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -185,7 +186,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
H5PLibraryDetails.updatePager = function () {
|
||||
H5PLibraryDetails.$pagerInfo.css({display: 'inline-block'});
|
||||
|
||||
if(H5PLibraryDetails.getNumPages() > 0) {
|
||||
if (H5PLibraryDetails.getNumPages() > 0) {
|
||||
var message = H5PUtils.translateReplace(H5PLibraryDetails.library.translations.pageXOfY, {
|
||||
'$x': (H5PLibraryDetails.currentPage+1),
|
||||
'$y': H5PLibraryDetails.getNumPages()
|
||||
|
@ -211,7 +212,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
var searchString = $('.h5p-content-search > input').val();
|
||||
|
||||
// If search string same as previous, just do nothing
|
||||
if(H5PLibraryDetails.currentFilter === searchString) {
|
||||
if (H5PLibraryDetails.currentFilter === searchString) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -219,7 +220,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
// If empty search, use the complete list
|
||||
H5PLibraryDetails.currentContent = H5PLibraryDetails.library.content;
|
||||
}
|
||||
else if(H5PLibraryDetails.filterCache[searchString]) {
|
||||
else if (H5PLibraryDetails.filterCache[searchString]) {
|
||||
// If search is cached, no need to filter
|
||||
H5PLibraryDetails.currentContent = H5PLibraryDetails.filterCache[searchString];
|
||||
}
|
||||
|
@ -227,10 +228,10 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
var listToFilter = H5PLibraryDetails.library.content;
|
||||
|
||||
// Check if we can filter the already filtered results (for performance)
|
||||
if(searchString.length > 1 && H5PLibraryDetails.currentFilter === searchString.substr(0, H5PLibraryDetails.currentFilter.length)) {
|
||||
if (searchString.length > 1 && H5PLibraryDetails.currentFilter === searchString.substr(0, H5PLibraryDetails.currentFilter.length)) {
|
||||
listToFilter = H5PLibraryDetails.currentContent;
|
||||
}
|
||||
H5PLibraryDetails.currentContent = $.grep(listToFilter, function(content) {
|
||||
H5PLibraryDetails.currentContent = $.grep(listToFilter, function (content) {
|
||||
return content.title && content.title.match(new RegExp(searchString, 'i'));
|
||||
});
|
||||
}
|
||||
|
@ -256,7 +257,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
|||
$('input', H5PLibraryDetails.$search).on('change keypress paste input', function () {
|
||||
// Here we start the filtering
|
||||
// We wait at least 500 ms after last input to perform search
|
||||
if(inputTimer) {
|
||||
if (inputTimer) {
|
||||
clearTimeout(inputTimer);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*jshint multistr: true */
|
||||
/* global H5PAdminIntegration H5PUtils */
|
||||
var H5PLibraryList = H5PLibraryList || {};
|
||||
|
||||
(function ($) {
|
||||
|
@ -25,7 +25,7 @@ var H5PLibraryList = H5PLibraryList || {};
|
|||
*/
|
||||
H5PLibraryList.createLibraryList = function (libraries) {
|
||||
var t = H5PAdminIntegration.l10n;
|
||||
if(libraries.listData === undefined || libraries.listData.length === 0) {
|
||||
if (libraries.listData === undefined || libraries.listData.length === 0) {
|
||||
return $('<div>' + t.NA + '</div>');
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,12 @@
|
|||
// Make iframe responsive
|
||||
iframe.style.width = '100%';
|
||||
|
||||
// Bugfix for Chrome: Force update of iframe width. If this is not done the
|
||||
// document size may not be updated before the content resizes.
|
||||
iframe.getBoundingClientRect();
|
||||
|
||||
// Tell iframe that it needs to resize when our window resizes
|
||||
var resize = function (event) {
|
||||
var resize = function () {
|
||||
if (iframe.contentWindow) {
|
||||
// Limit resize calls to avoid flickering
|
||||
respond('resize');
|
||||
|
@ -64,7 +68,7 @@
|
|||
* @param {Object} data Payload
|
||||
* @param {Function} respond Send a response to the iframe
|
||||
*/
|
||||
actionHandlers.resize = function (iframe, data, respond) {
|
||||
actionHandlers.resize = function (iframe, data) {
|
||||
// Resize iframe so all content is visible. Use scrollHeight to make sure we get everything
|
||||
iframe.style.height = data.scrollHeight + 'px';
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* global H5PAdminIntegration*/
|
||||
var H5PUtils = H5PUtils || {};
|
||||
|
||||
(function ($) {
|
||||
|
@ -9,7 +10,7 @@ var H5PUtils = H5PUtils || {};
|
|||
H5PUtils.createTable = function (headers) {
|
||||
var $table = $('<table class="h5p-admin-table' + (H5PAdminIntegration.extraTableClasses !== undefined ? ' ' + H5PAdminIntegration.extraTableClasses : '') + '"></table>');
|
||||
|
||||
if(headers) {
|
||||
if (headers) {
|
||||
var $thead = $('<thead></thead>');
|
||||
var $tr = $('<tr></tr>');
|
||||
|
||||
|
@ -44,7 +45,7 @@ var H5PUtils = H5PUtils || {};
|
|||
};
|
||||
}
|
||||
|
||||
$('<td/>', value).appendTo($tr);
|
||||
$('<td/>', value).appendTo($tr);
|
||||
});
|
||||
|
||||
return $tr;
|
||||
|
|
|
@ -7,11 +7,24 @@ H5P.Version = (function () {
|
|||
* @param {String} version
|
||||
*/
|
||||
function Version(version) {
|
||||
var versionSplit = version.split('.', 3);
|
||||
|
||||
// Public
|
||||
this.major =+ versionSplit[0];
|
||||
this.minor =+ versionSplit[1];
|
||||
if (typeof version === 'string') {
|
||||
// Name version string (used by content upgrade)
|
||||
var versionSplit = version.split('.', 3);
|
||||
this.major =+ versionSplit[0];
|
||||
this.minor =+ versionSplit[1];
|
||||
}
|
||||
else {
|
||||
// Library objects (used by editor)
|
||||
if (version.localMajorVersion !== undefined) {
|
||||
this.major =+ version.localMajorVersion;
|
||||
this.minor =+ version.localMinorVersion;
|
||||
}
|
||||
else {
|
||||
this.major =+ version.majorVersion;
|
||||
this.minor =+ version.minorVersion;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public. Custom string for this object.
|
||||
|
|
|
@ -217,7 +217,7 @@ H5P.XAPIEvent.prototype.setActor = function () {
|
|||
* @returns {number}
|
||||
* The max score, or null if not defined
|
||||
*/
|
||||
H5P.XAPIEvent.prototype.getMaxScore = function() {
|
||||
H5P.XAPIEvent.prototype.getMaxScore = function () {
|
||||
return this.getVerifiedStatementValue(['result', 'score', 'max']);
|
||||
};
|
||||
|
||||
|
@ -227,7 +227,7 @@ H5P.XAPIEvent.prototype.getMaxScore = function() {
|
|||
* @returns {number}
|
||||
* The score, or null if not defined
|
||||
*/
|
||||
H5P.XAPIEvent.prototype.getScore = function() {
|
||||
H5P.XAPIEvent.prototype.getScore = function () {
|
||||
return this.getVerifiedStatementValue(['result', 'score', 'raw']);
|
||||
};
|
||||
|
||||
|
@ -239,7 +239,7 @@ H5P.XAPIEvent.prototype.getScore = function() {
|
|||
*/
|
||||
H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) {
|
||||
var xAPIId;
|
||||
if (instance.contentId && H5PIntegration && H5PIntegration.contents) {
|
||||
if (instance.contentId && H5PIntegration && H5PIntegration.contents && H5PIntegration.contents['cid-' + instance.contentId]) {
|
||||
xAPIId = H5PIntegration.contents['cid-' + instance.contentId].url;
|
||||
if (instance.subContentId) {
|
||||
xAPIId += '?subContentId=' + instance.subContentId;
|
||||
|
@ -256,7 +256,7 @@ H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) {
|
|||
H5P.XAPIEvent.prototype.isFromChild = function () {
|
||||
var parentId = this.getVerifiedStatementValue(['context', 'contextActivities', 'parent', 0, 'id']);
|
||||
return !parentId || parentId.indexOf('subContentId') === -1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Figure out if a property exists in the statement and return it
|
||||
|
@ -267,7 +267,7 @@ H5P.XAPIEvent.prototype.isFromChild = function () {
|
|||
* @returns {*}
|
||||
* The value of the property if it is set, null otherwise.
|
||||
*/
|
||||
H5P.XAPIEvent.prototype.getVerifiedStatementValue = function(keys) {
|
||||
H5P.XAPIEvent.prototype.getVerifiedStatementValue = function (keys) {
|
||||
var val = this.data.statement;
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (val[keys[i]] === undefined) {
|
||||
|
|
|
@ -92,7 +92,7 @@ H5P.EventDispatcher.prototype.triggerXAPIScored = function (score, maxScore, ver
|
|||
this.trigger(event);
|
||||
};
|
||||
|
||||
H5P.EventDispatcher.prototype.setActivityStarted = function() {
|
||||
H5P.EventDispatcher.prototype.setActivityStarted = function () {
|
||||
if (this.activityStartTime === undefined) {
|
||||
// Don't trigger xAPI events in the editor
|
||||
if (this.contentId !== undefined &&
|
||||
|
|
97
js/h5p.js
97
js/h5p.js
|
@ -75,8 +75,9 @@ H5P.init = function (target) {
|
|||
* @type {boolean}
|
||||
*/
|
||||
H5P.fullscreenSupported = !(H5P.isFramed && H5P.externalEmbed !== false) || !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled);
|
||||
// We should consider document.msFullscreenEnabled when they get their
|
||||
// element sizing corrected. Ref. https://connect.microsoft.com/IE/feedback/details/838286/ie-11-incorrectly-reports-dom-element-sizes-in-fullscreen-mode-when-fullscreened-element-is-within-an-iframe
|
||||
// -We should consider document.msFullscreenEnabled when they get their
|
||||
// -element sizing corrected. Ref. https://connect.microsoft.com/IE/feedback/details/838286/ie-11-incorrectly-reports-dom-element-sizes-in-fullscreen-mode-when-fullscreened-element-is-within-an-iframe
|
||||
// Update: Seems to be no need as they've moved on to Webkit
|
||||
}
|
||||
|
||||
// Deprecated variable, kept to maintain backwards compatability
|
||||
|
@ -89,7 +90,7 @@ H5P.init = function (target) {
|
|||
}
|
||||
|
||||
// H5Ps added in normal DIV.
|
||||
var $containers = H5P.jQuery('.h5p-content:not(.h5p-initialized)', target).each(function () {
|
||||
H5P.jQuery('.h5p-content:not(.h5p-initialized)', target).each(function () {
|
||||
var $element = H5P.jQuery(this).addClass('h5p-initialized');
|
||||
var $container = H5P.jQuery('<div class="h5p-container"></div>').appendTo($element);
|
||||
var contentId = $element.data('content-id');
|
||||
|
@ -139,6 +140,7 @@ H5P.init = function (target) {
|
|||
'<div role="button" ' +
|
||||
'tabindex="0" ' +
|
||||
'class="h5p-enable-fullscreen" ' +
|
||||
'aria-label="' + H5P.t('fullscreen') +
|
||||
'title="' + H5P.t('fullscreen') + '">' +
|
||||
'</div>' +
|
||||
'</div>')
|
||||
|
@ -301,7 +303,7 @@ H5P.init = function (target) {
|
|||
});
|
||||
|
||||
// When resize has been prepared tell parent window to resize
|
||||
H5P.communicator.on('resizePrepared', function (data) {
|
||||
H5P.communicator.on('resizePrepared', function () {
|
||||
H5P.communicator.send('resize', {
|
||||
scrollHeight: document.body.scrollHeight
|
||||
});
|
||||
|
@ -494,7 +496,7 @@ H5P.fullScreen = function ($element, instance, exitCallback, body, forceSemiFull
|
|||
}
|
||||
|
||||
var $container = $element;
|
||||
var $classes, $iframe;
|
||||
var $classes, $iframe, $body;
|
||||
if (body === undefined) {
|
||||
$body = H5P.$body;
|
||||
}
|
||||
|
@ -569,7 +571,7 @@ H5P.fullScreen = function ($element, instance, exitCallback, body, forceSemiFull
|
|||
}
|
||||
|
||||
before('h5p-semi-fullscreen');
|
||||
var $disable = H5P.jQuery('<div role="button" tabindex="0" class="h5p-disable-fullscreen" title="' + H5P.t('disableFullscreen') + '"></div>').appendTo($container.find('.h5p-content-controls'));
|
||||
var $disable = H5P.jQuery('<div role="button" tabindex="0" class="h5p-disable-fullscreen" title="' + H5P.t('disableFullscreen') + '" aria-label="' + H5P.t('disableFullscreen') + '"></div>').appendTo($container.find('.h5p-content-controls'));
|
||||
var keyup, disableSemiFullscreen = H5P.exitFullScreen = function () {
|
||||
if (prevViewportContent) {
|
||||
// Use content from the previous viewport tag
|
||||
|
@ -924,7 +926,7 @@ H5P.Dialog = function (name, title, content, $element) {
|
|||
<div class="h5p-inner">\
|
||||
<h2>' + title + '</h2>\
|
||||
<div class="h5p-scroll-content">' + content + '</div>\
|
||||
<div class="h5p-close" role="button" tabindex="0" title="' + H5P.t('close') + '">\
|
||||
<div class="h5p-close" role="button" tabindex="0" aria-label="' + H5P.t('close') + '" title="' + H5P.t('close') + '"></div>\
|
||||
</div>\
|
||||
</div>')
|
||||
.insertAfter($element)
|
||||
|
@ -1089,7 +1091,7 @@ H5P.findCopyrights = function (info, parameters, contentId, extras) {
|
|||
}
|
||||
}
|
||||
|
||||
function buildFromMetadata (data, name, contentId) {
|
||||
function buildFromMetadata(data, name, contentId) {
|
||||
if (data.metadata) {
|
||||
const metadataCopyrights = H5P.buildMetadataCopyrights(data.metadata, name);
|
||||
if (metadataCopyrights !== undefined) {
|
||||
|
@ -1105,11 +1107,12 @@ H5P.findCopyrights = function (info, parameters, contentId, extras) {
|
|||
}
|
||||
};
|
||||
|
||||
H5P.buildMetadataCopyrights = function (metadata, contentTypeName) {
|
||||
H5P.buildMetadataCopyrights = function (metadata) {
|
||||
if (metadata && metadata.license !== undefined && metadata.license !== 'U') {
|
||||
var dataset = {
|
||||
contentType: metadata.contentType,
|
||||
title: metadata.title,
|
||||
author: (metadata.authors && metadata.authors.length > 0) ? metadata.authors.map(function(author) {
|
||||
author: (metadata.authors && metadata.authors.length > 0) ? metadata.authors.map(function (author) {
|
||||
return (author.role) ? author.name + ' (' + author.role + ')' : author.name;
|
||||
}).join(', ') : undefined,
|
||||
source: metadata.source,
|
||||
|
@ -1117,24 +1120,12 @@ H5P.buildMetadataCopyrights = function (metadata, contentTypeName) {
|
|||
license: metadata.license,
|
||||
version: metadata.licenseVersion,
|
||||
licenseExtras: metadata.licenseExtras,
|
||||
changes: (metadata.changes && metadata.changes.length > 0) ? metadata.changes.map(function(change) {
|
||||
changes: (metadata.changes && metadata.changes.length > 0) ? metadata.changes.map(function (change) {
|
||||
return change.log + (change.author ? ', ' + change.author : '') + (change.date ? ', ' + change.date : '');
|
||||
}).join(' / ') : undefined
|
||||
};
|
||||
|
||||
if (contentTypeName) {
|
||||
contentTypeName = contentTypeName
|
||||
.split(' ')[0]
|
||||
.replace(/^H5P\./, '')
|
||||
.replace(/([a-z])([A-Z])/g, '$1' + ' ' + '$2');
|
||||
}
|
||||
|
||||
return new H5P.MediaCopyright(
|
||||
dataset,
|
||||
{type: 'Content type', licenseExtras: 'License extras', changes: 'Changelog'},
|
||||
['type', 'title', 'license', 'author', 'year', 'source', 'licenseExtras', 'changes'],
|
||||
{type: contentTypeName}
|
||||
);
|
||||
return new H5P.MediaCopyright(dataset);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1192,10 +1183,10 @@ H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size) {
|
|||
updateEmbed();
|
||||
|
||||
// Select text and expand textareas
|
||||
$dialog.find('.h5p-embed-code-container').each(function(index, value) {
|
||||
H5P.jQuery(this).css('height', this.scrollHeight + 'px').focus(function() {
|
||||
H5P.jQuery(this).select();
|
||||
});
|
||||
$dialog.find('.h5p-embed-code-container').each(function () {
|
||||
H5P.jQuery(this).css('height', this.scrollHeight + 'px').focus(function () {
|
||||
H5P.jQuery(this).select();
|
||||
});
|
||||
});
|
||||
$dialog.find('.h5p-embed-code-container').eq(0).select();
|
||||
positionInner();
|
||||
|
@ -1212,7 +1203,7 @@ H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size) {
|
|||
$expander.addClass('h5p-open').text(H5P.t('hideAdvanced'));
|
||||
$content.show();
|
||||
}
|
||||
$dialog.find('.h5p-embed-code-container').each(function(index, value) {
|
||||
$dialog.find('.h5p-embed-code-container').each(function () {
|
||||
H5P.jQuery(this).css('height', this.scrollHeight + 'px');
|
||||
});
|
||||
positionInner();
|
||||
|
@ -1424,12 +1415,12 @@ H5P.MediaCopyright = function (copyright, labels, order, extraFields) {
|
|||
|
||||
if (order === undefined) {
|
||||
// Set default order
|
||||
order = ['title', 'author', 'year', 'source', 'license'];
|
||||
order = ['contentType', 'title', 'license', 'author', 'year', 'source', 'licenseExtras', 'changes'];
|
||||
}
|
||||
|
||||
for (var i = 0; i < order.length; i++) {
|
||||
var fieldName = order[i];
|
||||
if (copyright[fieldName] !== undefined) {
|
||||
if (copyright[fieldName] !== undefined && copyright[fieldName] !== '') {
|
||||
var humanValue = copyright[fieldName];
|
||||
if (fieldName === 'license') {
|
||||
humanValue = humanizeLicense(copyright.license, copyright.version);
|
||||
|
@ -1625,7 +1616,8 @@ H5P.Coords = function (x, y, w, h) {
|
|||
this.y = x.y;
|
||||
this.w = x.w;
|
||||
this.h = x.h;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (x !== undefined) {
|
||||
this.x = x;
|
||||
}
|
||||
|
@ -1881,7 +1873,7 @@ H5P.on = function (instance, eventType, handler) {
|
|||
* @returns {string} UUID
|
||||
*/
|
||||
H5P.createUUID = function () {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(char) {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (char) {
|
||||
var random = Math.random()*16|0, newChar = char === 'x' ? random : (random&0x3|0x8);
|
||||
return newChar.toString(16);
|
||||
});
|
||||
|
@ -2109,7 +2101,7 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
|||
}
|
||||
|
||||
preloadedData[options.subContentId][dataId] = data;
|
||||
contentUserDataAjax(contentId, dataId, options.subContentId, function (error, data) {
|
||||
contentUserDataAjax(contentId, dataId, options.subContentId, function (error) {
|
||||
if (options.errorCallback && error) {
|
||||
options.errorCallback(error);
|
||||
}
|
||||
|
@ -2222,23 +2214,13 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
|||
H5P.setClipboard(clipboardItem);
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a cache for pasted data to prevent parsing multiple times.
|
||||
* @type {Object}
|
||||
*/
|
||||
var parsedClipboard = null;
|
||||
|
||||
/**
|
||||
* Retrieve parsed clipboard data.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
H5P.getClipboard = function () {
|
||||
if (!parsedClipboard) {
|
||||
parsedClipboard = parseClipboard();
|
||||
}
|
||||
|
||||
return parsedClipboard;
|
||||
return parseClipboard();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2249,9 +2231,6 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
|||
H5P.setClipboard = function (clipboardItem) {
|
||||
localStorage.setItem('h5pClipboard', JSON.stringify(clipboardItem));
|
||||
|
||||
// Clear cache
|
||||
parsedClipboard = null;
|
||||
|
||||
// Trigger an event so all 'Paste' buttons may be enabled.
|
||||
H5P.externalDispatcher.trigger('datainclipboard', {reset: false});
|
||||
};
|
||||
|
@ -2271,7 +2250,6 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
|||
* Get item from the H5P Clipboard.
|
||||
*
|
||||
* @private
|
||||
* @param {boolean} [skipUpdateFileUrls]
|
||||
* @return {Object}
|
||||
*/
|
||||
var parseClipboard = function () {
|
||||
|
@ -2289,8 +2267,8 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Update file URLs
|
||||
updateFileUrls(clipboardData.specific, function (path) {
|
||||
// Update file URLs and reset content Ids
|
||||
recursiveUpdate(clipboardData.specific, function (path) {
|
||||
var isTmpFile = (path.substr(-4, 4) === '#tmp');
|
||||
if (!isTmpFile && clipboardData.contentId) {
|
||||
// Comes from existing content
|
||||
|
@ -2311,22 +2289,20 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
|||
if (clipboardData.generic) {
|
||||
// Use reference instead of key
|
||||
clipboardData.generic = clipboardData.specific[clipboardData.generic];
|
||||
|
||||
// Avoid multiple content with same ID
|
||||
delete clipboardData.generic.subContentId;
|
||||
}
|
||||
|
||||
return clipboardData;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update file URLs. Useful when copying content.
|
||||
* Update file URLs and reset content IDs.
|
||||
* Useful when copying content.
|
||||
*
|
||||
* @private
|
||||
* @param {object} params Reference
|
||||
* @param {function} handler Modifies the path to work when pasted
|
||||
*/
|
||||
var updateFileUrls = function (params, handler) {
|
||||
var recursiveUpdate = function (params, handler) {
|
||||
for (var prop in params) {
|
||||
if (params.hasOwnProperty(prop) && params[prop] instanceof Object) {
|
||||
var obj = params[prop];
|
||||
|
@ -2334,7 +2310,11 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
|||
obj.path = handler(obj.path);
|
||||
}
|
||||
else {
|
||||
updateFileUrls(obj, handler);
|
||||
if (obj.library !== undefined && obj.subContentId !== undefined) {
|
||||
// Avoid multiple content with same ID
|
||||
delete obj.subContentId;
|
||||
}
|
||||
recursiveUpdate(obj, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2346,9 +2326,6 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
|||
window.addEventListener('storage', function (event) {
|
||||
// Pick up clipboard changes from other tabs
|
||||
if (event.key === 'h5pClipboard') {
|
||||
// Clear cache
|
||||
parsedClipboard = null;
|
||||
|
||||
// Trigger an event so all 'Paste' buttons may be enabled.
|
||||
H5P.externalDispatcher.trigger('datainclipboard', {reset: event.newValue === null});
|
||||
}
|
||||
|
|
|
@ -13,3 +13,8 @@ var H5P = window.H5P = window.H5P || {};
|
|||
* @member
|
||||
*/
|
||||
H5P.jQuery = jQuery.noConflict(true);
|
||||
H5P.jQuery.ajaxPrefilter(function (s) {
|
||||
if (s.crossDomain) {
|
||||
s.contents.script = false;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -339,3 +339,6 @@ button.h5p-admin.disabled:hover {
|
|||
.h5p-data-view .h5p-facet-tag > span:active {
|
||||
color: #d20000;
|
||||
}
|
||||
.content-upgrade-log {
|
||||
color: red;
|
||||
}
|
||||
|
|
|
@ -455,3 +455,19 @@ div.h5p-fullscreen {
|
|||
.h5p-dialog-ok-button:active {
|
||||
background: #eeffee;
|
||||
}
|
||||
|
||||
/* This is loaded as part of Core and not Editor since this needs to be outside the editor iframe */
|
||||
.h5peditor-semi-fullscreen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 101;
|
||||
}
|
||||
iframe.h5peditor-semi-fullscreen {
|
||||
background: #fff;
|
||||
z-index: 100001;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue