diff --git a/fonts/FontAwesome.otf b/fonts/FontAwesome.otf
deleted file mode 100644
index 8b0f54e..0000000
Binary files a/fonts/FontAwesome.otf and /dev/null differ
diff --git a/fonts/fontawesome-webfont.eot b/fonts/fontawesome-webfont.eot
deleted file mode 100644
index 7c79c6a..0000000
Binary files a/fonts/fontawesome-webfont.eot and /dev/null differ
diff --git a/fonts/fontawesome-webfont.svg b/fonts/fontawesome-webfont.svg
deleted file mode 100644
index 45fdf33..0000000
--- a/fonts/fontawesome-webfont.svg
+++ /dev/null
@@ -1,414 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/fonts/fontawesome-webfont.ttf b/fonts/fontawesome-webfont.ttf
deleted file mode 100644
index e89738d..0000000
Binary files a/fonts/fontawesome-webfont.ttf and /dev/null differ
diff --git a/fonts/fontawesome-webfont.woff b/fonts/fontawesome-webfont.woff
deleted file mode 100644
index 8c1748a..0000000
Binary files a/fonts/fontawesome-webfont.woff and /dev/null differ
diff --git a/fonts/h5p.eot b/fonts/h5p.eot
index d74adc1..9680263 100644
Binary files a/fonts/h5p.eot and b/fonts/h5p.eot differ
diff --git a/fonts/h5p.svg b/fonts/h5p.svg
index 3364cd8..e4c9ef5 100644
--- a/fonts/h5p.svg
+++ b/fonts/h5p.svg
@@ -1,12 +1,42 @@
\ No newline at end of file
diff --git a/fonts/h5p.ttf b/fonts/h5p.ttf
index 904d19b..c0ffaf5 100644
Binary files a/fonts/h5p.ttf and b/fonts/h5p.ttf differ
diff --git a/fonts/h5p.woff b/fonts/h5p.woff
deleted file mode 100644
index de26840..0000000
Binary files a/fonts/h5p.woff and /dev/null differ
diff --git a/h5p.classes.php b/h5p.classes.php
index f5fa9ea..bf1b48d 100644
--- a/h5p.classes.php
+++ b/h5p.classes.php
@@ -55,6 +55,13 @@ interface H5PFrameworkInterface {
* @return string Path to the last uploaded h5p
*/
public function getUploadedH5pPath();
+
+ /**
+ * Get the list of the current installed libraries
+ *
+ * @return array Associative array containg one item per machine name. This item contains an array of libraries.
+ */
+ public function loadLibraries();
/**
* Get id to an excisting library
@@ -119,23 +126,23 @@ interface H5PFrameworkInterface {
* Object holding the information that is to be stored
*/
public function saveLibraryData(&$libraryData, $new = TRUE);
-
+
/**
- * Stores contentData
- *
- * @param string $contentJson
- * The content data that is to be stored
- * @param array $mainJsonData
- * The data extracted from the h5p.json file
- * @param array $mainLibraryId
- * Main library identifier
+ * Insert new content.
+ *
+ * @param object $content
* @param int $contentMainId
- * Any contentMainId defined by the framework, for instance to support revisioning
- * @param int $contentId
- * Framework specific id identifying the content
*/
- public function saveContentData($content, $contentMainId = NULL);
-
+ public function insertContent($content, $contentMainId = NULL);
+
+ /**
+ * Update old content.
+ *
+ * @param object $content
+ * @param int $contentMainId
+ */
+ public function updateContent($content, $contentMainId = NULL);
+
/**
* Save what libraries a library is dependending on
*
@@ -262,6 +269,51 @@ interface H5PFrameworkInterface {
* @return array
*/
public function loadContentDependencies($id, $type = NULL);
+
+ /**
+ * Get data from cache.
+ *
+ * @param string $group
+ * @param string $key
+ */
+ public function cacheGet($group, $key);
+
+ /**
+ * Store data in cache.
+ *
+ * @param string $group
+ * @param string $key
+ * @param mixed $data
+ */
+ public function cacheSet($group, $key, $data);
+
+ /**
+ * Delete data from cache.
+ *
+ * @param string $group
+ * @param string $key
+ */
+ public function cacheDel($group, $key = NULL);
+
+ /**
+ * 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.
+ *
+ * @param int $library_id
+ */
+ public function invalidateContentCache($library_id);
+
+ /**
+ * Get content without cache.
+ */
+ public function getNotCached();
+
+ /**
+ * Get number of contents using library as main library.
+ *
+ * @param int $library_id
+ */
+ public function getNumContent($library_id);
}
/**
@@ -998,6 +1050,9 @@ class H5PStorage {
if (isset($library['editorDependencies'])) {
$this->h5pF->saveLibraryDependencies($library['libraryId'], $library['editorDependencies'], 'editor');
}
+
+ // Make sure libraries dependencies, parameter filtering and export files gets regenerated for all content who uses this library.
+ $this->h5pF->invalidateContentCache($library['libraryId']);
}
}
@@ -1017,7 +1072,7 @@ class H5PStorage {
}
$content['library'] = $librariesInUse['preloaded-' . $this->h5pC->mainJsonData['mainLibrary']]['library'];
$content['params'] = file_get_contents($current_path . DIRECTORY_SEPARATOR . 'content.json');
- $contentId = $this->h5pF->saveContentData($content, $contentMainId);
+ $contentId = $this->h5pC->saveContent($content, $contentMainId);
$this->contentId = $contentId;
$contents_path = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR . 'content';
@@ -1105,96 +1160,86 @@ Class H5PExport {
$this->h5pF = $H5PFramework;
$this->h5pC = $H5PCore;
}
-
+
/**
* Return path to h5p package.
*
* Creates package if not already created
*
- * @param int/string $contentId
- * Identifier for this H5P
- * @param String $title
- * Title of H5P
- * @param string $language
- * Language code for H5P
+ * @param array $content
* @return string
- * Path to .h5p file
*/
- public function getExportPath($content) {
+ public function createExportFile($content) {
$h5pDir = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR;
$tempPath = $h5pDir . 'temp' . DIRECTORY_SEPARATOR . $content['id'];
$zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $content['id'] . '.h5p';
- // Check if h5p-package already exists.
- if (!file_exists($zipPath)) {
- // Temp dir to put the h5p files in
- @mkdir($tempPath, 0777, TRUE);
- @mkdir($h5pDir . 'exports', 0777, TRUE);
-
- // Create content folder
- if ($this->h5pC->copyFileTree($h5pDir . 'content' . DIRECTORY_SEPARATOR . $content['id'], $tempPath . DIRECTORY_SEPARATOR . 'content') === FALSE) {
- return FALSE;
- }
- file_put_contents($tempPath . DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR . 'content.json', $content['params']);
-
- // Make embedTypes into an array
- $embedTypes = explode(', ', $content['embedType']); // Won't content always be embedded in one way?
+ // Temp dir to put the h5p files in
+ @mkdir($tempPath, 0777, TRUE);
+ @mkdir($h5pDir . 'exports', 0777, TRUE);
- // Build h5p.json
- $h5pJson = array (
- 'title' => $content['title'],
- 'language' => $content['language'],
- 'mainLibrary' => $content['library']['name'],
- 'embedTypes' => $embedTypes,
+ // Create content folder
+ if ($this->h5pC->copyFileTree($h5pDir . 'content' . DIRECTORY_SEPARATOR . $content['id'], $tempPath . DIRECTORY_SEPARATOR . 'content') === FALSE) {
+ return FALSE;
+ }
+ file_put_contents($tempPath . DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR . 'content.json', $content['params']);
+
+ // Make embedTypes into an array
+ $embedTypes = explode(', ', $content['embedType']); // Won't content always be embedded in one way?
+
+ // Build h5p.json
+ $h5pJson = array (
+ 'title' => $content['title'],
+ 'language' => $content['language'],
+ 'mainLibrary' => $content['library']['name'],
+ 'embedTypes' => $embedTypes,
+ );
+
+ // Add dependencies to h5p
+ foreach ($content['dependencies'] as $dependency) {
+ $library = $dependency['library'];
+
+ // Copy library to h5p
+ $source = isset($library['path']) ? $library['path'] : $h5pDir . 'libraries' . DIRECTORY_SEPARATOR . H5PCore::libraryToString($library, TRUE);
+ $destination = $tempPath . DIRECTORY_SEPARATOR . $library['machineName'];
+ $this->h5pC->copyFileTree($source, $destination);
+
+ // Do not add editor dependencies to h5p json.
+ if ($dependency['type'] === 'editor') {
+ continue;
+ }
+
+ $h5pJson[$dependency['type'] . 'Dependencies'][] = array(
+ 'machineName' => $library['machineName'],
+ 'majorVersion' => $library['majorVersion'],
+ 'minorVersion' => $library['minorVersion']
);
-
- // Add dependencies to h5p
- $dependencies = $this->h5pC->loadContentDependencies($content['id']);
- foreach ($dependencies as $dependency) {
- // Copy library to h5p
- $source = isset($dependency['path']) ? $dependency['path'] : $h5pDir . 'libraries' . DIRECTORY_SEPARATOR . H5PCore::libraryToString($dependency, TRUE);
- $destination = $tempPath . DIRECTORY_SEPARATOR . $dependency['machineName'];
- $this->h5pC->copyFileTree($source, $destination);
-
- // Do not add editor dependencies to h5p json.
- if ($dependency['dependencyType'] === 'editor') {
- continue;
- }
-
- $h5pJson[$dependency['dependencyType'] . 'Dependencies'][] = array(
- 'machineName' => $dependency['machineName'],
- 'majorVersion' => $dependency['majorVersion'],
- 'minorVersion' => $dependency['minorVersion']
- );
- }
-
- // Save h5p.json
- $results = print_r(json_encode($h5pJson), true);
- file_put_contents($tempPath . DIRECTORY_SEPARATOR . 'h5p.json', $results);
-
- // Create new zip instance.
- $zip = new ZipArchive();
- $zip->open($zipPath, ZIPARCHIVE::CREATE);
-
- // Get all files and folders in $tempPath
- $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tempPath . DIRECTORY_SEPARATOR));
- // Add files to zip
- foreach ($iterator as $key=>$value) {
- $test = '.';
- // Do not add the folders '.' and '..' to the zip. This will make zip invalid.
- if (substr_compare($key, $test, -strlen($test), strlen($test)) !== 0) {
- // Get files path in $tempPath
- $filePath = explode($tempPath . DIRECTORY_SEPARATOR, $key);
- // Add files to the zip with the intended file-structure
- $zip->addFile($key, $filePath[1]);
- }
- }
- // Close zip and remove temp dir
- $zip->close();
- H5PCore::deleteFileTree($tempPath);
}
- return str_replace(DIRECTORY_SEPARATOR, '/', $zipPath);
+ // Save h5p.json
+ $results = print_r(json_encode($h5pJson), true);
+ file_put_contents($tempPath . DIRECTORY_SEPARATOR . 'h5p.json', $results);
+
+ // Create new zip instance.
+ $zip = new ZipArchive();
+ $zip->open($zipPath, ZIPARCHIVE::CREATE);
+
+ // Get all files and folders in $tempPath
+ $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tempPath . DIRECTORY_SEPARATOR));
+ // Add files to zip
+ foreach ($iterator as $key => $value) {
+ $test = '.';
+ // Do not add the folders '.' and '..' to the zip. This will make zip invalid.
+ if (substr_compare($key, $test, -strlen($test), strlen($test)) !== 0) {
+ // Get files path in $tempPath
+ $filePath = explode($tempPath . DIRECTORY_SEPARATOR, $key);
+ // Add files to the zip with the intended file-structure
+ $zip->addFile($key, $filePath[1]);
+ }
+ }
+ // Close zip and remove temp dir
+ $zip->close();
+ H5PCore::deleteFileTree($tempPath);
}
/**
@@ -1238,7 +1283,7 @@ class H5PCore {
public static $coreApi = array(
'majorVersion' => 1,
- 'minorVersion' => 2
+ 'minorVersion' => 3
);
public static $styles = array(
'styles/h5p.css',
@@ -1256,6 +1301,7 @@ class H5PCore {
public static $defaultLibraryWhitelistExtras = 'js css';
public $librariesJsonData, $contentJsonData, $mainJsonData, $h5pF, $path, $development_mode, $h5pD;
+ private $exportEnabled;
/**
* Constructor for the H5PCore
@@ -1264,13 +1310,15 @@ class H5PCore {
* The frameworks implementation of the H5PFrameworkInterface
* @param string $path H5P file storage directory.
* @param string $language code. Defaults to english.
+ * @param boolean $export enabled?
* @param int $development_mode mode.
*/
- public function __construct($H5PFramework, $path, $language = 'en', $development_mode = H5PDevelopment::MODE_NONE) {
+ public function __construct($H5PFramework, $path, $language = 'en', $export = FALSE, $development_mode = H5PDevelopment::MODE_NONE) {
$this->h5pF = $H5PFramework;
$this->h5pF = $H5PFramework;
$this->path = $path;
+ $this->exportEnabled = $export;
$this->development_mode = $development_mode;
if ($development_mode & H5PDevelopment::MODE_LIBRARY) {
@@ -1317,20 +1365,61 @@ class H5PCore {
);
unset($content['libraryId'], $content['libraryName'], $content['libraryEmbedTypes'], $content['libraryFullscreen']);
- if ($this->development_mode & H5PDevelopment::MODE_CONTENT) {
- // TODO: Remove Drupal specific stuff
- $json_content_path = file_create_path(file_directory_path() . '/' . variable_get('h5p_default_path', 'h5p') . '/content/' . $id . '/content.json');
- if (file_exists($json_content_path) === TRUE) {
- $json_content = file_get_contents($json_content_path);
- if (json_decode($json_content, TRUE) !== FALSE) {
- drupal_set_message(t('Invalid json in json content'), 'warning');
- }
- $content['params'] = $json_content;
- }
- }
+// // TODO: Move to filterParameters?
+// if ($this->development_mode & H5PDevelopment::MODE_CONTENT) {
+// // TODO: Remove Drupal specific stuff
+// $json_content_path = file_create_path(file_directory_path() . '/' . variable_get('h5p_default_path', 'h5p') . '/content/' . $id . '/content.json');
+// if (file_exists($json_content_path) === TRUE) {
+// $json_content = file_get_contents($json_content_path);
+// if (json_decode($json_content, TRUE) !== FALSE) {
+// drupal_set_message(t('Invalid json in json content'), 'warning');
+// }
+// $content['params'] = $json_content;
+// }
+// }
+ }
+
+ return $content;
+ }
+
+ /**
+ * Filter content run parameters, rebuild content dependecy cache and export file.
+ *
+ * @param Object $content
+ * @return Object NULL on failure.
+ */
+ public function filterParameters($content) {
+ $params = $this->h5pF->cacheGet('parameters', $content['id']);
+ if ($params !== NULL) {
+ return $params;
+ }
+
+ // Validate and filter against main library semantics.
+ $validator = new H5PContentValidator($this->h5pF, $this);
+ $params = (object) array(
+ 'library' => H5PCore::libraryToString($content['library']),
+ 'params' => json_decode($content['params'])
+ );
+ $validator->validateLibrary($params, (object) array('options' => array($params->library)));
+
+ $params = json_encode($params->params);
+
+ // Update content dependencies.
+ $content['dependencies'] = $validator->getDependencies();
+ $this->h5pF->deleteLibraryUsage($content['id']);
+ $this->h5pF->saveLibraryUsage($content['id'], $content['dependencies']);
+
+ if ($this->exportEnabled) {
+ // Recreate export file
+ $exporter = new H5PExport($this->h5pF, $this);
+ $exporter->createExportFile($content);
+
+ // TODO: Should we rather create the file once first accessed, like imagecache?
}
- return $content;
+ // Cache.
+ $this->h5pF->cacheSet('parameters', $content['id'], $params);
+ return $params;
}
/**
@@ -1427,7 +1516,7 @@ class H5PCore {
/**
* Load library semantics.
*
- * @return string 'div' or 'iframe'.
+ * @return string
*/
public function loadLibrarySemantics($name, $majorVersion, $minorVersion) {
$semantics = NULL;
@@ -1610,7 +1699,7 @@ class H5PCore {
* Returns FALSE only if string is not parsable in the normal library
* string formats "Lib.Name-x.y" or "Lib.Name x.y"
*/
- public function libraryFromString($libraryString) {
+ public static function libraryFromString($libraryString) {
$re = '/^([\w0-9\-\.]{1,255})[\-\ ]([0-9]{1,5})\.([0-9]{1,5})$/i';
$matches = array();
$res = preg_match($re, $libraryString, $matches);
@@ -1626,7 +1715,6 @@ class H5PCore {
/**
* Determine the correct embed type to use.
- * TODO: Use constants.
*
* @return string 'div' or 'iframe'.
*/
@@ -1645,6 +1733,60 @@ class H5PCore {
return $embedType;
}
+
+ /**
+ * Get the absolute version for the library as a human readable string.
+ *
+ * @param object $library
+ * @return string
+ */
+ public static function libraryVersion($library) {
+ return $library->major_version . '.' . $library->minor_version . '.' . $library->patch_version;
+ }
+
+ /**
+ * Detemine which versions content with the given library can be upgraded to.
+ *
+ * @param object $library
+ * @param array $versions
+ * @return array
+ */
+ public function getUpgrades($library, $versions) {
+ $upgrades = array();
+
+ foreach ($versions as $upgrade) {
+ if ($upgrade->major_version > $library->major_version || $upgrade->major_version === $library->major_version && $upgrade->minor_version > $library->minor_version) {
+ $upgrades[$upgrade->id] = H5PCore::libraryVersion($upgrade);
+ }
+ }
+
+ return $upgrades;
+ }
+
+ /**
+ * Converts all the properties of the given object or array from
+ * snake_case to camelCase. Useful after fetching data from the database.
+ *
+ * Note that some databases does not support camelCase.
+ *
+ * @param mixed $arr input
+ * @param boolean $obj return object
+ * @return mixed object or array
+ */
+ public static function snakeToCamel($arr, $obj = false) {
+ $newArr = array();
+
+ foreach ($arr as $key => $val) {
+ $next = -1;
+ while (($next = strpos($key, '_', $next + 1)) !== FALSE) {
+ $key = substr_replace($key, strtoupper($key{$next + 1}), $next, 2);
+ }
+
+ $newArr[$key] = $val;
+ }
+
+ return $obj ? (object) $newArr : $newArr;
+ }
}
/**
@@ -1654,7 +1796,7 @@ class H5PContentValidator {
public $h5pF;
public $h5pC;
private $typeMap;
- private $semanticsCache;
+ private $libraries, $dependencies;
/**
* Constructor for the H5PContentValidator
@@ -1680,33 +1822,24 @@ class H5PContentValidator {
'select' => 'validateSelect',
'library' => 'validateLibrary',
);
- // Cache for semantics used within this validation to avoid unneccessary
- // json_decodes if a library is used multiple times.
- $this->semanticsCache = array();
+
+ // Keep track of the libraries we load to avoid loading it multiple times.
+ $this->libraries = array();
+ // TODO: Should this possible be done in core's loadLibrary? This might be done multiple places.
+
+ // Keep track of all dependencies for the given content.
+ $this->dependencies = array();
}
/**
- * Validate the given value from content with the matching semantics
- * object from semantics
- *
- * Function will recurse via external functions for container objects like
- * 'list', 'group' and 'library'.
- *
- * @param object $value
- * Object to be verified. May be a string or an array. (normal or keyed)
- * @param object $semantics
- * Semantics object from semantics.json for main library. Further
- * semantics will be loaded from H5PFramework if any libraries are
- * found within the value data.
+ * Get the flat dependecy tree.
+ *
+ * @return array
*/
- public function validateBySemantics(&$value, $semantics) {
- $fakebaseobject = (object) array(
- 'type' => 'group',
- 'fields' => $semantics,
- );
- $this->validateGroup($value, $fakebaseobject, FALSE);
+ public function getDependencies() {
+ return $this->dependencies;
}
-
+
/**
* Validate given text value against text semantics.
*/
@@ -2047,31 +2180,47 @@ class H5PContentValidator {
/**
* Validate given library value against library semantics.
+ * Check if provided library is within allowed options.
*
* Will recurse into validating the library's semantics too.
*/
public function validateLibrary(&$value, $semantics) {
- // Check if provided library is within allowed options
- if (isset($value->library) && in_array($value->library, $semantics->options)) {
- if (isset($this->semanticsCache[$value->library])) {
- $librarySemantics = $this->semanticsCache[$value->library];
- }
- else {
- $libspec = $this->h5pC->libraryFromString($value->library);
- $librarySemantics = $this->h5pC->loadLibrarySemantics($libspec['machineName'], $libspec['majorVersion'], $libspec['minorVersion']);
- $this->semanticsCache[$value->library] = $librarySemantics;
- }
- $this->validateBySemantics($value->params, $librarySemantics);
- $validkeys = array('library', 'params');
- if (isset($semantics->extraAttributes)) {
- $validkeys = array_merge($validkeys, $semantics->extraAttributes);
- }
- $this->filterParams($value, $validkeys);
- }
- else {
+ if (!isset($value->library) || !in_array($value->library, $semantics->options)) {
$this->h5pF->setErrorMessage($this->h5pF->t('Library used in content is not a valid library according to semantics'));
$value = new stdClass();
+ return;
}
+
+ 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']);
+ $this->libraries[$value->library] = $library;
+
+ // Find all dependencies for this library
+ $depkey = 'preloaded-' . $libspec['machineName'];
+ if (!isset($this->dependencies[$depkey])) {
+ $this->dependencies[$depkey] = array(
+ 'library' => $library,
+ 'type' => 'preloaded'
+ );
+
+ $this->h5pC->findLibraryDependencies($this->dependencies, $library);
+ }
+ }
+ else {
+ $library = $this->libraries[$value->library];
+ }
+
+ $this->validateGroup($value->params, (object) array(
+ 'type' => 'group',
+ 'fields' => $library['semantics'],
+ ), FALSE);
+ $validkeys = array('library', 'params');
+ if (isset($semantics->extraAttributes)) {
+ $validkeys = array_merge($validkeys, $semantics->extraAttributes);
+ }
+ $this->filterParams($value, $validkeys);
}
/**
diff --git a/images/throbber.gif b/images/throbber.gif
new file mode 100644
index 0000000..1560b64
Binary files /dev/null and b/images/throbber.gif differ
diff --git a/js/flowplayer-3.2.12.min.js b/js/flowplayer-3.2.12.min.js
deleted file mode 100644
index ff7b48f..0000000
--- a/js/flowplayer-3.2.12.min.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * flowplayer.js 3.2.12. The Flowplayer API
- *
- * Copyright 2009-2011 Flowplayer Oy
- *
- * This file is part of Flowplayer.
- *
- * Flowplayer is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Flowplayer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Flowplayer. If not, see .
- *
- * Date: ${date}
- * Revision: ${revision}
- */
-!function(){function h(p){console.log("$f.fireEvent",[].slice.call(p))}function l(r){if(!r||typeof r!="object"){return r}var p=new r.constructor();for(var q in r){if(r.hasOwnProperty(q)){p[q]=l(r[q])}}return p}function n(u,r){if(!u){return}var p,q=0,s=u.length;if(s===undefined){for(p in u){if(r.call(u[p],p,u[p])===false){break}}}else{for(var t=u[0];q1){var u=arguments[1],r=(arguments.length==3)?arguments[2]:{};if(typeof u=="string"){u={src:u}}u=j({bgcolor:"#000000",version:[10,1],expressInstall:"http://releases.flowplayer.org/swf/expressinstall.swf",cachebusting:false},u);if(typeof p=="string"){if(p.indexOf(".")!=-1){var t=[];n(o(p),function(){t.push(new b(this,l(u),l(r)))});return new d(t)}else{var s=c(p);return new b(s!==null?s:l(p),l(u),l(r))}}else{if(p){return new b(p,l(u),l(r))}}}return null};j(window.$f,{fireEvent:function(){var q=[].slice.call(arguments);var r=$f(q[0]);return r?r._fireEvent(q.slice(1)):null},addPlugin:function(p,q){b.prototype[p]=q;return $f},each:n,extend:j});if(typeof jQuery=="function"){jQuery.fn.flowplayer=function(r,q){if(!arguments.length||typeof arguments[0]=="number"){var p=[];this.each(function(){var s=$f(this);if(s){p.push(s)}});return arguments.length?p[arguments[0]]:new d(p)}return this.each(function(){$f(this,l(r),q?l(q):{})})}}}();!function(){var h=document.all,j="http://get.adobe.com/flashplayer",c=typeof jQuery=="function",e=/(\d+)[^\d]+(\d+)[^\d]*(\d*)/,b={width:"100%",height:"100%",id:"_"+(""+Math.random()).slice(9),allowfullscreen:true,allowscriptaccess:"always",quality:"high",version:[3,0],onFail:null,expressInstall:null,w3c:false,cachebusting:false};if(window.attachEvent){window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}})}function i(m,l){if(l){for(var f in l){if(l.hasOwnProperty(f)){m[f]=l[f]}}}return m}function a(f,n){var m=[];for(var l in f){if(f.hasOwnProperty(l)){m[l]=n(f[l])}}return m}window.flashembed=function(f,m,l){if(typeof f=="string"){f=document.getElementById(f.replace("#",""))}if(!f){return}if(typeof m=="string"){m={src:m}}return new d(f,i(i({},b),m),l)};var g=i(window.flashembed,{conf:b,getVersion:function(){var m,f;try{f=navigator.plugins["Shockwave Flash"].description.slice(16)}catch(o){try{m=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");f=m&&m.GetVariable("$version")}catch(n){try{m=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");f=m&&m.GetVariable("$version")}catch(l){}}}f=e.exec(f);return f?[1*f[1],1*f[(f[1]*1>9?2:3)]*1]:[0,0]},asString:function(l){if(l===null||l===undefined){return null}var f=typeof l;if(f=="object"&&l.push){f="array"}switch(f){case"string":l=l.replace(new RegExp('(["\\\\])',"g"),"\\$1");l=l.replace(/^\s?(\d+\.?\d*)%/,"$1pct");return'"'+l+'"';case"array":return"["+a(l,function(o){return g.asString(o)}).join(",")+"]";case"function":return'"function()"';case"object":var m=[];for(var n in l){if(l.hasOwnProperty(n)){m.push('"'+n+'":'+g.asString(l[n]))}}return"{"+m.join(",")+"}"}return String(l).replace(/\s/g," ").replace(/\'/g,'"')},getHTML:function(o,l){o=i({},o);var n='";return n},isSupported:function(f){return k[0]>f[0]||k[0]==f[0]&&k[1]>=f[1]}});var k=g.getVersion();function d(f,n,m){if(g.isSupported(n.version)){f.innerHTML=g.getHTML(n,m)}else{if(n.expressInstall&&g.isSupported([6,65])){f.innerHTML=g.getHTML(i(n,{src:n.expressInstall}),{MMredirectURL:encodeURIComponent(location.href),MMplayerType:"PlugIn",MMdoctitle:document.title})}else{if(!f.innerHTML.replace(/\s/g,"")){f.innerHTML="Flash version "+n.version+" or greater is required
"+(k[0]>0?"Your version is "+k:"You have no flash plugin installed")+"
"+(f.tagName=="A"?"
Click here to download latest version
":"Download latest version from here
");if(f.tagName=="A"||f.tagName=="DIV"){f.onclick=function(){location.href=j}}}if(n.onFail){var l=n.onFail.call(this);if(typeof l=="string"){f.innerHTML=l}}}}if(h){window[n.id]=document.getElementById(n.id)}i(this,{getRoot:function(){return f},getOptions:function(){return n},getConf:function(){return m},getApi:function(){return f.firstChild}})}if(c){jQuery.tools=jQuery.tools||{version:"3.2.12"};jQuery.tools.flashembed={conf:b};jQuery.fn.flashembed=function(l,f){return this.each(function(){$(this).data("flashembed",flashembed(this,l,f))})}}}();
\ No newline at end of file
diff --git a/js/h5p-content-upgrade.js b/js/h5p-content-upgrade.js
new file mode 100644
index 0000000..5542bdd
--- /dev/null
+++ b/js/h5p-content-upgrade.js
@@ -0,0 +1,474 @@
+var H5PUpgrades = H5PUpgrades || {};
+
+(function ($) {
+ var info, $container;
+
+ // 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',
+ text: info.buttonLabel,
+ click: function () {
+ // Start new content upgrade
+ new ContentUpgrade($version.val());
+ }
+ }).appendTo($container);
+ });
+
+ /**
+ * Generate html for version select.
+ *
+ * @param {Object} versions
+ * @returns {String}
+ */
+ var getVersionSelect = function (versions) {
+ var html = '';
+ for (var id in versions) {
+ html += '';
+ }
+ if (html !== '') {
+ html = '';
+ 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.
+ if (!isArray) {
+ var ids = [];
+ for (id in obj) {
+ if (obj.hasOwnProperty(id)) {
+ ids.push(id);
+ }
+ }
+ }
+
+ var i = -1; // Keeps track of the current property
+
+ /**
+ * Private. Process the next property
+ */
+ var next = function () {
+ 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) {
+ i++;
+ if (i === (isArray ? obj.length : ids.length) || (err !== undefined && err !== null)) {
+ finished(err);
+ }
+ else {
+ next();
+ }
+ };
+
+ check(); // Start
+ };
+
+ /**
+ * Make it easy to keep track of version details.
+ *
+ * @param {String} version
+ * @param {Number} libraryId
+ * @returns {_L1.Version}
+ */
+ 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 () {
+ return version;
+ };
+ }
+
+ /**
+ * 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) {
+ $throbber.text(msg + ' ' + progress);
+ };
+ }
+
+ /**
+ * 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));
+
+ // Get the next batch
+ self.nextBatch({
+ libraryId: libraryId,
+ 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) {
+ $container.html(msg);
+ };
+
+ /**
+ * 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);
+
+ // 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)) + ' %');
+ }
+ next(err);
+ });
+
+ }, function (err) {
+ // Finished with all parameters that came in
+ if (err) {
+ return self.setStatus('' + info.error + '
' + err + '
');
+ }
+
+ // Save upgraded content and get next round of data to process
+ self.nextBatch({
+ libraryId: self.version.libraryId,
+ token: self.token,
+ params: JSON.stringify(upgraded)
+ });
+ });
+ };
+
+ /**
+ * Upgade the given content.
+ *
+ * @param {String} name
+ * @param {Version} oldVersion
+ * @param {Version} newVersion
+ * @param {Object} params
+ * @param {Function} next
+ * @returns {undefined}
+ */
+ 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) {
+ if (upgradedParams) {
+ params[field.name] = upgradedParams;
+ }
+ next(err);
+ });
+ }, function (err) {
+ next(err, params);
+ });
+ });
+ });
+ };
+
+ /**
+ * 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;
+
+ $.ajax({
+ dataType: 'json',
+ url: info.libraryBaseUrl + '/' + name + '/' + version.major + '/' + version.minor
+ }).fail(function () {
+ next(info.errorData.replace('%lib', name + ' ' + version));
+ }).done(function (library) {
+ if (library.upgradesScript) {
+ self.loadScript(library.upgradesScript, function (err) {
+ if (err) {
+ err = info.errorScript.replace('%lib', name + ' ' + version);
+ }
+ next(err, library);
+ });
+ }
+ else {
+ next(null, library);
+ }
+ });
+ };
+
+ /**
+ * Load script with upgrade hooks.
+ *
+ * @param {String} url
+ * @param {Function} next
+ */
+ ContentUpgrade.prototype.loadScript = function (url, next) {
+ $.ajax({
+ dataType: 'script',
+ cache: true,
+ url: url
+ }).fail(function () {
+ next(true);
+ }).done(function () {
+ next();
+ });
+ };
+
+ /**
+ * Run upgrade hooks on params.
+ *
+ * @param {Object} library
+ * @param {Version} oldVersion
+ * @param {Version} newVersion
+ * @param {Object} params
+ * @param {Function} next
+ */
+ ContentUpgrade.prototype.processParams = function (library, oldVersion, newVersion, params, next) {
+ if (H5PUpgrades[library.name] === undefined) {
+ if (library.upgradesScript) {
+ // 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);
+ }
+
+ // 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
+ nextMajor();
+ }
+ else {
+ // Go through the minor versions for this major version
+ asyncSerial(minors, function (minor, upgrade, nextMinor) {
+ if (minor <= oldVersion.minor || minor > newVersion.minor) {
+ // Older than or equal to the current version or newer than the selected
+ nextMinor();
+ }
+ else {
+ // We found an upgrade hook, run it
+ if (upgrade.contentUpgrade !== undefined && typeof upgrade.contentUpgrade === 'function') {
+ upgrade.contentUpgrade(params, function (err, upgradedParams) {
+ params = upgradedParams;
+ nextMinor(err);
+ });
+ }
+ else {
+ nextMinor(info.errorScript.replace('%lib', library.name + ' ' + newVersion));
+ }
+ }
+ }, nextMajor);
+ }
+ }, function (err) {
+ 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++) {
+ var availableLib = field.options[i].split(' ', 2);
+ if (availableLib[0] === usedLib[0]) {
+ 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) {
+ params.library = availableLib[0] + ' ' + availableVer.major + '.' + availableVer.minor;
+ params.params = upgraded;
+ }
+ next(err, params);
+ });
+ }
+ }
+ next();
+ break;
+
+ case 'group':
+ if (field.fields.length === 1) {
+ // Single field to process, wrapper will be skipped
+ self.processField(field.fields[0], params, function (err, upgradedParams) {
+ if (upgradedParams) {
+ params = upgradedParams;
+ }
+ next(err, params);
+ });
+ }
+ else {
+ // Go through all fields in the group
+ asyncSerial(field.fields, function (index, subField, next) {
+ self.processField(subField, params[subField.name], function (err, upgradedParams) {
+ if (upgradedParams) {
+ params[subField.name] = upgradedParams;
+ }
+ next(err);
+ });
+ }, function (err) {
+ next(err, params);
+ });
+ }
+ break;
+
+ case 'list':
+ // Go trough all params in the list
+ asyncSerial(params, function (index, subParams, next) {
+ self.processField(field.field, subParams, function (err, upgradedParams) {
+ if (upgradedParams) {
+ params[index] = upgradedParams;
+ }
+ next(err);
+ });
+ }, function (err) {
+ next(err, params);
+ });
+ break;
+
+ default:
+ next();
+ }
+ };
+
+})(H5P.jQuery);
\ No newline at end of file
diff --git a/js/h5p-embed.js b/js/h5p-embed.js
index b94fd29..ae8efc2 100644
--- a/js/h5p-embed.js
+++ b/js/h5p-embed.js
@@ -15,7 +15,7 @@ var H5P = H5P || (function () {
result += prefix + content[i] + suffix;
}
return result;
- }
+ };
/**
*
@@ -25,7 +25,7 @@ var H5P = H5P || (function () {
var data, callback = 'H5P' + id;
// Prevent duplicate loading.
- script.removeAttribute('data-h5p')
+ script.removeAttribute('data-h5p');
// Callback for when content data is loaded.
window[callback] = function (content) {
@@ -64,13 +64,13 @@ var H5P = H5P || (function () {
parent.removeChild(script);
head.removeChild(data);
delete window[callback];
- }
+ };
// Create data script
data = document.createElement('script');
data.src = url + (url.indexOf('?') === -1 ? '?' : '&') + 'callback=' + callback;
head.appendChild(data);
- }
+ };
/**
* Go throught all script tags with the data-h5p attribute and load content.
@@ -113,7 +113,7 @@ var H5P = H5P || (function () {
library: content.library,
jsonContent: content.params,
fullScreen: content.fullscreen,
- export: content.export,
+ exportUrl: content.exportUrl,
embedCode: content.embedCode
};
},
@@ -126,15 +126,20 @@ var H5P = H5P || (function () {
};
// Detect if we support fullscreen, and what prefix to use.
- var fullScreenBrowserPrefix;
+ var fullScreenBrowserPrefix, safariBrowser;
if (document.documentElement.requestFullScreen) {
fullScreenBrowserPrefix = '';
}
else if (document.documentElement.webkitRequestFullScreen
&& navigator.userAgent.indexOf('Android') === -1 // Skip Android
- && navigator.userAgent.indexOf('Version/') === -1 // Skip Safari
) {
- fullScreenBrowserPrefix = 'webkit';
+ safariBrowser = navigator.userAgent.match(/Version\/(\d)/);
+ safariBrowser = (safariBrowser === null ? 0 : parseInt(safariBrowser[1]));
+
+ // Do not allow fullscreen for safari < 7.
+ if (safariBrowser === 0 || safariBrowser > 6) {
+ fullScreenBrowserPrefix = 'webkit';
+ }
}
else if (document.documentElement.mozRequestFullScreen) {
fullScreenBrowserPrefix = 'moz';
@@ -151,32 +156,55 @@ var H5P = H5P || (function () {
var $classes = $element.add(body);
var $body = $classes.eq(1);
- var done = function (c) {
- H5P.isFullscreen = false;
- $classes.removeClass(c);
-
- if (H5P.fullScreenBrowserPrefix === undefined) {
- // Resize content.
- if (instance.$ !== undefined) {
- instance.$.trigger('resize');
- }
- }
+ /**
+ * Prepare for resize by setting the correct styles.
+ *
+ * @param {String} classes CSS
+ */
+ var before = function (classes) {
+ $classes.addClass(classes);
+ iframe.style.height = '100%';
+ };
- if (exitCallback !== undefined) {
- exitCallback();
- }
- };
+ /**
+ * Gets called when fullscreen mode has been entered.
+ * Resizes and sets focus on content.
+ */
+ var entered = function () {
+ // Do not rely on window resize events.
+ instance.$.trigger('resize');
+ instance.$.trigger('focus');
+ };
+
+ /**
+ * Gets called when fullscreen mode has been exited.
+ * Resizes and sets focus on content.
+ *
+ * @param {String} classes CSS
+ */
+ var done = function (classes) {
+ H5P.isFullscreen = false;
+ $classes.removeClass(classes);
+
+ // Do not rely on window resize events.
+ instance.$.trigger('resize');
+ instance.$.trigger('focus');
+
+ if (exitCallback !== undefined) {
+ exitCallback();
+ }
+ };
H5P.isFullscreen = true;
if (fullScreenBrowserPrefix === undefined) {
// Create semi fullscreen.
-
- $classes.addClass('h5p-semi-fullscreen');
- iframe.style.position = 'fixed';
+ before('h5p-semi-fullscreen');
+ iframe.style.position = 'fixed';
+
var $disable = $element.prepend('').children(':first');
var keyup, disableSemiFullscreen = function () {
- $disable.remove();
+ $disable.remove();
$body.unbind('keyup', keyup);
iframe.style.position = 'static';
done('h5p-semi-fullscreen');
@@ -189,17 +217,22 @@ var H5P = H5P || (function () {
};
$disable.click(disableSemiFullscreen);
$body.keyup(keyup); // TODO: Does not work with iframe's $!
-
+ entered();
}
else {
// Create real fullscreen.
-
+
+ before('h5p-fullscreen');
var first, eventName = (fullScreenBrowserPrefix === 'ms' ? 'MSFullscreenChange' : fullScreenBrowserPrefix + 'fullscreenchange');
document.addEventListener(eventName, function () {
if (first === undefined) {
+ // We are entering fullscreen mode
first = false;
+ entered();
return;
}
+
+ // We are exiting fullscreen
done('h5p-fullscreen');
document.removeEventListener(eventName, arguments.callee, false);
});
@@ -209,24 +242,9 @@ var H5P = H5P || (function () {
}
else {
var method = (fullScreenBrowserPrefix === 'ms' ? 'msRequestFullscreen' : fullScreenBrowserPrefix + 'RequestFullScreen');
- var params = (fullScreenBrowserPrefix === 'webkit' ? Element.ALLOW_KEYBOARD_INPUT : undefined);
+ var params = (fullScreenBrowserPrefix === 'webkit' && safariBrowser === 0 ? Element.ALLOW_KEYBOARD_INPUT : undefined);
iframe[method](params);
}
-
- $classes.addClass('h5p-fullscreen');
- }
-
- iframe.style.height = '100%';
- if (H5P.fullScreenBrowserPrefix === undefined) {
- // Resize content.
- if (instance.$ !== undefined) {
- instance.$.trigger('resize', [true]);
- }
- }
-
- // Allow H5P to set focus when entering fullscreen mode
- if (instance.focus !== undefined) {
- instance.focus();
}
};
diff --git a/js/h5p-library-details.js b/js/h5p-library-details.js
index 4341654..e274d22 100644
--- a/js/h5p-library-details.js
+++ b/js/h5p-library-details.js
@@ -39,8 +39,19 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
$libraryInfo.append(H5PUtils.createLabeledField(title, value));
});
+ var count;
+ if (H5PLibraryDetails.library.notCached !== undefined) {
+ count = H5PIntegration.i18n.H5P.NA;
+ }
+ else if (H5PLibraryDetails.library.content === undefined) {
+ count = 0;
+ }
+ else {
+ count = H5PLibraryDetails.library.content.length;
+ }
+
// List counter:
- $libraryInfo.append(H5PUtils.createLabeledField(H5PLibraryDetails.library.translations.contentCount, H5PLibraryDetails.currentContent ? H5PLibraryDetails.currentContent.length : 0));
+ $libraryInfo.append(H5PUtils.createLabeledField(H5PLibraryDetails.library.translations.contentCount, count));
return $libraryInfo;
};
@@ -49,6 +60,10 @@ var H5PLibraryDetails= H5PLibraryDetails || {};
* Create the content list with searching and paging
*/
H5PLibraryDetails.createContentElement = function () {
+ if (H5PLibraryDetails.library.notCached !== undefined) {
+ return H5PUtils.getRebuildCache(H5PLibraryDetails.library.notCached);
+ }
+
if (H5PLibraryDetails.currentContent === undefined) {
H5PLibraryDetails.$content = $('' + H5PLibraryDetails.library.translations.noContent + '
');
}
diff --git a/js/h5p-library-list.js b/js/h5p-library-list.js
index 4ddfc7d..a238d39 100644
--- a/js/h5p-library-list.js
+++ b/js/h5p-library-list.js
@@ -8,6 +8,11 @@ var H5PLibraryList= H5PLibraryList || {};
H5PLibraryList.init = function () {
var $adminContainer = H5PIntegration.getAdminContainer();
+ var libraryList = H5PIntegration.getLibraryList();
+ if (libraryList.notCached) {
+ $adminContainer.append(H5PUtils.getRebuildCache(libraryList.notCached));
+ }
+
// Create library list
$adminContainer.append(H5PLibraryList.createLibraryList(H5PIntegration.getLibraryList()));
};
@@ -28,25 +33,38 @@ var H5PLibraryList= H5PLibraryList || {};
$table.addClass('libraries');
// Add libraries
+ var t = H5PIntegration.i18n.H5P;
$.each (libraries.listData, function (index, library) {
var $libraryRow = H5PUtils.createTableRow([
- library.name,
- library.machineName,
- library.contentCount,
- library.libraryDependencyCount,
- '' +
- ''
+ library.title,
+ library.numContent,
+ library.numContentDependencies === -1 ? t.NA : library.numContentDependencies,
+ library.numLibraryDependencies,
+ '\
+ \
+ \
+ \
+
'
]);
+ if (library.upgradeUrl !== null && library.numContent !== 0) {
+ $('.h5p-admin-upgrade-library', $libraryRow).attr('title', t.upgradeLibrary).click(function () {
+ window.location.href = library.upgradeUrl;
+ });
+ }
+ else {
+ $('.h5p-admin-upgrade-library', $libraryRow).attr('disabled', true);
+ }
+
// Open details view when clicked
$('.h5p-admin-view-library', $libraryRow).on('click', function () {
window.location.href = library.detailsUrl;
});
var $deleteButton = $('.h5p-admin-delete-library', $libraryRow);
- if (library.contentCount !== 0 || library.libraryDependencyCount !== 0) {
+ if (library.numContent !== 0 || library.numContentDependencies !== 0 || library.numLibraryDependencies !== 0) {
// Disabled delete if content.
- $deleteButton.attr('disabled', true); //.addClass('disabled');
+ $deleteButton.attr('disabled', true).attr('title', t.deleteLibrary);
}
else {
// Go to delete page om click.
diff --git a/js/h5p-utils.js b/js/h5p-utils.js
index dae71e2..d8faf68 100644
--- a/js/h5p-utils.js
+++ b/js/h5p-utils.js
@@ -17,7 +17,7 @@ var H5PUtils = H5PUtils || {};
$tr.append('' + value + ' | ');
});
- $table.append($thead.append($tr))
+ $table.append($thead.append($tr));
}
return $table;
@@ -51,7 +51,7 @@ var H5PUtils = H5PUtils || {};
$field.append('' + value + '
');
return $field;
- }
+ };
/**
* Replaces placeholder fields in translation strings
@@ -61,9 +61,60 @@ var H5PUtils = H5PUtils || {};
*/
H5PUtils.translateReplace = function (template, replacors) {
$.each(replacors, function (key, value) {
- template = template.replace(new RegExp('\\'+key, 'g'), value)
+ template = template.replace(new RegExp('\\'+key, 'g'), value);
});
return template;
- }
+ };
+
+ /**
+ * Get throbber with given text.
+ *
+ * @param {String} text
+ * @returns {$}
+ */
+ H5PUtils.throbber = function (text) {
+ return $('', {
+ class: 'h5p-throbber',
+ text: text
+ });
+ };
+
+ /**
+ * Makes it possbile to rebuild all content caches from admin UI.
+ * @param {Object} notCached
+ * @returns {$}
+ */
+ H5PUtils.getRebuildCache = function (notCached) {
+ var $container = $('' + notCached.message + '
');
+ var $button = $('').appendTo($container).click(function () {
+ var $spinner = $('', {class: 'h5p-spinner'}).replaceAll($button);
+ var parts = ['|', '/', '-', '\\'];
+ var current = 0;
+ var spinning = setInterval(function () {
+ $spinner.text(parts[current]);
+ current++;
+ if (current === parts.length) current = 0;
+ }, 100);
+
+ var $counter = $container.find('.placeholder');
+ var build = function () {
+ $.post(notCached.url, function (left) {
+ if (left === '0') {
+ clearInterval(spinning);
+ $container.remove();
+ location.reload();
+ }
+ else {
+ var counter = $counter.text().split(' ', 2);
+ $counter.text(left + ' ' + counter[1]);
+ build();
+ }
+ });
+ };
+ build();
+ });
+
+ return $container;
+ };
})(H5P.jQuery);
\ No newline at end of file
diff --git a/js/h5p.js b/js/h5p.js
index fc65d9b..3b5db69 100644
--- a/js/h5p.js
+++ b/js/h5p.js
@@ -1,3 +1,4 @@
+// TODO: Should we split up the generic parts needed by the editor(and others), and the parts needed to "run" H5Ps?
var H5P = H5P || {};
// Determine if we're inside an iframe.
@@ -12,9 +13,14 @@ if (document.documentElement.requestFullScreen) {
}
else if (document.documentElement.webkitRequestFullScreen
&& navigator.userAgent.indexOf('Android') === -1 // Skip Android
- && navigator.userAgent.indexOf('Version/') === -1 // Skip Safari
) {
- H5P.fullScreenBrowserPrefix = 'webkit';
+ H5P.safariBrowser = navigator.userAgent.match(/Version\/(\d)/);
+ H5P.safariBrowser = (H5P.safariBrowser === null ? 0 : parseInt(H5P.safariBrowser[1]));
+
+ // Do not allow fullscreen for safari < 7.
+ if (H5P.safariBrowser === 0 || H5P.safariBrowser > 6) {
+ H5P.fullScreenBrowserPrefix = 'webkit';
+ }
}
else if (document.documentElement.mozRequestFullScreen) {
H5P.fullScreenBrowserPrefix = 'moz';
@@ -29,13 +35,13 @@ else if (document.documentElement.msRequestFullscreen) {
*/
H5P.init = function () {
// Useful jQuery object.
- H5P.$body = H5P.jQuery('body');
+ H5P.$body = H5P.jQuery(document.body);
// Prepare internal resizer for content.
- var $window = H5P.jQuery(window.top);
+ var $window = H5P.jQuery(window.parent);
// H5Ps added in normal DIV.
- var $containers = H5P.jQuery(".h5p-content").each(function () {
+ var $containers = H5P.jQuery(".h5p-content").each(function () {
var $element = H5P.jQuery(this);
var $container = H5P.jQuery('').appendTo($element);
var contentId = $element.data('content-id');
@@ -45,7 +51,7 @@ H5P.init = function () {
}
var library = {
library: contentData.library,
- params: H5P.jQuery.parseJSON(contentData.jsonContent)
+ params: JSON.parse(contentData.jsonContent)
};
// Create new instance.
@@ -59,10 +65,10 @@ H5P.init = function () {
};
var $actions = H5P.jQuery('');
- if (contentData.export !== '') {
+ if (contentData.exportUrl !== '') {
// Display export button
H5P.jQuery('' + H5P.t('download') + '').appendTo($actions).click(function () {
- window.location.href = contentData.export;
+ window.location.href = contentData.exportUrl;
});
}
if (instance.getCopyrights !== undefined) {
@@ -86,7 +92,7 @@ H5P.init = function () {
// 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 resizeIframe = function () {
- if (window.top.H5P.isFullscreen) {
+ if (window.parent.H5P.isFullscreen) {
return; // Skip if full screen.
}
@@ -104,9 +110,11 @@ H5P.init = function () {
iframe.parentElement.style.height = parentHeight;
};
+ var resizeDelay;
instance.$.on('resize', function () {
- // Use timeout to make sure iframe is resized to the correct size.
- setTimeout(function () {
+ // Use a delay to make sure iframe is resized to the correct size.
+ clearTimeout(resizeDelay);
+ resizeDelay = setTimeout(function () {
resizeIframe();
}, 1);
});
@@ -114,11 +122,9 @@ H5P.init = function () {
// Resize everything when window is resized.
$window.resize(function () {
- if (window.top.H5P.isFullscreen) {
+ if (window.parent.H5P.isFullscreen) {
// Use timeout to avoid bug in certain browsers when exiting fullscreen. Some browser will trigger resize before the fullscreenchange event.
- setTimeout(function () {
instance.$.trigger('resize');
- }, 1);
}
else {
instance.$.trigger('resize');
@@ -170,19 +176,43 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
$classes = $element.add(H5P.$body).add($classes);
- var done = function (c) {
- H5P.isFullscreen = false;
- $classes.removeClass(c);
+ /**
+ * Prepare for resize by setting the correct styles.
+ *
+ * @param {String} classes CSS
+ */
+ var before = function (classes) {
+ $classes.addClass(classes);
- if (H5P.fullScreenBrowserPrefix === undefined) {
- // Resize content.
- if (instance.$ !== undefined) {
- instance.$.trigger('resize');
- }
- else if (instance.resize !== undefined) {
- instance.resize();
- }
+ if ($iframe !== undefined) {
+ // Set iframe to its default size(100%).
+ $iframe.css('height', '');
}
+ };
+
+ /**
+ * Gets called when fullscreen mode has been entered.
+ * Resizes and sets focus on content.
+ */
+ var entered = function () {
+ // Do not rely on window resize events.
+ instance.$.trigger('resize');
+ instance.$.trigger('focus');
+ };
+
+ /**
+ * Gets called when fullscreen mode has been exited.
+ * Resizes and sets focus on content.
+ *
+ * @param {String} classes CSS
+ */
+ var done = function (classes) {
+ H5P.isFullscreen = false;
+ $classes.removeClass(classes);
+
+ // Do not rely on window resize events.
+ instance.$.trigger('resize');
+ instance.$.trigger('focus');
if (exitCallback !== undefined) {
exitCallback();
@@ -193,13 +223,12 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
if (H5P.fullScreenBrowserPrefix === undefined) {
// Create semi fullscreen.
- $classes.addClass('h5p-semi-fullscreen');
- var $disable = $container.prepend('').children(':first');
+ before('h5p-semi-fullscreen');
+ var $disable = H5P.jQuery('').appendTo($container.find('.h5p-content-controls'));
var keyup, disableSemiFullscreen = function () {
$disable.remove();
$body.unbind('keyup', keyup);
done('h5p-semi-fullscreen');
- return false;
};
keyup = function (event) {
if (event.keyCode === 27) {
@@ -208,16 +237,22 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
};
$disable.click(disableSemiFullscreen);
$body.keyup(keyup);
+ entered();
}
else {
// Create real fullscreen.
+ before('h5p-fullscreen');
var first, eventName = (H5P.fullScreenBrowserPrefix === 'ms' ? 'MSFullscreenChange' : H5P.fullScreenBrowserPrefix + 'fullscreenchange');
document.addEventListener(eventName, function () {
if (first === undefined) {
+ // We are entering fullscreen mode
first = false;
+ entered();
return;
}
+
+ // We are exiting fullscreen
done('h5p-fullscreen');
document.removeEventListener(eventName, arguments.callee, false);
});
@@ -227,31 +262,9 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
}
else {
var method = (H5P.fullScreenBrowserPrefix === 'ms' ? 'msRequestFullscreen' : H5P.fullScreenBrowserPrefix + 'RequestFullScreen');
- var params = (H5P.fullScreenBrowserPrefix === 'webkit' ? Element.ALLOW_KEYBOARD_INPUT : undefined);
+ var params = (H5P.fullScreenBrowserPrefix === 'webkit' && H5P.safariBrowser === 0 ? Element.ALLOW_KEYBOARD_INPUT : undefined);
$element[0][method](params);
}
-
- $classes.addClass('h5p-fullscreen');
- }
-
- if ($iframe !== undefined) {
- // Set iframe to its default size(100%).
- $iframe.css('height', '');
- }
-
- if (H5P.fullScreenBrowserPrefix === undefined) {
- // Resize content.
- if (instance.$ !== undefined) {
- instance.$.trigger('resize');
- }
- else if (instance.resize !== undefined) {
- instance.resize();
- }
- }
-
- // Allow H5P to set focus when entering fullscreen mode
- if (instance.focus !== undefined) {
- instance.focus();
}
};
@@ -266,11 +279,29 @@ H5P.fullScreen = function ($element, instance, exitCallback, body) {
* Id of the content requesting a path
*/
H5P.getPath = function (path, contentId) {
- if (path.substr(0, 7) === 'http://' || path.substr(0, 8) === 'https://') {
+ var hasProtocol = function (path) {
+ return path.match(/^[a-z0-9]+:\/\//i);
+ };
+
+ if (hasProtocol(path)) {
return path;
}
- return H5PIntegration.getContentPath(contentId) + path;
+ if (contentId !== undefined) {
+ prefix = H5PIntegration.getContentPath(contentId);
+ }
+ else if (window['H5PEditor'] !== undefined) {
+ prefix = H5PEditor.filesPath;
+ }
+ else {
+ return;
+ }
+
+ if (!hasProtocol(prefix)) {
+ prefix = window.parent.location.protocol + "//" + window.parent.location.host + prefix;
+ }
+
+ return prefix + '/' + path;
};
/**
@@ -874,6 +905,8 @@ H5P.cloneObject = function (object, recursive) {
/**
* Remove all empty spaces before and after the value.
* TODO: Only include this or String.trim(). What is best?
+ * I'm leaning towards implementing the missing ones: http://kangax.github.io/compat-table/es5/
+ * So should we make this function deprecated?
*
* @param {String} value
* @returns {@exp;value@call;replace}
@@ -889,13 +922,8 @@ H5P.trim = function (value) {
* @returns {Boolean}
*/
H5P.jsLoaded = function (path) {
- for (var i = 0; i < H5P.loadedJs.length; i++) {
- if (H5P.loadedJs[i] === path) {
- return true;
- }
- }
-
- return false;
+ H5P.loadedJs = H5P.loadedJs || [];
+ return H5P.jQuery.inArray(path, H5P.loadedJs) !== -1;
};
/**
@@ -905,13 +933,8 @@ H5P.jsLoaded = function (path) {
* @returns {Boolean}
*/
H5P.cssLoaded = function (path) {
- for (var i = 0; i < H5P.loadedCss.length; i++) {
- if (H5P.loadedCss[i] === path) {
- return true;
- }
- }
-
- return false;
+ H5P.loadedCss = H5P.loadedCss || [];
+ return H5P.jQuery.inArray(path, H5P.loadedCss) !== -1;
};
/**
@@ -972,8 +995,8 @@ if (String.prototype.trim === undefined) {
};
}
-// Finally, we want to run init when document is ready. But not if we're
-// in an iFrame. Then we wait for parent to start init().
+// Finally, we want to run init when document is ready.
+// TODO: Move to integration. Systems like Moodle using YUI cannot get its translations set before this starts!
if (H5P.jQuery) {
H5P.jQuery(document).ready(function () {
if (!H5P.initialized) {
diff --git a/styles/h5p-admin.css b/styles/h5p-admin.css
index 599afe0..44310b0 100644
--- a/styles/h5p-admin.css
+++ b/styles/h5p-admin.css
@@ -1,11 +1,4 @@
-/* Font Awesome font licensed under SIL OFL 1.1 · Code licensed under MIT License */
-@font-face {
- font-family: 'H5PFontAwesome4'; /* Named so to avoid collisions and preserve backwards compatibility! */
- src: url('../fonts/fontawesome-webfont.eot?v=4.0.3');
- src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');
- font-weight: normal;
- font-style: normal;
-}
+/* Administration interface styling */
.h5p-content {
border: 1px solid #DDD;
@@ -36,35 +29,56 @@
text-align: right;
}
+.h5p-admin-buttons-wrapper {
+ white-space: nowrap;
+}
+
.h5p-admin-table.libraries button {
- font-family: H5PFontAwesome4;
- font-size: 1.6em;
- font-style: normal;
- font-weight: normal;
- margin-right: 10px;
+ font-size: 2em;
cursor: pointer;
border: 1px solid #AAA;
border-radius: .2em;
- line-height: 1.6em;
- width: 1.6em;
background-color: #e0e0e0;
text-shadow: 0 0 0.5em #fff;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
+ padding: 0;
+ line-height: 1em;
+ width: 1.125em;
+ height: 1.05em;
+ text-indent: -0.125em;
+ margin: 0.125em 0.125em 0 0.125em;
}
-.h5p-admin-table.libraries button:hover,
-.h5p-admin-table.libraries .h5p-admin-delete-library:hover {
+.h5p-admin-upgrade-library:before {
+ font-family: 'H5P';
+ content: "\e888";
+}
+.h5p-admin-view-library:before {
+ font-family: 'H5P';
+ content: "\e889";
+}
+.h5p-admin-delete-library:before {
+ font-family: 'H5P';
+ content: "\e890";
+}
+
+.h5p-admin-table.libraries button:hover {
background-color: #d0d0d0;
}
-
-.h5p-admin-table.libraries .h5p-admin-delete-library:disabled:hover {
+.h5p-admin-table.libraries button:disabled:hover {
background-color: #e0e0e0;
+ cursor: default;
}
-.h5p-admin-table.libraries .h5p-admin-delete-library {
- color: #f9010f;
+.h5p-admin-upgrade-library {
+ color: #339900;
}
-.h5p-admin-table.libraries .h5p-admin-delete-library:disabled {
+.h5p-admin-view-library {
+ color: #0066cc;
+}
+.h5p-admin-delete-library {
+ color: #990000;
+}
+.h5p-admin-delete-library:disabled,
+.h5p-admin-upgrade-library:disabled {
cursor: default;
color: #c0c0c0;
}
@@ -114,10 +128,11 @@
box-shadow: 2px 2px 5px #888888;
}
.h5p-content-search:before {
- font-family: H5PFontAwesome4;
- margin: 0 10px;
- content: "\f002";
- font-size: 1.4em;
+ font-family: 'H5P';
+ vertical-align: bottom;
+ content: "\e88a";
+ font-size: 2em;
+ line-height: 1.25em;
}
.h5p-content-search input {
font-size: 120%;
@@ -187,7 +202,7 @@ button.h5p-admin.disabled:hover {
line-height: 130%;
border: none;
background: none;
- font-family: H5PFontAwesome4;
+ font-family: 'H5P'; /* TODO: Find content */
font-size: 1.4em;
}
.h5p-content-pager > button:focus {
@@ -225,3 +240,8 @@ button.h5p-admin.disabled:hover {
top: 0;
right: 0;
}
+.h5p-spinner {
+ padding: 0 0.5em;
+ font-size: 1.5em;
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/styles/h5p.css b/styles/h5p.css
index 673354c..c9099c6 100644
--- a/styles/h5p.css
+++ b/styles/h5p.css
@@ -1,25 +1,19 @@
-/* Font Awesome font licensed under SIL OFL 1.1 · Code licensed under MIT License */
-@font-face {
- font-family: 'H5PFontAwesome4'; /* Named so to avoid collisions and preserve backwards compatibility! */
- src: url('../fonts/fontawesome-webfont.eot?v=4.0.3');
- src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');
- font-weight: normal;
- font-style: normal;
-}
+/* General CSS for H5P. Licensed under the MIT License.*/
+/* Custom H5P font to use for icons. */
@font-face {
font-family: 'H5P';
- src:url('../fonts/h5p.eot?-r12eb7');
- src:url('../fonts/h5p.eot?#iefix-r12eb7') format('embedded-opentype'),
- url('../fonts/h5p.woff?-r12eb7') format('woff'),
- url('../fonts/h5p.ttf?-r12eb7') format('truetype'),
- url('../fonts/h5p.svg?-r12eb7#h5p_toolbar') format('svg');
+ src: url('../fonts/h5p.eot?ver=1.2.1');
+ src: url('../fonts/h5p.eot?#iefix&ver=1.2.1') format('embedded-opentype'),
+ url('data:application/font-woff;base64,d09GRk9UVE8AABCAAAoAAAAAEDgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAAA9AAAC5UAAAuVXPOdF09TLzIAAAyMAAAAYAAAAGAOkgW+Y21hcAAADOwAAABMAAAATBfN0XNnYXNwAAANOAAAAAgAAAAIAAAAEGhlYWQAAA1AAAAANgAAADYC8En+aGhlYQAADXgAAAAkAAAAJAgIBPtobXR4AAANnAAAAEQAAABERRUSm21heHAAAA3gAAAABgAAAAYAEVAAbmFtZQAADegAAAJ2AAACdoHSvKxwb3N0AAAQYAAAACAAAAAgAAMAAAEABAQAAQEBD2g1cC1jb3JlLWZvbnRzAAECAAEAO/gcAvgbA/gYBB4KAAl3/4uLHgoACXf/i4sMB4tLHAUp+lQFHQAAANQPHQAAANkRHQAAAAkdAAALjBIAEgEBDx0fISQpLjM4PUJHTFFWW2BlaDVwLWNvcmUtZm9udHNoNXAtY29yZS1mb250c3UwdTF1MjB1RTg4OHVFODg5dUU4OEF1RTg4QnVFODhDdUU4OER1RTg4RXVFODhGdUU4OTB1RTg5MXVFODkydUU4OTN1RTg5NAAAAgGJAA8AEQIAAQAEAAcACgANAGYAwQEmAkUDZQPyBNIHEQefCL4JYgoqCo3+lA7+lA7+lA78lA73vfko+VQV+yCL+wX7Bov7IIv7D+El9whzCIv3YjSLBYCLh5KSlAj3Gvc5BZKUlouTggj3Gfs5BZKDh4OAiwg0i4v7YgX3CKPi8Yv3D4r3IPsF9wb7IYsIDve9+Sr5UhX7IIv7BvsGi/sgi/sg9wb7Bvcgi/cgi/cG9waL9yCL9yD7BvcG+yCLCGNaFd+Li0k3i4vNBfcT/A8V+0KLi769i4v3M1mLi773GouL+2azi4tYBQ73vfox94EV+wb3BgWmsZu6i72L9xMj8/sTi/sUiyMji/sTi/sU8yP3FIu9i7mbsacI9wf7BwWQhpSLkJAIra0FkZGLk4WRCPvC3RUui0HVi+iL59XW6Ivni9ZAiy+LLkBBL4sIDve999j4yxWHho2HkYsI9wN/BZGKkJCKkQh/9wMFi5GHjYaHCCMjBdbOFUrMBYePhIuHhwh0dAWGh4uEkIYIzEoF+KvXFYePh4mLhQh/+wMFioWQhpGMCPcDlwWRi42PhpAII/MFz0AVzMwFj4+LkoePCHSiBYeQhIuGhghKSgXW+84VkJCJj4WLCPsDlwWFjIaGjIUIl/sDBYuFj4mPjwjz8wVBRxXLSwWQhpKLj5AIoqIFj4+LkoePCErMBfysQBWQh4+Ni5EIl/cDBYyRhpCFigj7A38FhYqJiI+GCPMjBUjWFUpKBYaHi4SQhwiidAWPhpKLj5AIzMsF2vfUFYv7jPgBi4v3jPwBiwX31PtfFfuni4v3Mveni4v7MgUO9734hPjvFY+Pio+FjAj7BJcFhYuHh4uFCJf7BAWMhY+Kj48I8/MFQEcVzEoFj4eSi5CPCKKiBY+Qi5KHjwhKzAX4bUAVj4ePjIyRCJb3BAWMkYePhYsI+wR/BYWKioePhwjzIwVH1hVKSgWHh4uEj4YIonQFj4eSi5CPCMzMBUD7jxWHh4yHkYoI9wR/BZGLj4+KkQiA9wQFipGHjIeHCCMjBdbPFUrMBYePhIuGhwh0cwWHh4uEj4cIzEoF/G3WFYePh4qKhQh/+wQFi4WPh5GLCPcElwWRjIyPh48II/MFz0AVzMwFj4+LkoeQCHOiBYePhIuHhwhKSgX7HPf3FYv8mvmDi4v4mv2DiwX5VvxtFf0pi4v4QPkpi4v8QAUO9735nPj8FZWLjZGFkgj7A/ceBYWSgouFhAj7A/seBYWEjoWUiwj3e4sF+zOTFYv7PAWLgpODlYsIvosFlYuSk4uUCIv3PAX7MvvsFYGLiYWRhAj3A/seBZGElIuRkgj3A/ceBZGSiJGCiwj7e4sF9zKDFYv3PAWLlISTgYsIWIsFgYuDg4uCCIv7PAUO9736u/j1FXWfa5Zhiwj7KYuLPvs9i31OBZeRnI+WjpeOlomWi7KLqn+jdKJ0l26LaItyhXN/dH90eXh1f4KHgo2CgQj3IouL9yTRiwW7i6+VoqGioZapi7GMsYCndqAIKvsNFYKDe4h0iwhoi4vhsosFoYubhpKDk4KPgYt/i36HgYKDCPu6YhV2i3l/gnkIJJq592Qni4v7N/sOi4v3N/sMi4v8FPcMi4v3JPcOi4v7JPcpiwV5lXyOf5V+lIGWg5eDl4WZhp0I8poFlHqdf6CLqIuio4uoi6h0o26LCA73vfqb+EEVjIiKi4mIdnVxfm2Efop/iX+Lf4uFi4KNiYuKjImNSMhGyEjIioyHi4qLc4VzhHGFCHKGcY5zmn6TgpaEmYeVkZiWjraYt5u0m5iQmY6aiY+LkIiQirV7tHy1e4yJjouPjQipk6uVqpOOjIyKjYkI/Iz7YxWelZ2ImXuYfot7gXafjpmFlXuWeYh7fHuQi5GLkIqah5aCj3yQfYh+goKGhISGh4UIhoWEhoeEfH1ziX2abKlyrXCseaJ7oHuhg5WGlIqYi5OMk5KRlJWTlJWVnZ2phpl2CI2KjIiNhwj3KvtoFaduBZx7qI6WoAiIjgV1oXKjdaKIjomQjZCMj4+Pj4yQjZCJjoeafJt7mX2afJt9mXuTgZaKloyaj5STkpkIjI6KjYmMYLZgtWG2iI6IkIySjZSWkJWFjImNi4uJtmC4XrZgjoiNi46LnYybmo6cCIuPi4yJjVq8Wb1avYeOio6LkIuPjpKQjJCNj4uQho6IkIaOiK9ormeuaJaAloGVgAiNio6JjI2jj5qlgaMIsooFi4qLi4uLjIOLgoqDhG16d26CiYuJiYuJgmxzdmmIiIuLiYqJeWpje2mXh42GjoaNCIWEg4WDiHB+bJF2oIKVgZSAlZOTkZOVlQiMigX7OvicFauBqYCrga2Aq4GsgI2Li4uNinmEe4Z7hYqLiYuJi1+ZXJpemYiNiomHigg7+04Fi4GQg5KDjoeOh42Kg4OEg4OBe55+n4qkCOT3aQWLi5iYmIgIDve9+Sj5UhX7IIv7BfsGi/sgi/sg9wX7Bvcgi/chi/cF9waL9yCL9yD7BfcG+yGLCPcc+98VkoSLgISECGlpBYSEgIuEkgg+2D8+BYSEgIuEkghprQWEkouWkpII19g/2AWEkouWkpIIra0FkpKWi5KECNc+2NgFkpKWi5KECK1pBZKEi4CEhAg+Ptg+BQ73vffY+MsVh4aNh5GLCPcDfwWRipCQipEIf/cDBYuRh42GhwgjIwXWzhVKzAWHj4SLh4cIdHQFhoeLhJCGCMxKBfir1xWHj4eJi4UIf/sDBYqFkIaRjAj3A5cFkYuNj4aQCCPzBc9AFczMBY+Pi5KHjwh0ogWHkISLhoYISkoF1vvOFZCQiY+Fiwj7A5cFhYyGhoyFCJf7AwWLhY+Jj48I8/MFQUcVy0sFkIaSi4+QCKKiBY+Pi5KHjwhKzAX8rEAVkIePjYuRCJf3AwWMkYaQhYoI+wN/BYWKiYiPhgjzIwVI1hVKSgWGh4uEkIcIonQFj4aSi4+QCMzLBdr31BWL+4z4AYuL94z8AYsF99T7XxX7p4uL9zL3p4uL+zIFDve9+Oz35RWPiI+Ei4YIi1AFi4aHiYeOCPtx9ygFho6IkouQCIu9BYuRjpKQjgj3cfcqBY+Oj4mLhQiLUAWLhoeEh4gI+y0gBYaIi4aQiAj3LSMF96bzFZCOi5CGjgj7LfUFh46Hk4uQCIvGBYuQj42PiAj3cfspBZCIjoSLhQiLWQWLhYiEhogI+3H7KAWHiIeNi5EIi8UFi5GPko+OCPct8wUO9734ivifFX6Lh4OTgQj3LftQBZOBmIuTlQj3LPdQBZSVh5N+iwj70YsF922BFYv3HwWLmIGWfosIRIsFfouBgIt+CIv7HwX3WPsdFYOLf4WGhQg/LgWGhIGBhIaLi4eHgIuBi4ePi4uEkIGVhpIIP+gFhpF/kYOLCPsWiwWCi4SEi4IIi/siBYuDkoSUiwj4rIsFk4uSkouTCIv3IgWLlISSg4sI+xeLBfvy+wcVfIt+mIuai5uYmJqLm4uXfot7i3x/fnuLCA73vfl7+FQV9vYFlJWLmoKVCFu6BYKVe4uCgQj7ACAg9gWClXuLgoEIW1wFgoGLfJSBCPYgICAFgoGLfJSBCLtcBZSBm4uUlQj29vcAIAWUgZuLlJUIu7oFlJWLmoKVCCD2BQ76lBT6lBWLDAoAAAAAAwQAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADolAPA/8D/wAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAACAAAAAwAAABQAAwABAAAAFAAEADgAAAAKAAgAAgACAAEAIOiU//3//wAAAAAAIOiI//3//wAB/+MXfAADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAEAANTpLhBfDzz1AAsEAAAAAADPxgMBAAAAAM/GAwEAAAAABEYC/wAAAAgAAgAAAAAAAAABAAADwP/AAAAFKQAAAAAERgABAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAIAAAAFKQGXBSkBmAUpAYcFKQEoBSkBHQUpAhsFKQDhBSkBIgUpAZcFKQEoBSkBcwUpAXkFKQHXAABQAAARAAAAAAAWAQ4AAQAAAAAAAQAcAAAAAQAAAAAAAgAOARYAAQAAAAAAAwAcANAAAQAAAAAABAAcASQAAQAAAAAABQAWALoAAQAAAAAABgAOAOwAAQAAAAAACQAoAJIAAQAAAAAACgAoAUAAAQAAAAAACwAcABwAAQAAAAAADQAWADgAAQAAAAAADgBEAE4AAwABBAkAAQAcAAAAAwABBAkAAgAOARYAAwABBAkAAwAcANAAAwABBAkABAAcASQAAwABBAkABQAWALoAAwABBAkABgAcAPoAAwABBAkACQAoAJIAAwABBAkACgAoAUAAAwABBAkACwAcABwAAwABBAkADQAWADgAAwABBAkADgBEAE4AaAA1AHAALQBjAG8AcgBlAC0AZgBvAG4AdABzAGgAdAB0AHAAOgAvAC8AaAA1AHAALgBvAHIAZwBNAEkAVAAgAGwAaQBjAGUAbgBzAGUAaAB0AHQAcAA6AC8ALwBvAHAAZQBuAHMAbwB1AHIAYwBlAC4AbwByAGcALwBsAGkAYwBlAG4AcwBlAHMALwBNAEkAVABNAGEAZwBuAHUAcwAgAFYAaQBrACAATQBhAGcAbgB1AHMAcwBlAG4AVgBlAHIAcwBpAG8AbgAgADEALgAwAGgANQBwAC0AYwBvAHIAZQAtAGYAbwBuAHQAc2g1cC1jb3JlLWZvbnRzAGgANQBwAC0AYwBvAHIAZQAtAGYAbwBuAHQAcwBSAGUAZwB1AGwAYQByAGgANQBwAC0AYwBvAHIAZQAtAGYAbwBuAHQAcwBHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') format('woff'),
+ url('../fonts/h5p.ttf?ver=1.2.1') format('truetype'),
+ url('../fonts/h5p.svg?ver=1.2.1#h5pregular') format('svg');
font-weight: normal;
font-style: normal;
}
html.h5p-iframe, html.h5p-iframe > body {
- font-family: Arial, Helvetica, sans-serif;
+ font-family: Sans-Serif; /* Use the browser's default sans-serif font. (Since Heletica doesn't look nice on Windows, and Arial on OS X.) */
width: 100%;
height: 100%;
margin: 0;
@@ -71,45 +65,35 @@ html.h5p-iframe .h5p-content {
color: #e5eef6;
}
-.h5p-enable-fullscreen:before, .h5p-disable-fullscreen:before {
- font-family: H5PFontAwesome4;
-
- font-size: 25px;
-}
.h5p-enable-fullscreen:before {
- content: "\f065";
+ font-family: 'H5P';
+ content: "\e88c";
}
.h5p-disable-fullscreen:before {
- content: "\f066";
+ font-family: 'H5P';
+ content: "\e891";
}
-
.h5p-enable-fullscreen, .h5p-disable-fullscreen {
- display: inline-block;
- line-height: 25px;
- width: 25px;
- height: 25px;
- padding: 6px 6px;
cursor: pointer;
color: #EEE;
background: rgb(0,0,0);
background: rgba(0,0,0,0.3);
- text-decoration: none;
- text-align: center;
+ line-height: 0.975em;
+ font-size: 2em;
+ width: 1.125em;
+ height: 0.925em;
+ text-indent: -0.0875em;
+ outline: none;
}
.h5p-disable-fullscreen {
- position: absolute;
- right: 10px;
- top: 10px;
- z-index: 201;
- background: rgb(0,0,0);
- background: rgba(0,0,0,0.7);
+ line-height: 0.925em;
+ width: 1.1em;
+ height: 0.9em;
}
.h5p-enable-fullscreen:hover, .h5p-disable-fullscreen:hover {
- text-decoration: none;
background: rgba(0,0,0,0.5);
}
-
-.h5p-semi-fullscreen .h5p-content-controls {
+.h5p-semi-fullscreen .h5p-enable-fullscreen {
display: none;
}
@@ -151,35 +135,6 @@ div.h5p-fullscreen {
border: 0;
display: block;
}
-.h5p-iframe-wrapper.h5p-semi-fullscreen .buttons button:before {
- content: 'Exit ';
-}
-.h5p-iframe-wrapper button.fullscreen {
- color: #e5eef6;
- text-decoration: none;
- padding: 6px 12px;
- background: #539ad7;
- background-image: -webkit-linear-gradient(top,#4584ba,#539ad7);
- background-image: -moz-linear-gradient(top,#4584ba,#539ad7);
- background-image: -o-linear-gradient(top,#4584ba,#539ad7);
- background-image: -ms-linear-gradient(top,#4584ba,#539ad7);
- background-image: linear-gradient(to bottom,#4584ba,#539ad7);
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4584ba',endColorstr='#539ad7',GradientType=0);
- box-shadow: 0 0 8px #bebebe;
- border: none;
- opacity: 0.8;
-}
-.h5p-iframe-wrapper button.fullscreen:hover {
- opacity: 1;
- background: #539ad7;
- background-image: -webkit-linear-gradient(top,#539ad7,#4584ba);
- background-image: -moz-linear-gradient(top,#539ad7,#4584ba);
- background-image: -o-linear-gradient(top,#539ad7,#4584ba);
- background-image: -ms-linear-gradient(top,#539ad7,#4584ba);
- background-image: linear-gradient(to bottom,#539ad7,#4584ba);
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#539ad7',endColorstr='#4584ba',GradientType=0);
- cursor: pointer;
-}
.h5p-content ul.h5p-actions {
box-sizing: border-box;
@@ -194,7 +149,7 @@ div.h5p-fullscreen {
border-top: 1px solid #EEE;
border-bottom: 1px solid #EEE;
clear: both;
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-family: Sans-Serif;
}
.h5p-fullscreen .h5p-actions, .h5p-semi-fullscreen .h5p-actions {
display: none;
@@ -214,35 +169,38 @@ div.h5p-fullscreen {
color: #666;
}
.h5p-actions > .h5p-button:before {
- font-family: H5PFontAwesome4;
+ font-family: 'H5P';
font-size: 1em;
- padding-right: 0.3em;
+ padding-right: 0;
+ font-size: 1.7em;
+ line-height: 1.125em;
+ vertical-align: middle;
}
.h5p-actions > .h5p-button.h5p-export:before {
- content: "\f019";
+ content: "\e893";
}
.h5p-actions > .h5p-button.h5p-copyrights:before {
- font-family: H5P;
- content: "\e668";
- font-size: 1.7em;
- padding-right: 0;
- vertical-align: bottom;
+ content: "\e88f";
}
.h5p-actions > .h5p-button.h5p-embed:before {
- content: "\f121";
+ content: "\e892";
}
.h5p-actions .h5p-link {
float: right;
margin-right: 0;
font-size: 2.0em;
+ line-height: 1;
overflow: hidden;
color: #999;
text-decoration: none;
outline: none;
}
.h5p-actions .h5p-link:before {
- font-family: H5P;
- content: "\e667";
+ font-family: 'H5P';
+ content: "\e88e";
+}
+.h5p-actions > li {
+ margin: 0;
}
.h5p-popup-dialog {
position: absolute;
@@ -254,7 +212,6 @@ div.h5p-fullscreen {
padding: 2em;
box-sizing: border-box;
-moz-box-sizing: border-box;
-/* background: rgba(50,50,50,0.5);*/
opacity: 0;
-webkit-transition: opacity 0.2s;
-moz-transition: opacity 0.2s;
@@ -315,8 +272,8 @@ div.h5p-fullscreen {
outline:none
}
.h5p-popup-dialog .h5p-close:after {
- font-family: H5PFontAwesome4;
- content: "\f00d";
+ font-family: 'H5P';
+ content: "\e894";
font-size: 2em;
position: absolute;
right: 0.5em;
@@ -360,3 +317,9 @@ div.h5p-fullscreen {
margin-left: 0.25em;
padding-left: 0.25em;
}
+.h5p-throbber {
+ background: url('../images/throbber.gif?ver=1.2.1') 10px center no-repeat;
+ padding-left: 38px;
+ min-height: 30px;
+ line-height: 30px;
+}
\ No newline at end of file