Merge branch 'master' into contentupgrade
commit
1d00397a24
|
@ -28,7 +28,8 @@
|
||||||
"h5p-development.class.php",
|
"h5p-development.class.php",
|
||||||
"h5p-file-storage.interface.php",
|
"h5p-file-storage.interface.php",
|
||||||
"h5p-default-storage.class.php",
|
"h5p-default-storage.class.php",
|
||||||
"h5p-event-base.class.php"
|
"h5p-event-base.class.php",
|
||||||
|
"h5p-metadata.class.php"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,9 @@ class H5PDevelopment {
|
||||||
|
|
||||||
// Save/update library.
|
// Save/update library.
|
||||||
$library['libraryId'] = $this->h5pF->getLibraryId($library['machineName'], $library['majorVersion'], $library['minorVersion']);
|
$library['libraryId'] = $this->h5pF->getLibraryId($library['machineName'], $library['majorVersion'], $library['minorVersion']);
|
||||||
|
if (!isset($library['metadata'])) {
|
||||||
|
$library['metadata'] = 0;
|
||||||
|
}
|
||||||
$this->h5pF->saveLibraryData($library, $library['libraryId'] === FALSE);
|
$this->h5pF->saveLibraryData($library, $library['libraryId'] === FALSE);
|
||||||
|
|
||||||
$library['path'] = 'development/' . $contents[$i];
|
$library['path'] = 'development/' . $contents[$i];
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Utility class for handling metadata
|
||||||
|
*/
|
||||||
|
abstract class H5PMetadata {
|
||||||
|
|
||||||
|
const FIELDS = array(
|
||||||
|
'title' => array(
|
||||||
|
'type' => 'text',
|
||||||
|
'maxLength' => 255
|
||||||
|
),
|
||||||
|
'authors' => array(
|
||||||
|
'type' => 'json'
|
||||||
|
),
|
||||||
|
'changes' => array(
|
||||||
|
'type' => 'json'
|
||||||
|
),
|
||||||
|
'source' => array(
|
||||||
|
'type' => 'text',
|
||||||
|
'maxLength' => 255
|
||||||
|
),
|
||||||
|
'license' => array(
|
||||||
|
'type' => 'text',
|
||||||
|
'maxLength' => 32
|
||||||
|
),
|
||||||
|
'licenseVersion' => array(
|
||||||
|
'type' => 'text',
|
||||||
|
'maxLength' => 10
|
||||||
|
),
|
||||||
|
'licenseExtras' => array(
|
||||||
|
'type' => 'text',
|
||||||
|
'maxLength' => 5000
|
||||||
|
),
|
||||||
|
'authorComments' => array(
|
||||||
|
'type' => 'text',
|
||||||
|
'maxLength' => 5000
|
||||||
|
),
|
||||||
|
'yearFrom' => array(
|
||||||
|
'type' => 'int'
|
||||||
|
),
|
||||||
|
'yearTo' => array(
|
||||||
|
'type' => 'int'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON encode metadata
|
||||||
|
*
|
||||||
|
* @param object $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function toJSON($content) {
|
||||||
|
// Note: deliberatly creating JSON string "manually" to improve performance
|
||||||
|
return
|
||||||
|
'{"title":' . (isset($content->title) ? json_encode($content->title) : 'null') .
|
||||||
|
',"authors":' . (isset($content->authors) ? $content->authors : 'null') .
|
||||||
|
',"source":' . (isset($content->source) ? '"' . $content->source . '"' : 'null') .
|
||||||
|
',"license":' . (isset($content->license) ? '"' . $content->license . '"' : 'null') .
|
||||||
|
',"licenseVersion":' . (isset($content->license_version) ? '"' . $content->license_version . '"' : 'null') .
|
||||||
|
',"licenseExtras":' . (isset($content->license_extras) ? json_encode($content->license_extras) : 'null') .
|
||||||
|
',"yearFrom":' . (isset($content->year_from) ? $content->year_from : 'null') .
|
||||||
|
',"yearTo":' . (isset($content->year_to) ? $content->year_to : 'null') .
|
||||||
|
',"changes":' . (isset($content->changes) ? $content->changes : 'null') .
|
||||||
|
',"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 array $types
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function toDBArray($metadata, $include_title = true, &$types = array()) {
|
||||||
|
$fields = array();
|
||||||
|
|
||||||
|
if (!is_array($metadata)) {
|
||||||
|
$metadata = (array) $metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (self::FIELDS as $key => $config) {
|
||||||
|
|
||||||
|
if ($key === 'title' && !$include_title) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($metadata[$key])) {
|
||||||
|
$value = $metadata[$key];
|
||||||
|
$db_field_name = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $key));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
}
|
212
h5p.classes.php
212
h5p.classes.php
|
@ -101,6 +101,21 @@ interface H5PFrameworkInterface {
|
||||||
*/
|
*/
|
||||||
public function getUploadedH5pPath();
|
public function getUploadedH5pPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load addon libraries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function loadAddons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load config for libraries
|
||||||
|
*
|
||||||
|
* @param array $libraries
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getLibraryConfig($libraries = NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of the current installed libraries
|
* Get a list of the current installed libraries
|
||||||
*
|
*
|
||||||
|
@ -195,6 +210,7 @@ interface H5PFrameworkInterface {
|
||||||
* - minorVersion: The library's minorVersion
|
* - minorVersion: The library's minorVersion
|
||||||
* - patchVersion: The library's patchVersion
|
* - patchVersion: The library's patchVersion
|
||||||
* - runnable: 1 if the library is a content type, 0 otherwise
|
* - runnable: 1 if the library is a content type, 0 otherwise
|
||||||
|
* - metadata: 1 if the library should support setting metadata (copyright etc)
|
||||||
* - fullscreen(optional): 1 if the library supports fullscreen, 0 otherwise
|
* - fullscreen(optional): 1 if the library supports fullscreen, 0 otherwise
|
||||||
* - embedTypes(optional): list of supported embed types
|
* - embedTypes(optional): list of supported embed types
|
||||||
* - preloadedJs(optional): list of associative arrays containing:
|
* - preloadedJs(optional): list of associative arrays containing:
|
||||||
|
@ -665,6 +681,7 @@ class H5PValidator {
|
||||||
'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|MPL|MPL2)$/',
|
'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,}$/',
|
||||||
|
'metadata' => '/^(0|1)$/',
|
||||||
'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}$/',
|
||||||
|
@ -1424,6 +1441,9 @@ class H5PStorage {
|
||||||
$library['saveDependencies'] = TRUE;
|
$library['saveDependencies'] = TRUE;
|
||||||
|
|
||||||
// Save library meta data
|
// Save library meta data
|
||||||
|
if (!isset($library['metadata'])) {
|
||||||
|
$library['metadata'] = 0;
|
||||||
|
}
|
||||||
$this->h5pF->saveLibraryData($library, $new);
|
$this->h5pF->saveLibraryData($library, $new);
|
||||||
|
|
||||||
// Save library folder
|
// Save library folder
|
||||||
|
@ -1642,7 +1662,7 @@ Class H5PExport {
|
||||||
$library['minorVersion']
|
$library['minorVersion']
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($isDevLibrary !== NULL) {
|
if ($isDevLibrary !== NULL && isset($library['path'])) {
|
||||||
$exportFolder = "/" . $library['path'];
|
$exportFolder = "/" . $library['path'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1806,7 +1826,7 @@ class H5PCore {
|
||||||
|
|
||||||
public static $coreApi = array(
|
public static $coreApi = array(
|
||||||
'majorVersion' => 1,
|
'majorVersion' => 1,
|
||||||
'minorVersion' => 16
|
'minorVersion' => 19
|
||||||
);
|
);
|
||||||
public static $styles = array(
|
public static $styles = array(
|
||||||
'styles/h5p.css',
|
'styles/h5p.css',
|
||||||
|
@ -1919,6 +1939,10 @@ class H5PCore {
|
||||||
$content = $this->h5pF->loadContent($id);
|
$content = $this->h5pF->loadContent($id);
|
||||||
|
|
||||||
if ($content !== NULL) {
|
if ($content !== NULL) {
|
||||||
|
// Validate main content's metadata
|
||||||
|
$validator = new H5PContentValidator($this->h5pF, $this);
|
||||||
|
$validator->validateMetadata($content['metadata']);
|
||||||
|
|
||||||
$content['library'] = array(
|
$content['library'] = array(
|
||||||
'id' => $content['libraryId'],
|
'id' => $content['libraryId'],
|
||||||
'name' => $content['libraryName'],
|
'name' => $content['libraryName'],
|
||||||
|
@ -1971,6 +1995,25 @@ class H5PCore {
|
||||||
}
|
}
|
||||||
$validator->validateLibrary($params, (object) array('options' => array($params->library)));
|
$validator->validateLibrary($params, (object) array('options' => array($params->library)));
|
||||||
|
|
||||||
|
// Handle addons:
|
||||||
|
$addons = $this->h5pF->loadAddons();
|
||||||
|
foreach ($addons as $addon) {
|
||||||
|
$add_to = json_decode($addon['addTo']);
|
||||||
|
|
||||||
|
if (isset($add_to->content->types)) {
|
||||||
|
foreach($add_to->content->types as $type) {
|
||||||
|
|
||||||
|
if (isset($type->text->regex) &&
|
||||||
|
$this->textAddonMatches($params->params, $type->text->regex)) {
|
||||||
|
$validator->addon($addon);
|
||||||
|
|
||||||
|
// An addon shall only be added once
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$params = json_encode($params->params);
|
$params = json_encode($params->params);
|
||||||
|
|
||||||
// Update content dependencies.
|
// Update content dependencies.
|
||||||
|
@ -2003,6 +2046,75 @@ class H5PCore {
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a value from a nested mixed array structure.
|
||||||
|
*
|
||||||
|
* @param Array $params Array to be looked in.
|
||||||
|
* @param String $path Supposed path to the value.
|
||||||
|
* @param String [$delimiter='.'] Property delimiter within the path.
|
||||||
|
* @return Object|NULL The object found or NULL.
|
||||||
|
*/
|
||||||
|
private function retrieveValue ($params, $path, $delimiter='.') {
|
||||||
|
$path = explode($delimiter, $path);
|
||||||
|
|
||||||
|
// Property not found
|
||||||
|
if (!isset($params[$path[0]])) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $params[$path[0]];
|
||||||
|
|
||||||
|
// End of path, done
|
||||||
|
if (sizeof($path) === 1) {
|
||||||
|
return $first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We cannot go deeper
|
||||||
|
if (!is_array($first)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular Array
|
||||||
|
if (isset($first[0])) {
|
||||||
|
foreach($first as $number => $object) {
|
||||||
|
$found = $this->retrieveValue($object, implode($delimiter, array_slice($path, 1)));
|
||||||
|
if (isset($found)) {
|
||||||
|
return $found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Associative Array
|
||||||
|
return $this->retrieveValue($first, implode('.', array_slice($path, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if params contain any match.
|
||||||
|
*
|
||||||
|
* @param {object} params - Parameters.
|
||||||
|
* @param {string} [pattern] - Regular expression to identify pattern.
|
||||||
|
* @param {boolean} [found] - Used for recursion.
|
||||||
|
* @return {boolean} True, if params matches pattern.
|
||||||
|
*/
|
||||||
|
private function textAddonMatches($params, $pattern, $found = false) {
|
||||||
|
$type = gettype($params);
|
||||||
|
if ($type === 'string') {
|
||||||
|
if (preg_match($pattern, $params) === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($type === 'array' || $type === 'object') {
|
||||||
|
foreach ($params as $value) {
|
||||||
|
$found = $this->textAddonMatches($value, $pattern, $found);
|
||||||
|
if ($found === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate content slug
|
* Generate content slug
|
||||||
*
|
*
|
||||||
|
@ -3237,6 +3349,19 @@ class H5PContentValidator {
|
||||||
$this->dependencies = array();
|
$this->dependencies = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Addon library.
|
||||||
|
*/
|
||||||
|
public function addon($library) {
|
||||||
|
$depKey = 'preloaded-' . $library['machineName'];
|
||||||
|
$this->dependencies[$depKey] = array(
|
||||||
|
'library' => $library,
|
||||||
|
'type' => 'preloaded'
|
||||||
|
);
|
||||||
|
$this->nextWeight = $this->h5pC->findLibraryDependencies($this->dependencies, $library, $this->nextWeight);
|
||||||
|
$this->dependencies[$depKey]['weight'] = $this->nextWeight++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the flat dependency tree.
|
* Get the flat dependency tree.
|
||||||
*
|
*
|
||||||
|
@ -3246,6 +3371,21 @@ class H5PContentValidator {
|
||||||
return $this->dependencies;
|
return $this->dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate metadata
|
||||||
|
*
|
||||||
|
* @param array $metadata
|
||||||
|
*/
|
||||||
|
public function validateMetadata(&$metadata) {
|
||||||
|
$semantics = $this->getMetadataSemantics();
|
||||||
|
|
||||||
|
$group = (object)$metadata;
|
||||||
|
$this->validateGroup($group, (object) array(
|
||||||
|
'type' => 'group',
|
||||||
|
'fields' => $semantics,
|
||||||
|
), FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate given text value against text semantics.
|
* Validate given text value against text semantics.
|
||||||
* @param $text
|
* @param $text
|
||||||
|
@ -3434,10 +3574,19 @@ class H5PContentValidator {
|
||||||
// We have a strict set of options to choose from.
|
// We have a strict set of options to choose from.
|
||||||
$strict = TRUE;
|
$strict = TRUE;
|
||||||
$options = array();
|
$options = array();
|
||||||
|
|
||||||
foreach ($semantics->options as $option) {
|
foreach ($semantics->options as $option) {
|
||||||
|
// Support optgroup - just flatten options into one
|
||||||
|
if (isset($option->type) && $option->type === 'optgroup') {
|
||||||
|
foreach ($option->options as $suboption) {
|
||||||
|
$options[$suboption->value] = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (isset($option->value)) {
|
||||||
$options[$option->value] = TRUE;
|
$options[$option->value] = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($semantics->multiple) && $semantics->multiple) {
|
if (isset($semantics->multiple) && $semantics->multiple) {
|
||||||
// Multi-choice generates array of values. Test each one against valid
|
// Multi-choice generates array of values. Test each one against valid
|
||||||
|
@ -3566,7 +3715,6 @@ class H5PContentValidator {
|
||||||
|
|
||||||
if (isset($file->copyright)) {
|
if (isset($file->copyright)) {
|
||||||
$this->validateGroup($file->copyright, $this->getCopyrightSemantics());
|
$this->validateGroup($file->copyright, $this->getCopyrightSemantics());
|
||||||
// TODO: We'll need to do something here about getMetadataSemantics() if we change the widgets
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3754,10 +3902,17 @@ class H5PContentValidator {
|
||||||
$library = $this->libraries[$value->library];
|
$library = $this->libraries[$value->library];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate parameters
|
||||||
$this->validateGroup($value->params, (object) array(
|
$this->validateGroup($value->params, (object) array(
|
||||||
'type' => 'group',
|
'type' => 'group',
|
||||||
'fields' => $library['semantics'],
|
'fields' => $library['semantics'],
|
||||||
), FALSE);
|
), FALSE);
|
||||||
|
|
||||||
|
// Validate subcontent's metadata
|
||||||
|
if (isset($value->metadata)) {
|
||||||
|
$this->validateMetadata($value->metadata);
|
||||||
|
}
|
||||||
|
|
||||||
$validKeys = array('library', 'params', 'subContentId', 'metadata');
|
$validKeys = array('library', 'params', 'subContentId', 'metadata');
|
||||||
if (isset($semantics->extraAttributes)) {
|
if (isset($semantics->extraAttributes)) {
|
||||||
$validKeys = array_merge($validKeys, $semantics->extraAttributes);
|
$validKeys = array_merge($validKeys, $semantics->extraAttributes);
|
||||||
|
@ -4155,12 +4310,7 @@ class H5PContentValidator {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$semantics = (object) array(
|
$semantics = array(
|
||||||
(object) array(
|
|
||||||
'name' => 'copyright',
|
|
||||||
'type' => 'group',
|
|
||||||
'label' => $this->h5pF->t('Copyright information'),
|
|
||||||
'fields' => array(
|
|
||||||
(object) array(
|
(object) array(
|
||||||
'name' => 'title',
|
'name' => 'title',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
@ -4243,7 +4393,7 @@ class H5PContentValidator {
|
||||||
'name' => 'licenseVersion',
|
'name' => 'licenseVersion',
|
||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
'label' => $this->h5pF->t('License Version'),
|
'label' => $this->h5pF->t('License Version'),
|
||||||
'options' => array(),
|
'options' => $cc_versions,
|
||||||
'optional' => TRUE
|
'optional' => TRUE
|
||||||
),
|
),
|
||||||
(object) array(
|
(object) array(
|
||||||
|
@ -4270,18 +4420,19 @@ class H5PContentValidator {
|
||||||
'label' => $this->h5pF->t('Source'),
|
'label' => $this->h5pF->t('Source'),
|
||||||
'placeholder' => 'https://',
|
'placeholder' => 'https://',
|
||||||
'optional' => TRUE
|
'optional' => TRUE
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
(object) array(
|
(object) array(
|
||||||
'name' => 'authorWidget',
|
'name' => 'authors',
|
||||||
|
'type' => 'list',
|
||||||
|
'field' => (object) array (
|
||||||
|
'name' => 'author',
|
||||||
'type' => 'group',
|
'type' => 'group',
|
||||||
'fields'=> array(
|
'fields'=> array(
|
||||||
(object) array(
|
(object) array(
|
||||||
'label' => $this->h5pF->t("Author's name"),
|
'label' => $this->h5pF->t("Author's name"),
|
||||||
'name' => "name",
|
'name' => 'name',
|
||||||
'optional' => TRUE,
|
'optional' => TRUE,
|
||||||
'type' => "text"
|
'type' => 'text'
|
||||||
),
|
),
|
||||||
(object) array(
|
(object) array(
|
||||||
'name' => 'role',
|
'name' => 'role',
|
||||||
|
@ -4308,25 +4459,23 @@ class H5PContentValidator {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
(object) array(
|
(object) array(
|
||||||
'name' => 'licenseExtras',
|
'name' => 'licenseExtras',
|
||||||
'type' => 'textarea',
|
'type' => 'text',
|
||||||
|
'widget' => 'textarea',
|
||||||
'label' => $this->h5pF->t('License Extras'),
|
'label' => $this->h5pF->t('License Extras'),
|
||||||
'optional' => TRUE,
|
'optional' => TRUE,
|
||||||
'description' => $this->h5pF->t('Any additional information about the license')
|
'description' => $this->h5pF->t('Any additional information about the license')
|
||||||
),
|
),
|
||||||
(object) array(
|
(object) array(
|
||||||
'name' => 'changeLog',
|
'name' => 'changes',
|
||||||
|
'type' => 'list',
|
||||||
|
'field' => (object) array(
|
||||||
|
'name' => 'change',
|
||||||
'type' => 'group',
|
'type' => 'group',
|
||||||
'expanded' => FALSE,
|
|
||||||
'label' => $this->h5pF->t('Change Log'),
|
'label' => $this->h5pF->t('Change Log'),
|
||||||
'fields' => array(
|
|
||||||
(object) array (
|
|
||||||
'name' => 'changeLogForm',
|
|
||||||
'type' => 'group',
|
|
||||||
'label' => $this->h5pF->t('Question'),
|
|
||||||
'expanded' => TRUE,
|
|
||||||
'fields' => array(
|
'fields' => array(
|
||||||
(object) array(
|
(object) array(
|
||||||
'name' => 'date',
|
'name' => 'date',
|
||||||
|
@ -4342,30 +4491,23 @@ class H5PContentValidator {
|
||||||
),
|
),
|
||||||
(object) array(
|
(object) array(
|
||||||
'name' => 'log',
|
'name' => 'log',
|
||||||
'type' => 'textarea',
|
'type' => 'text',
|
||||||
|
'widget' => 'textarea',
|
||||||
'label' => $this->h5pF->t('Description of change'),
|
'label' => $this->h5pF->t('Description of change'),
|
||||||
'placeholder' => $this->h5pF->t('Photo cropped, text changed, etc.'),
|
'placeholder' => $this->h5pF->t('Photo cropped, text changed, etc.'),
|
||||||
'optional' => TRUE
|
'optional' => TRUE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
),
|
),
|
||||||
(object) array (
|
(object) array (
|
||||||
'name' => 'authorComments',
|
'name' => 'authorComments',
|
||||||
'label' => $this->h5pF->t('Additional Information'),
|
'type' => 'text',
|
||||||
'type' => 'group',
|
'widget' => 'textarea',
|
||||||
'expanded' => FALSE,
|
|
||||||
'fields' => array(
|
|
||||||
(object) array (
|
|
||||||
'name' => 'authorComments',
|
|
||||||
'type' => 'textarea',
|
|
||||||
'label' => $this->h5pF->t('Author comments'),
|
'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)'),
|
'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
|
'optional' => TRUE
|
||||||
)
|
)
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return $semantics;
|
return $semantics;
|
||||||
|
|
|
@ -7,7 +7,7 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
* @class
|
* @class
|
||||||
* @namespace H5P
|
* @namespace H5P
|
||||||
*/
|
*/
|
||||||
function ContentUpgradeProcess(name, oldVersion, newVersion, params, extras, id, loadLibrary, done) {
|
function ContentUpgradeProcess(name, oldVersion, newVersion, params, id, loadLibrary, done) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Make params possible to work with
|
// Make params possible to work with
|
||||||
|
@ -24,38 +24,28 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make extras possible to work with
|
|
||||||
for (var element in extras) {
|
|
||||||
if (extras.hasOwnProperty(element)) {
|
|
||||||
try {
|
|
||||||
extras[element] = JSON.parse(extras[element]);
|
|
||||||
if (!(extras[element] instanceof Object)) {
|
|
||||||
throw true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (event) {
|
|
||||||
return done({
|
|
||||||
type: 'errorExtrasBroken',
|
|
||||||
id: id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.loadLibrary = loadLibrary;
|
self.loadLibrary = loadLibrary;
|
||||||
self.upgrade(name, oldVersion, newVersion, params, extras, function (err, result) {
|
self.upgrade(name, oldVersion, newVersion, params.params, params.metadata, function (err, upgradedParams, upgradedMetadata) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
done(null, JSON.stringify(params), JSON.stringify(extras));
|
done(null, JSON.stringify({params: upgradedParams, metadata: upgradedMetadata}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Run content upgrade.
|
||||||
*
|
*
|
||||||
|
* @public
|
||||||
|
* @param {string} name
|
||||||
|
* @param {Version} oldVersion
|
||||||
|
* @param {Version} newVersion
|
||||||
|
* @param {Object} params
|
||||||
|
* @param {Object} metadata
|
||||||
|
* @param {Function} done
|
||||||
*/
|
*/
|
||||||
ContentUpgradeProcess.prototype.upgrade = function (name, oldVersion, newVersion, params, extras, done) {
|
ContentUpgradeProcess.prototype.upgrade = function (name, oldVersion, newVersion, params, metadata, done) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Load library details and upgrade routines
|
// Load library details and upgrade routines
|
||||||
|
@ -65,7 +55,7 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run upgrade routines on params
|
// Run upgrade routines on params
|
||||||
self.processParams(library, oldVersion, newVersion, params, extras, function (err, params, extras) {
|
self.processParams(library, oldVersion, newVersion, params, metadata, function (err, params, metadata) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +69,7 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
next(err);
|
next(err);
|
||||||
});
|
});
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
done(err, params, extras);
|
done(err, params, metadata);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -95,7 +85,7 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
* @param {Object} params
|
* @param {Object} params
|
||||||
* @param {Function} next
|
* @param {Function} next
|
||||||
*/
|
*/
|
||||||
ContentUpgradeProcess.prototype.processParams = function (library, oldVersion, newVersion, params, extras, next) {
|
ContentUpgradeProcess.prototype.processParams = function (library, oldVersion, newVersion, params, metadata, next) {
|
||||||
if (H5PUpgrades[library.name] === undefined) {
|
if (H5PUpgrades[library.name] === undefined) {
|
||||||
if (library.upgradesScript) {
|
if (library.upgradesScript) {
|
||||||
// Upgrades script should be loaded so the upgrades should be here.
|
// Upgrades script should be loaded so the upgrades should be here.
|
||||||
|
@ -130,17 +120,11 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
try {
|
try {
|
||||||
unnecessaryWrapper(params, function (err, upgradedParams, upgradedExtras) {
|
unnecessaryWrapper(params, function (err, upgradedParams, upgradedExtras) {
|
||||||
params = upgradedParams;
|
params = upgradedParams;
|
||||||
/**
|
if (upgradedExtras && upgradedExtras.metadata) { // Optional
|
||||||
* "params" (and "extras", e.g. metadata) flow through each update function and are changed
|
metadata = upgradedExtras.metadata;
|
||||||
* if necessary. Since "extras" was added later and old update functions don't return
|
|
||||||
* it, we need to ignore undefined values here -- or change every single update function
|
|
||||||
* in all content types.
|
|
||||||
*/
|
|
||||||
if (upgradedExtras) {
|
|
||||||
extras = upgradedExtras;
|
|
||||||
}
|
}
|
||||||
nextMinor(err);
|
nextMinor(err);
|
||||||
}, extras);
|
}, {metadata: metadata});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
if (console && console.log) {
|
if (console && console.log) {
|
||||||
|
@ -154,7 +138,7 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
}, nextMajor);
|
}, nextMajor);
|
||||||
}
|
}
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
next(err, params, extras);
|
next(err, params, metadata);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,20 +179,13 @@ H5P.ContentUpgradeProcess = (function (Version) {
|
||||||
return done(); // Larger or same version that's available
|
return done(); // Larger or same version that's available
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, we only use metadata as additional things that might need change
|
|
||||||
var extras = {
|
|
||||||
metadata: params.metadata
|
|
||||||
};
|
|
||||||
|
|
||||||
// A newer version is available, upgrade params
|
// A newer version is available, upgrade params
|
||||||
return self.upgrade(availableLib[0], usedVer, availableVer, params.params, extras, function (err, upgraded, extras) {
|
return self.upgrade(availableLib[0], usedVer, availableVer, params.params, params.metadata, function (err, upgradedParams, upgradedMetadata) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
params.library = availableLib[0] + ' ' + availableVer.major + '.' + availableVer.minor;
|
params.library = availableLib[0] + ' ' + availableVer.major + '.' + availableVer.minor;
|
||||||
params.params = upgraded;
|
params.params = upgradedParams;
|
||||||
if (extras) {
|
if (upgradedMetadata) {
|
||||||
if (extras.metadata) {
|
params.metadata = upgradedMetadata;
|
||||||
params.metadata = extras.metadata;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done(err, params);
|
done(err, params);
|
||||||
|
|
|
@ -9,7 +9,7 @@ var libraryLoadedCallback;
|
||||||
var messageHandlers = {
|
var messageHandlers = {
|
||||||
newJob: function (job) {
|
newJob: function (job) {
|
||||||
// Start new job
|
// Start new job
|
||||||
new H5P.ContentUpgradeProcess(job.name, new H5P.Version(job.oldVersion), new H5P.Version(job.newVersion), job.params, job.extras, job.id, function loadLibrary(name, version, next) {
|
new H5P.ContentUpgradeProcess(job.name, new H5P.Version(job.oldVersion), new H5P.Version(job.newVersion), job.params, job.id, function loadLibrary(name, version, next) {
|
||||||
// TODO: Cache?
|
// TODO: Cache?
|
||||||
postMessage({
|
postMessage({
|
||||||
action: 'loadLibrary',
|
action: 'loadLibrary',
|
||||||
|
@ -17,7 +17,7 @@ var messageHandlers = {
|
||||||
version: version.toString()
|
version: version.toString()
|
||||||
});
|
});
|
||||||
libraryLoadedCallback = next;
|
libraryLoadedCallback = next;
|
||||||
}, function done(err, result, extras) {
|
}, function done(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
// Return error
|
// Return error
|
||||||
postMessage({
|
postMessage({
|
||||||
|
@ -33,8 +33,7 @@ var messageHandlers = {
|
||||||
postMessage({
|
postMessage({
|
||||||
action: 'done',
|
action: 'done',
|
||||||
id: job.id,
|
id: job.id,
|
||||||
params: result,
|
params: result
|
||||||
extras: extras
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -128,7 +128,7 @@
|
||||||
// Register message handlers
|
// Register message handlers
|
||||||
var messageHandlers = {
|
var messageHandlers = {
|
||||||
done: function (result) {
|
done: function (result) {
|
||||||
self.workDone(result.id, result.params, result.extras, this);
|
self.workDone(result.id, result.params, this);
|
||||||
},
|
},
|
||||||
error: function (error) {
|
error: function (error) {
|
||||||
self.printError(error.err);
|
self.printError(error.err);
|
||||||
|
@ -196,7 +196,7 @@
|
||||||
self.token = inData.token;
|
self.token = inData.token;
|
||||||
|
|
||||||
// Start processing
|
// Start processing
|
||||||
self.processBatch(inData.params, {metadata: inData.metadata});
|
self.processBatch(inData.params);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@
|
||||||
*
|
*
|
||||||
* @param {Object} parameters
|
* @param {Object} parameters
|
||||||
*/
|
*/
|
||||||
ContentUpgrade.prototype.processBatch = function (parameters, extras) {
|
ContentUpgrade.prototype.processBatch = function (parameters) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Track upgraded params
|
// Track upgraded params
|
||||||
|
@ -225,7 +225,6 @@
|
||||||
|
|
||||||
// Track current batch
|
// Track current batch
|
||||||
self.parameters = parameters;
|
self.parameters = parameters;
|
||||||
self.extras = extras;
|
|
||||||
|
|
||||||
// Create id mapping
|
// Create id mapping
|
||||||
self.ids = [];
|
self.ids = [];
|
||||||
|
@ -279,12 +278,11 @@
|
||||||
name: info.library.name,
|
name: info.library.name,
|
||||||
oldVersion: info.library.version,
|
oldVersion: info.library.version,
|
||||||
newVersion: self.version.toString(),
|
newVersion: self.version.toString(),
|
||||||
params: self.parameters[id],
|
params: self.parameters[id]
|
||||||
extras: self.extras
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
new H5P.ContentUpgradeProcess(info.library.name, new Version(info.library.version), self.version, self.parameters[id], self.extras, id, function loadLibrary(name, version, next) {
|
new H5P.ContentUpgradeProcess(info.library.name, new Version(info.library.version), self.version, self.parameters[id], id, function loadLibrary(name, version, next) {
|
||||||
self.loadLibrary(name, version, function (err, library) {
|
self.loadLibrary(name, version, function (err, library) {
|
||||||
if (library.upgradesScript) {
|
if (library.upgradesScript) {
|
||||||
self.loadScript(library.upgradesScript, function (err) {
|
self.loadScript(library.upgradesScript, function (err) {
|
||||||
|
@ -299,13 +297,13 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}, function done(err, result, extras) {
|
}, function done(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
self.printError(err);
|
self.printError(err);
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.workDone(id, result, extras);
|
self.workDone(id, result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -313,7 +311,7 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ContentUpgrade.prototype.workDone = function (id, result, extras, worker) {
|
ContentUpgrade.prototype.workDone = function (id, result, worker) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.working--;
|
self.working--;
|
||||||
|
@ -335,8 +333,7 @@
|
||||||
self.nextBatch({
|
self.nextBatch({
|
||||||
libraryId: self.version.libraryId,
|
libraryId: self.version.libraryId,
|
||||||
token: self.token,
|
token: self.token,
|
||||||
params: JSON.stringify(self.upgraded),
|
params: JSON.stringify(self.upgraded)
|
||||||
extras: extras
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -133,9 +133,10 @@ H5P.XAPIEvent.prototype.setObject = function (instance) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (H5PIntegration && H5PIntegration.contents && H5PIntegration.contents['cid-' + instance.contentId].title) {
|
var content = H5P.getContentForInstance(instance.contentId);
|
||||||
|
if (content && content.metadata && content.metadata.title) {
|
||||||
this.data.statement.object.definition.name = {
|
this.data.statement.object.definition.name = {
|
||||||
"en-US": H5P.createTitle(H5PIntegration.contents['cid-' + instance.contentId].title)
|
"en-US": H5P.createTitle(content.metadata.title)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +151,6 @@ H5P.XAPIEvent.prototype.setObject = function (instance) {
|
||||||
*/
|
*/
|
||||||
H5P.XAPIEvent.prototype.setContext = function (instance) {
|
H5P.XAPIEvent.prototype.setContext = function (instance) {
|
||||||
if (instance.parent && (instance.parent.contentId || instance.parent.subContentId)) {
|
if (instance.parent && (instance.parent.contentId || instance.parent.subContentId)) {
|
||||||
var parentId = instance.parent.subContentId === undefined ? instance.parent.contentId : instance.parent.subContentId;
|
|
||||||
this.data.statement.context = {
|
this.data.statement.context = {
|
||||||
"contextActivities": {
|
"contextActivities": {
|
||||||
"parent": [
|
"parent": [
|
||||||
|
|
29
js/h5p.js
29
js/h5p.js
|
@ -1657,8 +1657,8 @@ H5P.libraryFromString = function (library) {
|
||||||
if (res !== null) {
|
if (res !== null) {
|
||||||
return {
|
return {
|
||||||
'machineName': res[1],
|
'machineName': res[1],
|
||||||
'majorVersion': res[2],
|
'majorVersion': parseInt(res[2]),
|
||||||
'minorVersion': res[3]
|
'minorVersion': parseInt(res[3])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2140,6 +2140,20 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
||||||
contentUserDataAjax(contentId, dataId, subContentId, undefined, null);
|
contentUserDataAjax(contentId, dataId, subContentId, undefined, null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for getting content for a certain ID
|
||||||
|
*
|
||||||
|
* @param {number} contentId
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
H5P.getContentForInstance = function (contentId) {
|
||||||
|
var key = 'cid-' + contentId;
|
||||||
|
var exists = H5PIntegration && H5PIntegration.contents &&
|
||||||
|
H5PIntegration.contents[key];
|
||||||
|
|
||||||
|
return exists ? H5PIntegration.contents[key] : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares the content parameters for storing in the clipboard.
|
* Prepares the content parameters for storing in the clipboard.
|
||||||
*
|
*
|
||||||
|
@ -2242,6 +2256,17 @@ H5P.createTitle = function (rawTitle, maxLength) {
|
||||||
H5P.externalDispatcher.trigger('datainclipboard', {reset: false});
|
H5P.externalDispatcher.trigger('datainclipboard', {reset: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get config for a library
|
||||||
|
*
|
||||||
|
* @param string machineName
|
||||||
|
* @return Object
|
||||||
|
*/
|
||||||
|
H5P.getLibraryConfig = function (machineName) {
|
||||||
|
var hasConfig = H5PIntegration.libraryConfig && H5PIntegration.libraryConfig[machineName];
|
||||||
|
return hasConfig ? H5PIntegration.libraryConfig[machineName] : {};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get item from the H5P Clipboard.
|
* Get item from the H5P Clipboard.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue