diff --git a/.gitignore b/.gitignore index 9577d19..e8d34a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ vendor *~ - +.idea \ No newline at end of file diff --git a/fonts/h5p-core-14.eot b/fonts/h5p-core-14.eot deleted file mode 100644 index 9a90816..0000000 Binary files a/fonts/h5p-core-14.eot and /dev/null differ diff --git a/fonts/h5p-core-14.ttf b/fonts/h5p-core-14.ttf deleted file mode 100644 index 77aa1c7..0000000 Binary files a/fonts/h5p-core-14.ttf and /dev/null differ diff --git a/fonts/h5p-core-14.woff b/fonts/h5p-core-14.woff deleted file mode 100644 index e11a5c7..0000000 Binary files a/fonts/h5p-core-14.woff and /dev/null differ diff --git a/fonts/h5p-core-16.eot b/fonts/h5p-core-16.eot new file mode 100644 index 0000000..239079b Binary files /dev/null and b/fonts/h5p-core-16.eot differ diff --git a/fonts/h5p-core-14.svg b/fonts/h5p-core-16.svg similarity index 56% rename from fonts/h5p-core-14.svg rename to fonts/h5p-core-16.svg index f66252d..d0bdb88 100644 --- a/fonts/h5p-core-14.svg +++ b/fonts/h5p-core-16.svg @@ -1,14 +1,34 @@ -Generated by IcoMoon + + + +{ + "fontFamily": "h5p", + "description": "Font generated by IcoMoon.", + "majorVersion": 1, + "minorVersion": 1, + "version": "Version 1.1", + "fontId": "h5p", + "psName": "h5p", + "subFamily": "Regular", + "fullName": "h5p" +} + + + - + + + + + - + @@ -22,4 +42,17 @@ - \ No newline at end of file + + + + + + + + + + + + + + diff --git a/fonts/h5p-core-16.ttf b/fonts/h5p-core-16.ttf new file mode 100644 index 0000000..daf1571 Binary files /dev/null and b/fonts/h5p-core-16.ttf differ diff --git a/fonts/h5p-core-16.woff b/fonts/h5p-core-16.woff new file mode 100644 index 0000000..d654df4 Binary files /dev/null and b/fonts/h5p-core-16.woff differ diff --git a/h5p-default-storage.class.php b/h5p-default-storage.class.php index 6e39670..1141bda 100644 --- a/h5p-default-storage.class.php +++ b/h5p-default-storage.class.php @@ -399,6 +399,8 @@ class H5PDefaultStorage implements \H5PFileStorage { throw new \Exception('unabletocopy'); } + $ignoredFiles = self::getIgnoredFiles("{$source}/.h5pignore"); + $dir = opendir($source); if ($dir === FALSE) { trigger_error('Unable to open directory ' . $source, E_USER_WARNING); @@ -406,7 +408,7 @@ class H5PDefaultStorage implements \H5PFileStorage { } while (false !== ($file = readdir($dir))) { - if (($file != '.') && ($file != '..') && $file != '.git' && $file != '.gitignore') { + if (($file != '.') && ($file != '..') && $file != '.git' && $file != '.gitignore' && !in_array($file, $ignoredFiles)) { if (is_dir("{$source}/{$file}")) { self::copyFileTree("{$source}/{$file}", "{$destination}/{$file}"); } @@ -418,6 +420,25 @@ class H5PDefaultStorage implements \H5PFileStorage { closedir($dir); } + /** + * Retrieve array of file names from file. + * + * @param string $file + * @return array Array with files that should be ignored + */ + private static function getIgnoredFiles($file) { + if (file_exists($file) === FALSE) { + return array(); + } + + $contents = file_get_contents($file); + if ($contents === FALSE) { + return array(); + } + + return preg_split('/\s+/', $contents); + } + /** * Recursive function that makes sure the specified directory exists and * is writable. diff --git a/h5p.classes.php b/h5p.classes.php index cafa043..473d641 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -558,6 +558,16 @@ interface H5PFrameworkInterface { * Will trigger after the export file is created. */ public function afterExportCreated(); + + /** + * Check if user has permissions to an action + * + * @method hasPermission + * @param [H5PPermission] $permission Permission type, ref H5PPermission + * @param [int] $id Id need by platform to determine permission + * @return boolean + */ + public function hasPermission($permission, $id = NULL); } /** @@ -1669,6 +1679,20 @@ Class H5PExport { } } +abstract class H5PPermission { + const DOWNLOAD_H5P = 0; + const EMBED_H5P = 1; +} + +abstract class H5PDisplayOptionBehaviour { + const NEVER_SHOW = 0; + const CONTROLLED_BY_AUTHOR_DEFAULT_ON = 1; + const CONTROLLED_BY_AUTHOR_DEFAULT_OFF = 2; + const ALWAYS_SHOW = 3; + const CONTROLLED_BY_PERMISSIONS = 4; +} + + /** * Functions and storage shared by the other H5P classes */ @@ -1676,7 +1700,7 @@ class H5PCore { public static $coreApi = array( 'majorVersion' => 1, - 'minorVersion' => 11 + 'minorVersion' => 12 ); public static $styles = array( 'styles/h5p.css', @@ -1690,7 +1714,8 @@ class H5PCore { 'js/h5p-x-api-event.js', 'js/h5p-x-api.js', 'js/h5p-content-type.js', - 'js/h5p-confirmation-dialog.js' + 'js/h5p-confirmation-dialog.js', + 'js/h5p-action-bar.js' ); public static $adminScripts = array( 'js/jquery.js', @@ -1713,12 +1738,18 @@ class H5PCore { const DISABLE_COPYRIGHT = 8; const DISABLE_ABOUT = 16; + const DISPLAY_OPTION_FRAME = 'frame'; + const DISPLAY_OPTION_DOWNLOAD = 'export'; + const DISPLAY_OPTION_EMBED = 'embed'; + const DISPLAY_OPTION_COPYRIGHT = 'copyright'; + const DISPLAY_OPTION_ABOUT = 'icon'; + // Map flags to string public static $disable = array( - self::DISABLE_FRAME => 'frame', - self::DISABLE_DOWNLOAD => 'download', - self::DISABLE_EMBED => 'embed', - self::DISABLE_COPYRIGHT => 'copyright' + self::DISABLE_FRAME => self::DISPLAY_OPTION_FRAME, + self::DISABLE_DOWNLOAD => self::DISPLAY_OPTION_DOWNLOAD, + self::DISABLE_EMBED => self::DISPLAY_OPTION_EMBED, + self::DISABLE_COPYRIGHT => self::DISPLAY_OPTION_COPYRIGHT ); /** @@ -2423,7 +2454,9 @@ class H5PCore { // Handle libraries metadata if (isset($json->libraries)) { foreach ($json->libraries as $machineName => $libInfo) { - $this->h5pF->setLibraryTutorialUrl($machineName, $libInfo->tutorialUrl); + if (isset($libInfo->tutorialUrl)) { + $this->h5pF->setLibraryTutorialUrl($machineName, $libInfo->tutorialUrl); + } } } @@ -2440,54 +2473,152 @@ class H5PCore { } /** - * - */ - public function getGlobalDisable() { - $disable = self::DISABLE_NONE; - - // Allow global settings to override and disable options - if (!$this->h5pF->getOption('frame', TRUE)) { - $disable |= self::DISABLE_FRAME; - } - else { - if (!$this->h5pF->getOption('export', TRUE)) { - $disable |= self::DISABLE_DOWNLOAD; - } - if (!$this->h5pF->getOption('embed', TRUE)) { - $disable |= self::DISABLE_EMBED; - } - if (!$this->h5pF->getOption('copyright', TRUE)) { - $disable |= self::DISABLE_COPYRIGHT; - } - if (!$this->h5pF->getOption('icon', TRUE)) { - $disable |= self::DISABLE_ABOUT; - } - } - - return $disable; - } - - /** - * Determine disable state from sources. + * Create representation of display options as int * * @param array $sources * @param int $current * @return int */ - public function getDisable(&$sources, $current) { + public function getStorableDisplayOptions(&$sources, $current) { + // Download - force setting it if always on or always off + $download = $this->h5pF->getOption(self::DISPLAY_OPTION_DOWNLOAD, H5PDisplayOptionBehaviour::ALWAYS_SHOW); + if ($download == H5PDisplayOptionBehaviour::ALWAYS_SHOW || + $download == H5PDisplayOptionBehaviour::NEVER_SHOW) { + $sources[self::DISPLAY_OPTION_DOWNLOAD] = ($download == H5PDisplayOptionBehaviour::ALWAYS_SHOW); + } + + // Embed - force setting it if always on or always off + $embed = $this->h5pF->getOption(self::DISPLAY_OPTION_EMBED, H5PDisplayOptionBehaviour::ALWAYS_SHOW); + if ($embed == H5PDisplayOptionBehaviour::ALWAYS_SHOW || + $embed == H5PDisplayOptionBehaviour::NEVER_SHOW) { + $sources[self::DISPLAY_OPTION_EMBED] = ($embed == H5PDisplayOptionBehaviour::ALWAYS_SHOW); + } + foreach (H5PCore::$disable as $bit => $option) { - if ($this->h5pF->getOption(($bit & H5PCore::DISABLE_DOWNLOAD ? 'export' : $option), TRUE)) { - if (!isset($sources[$option]) || !$sources[$option]) { - $current |= $bit; // Disable - } - else { - $current &= ~$bit; // Enable - } + if (!isset($sources[$option]) || !$sources[$option]) { + $current |= $bit; // Disable + } + else { + $current &= ~$bit; // Enable } } return $current; } + /** + * Determine display options visibility and value on edit + * + * @param int $disable + * @return array + */ + public function getDisplayOptionsForEdit($disable = NULL) { + $display_options = []; + + $current_display_options = $disable === NULL ? [] : $this->getDisplayOptionsAsArray($disable); + + if ($this->h5pF->getOption(self::DISPLAY_OPTION_FRAME, TRUE)) { + $display_options[self::DISPLAY_OPTION_FRAME] = + isset($current_display_options[self::DISPLAY_OPTION_FRAME]) ? + $current_display_options[self::DISPLAY_OPTION_FRAME] : + TRUE; + + // Download + $export = $this->h5pF->getOption(self::DISPLAY_OPTION_DOWNLOAD, H5PDisplayOptionBehaviour::ALWAYS_SHOW); + if ($export == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_ON || + $export == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF) { + $display_options[self::DISPLAY_OPTION_DOWNLOAD] = + isset($current_display_options[self::DISPLAY_OPTION_DOWNLOAD]) ? + $current_display_options[self::DISPLAY_OPTION_DOWNLOAD] : + ($export == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_ON); + } + + // Embed + $embed = $this->h5pF->getOption(self::DISPLAY_OPTION_EMBED, H5PDisplayOptionBehaviour::ALWAYS_SHOW); + if ($embed == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_ON || + $embed == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF) { + $display_options[self::DISPLAY_OPTION_EMBED] = + isset($current_display_options[self::DISPLAY_OPTION_EMBED]) ? + $current_display_options[self::DISPLAY_OPTION_EMBED] : + ($embed == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_ON); + } + + // Copyright + if ($this->h5pF->getOption(self::DISPLAY_OPTION_COPYRIGHT, TRUE)) { + $display_options[self::DISPLAY_OPTION_COPYRIGHT] = + isset($current_display_options[self::DISPLAY_OPTION_COPYRIGHT]) ? + $current_display_options[self::DISPLAY_OPTION_COPYRIGHT] : + TRUE; + } + } + + return $display_options; + } + + /** + * Helper function used to figure out embed & download behaviour + * + * @param string $option_name + * @param H5PPermission $permission + * @param int $id + * @param bool &$value + */ + private function setDisplayOptionOverrides($option_name, $permission, $id, &$value) { + $behaviour = $this->h5pF->getOption($option_name, H5PDisplayOptionBehaviour::ALWAYS_SHOW); + // If never show globally, force hide + if ($behaviour == H5PDisplayOptionBehaviour::NEVER_SHOW) { + $value = false; + } + elseif ($behaviour == H5PDisplayOptionBehaviour::ALWAYS_SHOW) { + // If always show or permissions say so, force show + $value = true; + } + elseif ($behaviour == H5PDisplayOptionBehaviour::CONTROLLED_BY_PERMISSIONS) { + $value = $this->h5pF->hasPermission($permission, $id); + } + } + + /** + * Determine display option visibility when viewing H5P + * + * @param int $display_options + * @param int $id Might be content id or user id. + * Depends on what the platform needs to be able to determine permissions. + * @return array + */ + public function getDisplayOptionsForView($disable, $id) { + $display_options = $this->getDisplayOptionsAsArray($disable); + + if ($this->h5pF->getOption(self::DISPLAY_OPTION_FRAME, TRUE) == FALSE) { + $display_options[self::DISPLAY_OPTION_FRAME] = false; + } + else { + $this->setDisplayOptionOverrides(self::DISPLAY_OPTION_DOWNLOAD, H5PPermission::DOWNLOAD_H5P, $id, $display_options[self::DISPLAY_OPTION_DOWNLOAD]); + $this->setDisplayOptionOverrides(self::DISPLAY_OPTION_EMBED, H5PPermission::EMBED_H5P, $id, $display_options[self::DISPLAY_OPTION_EMBED]); + + if ($this->h5pF->getOption(self::DISPLAY_OPTION_COPYRIGHT, TRUE) == FALSE) { + $display_options[self::DISPLAY_OPTION_COPYRIGHT] = false; + } + } + + return $display_options; + } + + /** + * Convert display options as single byte to array + * + * @param int $disable + * @return array + */ + private function getDisplayOptionsAsArray($disable) { + return array( + self::DISPLAY_OPTION_FRAME => !($disable & H5PCore::DISABLE_FRAME), + self::DISPLAY_OPTION_DOWNLOAD => !($disable & H5PCore::DISABLE_DOWNLOAD), + self::DISPLAY_OPTION_EMBED => !($disable & H5PCore::DISABLE_EMBED), + self::DISPLAY_OPTION_COPYRIGHT => !($disable & H5PCore::DISABLE_COPYRIGHT), + self::DISPLAY_OPTION_ABOUT => $this->h5pF->getOption(self::DISPLAY_OPTION_ABOUT, TRUE), + ); + } + /** * Small helper for getting the library's ID. * @@ -3134,7 +3265,29 @@ class H5PContentValidator { return; } if (!in_array($value->library, $semantics->options)) { - $this->h5pF->setErrorMessage($this->h5pF->t('Library used in content is not a valid library according to semantics')); + $message = NULL; + // Create an understandable error message: + $machineName = explode(' ', $value->library)[0]; + foreach ($semantics->options as $semanticsLibrary) { + $semanticsMachineName = explode(' ', $semanticsLibrary)[0]; + if ($machineName === $semanticsMachineName) { + // Using the wrong version of the library in the content + $message = $this->h5pF->t('The version of the H5P library %machineName used in this content is not valid. Content contains %contentLibrary, but it should be %semanticsLibrary.', array( + '%machineName' => $machineName, + '%contentLibrary' => $value->library, + '%semanticsLibrary' => $semanticsLibrary + )); + break; + } + } + // Using a library in content that is not present at all in semantics + if ($message === NULL) { + $message = $this->h5pF->t('The H5P library %library used in the content is not valid', array( + '%library' => $value->library + )); + } + + $this->h5pF->setErrorMessage($message); $value = NULL; return; } diff --git a/js/disable.js b/js/disable.js deleted file mode 100644 index 0bfbb07..0000000 --- a/js/disable.js +++ /dev/null @@ -1,19 +0,0 @@ -(function ($) { - $(document).ready(function () { - var $inputs = $('.h5p-action-bar-settings input'); - var $frame = $inputs.filter('input[name="frame"], input[name="h5p_frame"]'); - var $others = $inputs.filter(':not(input[name="frame"], input[name="h5p_frame"])'); - - var toggle = function () { - if ($frame.is(':checked')) { - $others.attr('disabled', false); - } - else { - $others.attr('disabled', true); - } - }; - - $frame.change(toggle); - toggle(); - }); -})(H5P.jQuery); diff --git a/js/h5p-action-bar.js b/js/h5p-action-bar.js new file mode 100644 index 0000000..8e34eb7 --- /dev/null +++ b/js/h5p-action-bar.js @@ -0,0 +1,89 @@ +H5P.ActionBar = (function ($, EventDispatcher) { + "use strict"; + + function ActionBar(displayOptions) { + EventDispatcher.call(this); + + var self = this; + + var hasActions = false; + + // Create action bar + var $actions = H5P.jQuery('
    '); + + /** + * Helper for creating action bar buttons. + * + * @private + * @param {string} type + * @param {string} customClass Instead of type class + */ + var addActionButton = function (type, customClass) { + var handler = function () { + self.trigger(type); + }; + H5P.jQuery('
  • ', { + 'class': 'h5p-button h5p-' + (customClass ? customClass : type), + role: 'button', + tabindex: 0, + title: H5P.t(type + 'Description'), + html: H5P.t(type), + on: { + click: handler, + keypress: function (e) { + if (e.which === 32) { + handler(); + e.preventDefault(); // (since return false will block other inputs) + } + } + }, + appendTo: $actions + }); + + hasActions = true; + }; + + // Register action bar buttons + if (displayOptions.export) { + // Add export button + addActionButton('download', 'export'); + } + if (displayOptions.copyright) { + addActionButton('copyrights'); + } + if (displayOptions.embed) { + addActionButton('embed'); + } + if (displayOptions.icon) { + // Add about H5P button icon + H5P.jQuery('
  • ').appendTo($actions); + hasActions = true; + } + + /** + * Returns a reference to the dom element + * + * @method getDOMElement + * @return {H5P.jQuery} + */ + self.getDOMElement = function () { + return $actions; + }; + + /** + * Does the actionbar contain actions? + * + * @method hasActions + * @return {Boolean} + */ + self.hasActions = function () { + return hasActions; + } + }; + + ActionBar.prototype = Object.create(EventDispatcher.prototype); + ActionBar.prototype.constructor = ActionBar; + + return ActionBar; + +})(H5P.jQuery, H5P.EventDispatcher); diff --git a/js/h5p-display-options.js b/js/h5p-display-options.js new file mode 100644 index 0000000..9c8f664 --- /dev/null +++ b/js/h5p-display-options.js @@ -0,0 +1,23 @@ +/** + * Utility that makes it possible to hide fields when a checkbox is unchecked + */ +(function ($) { + function setupHiding () { + var $toggler = $(this); + + // Getting the field which should be hidden: + var $subject = $($toggler.data('h5p-visibility-subject-selector')); + + var toggle = function () { + $subject.toggle($toggler.is(':checked')); + }; + + $toggler.change(toggle); + toggle(); + } + + $(document).ready(function () { + // Get the checkboxes making other fields being hidden: + $('.h5p-visibility-toggler').each(setupHiding); + }); +})(H5P.jQuery); diff --git a/js/h5p.js b/js/h5p.js index b639868..e4d0138 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -32,7 +32,7 @@ if (document.documentElement.requestFullScreen) { H5P.fullScreenBrowserPrefix = ''; } else if (document.documentElement.webkitRequestFullScreen) { - H5P.safariBrowser = navigator.userAgent.match(/Version\/(\d)/); + H5P.safariBrowser = navigator.userAgent.match(/version\/([.\d]+)/i); H5P.safariBrowser = (H5P.safariBrowser === null ? 0 : parseInt(H5P.safariBrowser[1])); // Do not allow fullscreen for safari < 7. @@ -47,24 +47,6 @@ else if (document.documentElement.msRequestFullscreen) { H5P.fullScreenBrowserPrefix = 'ms'; } -/** @const {number} */ -H5P.DISABLE_NONE = 0; - -/** @const {number} */ -H5P.DISABLE_FRAME = 1; - -/** @const {number} */ -H5P.DISABLE_DOWNLOAD = 2; - -/** @const {number} */ -H5P.DISABLE_EMBED = 4; - -/** @const {number} */ -H5P.DISABLE_COPYRIGHT = 8; - -/** @const {number} */ -H5P.DISABLE_ABOUT = 16; - /** * Keep track of when the H5Ps where started. * @@ -85,18 +67,27 @@ H5P.init = function (target) { } // Determine if we can use full screen - if (H5P.canHasFullScreen === undefined) { + if (H5P.fullscreenSupported === undefined) { /** * Use this variable to check if fullscreen is supported. Fullscreen can be * restricted when embedding since not all browsers support the native * fullscreen, and the semi-fullscreen solution doesn't work when embedded. * @type {boolean} */ - H5P.canHasFullScreen = (H5P.isFramed && H5P.externalEmbed !== false) ? ((document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled) ? true : false) : true; + H5P.fullscreenSupported = !(H5P.isFramed && H5P.externalEmbed !== false) || !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled); // We should consider document.msFullscreenEnabled when they get their // element sizing corrected. Ref. https://connect.microsoft.com/IE/feedback/details/838286/ie-11-incorrectly-reports-dom-element-sizes-in-fullscreen-mode-when-fullscreened-element-is-within-an-iframe } + // Deprecated variable, kept to maintain backwards compatability + if (H5P.canHasFullScreen === undefined) { + /** + * @deprecated since version 1.11 + * @type {boolean} + */ + H5P.canHasFullScreen = H5P.fullscreenSupported; + } + // H5Ps added in normal DIV. var $containers = H5P.jQuery('.h5p-content:not(.h5p-initialized)', target).each(function () { var $element = H5P.jQuery(this).addClass('h5p-initialized'); @@ -141,87 +132,51 @@ H5P.init = function (target) { var instance = H5P.newRunnable(library, contentId, $container, true, {standalone: true}); // Check if we should add and display a fullscreen button for this H5P. - if (contentData.fullScreen == 1 && H5P.canHasFullScreen) { + if (contentData.fullScreen == 1 && H5P.fullscreenSupported) { H5P.jQuery('
    ').prependTo($container).children().click(function () { H5P.fullScreen($container, instance); }); } - // Create action bar - var $actions = H5P.jQuery('
      '); - /** - * Helper for creating action bar buttons. - * - * @private - * @param {string} type - * @param {function} handler - * @param {string} customClass Instead of type class + * Create action bar */ - var addActionButton = function (type, handler, customClass) { - H5P.jQuery('
    • ', { - 'class': 'h5p-button h5p-' + (customClass ? customClass : type), - role: 'button', - tabindex: 0, - title: H5P.t(type + 'Description'), - html: H5P.t(type), - on: { - click: handler, - keypress: function (e) { - if (e.which === 32) { - handler(); - e.preventDefault(); // (since return false will block other inputs) - } - } - }, - appendTo: $actions - }); - }; - - // Register action bar buttons - if (!(contentData.disable & H5P.DISABLE_DOWNLOAD)) { - // Add export button - addActionButton('download', function () { - // Use button for download to avoid people linking directly to the .h5p - window.location.href = contentData.exportUrl; - }, 'export'); - } - if (!(contentData.disable & H5P.DISABLE_COPYRIGHT)) { - var copyright = H5P.getCopyrights(instance, library.params, contentId); - - if (copyright) { - // Add copyright dialog button - addActionButton('copyrights', function () { - // Open dialog with copyright information - var dialog = new H5P.Dialog('copyrights', H5P.t('copyrightInformation'), copyright, $container); - dialog.open(); - }); + var displayOptions = contentData.displayOptions; + var displayFrame = false; + if (displayOptions.frame) { + // Special handling of copyrights + if (displayOptions.copyright) { + var copyrights = H5P.getCopyrights(instance, library.params, contentId); + if (!copyrights) { + displayOptions.copyright = false; + } } - } - if (!(contentData.disable & H5P.DISABLE_EMBED)) { - // Add embed button - addActionButton('embed', function () { - // Open dialog with embed information + + // Create action bar + var actionBar = new H5P.ActionBar(displayOptions); + var $actions = actionBar.getDOMElement(); + + actionBar.on('download', function () { + window.location.href = contentData.exportUrl; + }); + actionBar.on('copyrights', function () { + var dialog = new H5P.Dialog('copyrights', H5P.t('copyrightInformation'), copyrights, $container); + dialog.open(); + }); + actionBar.on('embed', function () { H5P.openEmbedDialog($actions, contentData.embedCode, contentData.resizeCode, { width: $element.width(), height: $element.height() }); }); + + if (actionBar.hasActions()) { + displayFrame = true; + $actions.insertAfter($container); + } } - if (!(contentData.disable & H5P.DISABLE_ABOUT)) { - // Add about H5P button icon - H5P.jQuery('
    • ').appendTo($actions); - } - - // Insert action bar if it has any content - if (!(contentData.disable & H5P.DISABLE_FRAME) && $actions.children().length) { - $actions.insertAfter($container); - $element.addClass('h5p-frame'); - } - else { - $element.addClass('h5p-no-frame'); - } + $element.addClass(displayFrame ? 'h5p-frame' : 'h5p-no-frame'); // Keep track of when we started H5P.opened[contentId] = new Date(); @@ -497,7 +452,7 @@ H5P.semiFullScreen = function ($element, instance, exitCallback, body) { * @param {Object} instance * @param {function} exitCallback Callback function called when user exits fullscreen. * @param {H5P.jQuery} $body For internal use. Gives the body of the iframe. - * @param {Boolean} forceSemiFullScreen + * @param {Boolean} forceSemiFullScreen */ H5P.fullScreen = function ($element, instance, exitCallback, body, forceSemiFullScreen) { if (H5P.exitFullScreen !== undefined) { @@ -1034,6 +989,28 @@ H5P.findCopyrights = function (info, parameters, contentId) { if (!parameters.hasOwnProperty(field)) { continue; // Do not check } + + /* + * TODO: Make parameters clean again + * Some content types adds jQuery or other objects to parameters + * in order to determine override settings for sub-content-types. + * For instance Question Set tells Multiple Choice that it should + * attach Multi Choice's confirmation dialog to a Question Set + * jQuery element, so that the confirmation dialog will not be restricted + * to the space confined by Multi Choice. + * Ideally this should not be added to parameters, we must make a better + * solution. We should likely be adding these to sub-content through + * functions/setters instead of passing them down as params. + * + * This solution is implemented as a hack that will ignore all parameters + * inside a "overrideSettings" field, this should suffice for now since + * all overridden objects are added to this field, however this is not very + * robust solution and will very likely lead to problems in the future. + */ + if (field === 'overrideSettings') { + continue; + } + var value = parameters[field]; if (value instanceof Array) { @@ -1059,8 +1036,6 @@ H5P.findCopyrights = function (info, parameters, contentId) { info.addMedia(copyrights); } } - else { - } } }; @@ -1657,7 +1632,8 @@ H5P.shuffleArray = function (array) { * Reported time consumption/usage */ H5P.setFinished = function (contentId, score, maxScore, time) { - if (typeof score === 'number' && H5PIntegration.postUserStatistics === true) { + var validScore = typeof score === 'number' || score instanceof Number; + if (validScore && H5PIntegration.postUserStatistics === true) { /** * Return unix timestamp for the given JS Date. * @@ -2002,6 +1978,20 @@ H5P.createTitle = function (rawTitle, maxLength) { // Init H5P when page is fully loadded $(document).ready(function () { + + /** + * Indicates if H5P is embedded on an external page using iframe. + * @member {boolean} H5P.externalEmbed + */ + + // Relay events to top window. This must be done before H5P.init + // since events may be fired on initialization. + if (H5P.isFramed && H5P.externalEmbed === false) { + H5P.externalDispatcher.on('*', function (event) { + window.parent.H5P.externalDispatcher.trigger.call(this, event); + }); + } + /** * Prevent H5P Core from initializing. Must be overriden before document ready. * @member {boolean} H5P.preventInit @@ -2043,18 +2033,6 @@ H5P.createTitle = function (rawTitle, maxLength) { // pagehide is used on iPad when tabs are switched H5P.$window.on('pagehide', storeCurrentState); } - - /** - * Indicates if H5P is embedded on an external page using iframe. - * @member {boolean} H5P.externalEmbed - */ - - // Relay events to top window. - if (H5P.isFramed && H5P.externalEmbed === false) { - H5P.externalDispatcher.on('*', function (event) { - window.parent.H5P.externalDispatcher.trigger.call(this, event); - }); - } }); })(H5P.jQuery); diff --git a/styles/h5p-confirmation-dialog.css b/styles/h5p-confirmation-dialog.css index 2923b17..4fd45c0 100644 --- a/styles/h5p-confirmation-dialog.css +++ b/styles/h5p-confirmation-dialog.css @@ -5,7 +5,7 @@ left: 0; top: 0; - background: rgba(255, 255, 255, 0.85); + background: rgba(28, 34, 41, 0.9); opacity: 1; visibility: visible; -webkit-transition: opacity 0.1s, linear 0s, visibility 0s linear 0s; @@ -46,7 +46,7 @@ transform: translate(-50%, 0%); color: #555; - box-shadow: 0 0 6px 1px #ddd; + box-shadow: 0 0 6px 6px rgba(10,10,10,0.3); -webkit-transition: transform 0.1s ease-in; transition: transform 0.1s ease-in; @@ -61,7 +61,7 @@ .h5p-confirmation-dialog-header { padding: 1.5em; background: #fff; - color: #1a73d9; + color: #356593; } .h5p-confirmation-dialog-header-text { @@ -69,8 +69,9 @@ } .h5p-confirmation-dialog-body { + background: #fafbfc; + border-top: solid 1px #dde0e9; padding: 1.25em 1.5em; - background: #fafafa; } .h5p-confirmation-dialog-text { @@ -90,14 +91,14 @@ button.h5p-confirmation-dialog-exit { font-size: 2.5em; top: -0.9em; right: -1.15em; - color: #777; + color: #fff; cursor: pointer; text-decoration: none; } button.h5p-confirmation-dialog-exit:focus, button.h5p-confirmation-dialog-exit:hover { - color: #555; + color: #E4ECF5; } .h5p-confirmation-dialog-exit:before { diff --git a/styles/h5p-core-button.css b/styles/h5p-core-button.css index 3ba392e..eb4e08d 100644 --- a/styles/h5p-core-button.css +++ b/styles/h5p-core-button.css @@ -1,13 +1,15 @@ button.h5p-core-button:visited, button.h5p-core-button:link, button.h5p-core-button { + font-family: "Open Sans", sans-serif; + font-weight: 600; font-size: 1em; line-height: 1.2; padding: 0.5em 1.25em; border-radius: 2em; - background: #1a73d9; - color: #ffffff; + background: #488ac9; + color: #fff; cursor: pointer; border: none; @@ -22,7 +24,7 @@ button.h5p-core-button { } button.h5p-core-button:hover, button.h5p-core-button:focus { - background: #1356a3; + background: #3b71a5; color: #fff; text-decoration: none; -webkit-transition: initial; diff --git a/styles/h5p.css b/styles/h5p.css index b0e7ee2..2e5842e 100644 --- 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-14.eot?inh2er'); - src: url('../fonts/h5p-core-14.eot?inh2er#iefix') format('embedded-opentype'), - url('../fonts/h5p-core-14.ttf?inh2er') format('truetype'), - url('../fonts/h5p-core-14.woff?inh2er') format('woff'), - url('../fonts/h5p-core-14.svg?inh2er#h5p-core-14') format('svg'); + src: url('../fonts/h5p-core-16.eot?80e76o'); + src: url('../fonts/h5p-core-16.eot?80e76o#iefix') format('embedded-opentype'), + url('../fonts/h5p-core-16.ttf?80e76o') format('truetype'), + url('../fonts/h5p-core-16.woff?80e76o') format('woff'), + url('../fonts/h5p-core-16.svg?80e76o#h5p-core-15') format('svg'); font-weight: normal; font-style: normal; } @@ -235,6 +235,7 @@ div.h5p-fullscreen { } .h5p-actions > li { margin: 0; + list-style: none; } .h5p-popup-dialog { position: absolute;