From 515365d8df2ff00215d8ad6d67535529430eb39b Mon Sep 17 00:00:00 2001 From: thomasmars Date: Thu, 2 Mar 2017 14:14:26 +0100 Subject: [PATCH 01/17] Add common hub endpoint to core HFP-794 --- h5p.classes.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/h5p.classes.php b/h5p.classes.php index f12ae20..c85091f 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1725,6 +1725,12 @@ class H5PCore { 'js/h5p-utils.js', ); + const CONTENT_TYPES = 0; + + public static $hubEndpoints = array( + self::CONTENT_TYPES => 'api.h5p.org/v1/content-types/' + ); + public static $defaultContentWhitelist = 'json png jpg jpeg gif bmp tif tiff svg eot ttf woff woff2 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'; From 79e32f0a7f1da3b7f94e9a414f9bdb0384d1c519 Mon Sep 17 00:00:00 2001 From: thomasmars Date: Thu, 2 Mar 2017 14:21:11 +0100 Subject: [PATCH 02/17] Added proper protocol for endpoints HFP-794 --- h5p.classes.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index c85091f..85f0116 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2770,8 +2770,6 @@ class H5PCore { * @return bool|object Returns endpoint data if found, otherwise FALSE */ public function updateContentTypeCache($postData = NULL) { - $endpoint = 'http://api.h5p.org/v1/content-types'; - $interface = $this->h5pF; // Set uuid @@ -2783,7 +2781,9 @@ class H5PCore { $postData['current_cache'] = $this->h5pF->getOption('content_type_cache_updated_at', 0); - $data = $interface->fetchExternalData($endpoint, $postData); + $protocol = (extension_loaded('openssl') ? 'https' : 'http'); + $endpoint = H5PCore::$hubEndpoints[H5PCore::CONTENT_TYPES]; + $data = $interface->fetchExternalData($protocol . $endpoint, $postData); // No data received if (!$data) { From c0e82edfb4b4e4c422fb5613e21ab5303000a5ea Mon Sep 17 00:00:00 2001 From: thomasmars Date: Thu, 2 Mar 2017 14:25:30 +0100 Subject: [PATCH 03/17] Fixed endpoint address HFP-794 --- h5p.classes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index 85f0116..0ce52a2 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2783,7 +2783,7 @@ class H5PCore { $protocol = (extension_loaded('openssl') ? 'https' : 'http'); $endpoint = H5PCore::$hubEndpoints[H5PCore::CONTENT_TYPES]; - $data = $interface->fetchExternalData($protocol . $endpoint, $postData); + $data = $interface->fetchExternalData("{$protocol}://{$endpoint}", $postData); // No data received if (!$data) { From 0af411bac8fd6d09b61f86ce887257a0144fe54f Mon Sep 17 00:00:00 2001 From: thomasmars Date: Thu, 2 Mar 2017 14:39:36 +0100 Subject: [PATCH 04/17] Send json as camelCase HFP-794 --- h5p.classes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index 0ce52a2..478844d 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2704,7 +2704,7 @@ class H5PCore { } if ($error_code !== NULL) { - $response['error_code'] = $error_code; + $response['errorCode'] = $error_code; } self::printJson($response); From 410c2a9ae18af0d66ae50f13b77e1b1f6ffadba3 Mon Sep 17 00:00:00 2001 From: thomasmars Date: Fri, 3 Mar 2017 10:33:21 +0100 Subject: [PATCH 05/17] Added permission check for restricted local libraries Renamed cached library map function to something more appropriate HFP-797 --- h5p.classes.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 478844d..e3dc773 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1685,6 +1685,7 @@ Class H5PExport { abstract class H5PPermission { const DOWNLOAD_H5P = 0; const EMBED_H5P = 1; + const CREATE_RESTRICTED = 2; } abstract class H5PDisplayOptionBehaviour { @@ -2818,10 +2819,10 @@ class H5PCore { * * @param object $cached_library A single library from the content type cache * - * @return array A list containing the necessary properties for a cached + * @return array A map containing the necessary properties for a cached * library to send to the front-end */ - public function getCachedLibAsList($cached_library) { + public function getCachedLibsMap($cached_library) { return array( 'id' => $cached_library->id, 'machineName' => $cached_library->machine_name, @@ -2862,6 +2863,7 @@ class H5PCore { * @param array $cached_libraries Cached libraries from the H5P hub */ public function mergeLocalLibsIntoCachedLibs($local_libraries, &$cached_libraries) { + $can_create_restricted = $this->h5pF->hasPermission(H5PPermission::CREATE_RESTRICTED); // Add local libraries to supplement content type cache foreach ($local_libraries as $local_lib) { @@ -2875,7 +2877,8 @@ class H5PCore { // Set local properties $cached_lib['installed'] = TRUE; - $cached_lib['restricted'] = $local_lib->restricted; + $cached_lib['restricted'] = $can_create_restricted ? FALSE + : $local_lib->restricted; // TODO: set icon if it exists locally HFP-807 // Determine if library is the same as ct cache @@ -2900,7 +2903,7 @@ class H5PCore { 'patchVersion' => $local_lib->patch_version, 'installed' => TRUE, 'isUpToDate' => TRUE, - 'restricted' => $local_lib->restricted + 'restricted' => $can_create_restricted ? FALSE : $local_lib->restricted ); } } From 318b9f48195af78cfb9e5133c3b7176a289c7d8e Mon Sep 17 00:00:00 2001 From: thomasmars Date: Fri, 3 Mar 2017 10:43:39 +0100 Subject: [PATCH 06/17] Restrict LRS dependent content if set HFP-797 --- h5p.classes.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/h5p.classes.php b/h5p.classes.php index e3dc773..8112a5c 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2907,6 +2907,15 @@ class H5PCore { ); } } + + // Restrict LRS dependent content + if (!$this->h5pF->getOption('enable_lrs_content_types')) { + foreach ($cached_libraries as &$lib) { + if ($lib['machineName'] === 'H5P.Questionnaire') { + $lib['restricted'] = TRUE; + } + } + } } /** From 217c2006a4a54238010bf61d480c4c12db31fd5f Mon Sep 17 00:00:00 2001 From: thomasmars Date: Fri, 3 Mar 2017 11:29:09 +0100 Subject: [PATCH 07/17] Separate between setup error messages and disabling hub HFP-509 --- h5p.classes.php | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 8112a5c..f6227a2 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2921,72 +2921,81 @@ class H5PCore { /** * Check if the current server setup is valid and set error messages * - * @return array Errors found + * @return object Setup object with errors and disable hub properties */ public function checkSetupErrorMessage() { - $errors = array(); + $setup = (object) array( + 'errors' => array(), + 'disable_hub' => FALSE + ); if (!class_exists('ZipArchive')) { - $errors[] = $this->h5pF->t('Your PHP version does not support ZipArchive.'); + $setup->errors[] = $this->h5pF->t('Your PHP version does not support ZipArchive.'); + $setup->disable_hub = TRUE; } if (!extension_loaded('mbstring')) { - $errors[] = - $this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'); + $setup->errors[] = $this->h5pF->t( + 'The mbstring PHP extension is not loaded. H5P need this to function properly' + ); + $setup->disable_hub = TRUE; } // Check php version >= 5.2 $php_version = explode('.', phpversion()); if ($php_version[0] < 5 || ($php_version[0] === 5 && $php_version[1] < 2)) { - $errors[] = - $this->h5pF->t('Your PHP version is outdated. H5P requires version 5.2 to function properly. Version 5.6 or later is recommended.'); + $setup->errors[] = $this->h5pF->t('Your PHP version is outdated. H5P requires version 5.2 to function properly. Version 5.6 or later is recommended.'); + $setup->disable_hub = TRUE; } // Check write access if (!$this->fs->hasWriteAccess()) { - $errors[] = - $this->h5pF->t('A problem with the server write access was detected. Please make sure that your server can write to your data folder.'); + $setup->errors[] = $this->h5pF->t('A problem with the server write access was detected. Please make sure that your server can write to your data folder.'); + $setup->disable_hub = TRUE; } $max_upload_size = self::returnBytes(ini_get('upload_max_filesize')); $max_post_size = self::returnBytes(ini_get('post_max_size')); $byte_threshold = 5000000; // 5MB if ($max_upload_size < $byte_threshold) { - $errors[] = + $setup->errors[] = $this->h5pF->t('Your PHP max upload size option is too small. You should consider to increase it to more than 5MB.'); } if ($max_post_size < $byte_threshold) { - $errors[] = + $setup->errors[] = $this->h5pF->t('Your PHP max post size option is too small. You should consider to increase it to more than 5MB.'); } if ($max_upload_size > $max_post_size) { - $errors[] = + $setup->errors[] = $this->h5pF->t('Your PHP max upload size is bigger than your max post size. This is known to cause issues in some installations.'); } // Check SSL if (!extension_loaded('openssl')) { - $errors[] = + $setup->errors[] = $this->h5pF->t('Your server does not have SSL enabled. SSL should be enabled to ensure a secure connection with the H5P hub.'); + $setup->disable_hub = TRUE; } - return $errors; + return $setup; } /** * Check that all H5P requirements for the server setup is met. */ public function checkSetupForRequirements() { - $errors = $this->checkSetupErrorMessage(); + $setup = $this->checkSetupErrorMessage(); - $this->h5pF->setOption('hub_is_enabled', empty($errors)); - if (!empty($errors)) { - foreach ($errors as $err) { + $this->h5pF->setOption('hub_is_enabled', !$setup->disable_hub); + if (!empty($setup->errors)) { + foreach ($setup->errors as $err) { $this->h5pF->setErrorMessage($err); } + } + if ($setup->disable_hub) { // Inform how to re-enable hub $this->h5pF->setErrorMessage( $this->h5pF->t('H5P hub communication has been disabled because one or more H5P requirements failed.') From a95323948eeda654e8ea72d6c89275015e461a49 Mon Sep 17 00:00:00 2001 From: thomasmars Date: Fri, 3 Mar 2017 14:47:15 +0100 Subject: [PATCH 08/17] Improved upload size error msg HFP-509 --- h5p.classes.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index f6227a2..d5569d1 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2959,12 +2959,12 @@ class H5PCore { $byte_threshold = 5000000; // 5MB if ($max_upload_size < $byte_threshold) { $setup->errors[] = - $this->h5pF->t('Your PHP max upload size option is too small. You should consider to increase it to more than 5MB.'); + $this->h5pF->t('Your PHP max upload size is quite small. With your current setup, you may not upload files larger than %number MB. This might be a problem when trying to upload H5Ps, images and videos. Please consider to increase it to more than 5MB.', array('%number' => number_format($max_upload_size / 1024 / 1024, 2, '.', ' '))); } if ($max_post_size < $byte_threshold) { $setup->errors[] = - $this->h5pF->t('Your PHP max post size option is too small. You should consider to increase it to more than 5MB.'); + $this->h5pF->t('Your PHP max post size is quite small. With your current setup, you may not upload files larger than %number MB. This might be a problem when trying to upload H5Ps, images and videos. Please consider to increase it to more than 5MB', array('%number' => number_format($max_upload_size / 1024 / 1024, 2, '.', ' '))); } if ($max_upload_size > $max_post_size) { From ae56eef91da34b57eb77dc01e360ae86ebf9fcc2 Mon Sep 17 00:00:00 2001 From: thomasmars Date: Fri, 3 Mar 2017 15:45:19 +0100 Subject: [PATCH 09/17] Use ID instead of library_id for lbiraries HFP-793 --- h5p.classes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index d5569d1..f9508d0 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2896,7 +2896,7 @@ class H5PCore { // Add minimal data to display local only libraries if ($is_local_only) { $cached_libraries[] = array( - 'id' => $local_lib->library_id, + 'id' => $local_lib->id, 'machineName' => $local_lib->machine_name, 'majorVersion' => $local_lib->major_version, 'minorVersion' => $local_lib->minor_version, From c8b123c5c3205818485bf3880e1e85816097b390 Mon Sep 17 00:00:00 2001 From: Paal Joergensen Date: Tue, 7 Mar 2017 09:46:16 +0100 Subject: [PATCH 10/17] Using local icon if present (HFP-807) --- h5p.classes.php | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index f9508d0..e2e1bba 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -67,6 +67,8 @@ interface H5PFrameworkInterface { */ public function t($message, $replacements = array()); + public function getLibraryFilePath($library_folder, $file); + /** * Get the Path to the last uploaded h5p * @@ -2868,18 +2870,33 @@ class H5PCore { // Add local libraries to supplement content type cache foreach ($local_libraries as $local_lib) { $is_local_only = TRUE; - foreach ($cached_libraries as &$cached_lib) { + // Check if icon is available locally: + if($local_lib->has_icon) { + // Create path to icon: + $library_folder = H5PCore::libraryToString(array( + 'machineName' => $local_lib->machine_name, + 'majorVersion' => $local_lib->major_version, + 'minorVersion' => $local_lib->minor_version + ), TRUE); + $icon_path = $this->h5pF->getLibraryFilePath($library_folder, 'icon.svg'); + } + + foreach ($cached_libraries as &$cached_lib) { // Determine if library is local $is_matching_library = $cached_lib['machineName'] === $local_lib->machine_name; if ($is_matching_library) { $is_local_only = FALSE; + // Set icon if it exists locally + if(isset($icon_path)) { + $cached_lib['icon'] = $icon_path; + } + // Set local properties $cached_lib['installed'] = TRUE; $cached_lib['restricted'] = $can_create_restricted ? FALSE : $local_lib->restricted; - // TODO: set icon if it exists locally HFP-807 // Determine if library is the same as ct cache $is_updated_library = @@ -2895,7 +2912,7 @@ class H5PCore { // Add minimal data to display local only libraries if ($is_local_only) { - $cached_libraries[] = array( + $local_only_lib = array( 'id' => $local_lib->id, 'machineName' => $local_lib->machine_name, 'majorVersion' => $local_lib->major_version, @@ -2905,6 +2922,12 @@ class H5PCore { 'isUpToDate' => TRUE, 'restricted' => $can_create_restricted ? FALSE : $local_lib->restricted ); + + if (isset($icon_path)) { + $local_only_lib['icon'] = $icon_path; + } + + $cached_libraries[] = $local_only_lib; } } From 37f4399ab4b4a1d3ae68390f47e8eb8b5edd3d62 Mon Sep 17 00:00:00 2001 From: Paal Joergensen Date: Tue, 7 Mar 2017 10:25:52 +0100 Subject: [PATCH 11/17] Added interface function that returns library file URL [HFP-805] --- h5p.classes.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index e2e1bba..90c0333 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -67,7 +67,13 @@ interface H5PFrameworkInterface { */ public function t($message, $replacements = array()); - public function getLibraryFilePath($library_folder, $file); + /** + * Get URL to file in the specific library + * @param string $libraryFolderName + * @param string $fileName + * @return string URL to file + */ + public function getLibraryFileUrl($libraryFolderName, $fileName); /** * Get the Path to the last uploaded h5p From 914ee55ac51e5ae61a83f0ed75e2e51ead677dca Mon Sep 17 00:00:00 2001 From: Paal Joergensen Date: Tue, 7 Mar 2017 10:36:49 +0100 Subject: [PATCH 12/17] Fixed broken core - using wrong function name [HFP-805] --- h5p.classes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index 90c0333..52856fd 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2885,7 +2885,7 @@ class H5PCore { 'majorVersion' => $local_lib->major_version, 'minorVersion' => $local_lib->minor_version ), TRUE); - $icon_path = $this->h5pF->getLibraryFilePath($library_folder, 'icon.svg'); + $icon_path = $this->h5pF->getLibraryFileUrl($library_folder, 'icon.svg'); } foreach ($cached_libraries as &$cached_lib) { From f247bbdfe8c2457ee12f1be639144522523246ff Mon Sep 17 00:00:00 2001 From: Paal Joergensen Date: Tue, 7 Mar 2017 11:24:08 +0100 Subject: [PATCH 13/17] Improved json returned from content type cache endpoint --- h5p.classes.php | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 52856fd..7ef173d 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -2831,33 +2831,46 @@ class H5PCore { * library to send to the front-end */ public function getCachedLibsMap($cached_library) { - return array( - 'id' => $cached_library->id, + // Add mandatory fields + $lib = array( + 'id' => intval($cached_library->id), 'machineName' => $cached_library->machine_name, - 'majorVersion' => $cached_library->major_version, - 'minorVersion' => $cached_library->minor_version, - 'patchVersion' => $cached_library->patch_version, - 'h5pMajorVersion' => $cached_library->h5p_major_version, - 'h5pMinorVersion' => $cached_library->h5p_minor_version, + 'majorVersion' => intval( $cached_library->major_version), + 'minorVersion' => intval($cached_library->minor_version), + 'patchVersion' => intval($cached_library->patch_version), + 'h5pMajorVersion' => intval($cached_library->h5p_major_version), + 'h5pMinorVersion' => intval($cached_library->h5p_minor_version), 'title' => $cached_library->title, 'summary' => $cached_library->summary, 'description' => $cached_library->description, 'icon' => $cached_library->icon, - 'createdAt' => $cached_library->created_at, - 'updatedAt' => $cached_library->updated_at, - 'isRecommended' => $cached_library->is_recommended, - 'popularity' => $cached_library->popularity, + 'createdAt' => intval($cached_library->created_at), + 'updatedAt' => intval($cached_library->updated_at), + 'isRecommended' => $cached_library->is_recommended != 0, + 'popularity' => intval($cached_library->popularity), 'screenshots' => json_decode($cached_library->screenshots), 'license' => $cached_library->license, - 'example' => $cached_library->example, - 'tutorial' => $cached_library->tutorial, - 'keywords' => json_decode($cached_library->keywords), - 'categories' => json_decode($cached_library->categories), 'owner' => $cached_library->owner, 'installed' => FALSE, 'isUpToDate' => FALSE, 'restricted' => isset($cached_library->restricted) ? $cached_library->restricted : FALSE ); + + // Add optional fields + if (!empty($cached_library->categories)) { + $lib['categories'] = json_decode($cached_library->categories); + } + if (!empty($cached_library->keywords)) { + $lib['keywords'] = json_decode($cached_library->keywords); + } + if (!empty($cached_library->tutorial)) { + $lib['tutorial'] = $cached_library->tutorial; + } + if (!empty($cached_library->example)) { + $lib['example'] = $cached_library->example; + } + + return $lib; } /** From 358424f2be43a37707d09916c07bb5f792b0c2be Mon Sep 17 00:00:00 2001 From: Andreas Nergaard Date: Wed, 8 Mar 2017 12:25:56 +0100 Subject: [PATCH 14/17] HFP-826 Added 2 new icons to the core font. --- fonts/h5p-core-17.eot | Bin 6072 -> 0 bytes fonts/h5p-core-17.ttf | Bin 5924 -> 0 bytes fonts/h5p-core-17.woff | Bin 6000 -> 0 bytes fonts/h5p-core-18.eot | Bin 0 -> 6532 bytes fonts/{h5p-core-17.svg => h5p-core-18.svg} | 50 +++++++++++---------- fonts/h5p-core-18.ttf | Bin 0 -> 6384 bytes fonts/h5p-core-18.woff | Bin 0 -> 6460 bytes styles/h5p.css | 10 ++--- 8 files changed, 31 insertions(+), 29 deletions(-) delete mode 100755 fonts/h5p-core-17.eot delete mode 100755 fonts/h5p-core-17.ttf delete mode 100755 fonts/h5p-core-17.woff create mode 100755 fonts/h5p-core-18.eot rename fonts/{h5p-core-17.svg => h5p-core-18.svg} (50%) create mode 100755 fonts/h5p-core-18.ttf create mode 100755 fonts/h5p-core-18.woff diff --git a/fonts/h5p-core-17.eot b/fonts/h5p-core-17.eot deleted file mode 100755 index 89bfcc6349e3036065ebc568728a7ad0eae161a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6072 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 literal 0 HcmV?d00001 diff --git a/fonts/h5p-core-17.svg b/fonts/h5p-core-18.svg similarity index 50% rename from fonts/h5p-core-17.svg rename to fonts/h5p-core-18.svg index 9c12732..13da36e 100755 --- a/fonts/h5p-core-17.svg +++ b/fonts/h5p-core-18.svg @@ -23,28 +23,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/h5p-core-18.ttf b/fonts/h5p-core-18.ttf new file mode 100755 index 0000000000000000000000000000000000000000..37f845e07c942ee71609208e7bb775764e297355 GIT binary patch literal 6384 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 PBP&$QA9rW*|IGdyo!5`V literal 0 HcmV?d00001 diff --git a/styles/h5p.css b/styles/h5p.css index 7bb0a56..cdf593a 100755 --- a/styles/h5p.css +++ b/styles/h5p.css @@ -3,11 +3,11 @@ /* Custom H5P font to use for icons. */ @font-face { font-family: 'h5p'; - src: url('../fonts/h5p-core-17.eot?ddjqkb'); - src: url('../fonts/h5p-core-17.eot?ddjqkb#iefix') format('embedded-opentype'), - url('../fonts/h5p-core-17.ttf?ddjqkb') format('truetype'), - url('../fonts/h5p-core-17.woff?ddjqkb') format('woff'), - url('../fonts/h5p-core-17.svg?ddjqkb#h5p') format('svg'); + src: url('../fonts/h5p-core-18.eot?cb8kvi'); + src: url('../fonts/h5p-core-18.eot?cb8kvi#iefix') format('embedded-opentype'), + url('../fonts/h5p-core-18.ttf?cb8kvi') format('truetype'), + url('../fonts/h5p-core-18.woff?cb8kvi') format('woff'), + url('../fonts/h5p-core-18.svg?cb8kvi#h5p') format('svg'); font-weight: normal; font-style: normal; } From a720d465487e0048bc27c846efa010c749b77b5e Mon Sep 17 00:00:00 2001 From: thomasmars Date: Thu, 9 Mar 2017 17:36:20 +0100 Subject: [PATCH 15/17] Make it easier to send files to the editor HFP-822 --- h5p-default-storage.class.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/h5p-default-storage.class.php b/h5p-default-storage.class.php index eba4257..479c86a 100644 --- a/h5p-default-storage.class.php +++ b/h5p-default-storage.class.php @@ -408,7 +408,7 @@ class H5PDefaultStorage implements \H5PFileStorage { * * @throws Exception Unable to copy the file */ - private static function copyFileTree($source, $destination) { + public static function copyFileTree($source, $destination) { if (!self::dirReady($destination)) { throw new \Exception('unabletocopy'); } @@ -482,4 +482,13 @@ class H5PDefaultStorage implements \H5PFileStorage { return TRUE; } + + /** + * Easy helper function for retrieving the editor path + * + * @return null|string Path to editor files + */ + public function getEditorPath() { + return $this->alteditorpath; + } } From 4999862689de67a8e81042ad4ec7e1cd4666b280 Mon Sep 17 00:00:00 2001 From: Luke Muller Date: Fri, 10 Mar 2017 12:31:20 +1000 Subject: [PATCH 16/17] Fixed iOS bug for Image Hotspots and iFrames There is a bug in iOS with IFrame's that when changing orientation width: 100% stays at landscape rather than going back to portrait. https://bugs.webkit.org/show_bug.cgi?id=155198. Tested on iOS 10 iPhone 7 on image hotspot. --- styles/h5p.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/styles/h5p.css b/styles/h5p.css index cdf593a..cbc296a 100755 --- a/styles/h5p.css +++ b/styles/h5p.css @@ -147,7 +147,9 @@ div.h5p-fullscreen { z-index: 20; } .h5p-iframe-wrapper iframe.h5p-iframe { - width: 100%; + width: 10px; + min-width: 100%; + *width: 100%; height: 100%; z-index: 10; overflow: hidden; From 58d5eef4224f7c6877bad135bb844ead2275a1b4 Mon Sep 17 00:00:00 2001 From: Svein-Tore Griff With Date: Fri, 10 Mar 2017 08:59:46 +0100 Subject: [PATCH 17/17] Document ios landscape / portrait hack --- styles/h5p.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/styles/h5p.css b/styles/h5p.css index cbc296a..b13c6e0 100755 --- a/styles/h5p.css +++ b/styles/h5p.css @@ -147,9 +147,11 @@ div.h5p-fullscreen { z-index: 20; } .h5p-iframe-wrapper iframe.h5p-iframe { + /* Hack for IOS landscape / portrait */ width: 10px; min-width: 100%; *width: 100%; + /* End of hack */ height: 100%; z-index: 10; overflow: hidden;