Resolving conflicts
commit
b3da2c5b32
|
@ -153,14 +153,14 @@ class H5PDevelopment {
|
||||||
* @param int $minorVersion of the library.
|
* @param int $minorVersion of the library.
|
||||||
* @return string Translation
|
* @return string Translation
|
||||||
*/
|
*/
|
||||||
public function getLanguage($name, $majorVersion, $minorVersion) {
|
public function getLanguage($name, $majorVersion, $minorVersion, $language) {
|
||||||
$library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion);
|
$library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion);
|
||||||
|
|
||||||
if (isset($this->libraries[$library]) === FALSE) {
|
if (isset($this->libraries[$library]) === FALSE) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getFileContents($this->libraries[$library]['path'] . '/language/' . $this->language . '.json');
|
return $this->getFileContents($this->libraries[$library]['path'] . '/language/' . $language . '.json');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,4 +175,3 @@ class H5PDevelopment {
|
||||||
return $name . ' ' . $majorVersion . '.' . $minorVersion;
|
return $name . ' ' . $majorVersion . '.' . $minorVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -394,10 +394,10 @@ interface H5PFrameworkInterface {
|
||||||
/**
|
/**
|
||||||
* Delete a library from database and file system
|
* Delete a library from database and file system
|
||||||
*
|
*
|
||||||
* @param int $libraryId
|
* @param stdClass $library
|
||||||
* Library identifier
|
* Library object with id, name, major version and minor version.
|
||||||
*/
|
*/
|
||||||
public function deleteLibrary($libraryId);
|
public function deleteLibrary($library);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load content.
|
* Load content.
|
||||||
|
@ -444,57 +444,58 @@ interface H5PFrameworkInterface {
|
||||||
public function loadContentDependencies($id, $type = NULL);
|
public function loadContentDependencies($id, $type = NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get data from cache.
|
* Get stored setting.
|
||||||
*
|
*
|
||||||
* @param string $group
|
* @param string $name
|
||||||
* Identifier for the cache group
|
* Identifier for the setting
|
||||||
* @param string $key
|
* @param string $default
|
||||||
* Unique identifier within the group
|
* Optional default value if settings is not set
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* Whatever has been stored in the cache. NULL if the entry doesn't exist
|
* Whatever has been stored as the setting
|
||||||
*/
|
*/
|
||||||
public function cacheGet($group, $key);
|
public function getOption($name, $default = NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store data in cache.
|
* Stores the given setting.
|
||||||
|
* For example when did we last check h5p.org for updates to our libraries.
|
||||||
*
|
*
|
||||||
* @param string $group
|
* @param string $name
|
||||||
* The cache group where the data should be stored
|
* Identifier for the setting
|
||||||
* @param string $key
|
* @param mixed $value Data
|
||||||
* A unique key identifying where the data should be stored
|
* Whatever we want to store as the setting
|
||||||
* @param mixed $data
|
|
||||||
* The data you want to cache
|
|
||||||
*/
|
*/
|
||||||
public function cacheSet($group, $key, $data);
|
public function setOption($name, $value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete data from cache.
|
* This will set the filtered parameters for the given content.
|
||||||
*
|
*
|
||||||
* @param string $group
|
* @param int $content_id
|
||||||
* Identifier for the cache group
|
* @param string $parameters filtered
|
||||||
* @param string $key
|
|
||||||
* Unique identifier within the group
|
|
||||||
*/
|
*/
|
||||||
public function cacheDel($group, $key = NULL);
|
public function setFilteredParameters($content_id, $parameters = '');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will invalidate the cache for the content that uses the specified library.
|
* Will clear filtered params for all the content that uses the specified
|
||||||
* This means that the content dependencies has to be rebuilt, and the parameters refiltered.
|
* library. This means that the content dependencies will have to be rebuilt,
|
||||||
|
* and the parameters refiltered.
|
||||||
*
|
*
|
||||||
* @param int $libraryId
|
* @param int $library_id
|
||||||
*/
|
*/
|
||||||
public function invalidateContentCache($libraryId);
|
public function clearFilteredParameters($library_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get number of content that hasn't been cached
|
* Get number of contents that has to get their content dependencies rebuilt
|
||||||
|
* and parameters refiltered.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getNotCached();
|
public function getNumNotFiltered();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get number of contents using library as main library.
|
* Get number of contents using library as main library.
|
||||||
*
|
*
|
||||||
* @param int $libraryId
|
* @param int $libraryId
|
||||||
* Identifier for a library
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getNumContent($libraryId);
|
public function getNumContent($libraryId);
|
||||||
}
|
}
|
||||||
|
@ -1265,7 +1266,7 @@ class H5PStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure libraries dependencies, parameter filtering and export files gets regenerated for all content who uses this library.
|
// Make sure libraries dependencies, parameter filtering and export files gets regenerated for all content who uses this library.
|
||||||
$this->h5pF->invalidateContentCache($library['libraryId']);
|
$this->h5pF->clearFilteredParameters($library['libraryId']);
|
||||||
|
|
||||||
$upgradedLibsCount++;
|
$upgradedLibsCount++;
|
||||||
}
|
}
|
||||||
|
@ -1525,9 +1526,9 @@ class H5PCore {
|
||||||
public static $defaultContentWhitelist = 'json png jpg jpeg gif bmp tif tiff svg eot ttf woff otf webm mp4 ogg mp3 txt pdf rtf doc docx xls xlsx ppt pptx odt ods odp xml csv diff patch swf md textile';
|
public static $defaultContentWhitelist = 'json png jpg jpeg gif bmp tif tiff svg eot ttf woff otf webm mp4 ogg mp3 txt pdf rtf doc docx xls xlsx ppt pptx odt ods odp xml csv diff patch swf md textile';
|
||||||
public static $defaultLibraryWhitelistExtras = 'js css';
|
public static $defaultLibraryWhitelistExtras = 'js css';
|
||||||
|
|
||||||
|
public $librariesJsonData, $contentJsonData, $mainJsonData, $h5pF, $path, $development_mode, $h5pD, $disableFileCheck;
|
||||||
const SECONDS_IN_WEEK = 604800;
|
const SECONDS_IN_WEEK = 604800;
|
||||||
|
|
||||||
public $librariesJsonData, $contentJsonData, $mainJsonData, $h5pF, $path, $development_mode, $h5pD;
|
|
||||||
private $exportEnabled;
|
private $exportEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1567,11 +1568,6 @@ class H5PCore {
|
||||||
$content['id'] = $this->h5pF->insertContent($content, $contentMainId);
|
$content['id'] = $this->h5pF->insertContent($content, $contentMainId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($content['filtered'])) {
|
|
||||||
// TODO: Add filtered to all impl. and remove
|
|
||||||
$this->h5pF->cacheDel('parameters', $content['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $content['id'];
|
return $content['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1619,16 +1615,8 @@ class H5PCore {
|
||||||
* @return Object NULL on failure.
|
* @return Object NULL on failure.
|
||||||
*/
|
*/
|
||||||
public function filterParameters($content) {
|
public function filterParameters($content) {
|
||||||
if (isset($content['filtered'])) {
|
if (isset($content['filtered']) && $content['filtered'] !== '') {
|
||||||
$params = ($content['filtered'] === '' ? NULL : $content['filtered']);
|
return $content['filtered'];
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO: Add filtered to all impl. and remove
|
|
||||||
$params = $this->h5pF->cacheGet('parameters', $content['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($params !== NULL) {
|
|
||||||
return $params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate and filter against main library semantics.
|
// Validate and filter against main library semantics.
|
||||||
|
@ -1655,7 +1643,7 @@ class H5PCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache.
|
// Cache.
|
||||||
$this->h5pF->cacheSet('parameters', $content['id'], $params);
|
$this->h5pF->setFilteredParameters($content['id'], $params);
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2309,6 +2297,10 @@ class H5PContentValidator {
|
||||||
* FALSE if one or more files fail validation. Error message should be set accordingly by validator.
|
* FALSE if one or more files fail validation. Error message should be set accordingly by validator.
|
||||||
*/
|
*/
|
||||||
public function validateContentFiles($contentPath, $isLibrary = FALSE) {
|
public function validateContentFiles($contentPath, $isLibrary = FALSE) {
|
||||||
|
if ($this->h5pC->disableFileCheck === TRUE) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
// Scan content directory for files, recurse into sub directories.
|
// Scan content directory for files, recurse into sub directories.
|
||||||
$files = array_diff(scandir($contentPath), array('.','..'));
|
$files = array_diff(scandir($contentPath), array('.','..'));
|
||||||
$valid = TRUE;
|
$valid = TRUE;
|
||||||
|
@ -2598,7 +2590,7 @@ class H5PContentValidator {
|
||||||
if (!isset($this->libraries[$value->library])) {
|
if (!isset($this->libraries[$value->library])) {
|
||||||
$libspec = H5PCore::libraryFromString($value->library);
|
$libspec = H5PCore::libraryFromString($value->library);
|
||||||
$library = $this->h5pC->loadLibrary($libspec['machineName'], $libspec['majorVersion'], $libspec['minorVersion']);
|
$library = $this->h5pC->loadLibrary($libspec['machineName'], $libspec['majorVersion'], $libspec['minorVersion']);
|
||||||
$library['semantics'] = json_decode($library['semantics']);
|
$library['semantics'] = $this->h5pC->loadLibrarySemantics($libspec['machineName'], $libspec['majorVersion'], $libspec['minorVersion']);
|
||||||
$this->libraries[$value->library] = $library;
|
$this->libraries[$value->library] = $library;
|
||||||
|
|
||||||
// Find all dependencies for this library
|
// Find all dependencies for this library
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint -W083 */
|
||||||
var H5PUpgrades = H5PUpgrades || {};
|
var H5PUpgrades = H5PUpgrades || {};
|
||||||
|
|
||||||
(function ($) {
|
(function ($) {
|
||||||
|
@ -212,18 +213,28 @@ var H5PUpgrades = H5PUpgrades || {};
|
||||||
var current = 0; // Track progress
|
var current = 0; // Track progress
|
||||||
asyncSerial(parameters, function (id, params, next) {
|
asyncSerial(parameters, function (id, params, next) {
|
||||||
|
|
||||||
|
try {
|
||||||
// Make params possible to work with
|
// Make params possible to work with
|
||||||
params = JSON.parse(params);
|
params = JSON.parse(params);
|
||||||
|
if (!(params instanceof Object)) {
|
||||||
|
throw true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (event) {
|
||||||
|
return next(info.errorContent.replace('%id', id) + ' ' + info.errorParamsBroken);
|
||||||
|
}
|
||||||
|
|
||||||
// Upgrade this content.
|
// Upgrade this content.
|
||||||
self.upgrade(info.library.name, new Version(info.library.version), self.version, params, function (err, params) {
|
self.upgrade(info.library.name, new Version(info.library.version), self.version, params, function (err, params) {
|
||||||
if (!err) {
|
if (err) {
|
||||||
|
return next(info.errorContent.replace('%id', id) + ' ' + err);
|
||||||
|
}
|
||||||
|
|
||||||
upgraded[id] = JSON.stringify(params);
|
upgraded[id] = JSON.stringify(params);
|
||||||
|
|
||||||
current++;
|
current++;
|
||||||
self.throbber.setProgress(Math.round((info.total - self.left + current) / (info.total / 100)) + ' %');
|
self.throbber.setProgress(Math.round((info.total - self.left + current) / (info.total / 100)) + ' %');
|
||||||
}
|
next();
|
||||||
next(err);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
|
@ -374,14 +385,16 @@ var H5PUpgrades = H5PUpgrades || {};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We found an upgrade hook, run it
|
// We found an upgrade hook, run it
|
||||||
if (upgrade.contentUpgrade !== undefined && typeof upgrade.contentUpgrade === 'function') {
|
var unnecessaryWrapper = (upgrade.contentUpgrade !== undefined ? upgrade.contentUpgrade : upgrade);
|
||||||
upgrade.contentUpgrade(params, function (err, upgradedParams) {
|
|
||||||
|
try {
|
||||||
|
unnecessaryWrapper(params, function (err, upgradedParams) {
|
||||||
params = upgradedParams;
|
params = upgradedParams;
|
||||||
nextMinor(err);
|
nextMinor(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
catch (err) {
|
||||||
nextMinor(info.errorScript.replace('%lib', library.name + ' ' + newVersion));
|
next(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, nextMajor);
|
}, nextMajor);
|
||||||
|
|
|
@ -0,0 +1,255 @@
|
||||||
|
var H5PDataView = (function ($) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new H5P data view.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @param {Object} container
|
||||||
|
* Element to clear out and append to.
|
||||||
|
* @param {String} source
|
||||||
|
* URL to get data from. Data format: {num: 123, rows:[[1,2,3],[2,4,6]]}
|
||||||
|
* @param {Array} headers
|
||||||
|
* List with column headers. Can be strings or objects with options like
|
||||||
|
* "text" and "sortable". E.g.
|
||||||
|
* [{text: 'Col 1', sortable: true}, 'Col 2', 'Col 3']
|
||||||
|
* @param {Object} l10n
|
||||||
|
* Localization / translations. e.g.
|
||||||
|
* {
|
||||||
|
* loading: 'Loading data.',
|
||||||
|
* ajaxFailed: 'Failed to load data.',
|
||||||
|
* noData: "There's no data available that matches your criteria.",
|
||||||
|
* currentPage: 'Page $current of $total',
|
||||||
|
* nextPage: 'Next page',
|
||||||
|
* previousPage: 'Previous page',
|
||||||
|
* search: 'Search'
|
||||||
|
* }
|
||||||
|
* @param {Object} classes
|
||||||
|
* Custom html classes to use on elements.
|
||||||
|
* e.g. {tableClass: 'fixed'}.
|
||||||
|
* @param {Array} filters
|
||||||
|
* Make it possible to filter/search in the given column.
|
||||||
|
* e.g. [null, true, null, null] will make it possible to do a text
|
||||||
|
* search in column 2.
|
||||||
|
* @param {Function} loaded
|
||||||
|
* Callback for when data has been loaded.
|
||||||
|
*/
|
||||||
|
function H5PDataView(container, source, headers, l10n, classes, filters, loaded) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.$container = $(container).addClass('h5p-data-view').html('');
|
||||||
|
|
||||||
|
self.source = source;
|
||||||
|
self.headers = headers;
|
||||||
|
self.l10n = l10n;
|
||||||
|
self.classes = (classes === undefined ? {} : classes);
|
||||||
|
self.filters = (filters === undefined ? [] : filters);
|
||||||
|
self.loaded = loaded;
|
||||||
|
|
||||||
|
self.limit = 20;
|
||||||
|
self.offset = 0;
|
||||||
|
self.filterOn = [];
|
||||||
|
|
||||||
|
self.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load data from source URL.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
H5PDataView.prototype.loadData = function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Throbb
|
||||||
|
self.setMessage(H5PUtils.throbber(self.l10n.loading));
|
||||||
|
|
||||||
|
// Create URL
|
||||||
|
var url = self.source;
|
||||||
|
url += (url.indexOf('?') === -1 ? '?' : '&') + 'offset=' + self.offset + '&limit=' + self.limit;
|
||||||
|
|
||||||
|
// Add sorting
|
||||||
|
if (self.sortBy !== undefined && self.sortDir !== undefined) {
|
||||||
|
url += '&sortBy=' + self.sortBy + '&sortDir=' + self.sortDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add filters
|
||||||
|
var filtering;
|
||||||
|
for (var i = 0; i < self.filterOn.length; i++) {
|
||||||
|
if (self.filterOn[i] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
filtering = true;
|
||||||
|
url += '&filters[' + i + ']=' + encodeURIComponent(self.filterOn[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire ajax request
|
||||||
|
$.ajax({
|
||||||
|
dataType: 'json',
|
||||||
|
cache: true,
|
||||||
|
url: url
|
||||||
|
}).fail(function () {
|
||||||
|
// Error handling
|
||||||
|
self.setMessage($('<p/>', {text: self.l10n.ajaxFailed}));
|
||||||
|
}).done(function (data) {
|
||||||
|
if (!data.rows.length) {
|
||||||
|
self.setMessage($('<p/>', {text: filtering ? self.l10n.noData : self.l10n.empty}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Update table data
|
||||||
|
self.updateTable(data.rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update pagination widget
|
||||||
|
self.updatePagination(data.num);
|
||||||
|
|
||||||
|
if (self.loaded !== undefined) {
|
||||||
|
self.loaded();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the given message to the user.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {jQuery} $message wrapper with message
|
||||||
|
*/
|
||||||
|
H5PDataView.prototype.setMessage = function ($message) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (self.table === undefined) {
|
||||||
|
self.$container.html('').append($message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.table.setBody($message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update table data.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {Array} rows
|
||||||
|
*/
|
||||||
|
H5PDataView.prototype.updateTable = function (rows) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (self.table === undefined) {
|
||||||
|
// Clear out container
|
||||||
|
self.$container.html('');
|
||||||
|
|
||||||
|
// Add filters
|
||||||
|
self.addFilters();
|
||||||
|
|
||||||
|
// Create new table
|
||||||
|
self.table = new H5PUtils.Table(self.classes, self.headers);
|
||||||
|
self.table.setHeaders(self.headers, function (col, dir) {
|
||||||
|
// Sorting column or direction has changed callback.
|
||||||
|
self.sortBy = col;
|
||||||
|
self.sortDir = dir;
|
||||||
|
self.loadData();
|
||||||
|
});
|
||||||
|
self.table.appendTo(self.$container);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add/update rows
|
||||||
|
self.table.setRows(rows);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update pagination widget.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {Number} num size of data collection
|
||||||
|
*/
|
||||||
|
H5PDataView.prototype.updatePagination = function (num) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (self.pagination === undefined) {
|
||||||
|
// Create new widget
|
||||||
|
var $pagerContainer = $('<div/>', {'class': 'h5p-pagination'});
|
||||||
|
self.pagination = new H5PUtils.Pagination(num, self.limit, function (offset) {
|
||||||
|
// Handle page changes in pagination widget
|
||||||
|
self.offset = offset;
|
||||||
|
self.loadData();
|
||||||
|
}, self.l10n);
|
||||||
|
|
||||||
|
self.pagination.appendTo($pagerContainer);
|
||||||
|
self.table.setFoot($pagerContainer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Update existing widget
|
||||||
|
self.pagination.update(num, self.limit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add filters.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
H5PDataView.prototype.addFilters = function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
for (var i = 0; i < self.filters.length; i++) {
|
||||||
|
if (self.filters[i] === true) {
|
||||||
|
// Add text input filter for col i
|
||||||
|
self.addTextFilter(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add text filter for given col num.
|
||||||
|
|
||||||
|
* @public
|
||||||
|
* @param {Number} col
|
||||||
|
*/
|
||||||
|
H5PDataView.prototype.addTextFilter = function (col) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find input value and filter on it.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var search = function () {
|
||||||
|
var filterOn = $input.val().replace(/^\s+|\s+$/g, '');
|
||||||
|
if (filterOn === '') {
|
||||||
|
filterOn = undefined;
|
||||||
|
}
|
||||||
|
if (filterOn !== self.filterOn[col]) {
|
||||||
|
self.filterOn[col] = filterOn;
|
||||||
|
self.loadData();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add text field for filtering
|
||||||
|
var typing;
|
||||||
|
var $input = $('<input/>', {
|
||||||
|
type: 'text',
|
||||||
|
placeholder: self.l10n.search,
|
||||||
|
on: {
|
||||||
|
'blur': function () {
|
||||||
|
clearTimeout(typing);
|
||||||
|
search();
|
||||||
|
},
|
||||||
|
'keyup': function (event) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
clearTimeout(typing);
|
||||||
|
search();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clearTimeout(typing);
|
||||||
|
typing = setTimeout(function () {
|
||||||
|
search();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).appendTo(self.$container);
|
||||||
|
};
|
||||||
|
|
||||||
|
return H5PDataView;
|
||||||
|
})(H5P.jQuery);
|
|
@ -1,3 +1,5 @@
|
||||||
|
/*jshint multistr: true */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -130,8 +132,8 @@ var H5P = H5P || (function () {
|
||||||
if (document.documentElement.requestFullScreen) {
|
if (document.documentElement.requestFullScreen) {
|
||||||
fullScreenBrowserPrefix = '';
|
fullScreenBrowserPrefix = '';
|
||||||
}
|
}
|
||||||
else if (document.documentElement.webkitRequestFullScreen
|
else if (document.documentElement.webkitRequestFullScreen &&
|
||||||
&& navigator.userAgent.indexOf('Android') === -1 // Skip Android
|
navigator.userAgent.indexOf('Android') === -1 // Skip Android
|
||||||
) {
|
) {
|
||||||
safariBrowser = navigator.userAgent.match(/Version\/(\d)/);
|
safariBrowser = navigator.userAgent.match(/Version\/(\d)/);
|
||||||
safariBrowser = (safariBrowser === null ? 0 : parseInt(safariBrowser[1]));
|
safariBrowser = (safariBrowser === null ? 0 : parseInt(safariBrowser[1]));
|
||||||
|
|
|
@ -257,7 +257,7 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
|
||||||
H5PLibraryDetails.updatePager();
|
H5PLibraryDetails.updatePager();
|
||||||
};
|
};
|
||||||
|
|
||||||
var inputTimer = undefined;
|
var inputTimer;
|
||||||
$('input', H5PLibraryDetails.$search).on('change keypress paste input', function () {
|
$('input', H5PLibraryDetails.$search).on('change keypress paste input', function () {
|
||||||
// Here we start the filtering
|
// Here we start the filtering
|
||||||
// We wait at least 500 ms after last input to perform search
|
// We wait at least 500 ms after last input to perform search
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint multistr: true */
|
||||||
var H5PLibraryList = H5PLibraryList || {};
|
var H5PLibraryList = H5PLibraryList || {};
|
||||||
|
|
||||||
(function ($) {
|
(function ($) {
|
||||||
|
|
349
js/h5p-utils.js
349
js/h5p-utils.js
|
@ -130,4 +130,353 @@ var H5PUtils = H5PUtils || {};
|
||||||
return $container;
|
return $container;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic table class with useful helpers.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @param {Object} classes
|
||||||
|
* Custom html classes to use on elements.
|
||||||
|
* e.g. {tableClass: 'fixed'}.
|
||||||
|
*/
|
||||||
|
H5PUtils.Table = function (classes) {
|
||||||
|
var numCols;
|
||||||
|
var sortByCol;
|
||||||
|
var $sortCol;
|
||||||
|
var sortCol;
|
||||||
|
var sortDir;
|
||||||
|
|
||||||
|
// Create basic table
|
||||||
|
var tableOptions = {};
|
||||||
|
if (classes.table !== undefined) {
|
||||||
|
tableOptions['class'] = classes.table;
|
||||||
|
}
|
||||||
|
var $table = $('<table/>', tableOptions);
|
||||||
|
var $thead = $('<thead/>').appendTo($table);
|
||||||
|
var $tfoot = $('<tfoot/>').appendTo($table);
|
||||||
|
var $tbody = $('<tbody/>').appendTo($table);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add columns to given table row.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {jQuery} $tr Table row
|
||||||
|
* @param {(String|Object)} col Column properties
|
||||||
|
* @param {Number} id Used to seperate the columns
|
||||||
|
*/
|
||||||
|
var addCol = function ($tr, col, id) {
|
||||||
|
var options = {
|
||||||
|
on: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!(col instanceof Object)) {
|
||||||
|
options.text = col;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (col.text !== undefined) {
|
||||||
|
options.text = col.text;
|
||||||
|
}
|
||||||
|
if (col.class !== undefined) {
|
||||||
|
options.class = col.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortByCol !== undefined && col.sortable === true) {
|
||||||
|
// Make sortable
|
||||||
|
options.role = 'button';
|
||||||
|
options.tabIndex = 1;
|
||||||
|
|
||||||
|
// This is the first sortable column, use as default sort
|
||||||
|
if (sortCol === undefined) {
|
||||||
|
sortCol = id;
|
||||||
|
sortDir = 0;
|
||||||
|
options['class'] = 'h5p-sort';
|
||||||
|
}
|
||||||
|
|
||||||
|
options.on.click = function () {
|
||||||
|
sort($th, id);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append
|
||||||
|
var $th = $('<th>', options).appendTo($tr);
|
||||||
|
if (sortCol === id) {
|
||||||
|
$sortCol = $th; // Default sort column
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the UI when a column header has been clicked.
|
||||||
|
* Triggers sorting callback.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {jQuery} $th Table header
|
||||||
|
* @param {Number} id Used to seperate the columns
|
||||||
|
*/
|
||||||
|
var sort = function ($th, id) {
|
||||||
|
if (id === sortCol) {
|
||||||
|
// Change sorting direction
|
||||||
|
if (sortDir === 0) {
|
||||||
|
sortDir = 1;
|
||||||
|
$th.addClass('h5p-reverse');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sortDir = 0;
|
||||||
|
$th.removeClass('h5p-reverse');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Change sorting column
|
||||||
|
$sortCol.removeClass('h5p-sort').removeClass('h5p-reverse');
|
||||||
|
$sortCol = $th.addClass('h5p-sort');
|
||||||
|
sortCol = id;
|
||||||
|
sortDir = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sortByCol(sortCol, sortDir);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set table headers.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {Array} cols
|
||||||
|
* Table header data. Can be strings or objects with options like
|
||||||
|
* "text" and "sortable". E.g.
|
||||||
|
* [{text: 'Col 1', sortable: true}, 'Col 2', 'Col 3']
|
||||||
|
* @param {Function} sort Callback which is runned when sorting changes
|
||||||
|
*/
|
||||||
|
this.setHeaders = function (cols, sort) {
|
||||||
|
numCols = cols.length;
|
||||||
|
sortByCol = sort;
|
||||||
|
|
||||||
|
// Create new head
|
||||||
|
var $newThead = $('<thead/>');
|
||||||
|
var $tr = $('<tr/>').appendTo($newThead);
|
||||||
|
for (var i = 0; i < cols.length; i++) {
|
||||||
|
addCol($tr, cols[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update DOM
|
||||||
|
$thead.replaceWith($newThead);
|
||||||
|
$thead = $newThead;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set table rows.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {Array} rows Table rows with cols: [[1,'hello',3],[2,'asd',6]]
|
||||||
|
*/
|
||||||
|
this.setRows = function (rows) {
|
||||||
|
var $newTbody = $('<tbody/>');
|
||||||
|
|
||||||
|
for (var i = 0; i < rows.length; i++) {
|
||||||
|
var $tr = $('<tr/>').appendTo($newTbody);
|
||||||
|
|
||||||
|
for (var j = 0; j < rows[i].length; j++) {
|
||||||
|
$('<td>', {
|
||||||
|
html: rows[i][j]
|
||||||
|
}).appendTo($tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$tbody.replaceWith($newTbody);
|
||||||
|
$tbody = $newTbody;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set custom table body content. This can be a message or a throbber.
|
||||||
|
* Will cover all table columns.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {jQuery} $content Custom content
|
||||||
|
*/
|
||||||
|
this.setBody = function ($content) {
|
||||||
|
var $newTbody = $('<tbody/>');
|
||||||
|
var $tr = $('<tr/>').appendTo($newTbody);
|
||||||
|
$('<td>', {
|
||||||
|
colspan: numCols
|
||||||
|
}).append($content).appendTo($tr);
|
||||||
|
$tbody.replaceWith($newTbody);
|
||||||
|
$tbody = $newTbody;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set custom table foot content. This can be a pagination widget.
|
||||||
|
* Will cover all table columns.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {jQuery} $content Custom content
|
||||||
|
*/
|
||||||
|
this.setFoot = function ($content) {
|
||||||
|
var $newTfoot = $('<tfoot/>');
|
||||||
|
var $tr = $('<tr/>').appendTo($newTfoot);
|
||||||
|
$('<td>', {
|
||||||
|
colspan: numCols
|
||||||
|
}).append($content).appendTo($tr);
|
||||||
|
$tfoot.replaceWith($newTfoot);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the table to the given container.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {jQuery} $container
|
||||||
|
*/
|
||||||
|
this.appendTo = function ($container) {
|
||||||
|
$table.appendTo($container);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic pagination class. Creates a useful pagination widget.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @param {Number} num Total number of items to pagiate.
|
||||||
|
* @param {Number} limit Number of items to dispaly per page.
|
||||||
|
* @param {Function} goneTo
|
||||||
|
* Callback which is fired when the user wants to go to another page.
|
||||||
|
* @param {Object} l10n
|
||||||
|
* Localization / translations. e.g.
|
||||||
|
* {
|
||||||
|
* currentPage: 'Page $current of $total',
|
||||||
|
* nextPage: 'Next page',
|
||||||
|
* previousPage: 'Previous page'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
H5PUtils.Pagination = function (num, limit, goneTo, l10n) {
|
||||||
|
var current = 0;
|
||||||
|
var pages = Math.ceil(num / limit);
|
||||||
|
|
||||||
|
// Create components
|
||||||
|
|
||||||
|
// Previous button
|
||||||
|
var $left = $('<button/>', {
|
||||||
|
html: '<',
|
||||||
|
'class': 'button',
|
||||||
|
title: l10n.previousPage
|
||||||
|
}).click(function () {
|
||||||
|
goTo(current - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Current page text
|
||||||
|
var $text = $('<span/>').click(function () {
|
||||||
|
$input.width($text.width()).show().val(current + 1).focus();
|
||||||
|
$text.hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Jump to page input
|
||||||
|
var $input = $('<input/>', {
|
||||||
|
type: 'number',
|
||||||
|
min : 1,
|
||||||
|
max: pages,
|
||||||
|
on: {
|
||||||
|
'blur': function () {
|
||||||
|
gotInput();
|
||||||
|
},
|
||||||
|
'keyup': function (event) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
gotInput();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).hide();
|
||||||
|
|
||||||
|
// Next button
|
||||||
|
var $right = $('<button/>', {
|
||||||
|
html: '>',
|
||||||
|
'class': 'button',
|
||||||
|
title: l10n.nextPage
|
||||||
|
}).click(function () {
|
||||||
|
goTo(current + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check what page the user has typed in and jump to it.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var gotInput = function () {
|
||||||
|
var page = parseInt($input.hide().val());
|
||||||
|
if (!isNaN(page)) {
|
||||||
|
goTo(page - 1);
|
||||||
|
}
|
||||||
|
$text.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update UI elements.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var updateUI = function () {
|
||||||
|
var next = current + 1;
|
||||||
|
|
||||||
|
// Disable or enable buttons
|
||||||
|
$left.attr('disabled', current === 0);
|
||||||
|
$right.attr('disabled', next === pages);
|
||||||
|
|
||||||
|
// Update counter
|
||||||
|
$text.html(l10n.currentPage.replace('$current', next).replace('$total', pages));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to go to the requested page.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Number} page
|
||||||
|
*/
|
||||||
|
var goTo = function (page) {
|
||||||
|
if (page === current || page < 0 || page >= pages) {
|
||||||
|
return; // Invalid page number
|
||||||
|
}
|
||||||
|
current = page;
|
||||||
|
|
||||||
|
updateUI();
|
||||||
|
|
||||||
|
// Fire callback
|
||||||
|
goneTo(page * limit);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update number of items and limit.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {Number} newNum Total number of items to pagiate.
|
||||||
|
* @param {Number} newLimit Number of items to dispaly per page.
|
||||||
|
*/
|
||||||
|
this.update = function (newNum, newLimit) {
|
||||||
|
if (newNum !== num || newLimit !== limit) {
|
||||||
|
// Update num and limit
|
||||||
|
num = newNum;
|
||||||
|
limit = newLimit;
|
||||||
|
pages = Math.ceil(num / limit);
|
||||||
|
$input.attr('max', pages);
|
||||||
|
|
||||||
|
if (current >= pages) {
|
||||||
|
// Content is gone, move to last page.
|
||||||
|
goTo(pages - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the pagination widget to the given container.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {jQuery} $container
|
||||||
|
*/
|
||||||
|
this.appendTo = function ($container) {
|
||||||
|
$left.add($text).add($input).add($right).appendTo($container);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update UI
|
||||||
|
updateUI();
|
||||||
|
};
|
||||||
|
|
||||||
})(H5P.jQuery);
|
})(H5P.jQuery);
|
137
js/h5p.js
137
js/h5p.js
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint multistr: true */
|
||||||
// TODO: Should we split up the generic parts needed by the editor(and others), and the parts needed to "run" H5Ps?
|
// TODO: Should we split up the generic parts needed by the editor(and others), and the parts needed to "run" H5Ps?
|
||||||
var H5P = H5P || {};
|
var H5P = H5P || {};
|
||||||
|
|
||||||
|
@ -13,9 +14,7 @@ H5P.instances = [];
|
||||||
if (document.documentElement.requestFullScreen) {
|
if (document.documentElement.requestFullScreen) {
|
||||||
H5P.fullScreenBrowserPrefix = '';
|
H5P.fullScreenBrowserPrefix = '';
|
||||||
}
|
}
|
||||||
else if (document.documentElement.webkitRequestFullScreen
|
else if (document.documentElement.webkitRequestFullScreen) {
|
||||||
&& navigator.userAgent.indexOf('Android') === -1 // Skip Android
|
|
||||||
) {
|
|
||||||
H5P.safariBrowser = navigator.userAgent.match(/Version\/(\d)/);
|
H5P.safariBrowser = navigator.userAgent.match(/Version\/(\d)/);
|
||||||
H5P.safariBrowser = (H5P.safariBrowser === null ? 0 : parseInt(H5P.safariBrowser[1]));
|
H5P.safariBrowser = (H5P.safariBrowser === null ? 0 : parseInt(H5P.safariBrowser[1]));
|
||||||
|
|
||||||
|
@ -31,6 +30,9 @@ else if (document.documentElement.msRequestFullscreen) {
|
||||||
H5P.fullScreenBrowserPrefix = 'ms';
|
H5P.fullScreenBrowserPrefix = 'ms';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep track of when the H5Ps where started
|
||||||
|
H5P.opened = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize H5P content.
|
* Initialize H5P content.
|
||||||
* Scans for ".h5p-content" in the document and initializes H5P instances where found.
|
* Scans for ".h5p-content" in the document and initializes H5P instances where found.
|
||||||
|
@ -64,7 +66,7 @@ H5P.init = function () {
|
||||||
H5P.jQuery('<div class="h5p-content-controls"><div role="button" tabindex="1" class="h5p-enable-fullscreen" title="' + H5P.t('fullscreen') + '"></div></div>').prependTo($container).children().click(function () {
|
H5P.jQuery('<div class="h5p-content-controls"><div role="button" tabindex="1" class="h5p-enable-fullscreen" title="' + H5P.t('fullscreen') + '"></div></div>').prependTo($container).children().click(function () {
|
||||||
H5P.fullScreen($container, instance);
|
H5P.fullScreen($container, instance);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
var $actions = H5P.jQuery('<ul class="h5p-actions"></ul>');
|
var $actions = H5P.jQuery('<ul class="h5p-actions"></ul>');
|
||||||
if (contentData.exportUrl !== '') {
|
if (contentData.exportUrl !== '') {
|
||||||
|
@ -73,12 +75,12 @@ H5P.init = function () {
|
||||||
window.location.href = contentData.exportUrl;
|
window.location.href = contentData.exportUrl;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (instance.getCopyrights !== undefined) {
|
|
||||||
// Display copyrights button
|
// Display copyrights button
|
||||||
H5P.jQuery('<li class="h5p-button h5p-copyrights" role="button" tabindex="1" title="' + H5P.t('copyrightsDescription') + '">' + H5P.t('copyrights') + '</li>').appendTo($actions).click(function () {
|
H5P.jQuery('<li class="h5p-button h5p-copyrights" role="button" tabindex="1" title="' + H5P.t('copyrightsDescription') + '">' + H5P.t('copyrights') + '</li>').appendTo($actions).click(function () {
|
||||||
H5P.openCopyrightsDialog($actions, instance);
|
H5P.openCopyrightsDialog($actions, instance, library.params, contentId);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
if (contentData.embedCode !== undefined) {
|
if (contentData.embedCode !== undefined) {
|
||||||
// Display embed button
|
// Display embed button
|
||||||
H5P.jQuery('<li class="h5p-button h5p-embed" role="button" tabindex="1" title="' + H5P.t('embedDescription') + '">' + H5P.t('embed') + '</li>').appendTo($actions).click(function () {
|
H5P.jQuery('<li class="h5p-button h5p-embed" role="button" tabindex="1" title="' + H5P.t('embedDescription') + '">' + H5P.t('embed') + '</li>').appendTo($actions).click(function () {
|
||||||
|
@ -90,6 +92,16 @@ H5P.init = function () {
|
||||||
}
|
}
|
||||||
$actions.insertAfter($container);
|
$actions.insertAfter($container);
|
||||||
|
|
||||||
|
// Keep track of when we started
|
||||||
|
H5P.opened[contentId] = new Date();
|
||||||
|
|
||||||
|
// Handle events when the user finishes the content. Useful for logging exercise results.
|
||||||
|
instance.$.on('finish', function (event) {
|
||||||
|
if (event.data !== undefined) {
|
||||||
|
H5P.setFinished(contentId, event.data.score, event.data.maxScore, event.data.time);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (H5P.isFramed) {
|
if (H5P.isFramed) {
|
||||||
// Make it possible to resize the iframe when the content changes size. This way we get no scrollbars.
|
// Make it possible to resize the iframe when the content changes size. This way we get no scrollbars.
|
||||||
var iframe = window.parent.document.getElementById('h5p-iframe-' + contentId);
|
var iframe = window.parent.document.getElementById('h5p-iframe-' + contentId);
|
||||||
|
@ -122,6 +134,7 @@ H5P.init = function () {
|
||||||
});
|
});
|
||||||
H5P.instances.push(instance);
|
H5P.instances.push(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.on('xAPI', H5P.xAPIListener);
|
instance.on('xAPI', H5P.xAPIListener);
|
||||||
|
|
||||||
// Resize everything when window is resized.
|
// Resize everything when window is resized.
|
||||||
|
@ -303,7 +316,7 @@ H5P.getPath = function (path, contentId) {
|
||||||
if (contentId !== undefined) {
|
if (contentId !== undefined) {
|
||||||
prefix = H5PIntegration.getContentPath(contentId);
|
prefix = H5PIntegration.getContentPath(contentId);
|
||||||
}
|
}
|
||||||
else if (window['H5PEditor'] !== undefined) {
|
else if (window.H5PEditor !== undefined) {
|
||||||
prefix = H5PEditor.filesPath;
|
prefix = H5PEditor.filesPath;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -357,10 +370,11 @@ H5P.classFromName = function (name) {
|
||||||
* @param {Object} The parent of this H5P
|
* @param {Object} The parent of this H5P
|
||||||
* @return {Object} Instance.
|
* @return {Object} Instance.
|
||||||
*/
|
*/
|
||||||
H5P.newRunnable = function (library, contentId, $attachTo, skipResize, parent) {
|
H5P.newRunnable = function (library, contentId, $attachTo, skipResize) {
|
||||||
|
var nameSplit, versionSplit;
|
||||||
try {
|
try {
|
||||||
var nameSplit = library.library.split(' ', 2);
|
nameSplit = library.library.split(' ', 2);
|
||||||
var versionSplit = nameSplit[1].split('.', 2);
|
versionSplit = nameSplit[1].split('.', 2);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
return H5P.error('Invalid library string: ' + library.library);
|
return H5P.error('Invalid library string: ' + library.library);
|
||||||
|
@ -372,12 +386,13 @@ H5P.newRunnable = function (library, contentId, $attachTo, skipResize, parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find constructor function
|
// Find constructor function
|
||||||
|
var constructor;
|
||||||
try {
|
try {
|
||||||
nameSplit = nameSplit[0].split('.');
|
nameSplit = nameSplit[0].split('.');
|
||||||
var constructor = window;
|
constructor = window;
|
||||||
for (var i = 0; i < nameSplit.length; i++) {
|
for (var i = 0; i < nameSplit.length; i++) {
|
||||||
constructor = constructor[nameSplit[i]];
|
constructor = constructor[nameSplit[i]];
|
||||||
};
|
}
|
||||||
if (typeof constructor !== 'function') {
|
if (typeof constructor !== 'function') {
|
||||||
throw null;
|
throw null;
|
||||||
}
|
}
|
||||||
|
@ -632,19 +647,77 @@ H5P.Dialog = function (name, title, content, $element) {
|
||||||
* @param {object} instance to get copyright information from.
|
* @param {object} instance to get copyright information from.
|
||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
H5P.openCopyrightsDialog = function ($element, instance) {
|
H5P.openCopyrightsDialog = function ($element, instance, parameters, contentId) {
|
||||||
var copyrights = instance.getCopyrights();
|
var copyrights;
|
||||||
|
if (instance.getCopyrights !== undefined) {
|
||||||
|
// Use the instance's own copyright generator
|
||||||
|
copyrights = instance.getCopyrights();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Create a generic flat copyright list
|
||||||
|
copyrights = new H5P.ContentCopyrights();
|
||||||
|
H5P.findCopyrights(copyrights, parameters, contentId);
|
||||||
|
}
|
||||||
|
|
||||||
if (copyrights !== undefined) {
|
if (copyrights !== undefined) {
|
||||||
|
// Convert to string
|
||||||
copyrights = copyrights.toString();
|
copyrights = copyrights.toString();
|
||||||
}
|
}
|
||||||
if (copyrights === undefined || copyrights === '') {
|
if (copyrights === undefined || copyrights === '') {
|
||||||
|
// Use no copyrights default text
|
||||||
copyrights = H5P.t('noCopyrights');
|
copyrights = H5P.t('noCopyrights');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open dialog with copyright information
|
||||||
var dialog = new H5P.Dialog('copyrights', H5P.t('copyrightInformation'), copyrights, $element);
|
var dialog = new H5P.Dialog('copyrights', H5P.t('copyrightInformation'), copyrights, $element);
|
||||||
dialog.open();
|
dialog.open();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather a flat list of copyright information from the given parameters.
|
||||||
|
*
|
||||||
|
* @param {H5P.ContentCopyrights} info Used to collect all information in.
|
||||||
|
* @param {(Object|Arrray)} parameters To search for file objects in.
|
||||||
|
* @param {Number} contentId Used to insert thumbnails for images.
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
H5P.findCopyrights = function (info, parameters, contentId) {
|
||||||
|
// Cycle through parameters
|
||||||
|
for (var field in parameters) {
|
||||||
|
if (!parameters.hasOwnProperty(field)) {
|
||||||
|
continue; // Do not check
|
||||||
|
}
|
||||||
|
var value = parameters[field];
|
||||||
|
|
||||||
|
if (value instanceof Array) {
|
||||||
|
// Cycle through array
|
||||||
|
H5P.findCopyrights(info, value, contentId);
|
||||||
|
}
|
||||||
|
else if (value instanceof Object) {
|
||||||
|
// Check if object is a file with copyrights
|
||||||
|
if (value.copyright === undefined ||
|
||||||
|
value.copyright.license === undefined ||
|
||||||
|
value.path === undefined ||
|
||||||
|
value.mime === undefined) {
|
||||||
|
|
||||||
|
// Nope, cycle throught object
|
||||||
|
H5P.findCopyrights(info, value, contentId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Found file, add copyrights
|
||||||
|
var copyrights = new H5P.MediaCopyright(value.copyright);
|
||||||
|
if (value.width !== undefined && value.height !== undefined) {
|
||||||
|
copyrights.setThumbnail(new H5P.Thumbnail(H5P.getPath(value.path, contentId), value.width, value.height));
|
||||||
|
}
|
||||||
|
info.addMedia(copyrights);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a dialog containing the embed code.
|
* Display a dialog containing the embed code.
|
||||||
*
|
*
|
||||||
|
@ -716,7 +789,7 @@ H5P.ContentCopyrights = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add sub content rights
|
// Add sub content rights
|
||||||
for (var i = 0; i < content.length; i++) {
|
for (i = 0; i < content.length; i++) {
|
||||||
html += content[i];
|
html += content[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1113,16 +1186,38 @@ H5P.shuffleArray = function (array) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED! Do not use this function directly, trigger the finish event
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
* Post finished results for user.
|
* Post finished results for user.
|
||||||
* TODO: Should we use events instead? That way the parent can handle the results of the child.
|
|
||||||
*
|
*
|
||||||
* @param {Number} contentId
|
* @param {Number} contentId
|
||||||
* @param {Number} points
|
* @param {Number} score achieved
|
||||||
* @param {Number} maxPoints
|
* @param {Number} maxScore that can be achieved
|
||||||
|
* @param {Number} time optional reported time usage
|
||||||
*/
|
*/
|
||||||
H5P.setFinished = function (contentId, points, maxPoints) {
|
H5P.setFinished = function (contentId, score, maxScore, time) {
|
||||||
if (H5P.postUserStatistics === true) {
|
if (H5P.postUserStatistics === true) {
|
||||||
H5P.jQuery.post(H5P.ajaxPath + 'setFinished', {contentId: contentId, points: points, maxPoints: maxPoints});
|
/**
|
||||||
|
* Return unix timestamp for the given JS Date.
|
||||||
|
*
|
||||||
|
* @param {Date} date
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
var toUnix = function (date) {
|
||||||
|
return Math.round(date.getTime() / 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Post the results
|
||||||
|
// TODO: Should we use a variable with the complete path?
|
||||||
|
H5P.jQuery.post(H5P.ajaxPath + 'setFinished', {
|
||||||
|
contentId: contentId,
|
||||||
|
score: score,
|
||||||
|
maxScore: maxScore,
|
||||||
|
opened: toUnix(H5P.opened[contentId]),
|
||||||
|
finished: toUnix(new Date()),
|
||||||
|
time: time
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -11,7 +11,8 @@
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.h5p-admin-table tr:nth-child(odd) {
|
.h5p-admin-table tr:nth-child(odd),
|
||||||
|
.h5p-data-view tr:nth-child(odd) {
|
||||||
background-color: #F9F9F9;
|
background-color: #F9F9F9;
|
||||||
}
|
}
|
||||||
.h5p-admin-table tbody tr:hover {
|
.h5p-admin-table tbody tr:hover {
|
||||||
|
@ -245,3 +246,40 @@ button.h5p-admin.disabled:hover {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
#h5p-admin-container .h5p-admin-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.h5p-pagination {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.h5p-pagination > span, .h5p-pagination > input {
|
||||||
|
margin: 0 1em;
|
||||||
|
}
|
||||||
|
.h5p-data-view input[type="text"] {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.h5p-data-view input[type="text"]::-ms-clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h5p-data-view th[role="button"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.h5p-data-view th[role="button"].h5p-sort:after,
|
||||||
|
.h5p-data-view th[role="button"]:hover:after,
|
||||||
|
.h5p-data-view th[role="button"].h5p-sort.h5p-reverse:hover:after {
|
||||||
|
content: "\25BE";
|
||||||
|
position: relative;
|
||||||
|
left: 0.5em;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
.h5p-data-view th[role="button"].h5p-sort.h5p-reverse:after,
|
||||||
|
.h5p-data-view th[role="button"].h5p-sort:hover:after {
|
||||||
|
content: "\25B4";
|
||||||
|
top: -2px;
|
||||||
|
}
|
||||||
|
.h5p-data-view th[role="button"]:hover:after,
|
||||||
|
.h5p-data-view th[role="button"].h5p-sort.h5p-reverse:hover:after,
|
||||||
|
.h5p-data-view th[role="button"].h5p-sort:hover:after {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
|
@ -234,6 +234,8 @@ div.h5p-fullscreen {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
margin: 0.25em 0;
|
margin: 0.25em 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
line-height: 1.25em;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
.h5p-embed-dialog .h5p-inner {
|
.h5p-embed-dialog .h5p-inner {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
|
Loading…
Reference in New Issue