diff --git a/h5p-development.class.php b/h5p-development.class.php index d599ca1..75e9daf 100644 --- a/h5p-development.class.php +++ b/h5p-development.class.php @@ -30,7 +30,7 @@ class H5PDevelopment { $this->findLibraries($filesPath . '/development'); } } - + /** * Get contents of file. * @@ -41,15 +41,15 @@ class H5PDevelopment { if (file_exists($file) === FALSE) { return NULL; } - + $contents = file_get_contents($file); if ($contents === FALSE) { return NULL; } - + return $contents; } - + /** * Scans development directory and find all libraries. * @@ -57,39 +57,39 @@ class H5PDevelopment { */ private function findLibraries($path) { $this->libraries = array(); - + if (is_dir($path) === FALSE) { - return; + return; } - + $contents = scandir($path); - + for ($i = 0, $s = count($contents); $i < $s; $i++) { if ($contents[$i]{0} === '.') { continue; // Skip hidden stuff. } - + $libraryPath = $path . '/' . $contents[$i]; $libraryJSON = $this->getFileContents($libraryPath . '/library.json'); if ($libraryJSON === NULL) { continue; // No JSON file, skip. } - + $library = json_decode($libraryJSON, TRUE); if ($library === FALSE) { continue; // Invalid JSON. } - + // 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']); $this->h5pF->saveLibraryData($library, $library['libraryId'] === FALSE); - + $library['path'] = $libraryPath; $this->libraries[H5PDevelopment::libraryToString($library['machineName'], $library['majorVersion'], $library['minorVersion'])] = $library; } - + // TODO: Should we remove libraries without files? Not really needed, but must be cleaned up some time, right? // Go trough libraries and insert dependencies. Missing deps. will just be ignored and not available. (I guess?!) @@ -106,17 +106,17 @@ class H5PDevelopment { } // TODO: Deps must be inserted into h5p_nodes_libraries as well... ? But only if they are used?! } - + /** * @return array Libraris in development folder. */ public function getLibraries() { return $this->libraries; } - + /** * Get library - * + * * @param string $name of the library. * @param int $majorVersion of the library. * @param int $minorVersion of the library. @@ -126,10 +126,10 @@ class H5PDevelopment { $library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion); return isset($this->libraries[$library]) === TRUE ? $this->libraries[$library] : NULL; } - + /** * Get semantics for the given library. - * + * * @param string $name of the library. * @param int $majorVersion of the library. * @param int $minorVersion of the library. @@ -137,32 +137,32 @@ class H5PDevelopment { */ public function getSemantics($name, $majorVersion, $minorVersion) { $library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion); - + if (isset($this->libraries[$library]) === FALSE) { return NULL; } - + return $this->getFileContents($this->libraries[$library]['path'] . '/semantics.json'); } - + /** * Get translations for the given library. - * + * * @param string $name of the library. * @param int $majorVersion of the library. * @param int $minorVersion of the library. * @return string Translation */ - public function getLanguage($name, $majorVersion, $minorVersion) { + public function getLanguage($name, $majorVersion, $minorVersion, $language) { $library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion); - + if (isset($this->libraries[$library]) === FALSE) { return NULL; } - - return $this->getFileContents($this->libraries[$library]['path'] . '/language/' . $this->language . '.json'); + + return $this->getFileContents($this->libraries[$library]['path'] . '/language/' . $language . '.json'); } - + /** * Writes library as string on the form "name majorVersion.minorVersion" * @@ -175,4 +175,3 @@ class H5PDevelopment { return $name . ' ' . $majorVersion . '.' . $minorVersion; } } - diff --git a/h5p.classes.php b/h5p.classes.php index f6f9855..dffb390 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -394,10 +394,10 @@ interface H5PFrameworkInterface { /** * Delete a library from database and file system * - * @param int $libraryId - * Library identifier + * @param stdClass $library + * Library object with id, name, major version and minor version. */ - public function deleteLibrary($libraryId); + public function deleteLibrary($library); /** * Load content. @@ -444,57 +444,58 @@ interface H5PFrameworkInterface { public function loadContentDependencies($id, $type = NULL); /** - * Get data from cache. + * Get stored setting. * - * @param string $group - * Identifier for the cache group - * @param string $key - * Unique identifier within the group + * @param string $name + * Identifier for the setting + * @param string $default + * Optional default value if settings is not set * @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 - * The cache group where the data should be stored - * @param string $key - * A unique key identifying where the data should be stored - * @param mixed $data - * The data you want to cache + * @param string $name + * Identifier for the setting + * @param mixed $value Data + * Whatever we want to store as the setting */ - 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 - * Identifier for the cache group - * @param string $key - * Unique identifier within the group + * @param int $content_id + * @param string $parameters filtered */ - public function cacheDel($group, $key = NULL); + public function setFilteredParameters($content_id, $parameters = ''); /** - * Will invalidate the cache for the content that uses the specified library. - * This means that the content dependencies has to be rebuilt, and the parameters refiltered. + * Will clear filtered params for all the content that uses the specified + * 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. * * @param int $libraryId - * Identifier for a library + * @return int */ 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. - $this->h5pF->invalidateContentCache($library['libraryId']); + $this->h5pF->clearFilteredParameters($library['libraryId']); $upgradedLibsCount++; } @@ -1567,11 +1568,6 @@ class H5PCore { $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']; } @@ -1619,16 +1615,8 @@ class H5PCore { * @return Object NULL on failure. */ public function filterParameters($content) { - if (isset($content['filtered'])) { - $params = ($content['filtered'] === '' ? NULL : $content['filtered']); - } - else { - // TODO: Add filtered to all impl. and remove - $params = $this->h5pF->cacheGet('parameters', $content['id']); - } - - if ($params !== NULL) { - return $params; + if (isset($content['filtered']) && $content['filtered'] !== '') { + return $content['filtered']; } // Validate and filter against main library semantics. @@ -1655,7 +1643,7 @@ class H5PCore { } // Cache. - $this->h5pF->cacheSet('parameters', $content['id'], $params); + $this->h5pF->setFilteredParameters($content['id'], $params); return $params; } @@ -2598,7 +2586,7 @@ class H5PContentValidator { if (!isset($this->libraries[$value->library])) { $libspec = H5PCore::libraryFromString($value->library); $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; // Find all dependencies for this library diff --git a/js/h5p-content-upgrade.js b/js/h5p-content-upgrade.js index bbea037..ff3756f 100644 --- a/js/h5p-content-upgrade.js +++ b/js/h5p-content-upgrade.js @@ -1,19 +1,20 @@ +/*jshint -W083 */ var H5PUpgrades = H5PUpgrades || {}; (function ($) { var info, $container, librariesCache = {}; - + // Initialize $(document).ready(function () { // Get library info info = H5PIntegration.getLibraryInfo(); - + // Get and reset container $container = $('#h5p-admin-container').html('
' + info.message + '
'); - + // Make it possible to select version var $version = $(getVersionSelect(info.versions)).appendTo($container); - + // Add "go" button $('', { class: 'h5p-admin-upgrade-button', @@ -23,11 +24,11 @@ var H5PUpgrades = H5PUpgrades || {}; new ContentUpgrade($version.val()); } }).appendTo($container); - }); + }); /** * Generate html for version select. - * + * * @param {Object} versions * @returns {String} */ @@ -41,18 +42,18 @@ var H5PUpgrades = H5PUpgrades || {}; return html; } }; - + /** * Private. Helps process each property on the given object asynchronously in serial order. - * + * * @param {Object} obj * @param {Function} process * @param {Function} finished */ var asyncSerial = function (obj, process, finished) { var id, isArray = obj instanceof Array; - - // Keep track of each property that belongs to this object. + + // Keep track of each property that belongs to this object. if (!isArray) { var ids = []; for (id in obj) { @@ -61,9 +62,9 @@ var H5PUpgrades = H5PUpgrades || {}; } } } - + var i = -1; // Keeps track of the current property - + /** * Private. Process the next property */ @@ -71,10 +72,10 @@ var H5PUpgrades = H5PUpgrades || {}; id = isArray ? i : ids[i]; process(id, obj[id], check); }; - + /** * Private. Check if we're done or have an error. - * + * * @param {String} err */ var check = function (err) { @@ -89,13 +90,13 @@ var H5PUpgrades = H5PUpgrades || {}; } }, 0); }; - + check(); // Start }; - /** + /** * Make it easy to keep track of version details. - * + * * @param {String} version * @param {Number} libraryId * @returns {_L1.Version} @@ -103,19 +104,19 @@ var H5PUpgrades = H5PUpgrades || {}; function Version(version, libraryId) { if (libraryId !== undefined) { version = info.versions[libraryId]; - + // Public this.libraryId = libraryId; } var versionSplit = version.split('.', 3); - + // Public this.major = versionSplit[0]; this.minor = versionSplit[1]; - + /** * Public. Custom string for this object. - * + * * @returns {String} */ this.toString = function () { @@ -125,17 +126,17 @@ var H5PUpgrades = H5PUpgrades || {}; /** * Displays a throbber in the status field. - * + * * @param {String} msg * @returns {_L1.Throbber} */ function Throbber(msg) { var $throbber = H5PUtils.throbber(msg); $container.html('').append($throbber); - + /** * Makes it possible to set the progress. - * + * * @param {String} progress */ this.setProgress = function (progress) { @@ -145,16 +146,16 @@ var H5PUpgrades = H5PUpgrades || {}; /** * Start a new content upgrade. - * + * * @param {Number} libraryId * @returns {_L1.ContentUpgrade} */ function ContentUpgrade(libraryId) { var self = this; - + // Get selected version self.version = new Version(null, libraryId); - + // Create throbber with loading text and progress self.throbber = new Throbber(info.inProgress.replace('%ver', self.version)); @@ -164,36 +165,36 @@ var H5PUpgrades = H5PUpgrades || {}; token: info.token }); } - + /** * Get the next batch and start processing it. - * + * * @param {Object} outData */ ContentUpgrade.prototype.nextBatch = function (outData) { var self = this; - + $.post(info.infoUrl, outData, function (inData) { if (!(inData instanceof Object)) { // Print errors from backend return self.setStatus(inData); - } + } if (inData.left === 0) { // Nothing left to process return self.setStatus(info.done); } - + self.left = inData.left; self.token = inData.token; - + // Start processing self.processBatch(inData.params); }); }; - + /** * Set current status message. - * + * * @param {String} msg */ ContentUpgrade.prototype.setStatus = function (msg) { @@ -202,28 +203,38 @@ var H5PUpgrades = H5PUpgrades || {}; /** * Process the given parameters. - * + * * @param {Object} parameters */ ContentUpgrade.prototype.processBatch = function (parameters) { var self = this; var upgraded = {}; // Track upgraded params - + var current = 0; // Track progress asyncSerial(parameters, function (id, params, next) { - - // Make params possible to work with - params = JSON.parse(params); - + + try { + // Make params possible to work with + params = JSON.parse(params); + if (!(params instanceof Object)) { + throw true; + } + } + catch (event) { + return next(info.errorContent.replace('%id', id) + ' ' + info.errorParamsBroken); + } + // Upgrade this content. self.upgrade(info.library.name, new Version(info.library.version), self.version, params, function (err, params) { - if (!err) { - upgraded[id] = JSON.stringify(params); - - current++; - self.throbber.setProgress(Math.round((info.total - self.left + current) / (info.total / 100)) + ' %'); + if (err) { + return next(info.errorContent.replace('%id', id) + ' ' + err); } - next(err); + + upgraded[id] = JSON.stringify(params); + + current++; + self.throbber.setProgress(Math.round((info.total - self.left + current) / (info.total / 100)) + ' %'); + next(); }); }, function (err) { @@ -240,10 +251,10 @@ var H5PUpgrades = H5PUpgrades || {}; }); }); }; - + /** * Upgade the given content. - * + * * @param {String} name * @param {Version} oldVersion * @param {Version} newVersion @@ -253,19 +264,19 @@ var H5PUpgrades = H5PUpgrades || {}; */ ContentUpgrade.prototype.upgrade = function (name, oldVersion, newVersion, params, next) { var self = this; - + // Load library details and upgrade routines self.loadLibrary(name, newVersion, function (err, library) { if (err) { return next(err); } - + // Run upgrade routines on params self.processParams(library, oldVersion, newVersion, params, function (err, params) { if (err) { return next(err); } - + // Check if any of the sub-libraries need upgrading asyncSerial(library.semantics, function (index, field, next) { self.processField(field, params[field.name], function (err, upgradedParams) { @@ -280,24 +291,24 @@ var H5PUpgrades = H5PUpgrades || {}; }); }); }; - + /** * Load library data needed for content upgrade. - * + * * @param {String} name * @param {Version} version * @param {Function} next */ ContentUpgrade.prototype.loadLibrary = function (name, version, next) { var self = this; - + var key = name + '/' + version.major + '/' + version.minor; if (librariesCache[key] !== undefined) { // Library has been loaded before. Return cache. next(null, librariesCache[key]); return; } - + $.ajax({ dataType: 'json', cache: true, @@ -306,7 +317,7 @@ var H5PUpgrades = H5PUpgrades || {}; next(info.errorData.replace('%lib', name + ' ' + version)); }).done(function (library) { librariesCache[key] = library; - + if (library.upgradesScript) { self.loadScript(library.upgradesScript, function (err) { if (err) { @@ -320,10 +331,10 @@ var H5PUpgrades = H5PUpgrades || {}; } }); }; - + /** * Load script with upgrade hooks. - * + * * @param {String} url * @param {Function} next */ @@ -338,10 +349,10 @@ var H5PUpgrades = H5PUpgrades || {}; next(); }); }; - + /** * Run upgrade hooks on params. - * + * * @param {Object} library * @param {Version} oldVersion * @param {Version} newVersion @@ -354,7 +365,7 @@ var H5PUpgrades = H5PUpgrades || {}; // Upgrades script should be loaded so the upgrades should be here. return next(info.errorScript.replace('%lib', library.name + ' ' + newVersion)); } - + // No upgrades script. Move on return next(null, params); } @@ -362,7 +373,7 @@ var H5PUpgrades = H5PUpgrades || {}; // Run upgrade hooks. Start by going through major versions asyncSerial(H5PUpgrades[library.name], function (major, minors, nextMajor) { if (major < oldVersion.major || major > newVersion.major) { - // Older than the current version or newer than the selected + // Older than the current version or newer than the selected nextMajor(); } else { @@ -374,14 +385,16 @@ var H5PUpgrades = H5PUpgrades || {}; } else { // We found an upgrade hook, run it - if (upgrade.contentUpgrade !== undefined && typeof upgrade.contentUpgrade === 'function') { - upgrade.contentUpgrade(params, function (err, upgradedParams) { + var unnecessaryWrapper = (upgrade.contentUpgrade !== undefined ? upgrade.contentUpgrade : upgrade); + + try { + unnecessaryWrapper(params, function (err, upgradedParams) { params = upgradedParams; nextMinor(err); }); } - else { - nextMinor(info.errorScript.replace('%lib', library.name + ' ' + newVersion)); + catch (err) { + next(err); } } }, nextMajor); @@ -390,27 +403,27 @@ var H5PUpgrades = H5PUpgrades || {}; next(err, params); }); }; - + /** * Process parameter fields to find and upgrade sub-libraries. - * + * * @param {Object} field * @param {Object} params * @param {Function} next */ ContentUpgrade.prototype.processField = function (field, params, next) { var self = this; - + if (params === undefined) { return next(); } - + switch (field.type) { case 'library': if (params.library === undefined || params.params === undefined) { return next(); } - + // Look for available upgrades var usedLib = params.library.split(' ', 2); for (var i = 0; i < field.options.length; i++) { @@ -419,14 +432,14 @@ var H5PUpgrades = H5PUpgrades || {}; if (availableLib[1] === usedLib[1]) { return next(); // Same version } - + // We have different versions 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 next(); // Larger or same version that's available } - + // A newer version is available, upgrade params return self.upgrade(availableLib[0], usedVer, availableVer, params.params, function (err, upgraded) { if (!err) { @@ -484,4 +497,4 @@ var H5PUpgrades = H5PUpgrades || {}; } }; -})(H5P.jQuery); \ No newline at end of file +})(H5P.jQuery); diff --git a/js/h5p-embed.js b/js/h5p-embed.js index ae8efc2..b1b58c3 100644 --- a/js/h5p-embed.js +++ b/js/h5p-embed.js @@ -1,3 +1,5 @@ +/*jshint multistr: true */ + /** * */ @@ -5,7 +7,7 @@ var H5P = H5P || (function () { var head = document.getElementsByTagName('head')[0]; var contentId = 0; var contents = {}; - + /** * Wraps multiple content between a prefix and a suffix. */ @@ -16,25 +18,25 @@ var H5P = H5P || (function () { } return result; }; - + /** - * + * */ var loadContent = function (id, script) { var url = script.getAttribute('data-h5p'); var data, callback = 'H5P' + id; - + // Prevent duplicate loading. script.removeAttribute('data-h5p'); - + // Callback for when content data is loaded. window[callback] = function (content) { contents[id] = content; - + var iframe = document.createElement('iframe'); var parent = script.parentNode; parent.insertBefore(iframe, script); - + iframe.id = 'h5p-iframe-' + id; iframe.style.display = 'block'; iframe.style.width = '100%'; @@ -59,19 +61,19 @@ var H5P = H5P || (function () {