From b82015d307bfe5de449b1b8e067817bb0b167026 Mon Sep 17 00:00:00 2001 From: mjansen Date: Tue, 14 Jan 2025 20:41:45 +0100 Subject: [PATCH] Badge/User: Improve toggling hidden badges in public profile See: https://mantis.ilias.de/view.php?id=43589 --- components/ILIAS/Badge/Badge.php | 7 +- components/ILIAS/Badge/js/ilBadge.js | 49 ---------- .../Badge/resources/PublicProfileBadges.js | 95 +++++++++++++++++++ .../Profile/class.ilPublicUserProfileGUI.php | 17 ++-- .../default/tpl.usr_public_profile.html | 28 +----- 5 files changed, 114 insertions(+), 82 deletions(-) delete mode 100755 components/ILIAS/Badge/js/ilBadge.js create mode 100644 components/ILIAS/Badge/resources/PublicProfileBadges.js diff --git a/components/ILIAS/Badge/Badge.php b/components/ILIAS/Badge/Badge.php index 7fee06069ffd..4a57fd4a8a0d 100644 --- a/components/ILIAS/Badge/Badge.php +++ b/components/ILIAS/Badge/Badge.php @@ -32,9 +32,12 @@ public function init( array | \ArrayAccess &$pull, array | \ArrayAccess &$internal, ): void { - $contribute[\ILIAS\Setup\Agent::class] = static fn() => - new \ilBadgeSetupAgent( + $contribute[\ILIAS\Setup\Agent::class] = static fn() => new \ilBadgeSetupAgent( $pull[\ILIAS\Refinery\Factory::class] ); + $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS( + $this, + 'PublicProfileBadges.js' + ); } } diff --git a/components/ILIAS/Badge/js/ilBadge.js b/components/ILIAS/Badge/js/ilBadge.js deleted file mode 100755 index 30f35b4369bd..000000000000 --- a/components/ILIAS/Badge/js/ilBadge.js +++ /dev/null @@ -1,49 +0,0 @@ -il.Badge = { - - url: "", - - setUrl: function(url) { - il.Badge.url = url; - }, - - publish: function(id) { - il.Util.sendAjaxGetRequestToUrl(il.Badge.url, {id: id}, {}, this.prepared); - return false; - }, - - prepared: function(o) { - if(o.responseText !== undefined) - { - if(o.responseText) - { - var result = JSON.parse(o.responseText); - if(result.error === false) - { - var url = result.url; - il.Badge.publishMulti([url]); - } - } - } - }, - - publishMulti: function(urls) { - // console.log(urls); - - OpenBadges.issue(urls, function(errors, successes) { - // console.log(errors); - // console.log(successes); - - /* see https://github.com/mozilla/openbadges-backpack/wiki/using-the-issuer-api - DENIED - The user denied permission to add the badge. - EXISTS - The badge is already in the earner's backpack. - INACCESSIBLE - The assertion provided could not be retrieved. - e.g. The assertion URL itself may be malformed, or attempting to access the - assertion may have resulted in 404 Not Found or 403 Forbidden. - MALFORMED - The assertion URL provided exists but was malformed. - INVALID - The assertion URL provided exists and is well-formed, but is not valid. - e.g. The recipient of the assertion may not be the currently logged-in user. - */ - - }); - } -} \ No newline at end of file diff --git a/components/ILIAS/Badge/resources/PublicProfileBadges.js b/components/ILIAS/Badge/resources/PublicProfileBadges.js new file mode 100644 index 000000000000..e9c07972e0ba --- /dev/null +++ b/components/ILIAS/Badge/resources/PublicProfileBadges.js @@ -0,0 +1,95 @@ +class BadgeToggle { + static HIDDEN_CLASS = 'ilNoDisplay'; + + static BADGE_CLASS = 'ilHiddenProfileBadge'; + + constructor(containerId, showButtonId, hideButtonId) { + this.badgeContainer = document.getElementById(containerId); + this.showButton = document.getElementById(showButtonId); + this.hideButton = document.getElementById(hideButtonId); + + this.init(); + } + + init() { + this.showButton.addEventListener('click', (e) => this.handleClick(e, true)); + this.hideButton.addEventListener('click', (e) => this.handleClick(e, false)); + } + + handleClick(event, show) { + event.preventDefault(); + this.toggleButtonVisibility(show) + .then(() => this.toggleBadgeVisibility(show)); + } + + toggleBadgeVisibility(show) { + return new Promise((resolve) => { + const badges = this.badgeContainer.querySelectorAll(`.${BadgeToggle.BADGE_CLASS}`); + const promises = Array.from(badges).map((badge) => this.animateBadge(badge, show)); + Promise.all(promises).then(resolve); + }); + } + + animateBadge(badge, show) { + return new Promise((resolve) => { + const height = badge.scrollHeight; + + const stylesBeforeAnimation = show ? { + display: 'inline-block', + height: '0px', + opacity: '0', + overflow: 'hidden', + } : { + overflow: 'hidden', + }; + + const stylesAfterAnimation = show ? { + height: '', + opacity: '', + overflow: '', + } : { + display: 'none', + height: '', + opacity: '', + overflow: '', + }; + + const classAction = show ? 'remove' : 'add'; + + Object.assign(badge.style, stylesBeforeAnimation); + + this.animateHeightOpacity( + badge, + show ? 0 : height, + show ? height : 0, + show ? 0 : 1, + show ? 1 : 0, + ).then(() => { + Object.assign(badge.style, stylesAfterAnimation); + badge.classList[classAction](BadgeToggle.HIDDEN_CLASS); + resolve(); + }); + }); + } + + animateHeightOpacity(element, fromHeight, toHeight, fromOpacity, toOpacity) { + return new Promise((resolve) => { + const animation = element.animate( + [ + { height: `${fromHeight}px`, opacity: fromOpacity }, + { height: `${toHeight}px`, opacity: toOpacity }, + ], + { duration: 200, easing: 'cubic-bezier(0.42, 0, 0.58, 1)' }, + ); + animation.onfinish = resolve; + }); + } + + toggleButtonVisibility(show) { + return new Promise((resolve) => { + this.showButton.classList.toggle(BadgeToggle.HIDDEN_CLASS); + this.hideButton.classList.toggle(BadgeToggle.HIDDEN_CLASS); + resolve(); + }); + } +} diff --git a/components/ILIAS/User/classes/Profile/class.ilPublicUserProfileGUI.php b/components/ILIAS/User/classes/Profile/class.ilPublicUserProfileGUI.php index 73d99c6f1800..c737a2911198 100755 --- a/components/ILIAS/User/classes/Profile/class.ilPublicUserProfileGUI.php +++ b/components/ILIAS/User/classes/Profile/class.ilPublicUserProfileGUI.php @@ -20,7 +20,6 @@ use ILIAS\User\Profile\GUIRequest; use ILIAS\User\Profile\VCard; - use ILIAS\Language\Language; /** @@ -568,6 +567,8 @@ public function getEmbeddable(bool $a_add_goto = false): string } // badges + $this->tpl->addJavaScript('assets/js/PublicProfileBadges.js'); + $this->tpl->addOnLoadCode('new BadgeToggle("ilbdgprcont", "ilbdgprfhdm", "ilbdgprfhdl");'); $user_badges = ilBadgeAssignment::getInstancesByUserId($user->getId()); if ($user_badges) { $has_public_badge = false; @@ -583,13 +584,14 @@ public function getEmbeddable(bool $a_add_goto = false): string $renderer = new ilBadgeRenderer($ass); // limit to 20, [MORE] link - if ($cnt <= $cut) { - $tpl->setCurrentBlock('badge_bl'); - $tpl->setVariable('BADGE', $renderer->getHTML()); - } else { - $tpl->setCurrentBlock('badge_hidden_item_bl'); - $tpl->setVariable('BADGE_HIDDEN', $renderer->getHTML()); + if ($cnt > $cut) { + $tpl->setCurrentBlock('hidden_badge'); + $tpl->touchBlock('hidden_badge'); + $tpl->parseCurrentBlock(); } + + $tpl->setCurrentBlock('badge_bl'); + $tpl->setVariable('BADGE', $renderer->getHTML()); $tpl->parseCurrentBlock(); $has_public_badge = true; @@ -600,7 +602,6 @@ public function getEmbeddable(bool $a_add_goto = false): string $this->lng->loadLanguageModule('badge'); $tpl->setVariable('BADGE_HIDDEN_TXT_MORE', $this->lng->txt('badge_profile_more')); $tpl->setVariable('BADGE_HIDDEN_TXT_LESS', $this->lng->txt('badge_profile_less')); - $tpl->touchBlock('badge_js_bl'); } if ($has_public_badge) { diff --git a/components/ILIAS/User/templates/default/tpl.usr_public_profile.html b/components/ILIAS/User/templates/default/tpl.usr_public_profile.html index 969b5ff80871..8caa81cc8b0b 100755 --- a/components/ILIAS/User/templates/default/tpl.usr_public_profile.html +++ b/components/ILIAS/User/templates/default/tpl.usr_public_profile.html @@ -88,21 +88,14 @@

{TXT_PORTFOLIO}

{TXT_BADGES}

-
+
- {BADGE} + {BADGE}
- - - - {BADGE_HIDDEN_TXT_MORE} - + {BADGE_HIDDEN_TXT_MORE} + {BADGE_HIDDEN_TXT_LESS}
@@ -113,15 +106,4 @@

{TXT_BADGES}

- - - - + \ No newline at end of file