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..5b23280 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++; } @@ -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 $defaultLibraryWhitelistExtras = 'js css'; + public $librariesJsonData, $contentJsonData, $mainJsonData, $h5pF, $path, $development_mode, $h5pD, $disableFileCheck; const SECONDS_IN_WEEK = 604800; - public $librariesJsonData, $contentJsonData, $mainJsonData, $h5pF, $path, $development_mode, $h5pD; private $exportEnabled; /** @@ -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; } @@ -2309,6 +2297,10 @@ class H5PContentValidator { * FALSE if one or more files fail validation. Error message should be set accordingly by validator. */ public function validateContentFiles($contentPath, $isLibrary = FALSE) { + if ($this->h5pC->disableFileCheck === TRUE) { + return TRUE; + } + // Scan content directory for files, recurse into sub directories. $files = array_diff(scandir($contentPath), array('.','..')); $valid = TRUE; @@ -2598,7 +2590,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-data-view.js b/js/h5p-data-view.js new file mode 100644 index 0000000..323290a --- /dev/null +++ b/js/h5p-data-view.js @@ -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($('', {text: self.l10n.ajaxFailed})); + }).done(function (data) { + if (!data.rows.length) { + self.setMessage($('', {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 = $('', {'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 = $('', { + 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); 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 () {