From 0a23dc043d0ab3195a5db24470235d851e322600 Mon Sep 17 00:00:00 2001 From: Paal Joergensen Date: Tue, 13 Dec 2016 10:29:33 +0100 Subject: [PATCH] Download and embed granularity (HFP-277) --- h5p.classes.php | 142 +++++++++++++++++++++++++++++--------- js/disable.js | 19 ----- js/h5p-action-bar.js | 77 +++++++++++++++++++++ js/h5p-display-options.js | 23 ++++++ js/h5p.js | 103 +++++++-------------------- 5 files changed, 236 insertions(+), 128 deletions(-) delete mode 100644 js/disable.js create mode 100644 js/h5p-action-bar.js create mode 100644 js/h5p-display-options.js diff --git a/h5p.classes.php b/h5p.classes.php index dabca7d..5f8a10a 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -558,6 +558,8 @@ interface H5PFrameworkInterface { * Will trigger after the export file is created. */ public function afterExportCreated(); + + public function hasPermission($permission, $content_id = NULL); } /** @@ -1669,6 +1671,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 */ @@ -1690,7 +1706,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', @@ -2439,34 +2456,6 @@ 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. * @@ -2474,7 +2463,7 @@ class H5PCore { * @param int $current * @return int */ - public function getDisable(&$sources, $current) { + public function getDisplayOptionsAsByte(&$sources, $current) { foreach (H5PCore::$disable as $bit => $option) { if ($this->h5pF->getOption(($bit & H5PCore::DISABLE_DOWNLOAD ? 'export' : $option), TRUE)) { if (!isset($sources[$option]) || !$sources[$option]) { @@ -2488,6 +2477,98 @@ class H5PCore { return $current; } + /** + * Determine display options visibility and value on edit + * + * @method getDisplayOptionsForEdit + * @param [int] $disable + * @return [Array] + */ + public function getDisplayOptionsForEdit($disable = NULL) { + $display_options = []; + + $current_display_options = $disable === NULL ? [] : $this->getDisplayOptionsAsArray($disable); + + if ($this->h5pF->getOption('frame', TRUE)) { + $display_options['frame'] = isset($current_display_options['showFrame']) ? $current_display_options['showFrame'] : TRUE; + + $export = $this->h5pF->getOption('export', H5PDisplayOptionBehaviour::ALWAYS_SHOW); + if ($export == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_ON || $export == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF) { + $display_options['download'] = isset($current_display_options['showDownload']) ? $current_display_options['showDownload'] : ($export == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_ON); + } + $embed = $this->h5pF->getOption('embed', H5PDisplayOptionBehaviour::ALWAYS_SHOW); + if ($embed == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_ON || $embed == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF) { + $display_options['embed'] = isset($current_display_options['showEmbed']) ? $current_display_options['showEmbed'] : ($embed == H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_ON); + } + if ($this->h5pF->getOption('copyright', TRUE)) { + $display_options['copyright'] = isset($current_display_options['showCopyright']) ? $current_display_options['showCopyright'] : TRUE; + } + } + + return $display_options; + } + + /** + * Determine display option visibility when viewing H5P + * + * @method getDisplayOptionsForView + * @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('frame', TRUE) == FALSE) { + $display_options['showFrame'] = false; + } + else { + $export = $this->h5pF->getOption('export', H5PDisplayOptionBehaviour::ALWAYS_SHOW); + if ($export == H5PDisplayOptionBehaviour::NEVER_SHOW) { + // If never show globally, force hide + $display_options['showDownload'] = false; + } + elseif ($export == H5PDisplayOptionBehaviour::ALWAYS_SHOW || ($export == H5PDisplayOptionBehaviour::CONTROLLED_BY_PERMISSIONS && $this->h5pF->hasPermission(H5PPermission::DOWNLOAD_H5P, $id))) { + // If always show or permissions say so, force show + $display_options['showDownload'] = true; + } + + $embed = $this->h5pF->getOption('embed', H5PDisplayOptionBehaviour::ALWAYS_SHOW); + if ($embed == H5PDisplayOptionBehaviour::NEVER_SHOW) { + // If never show globally, force hide + $display_options['showEmbed'] = false; + } + elseif ($embed == H5PDisplayOptionBehaviour::ALWAYS_SHOW || ($embed == H5PDisplayOptionBehaviour::CONTROLLED_BY_PERMISSIONS && $this->h5pF->hasPermission(H5PPermission::EMBED_H5P, $id))) { + // If always show or permissions say so, force show + $display_options['showEmbed'] = true; + } + + if ($this->h5pF->getOption('copyright', TRUE) == FALSE) { + $display_options['showCopyright'] = false; + } + } + + return $display_options; + } + + /** + * Convert display options as single byte to array + * + * @method getDisplayOptionsAsArray + * @param [int] $disable + * @return [Array] + */ + private function getDisplayOptionsAsArray($disable) { + return array( + 'showFrame' => !($disable & H5PCore::DISABLE_FRAME), + 'showDownload' => !($disable & H5PCore::DISABLE_DOWNLOAD), + 'showEmbed' => !($disable & H5PCore::DISABLE_EMBED), + 'showCopyright' => !($disable & H5PCore::DISABLE_COPYRIGHT), + 'showAbout' => $this->h5pF->getOption('icon', TRUE), + ); + } + /** * Small helper for getting the library's ID. * @@ -3147,7 +3228,6 @@ class H5PContentValidator { 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( 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..a80ef60 --- /dev/null +++ b/js/h5p-action-bar.js @@ -0,0 +1,77 @@ +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.showDownload) { + // Add export button + addActionButton('download', 'export'); + } + if (displayOptions.showCopyrights) { + addActionButton('copyrights'); + } + if (displayOptions.showEmbed) { + addActionButton('embed'); + } + if (displayOptions.showAbout) { + // Add about H5P button icon + H5P.jQuery('
  • ').appendTo($actions); + hasActions = true; + } + + self.getDOMElement = function () { + return $actions; + }; + + 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 77f9f0e..5fe8c78 100644 --- a/js/h5p.js +++ b/js/h5p.js @@ -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. * @@ -147,76 +129,41 @@ H5P.init = function (target) { }); } - // 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; + if (displayOptions.showFrame) { + // Special handling of copyrights + if (displayOptions.showCopyrights) { + var copyrights = H5P.getCopyrights(instance, library.params, contentId); + if (!copyrights) { + displayOptions.showCopyrights = 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 (!(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); + } + + if (displayOptions.showFrame && actionBar.hasActions()) { $element.addClass('h5p-frame'); } else {