From a9807917ebc48fb12ece72eabd87b575db925345 Mon Sep 17 00:00:00 2001
From: Frank Naegler <frank.naegler@typo3.org>
Date: Mon, 21 Aug 2017 22:35:34 +0200
Subject: [PATCH] [BUGFIX] Refactoring of CardLayout.js

This patch refactors the CardLayput.js to prevent some trouble with
the navigation icons in the doc header.

Resolves: #82151
Releases: master
Change-Id: I6739de816b458a7b8c85c519d46664831dfa070c
Reviewed-on: https://review.typo3.org/53762
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Mona Muzaffar <mona.muzaffar@gmx.de>
Tested-by: Mona Muzaffar <mona.muzaffar@gmx.de>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
---
 .../Public/JavaScript/Modules/CardLayout.js   | 219 ++++++++++++------
 1 file changed, 152 insertions(+), 67 deletions(-)

diff --git a/typo3/sysext/install/Resources/Public/JavaScript/Modules/CardLayout.js b/typo3/sysext/install/Resources/Public/JavaScript/Modules/CardLayout.js
index f1e703e42411..964ee2c5311b 100644
--- a/typo3/sysext/install/Resources/Public/JavaScript/Modules/CardLayout.js
+++ b/typo3/sysext/install/Resources/Public/JavaScript/Modules/CardLayout.js
@@ -17,78 +17,163 @@
 define(['jquery', 'bootstrap'], function ($) {
 	'use strict';
 
-	return {
-		initialize: function() {
-			// Card expand / collapse handling
-			$(document).on('click', '.gridder-list', function(e) {
-				e.preventDefault();
-				var $element = $(this);
-				var $contentContainer = $element.next();
-				if (!$element.hasClass('selectedItem')) {
-					// Find possible current open one and close it
-					$('.gridder-list').removeClass('selectedItem');
-					$('.gridder-content.gridder-show').slideUp(function() {
-						$(this).removeClass('gridder-show');
-					});
-					// Open clicked one in parallel
-					$element.addClass('selectedItem');
-					$contentContainer.addClass('gridder-show').slideDown();
-				} else {
-					// Collapse this currently open grid
-					$contentContainer.slideUp(function() {
-						$contentContainer.removeClass('gridder-show');
-					});
-					$element.removeClass('selectedItem');
-				}
-			});
+	/**
+	 *
+	 * @type {{transitionInProgress: boolean}}
+	 */
+	var CardLayout = {
+		transitionInProgress: false
+	};
 
-			// Close current and open previous card
-			$(document).on('click', '.gridder-nav-prev', function() {
-				var $currentOpenContent = $('.gridder-content.gridder-show');
-				if ($currentOpenContent.length > 0) {
-					var $currentOpenCard = $currentOpenContent.prev();
-					var $previousCardContent = $currentOpenCard.prev();
-					var $previousCard = $previousCardContent.prev();
-					if ($previousCard.length > 0) {
-						$currentOpenCard.removeClass('selectedItem');
-						$currentOpenContent.slideUp(function() {
-							$(this).removeClass('gridder-show');
-						});
-						$previousCard.addClass('selectedItem');
-						$previousCardContent.addClass('gridder-show').slideDown();
-					}
-				}
-			});
+	/**
+	 * Initialize the CardLayout, bind events
+	 */
+	CardLayout.initialize = function() {
+		$(document).on('click', '.gridder-list', function(e) {
+			e.preventDefault();
+			var $element = $(this);
+			if (!$element.hasClass('selectedItem')) {
+				CardLayout.openCard($element);
+			} else {
+				CardLayout.closeCard($element);
+			}
+		});
+
+		// Close current and open previous card
+		$(document).on('click', '.gridder-nav-prev', function(e) {
+			e.preventDefault();
+			CardLayout.openPrevCard();
+		});
+
+		// Close current and open next card
+		$(document).on('click', '.gridder-nav-next', function(e) {
+			e.preventDefault();
+			CardLayout.openNextCard();
+		});
+
+		// Close current open card
+		$(document).on('click', '.gridder-close', function(e) {
+			e.preventDefault();
+			CardLayout.closeCurrentCard();
+		});
+
+		CardLayout.checkNavigationButtons();
+	};
+
+	/**
+	 * Find and return the current open card
+	 *
+	 * @returns {jQuery}
+	 */
+	CardLayout.getCurrentOpenCard = function() {
+		return $('.gridder-content.gridder-show').prev();
+	};
+
+	/**
+	 * Find and close the current open card
+	 */
+	CardLayout.closeCurrentCard = function() {
+		CardLayout.closeCard(CardLayout.getCurrentOpenCard());
+		CardLayout.checkNavigationButtons();
+	};
+
+	/**
+	 * Open the given card and call the callback function
+	 *
+	 * @param {jQuery} $element
+	 * @param {function} callback
+	 * @returns {boolean}
+	 */
+	CardLayout.openCard = function($element, callback) {
+		if (CardLayout.transitionInProgress) {
+			return false;
+		}
+		CardLayout.transitionInProgress = true;
+		$('.gridder-list').removeClass('selectedItem');
+		$('.gridder-content.gridder-show').slideUp(function() {
+			$(this).removeClass('gridder-show');
+		});
+		$element.addClass('selectedItem');
+		$element.next().addClass('gridder-show').slideDown(function() {
+			CardLayout.transitionInProgress = false;
+			if (typeof callback === 'function') {
+				callback();
+			}
+			CardLayout.checkNavigationButtons();
+		});
+	};
 
-			// Close current and open next card
-			$(document).on('click', '.gridder-nav-next', function() {
-				var $currentOpenContent = $('.gridder-content.gridder-show');
-				if ($currentOpenContent.length > 0) {
-					var $currentOpenCard = $currentOpenContent.prev();
-					var $nextCard = $currentOpenContent.next();
-					var $nextCardContent = $nextCard.next();
-					if ($nextCardContent.length > 0) {
-						$currentOpenCard.removeClass('selectedItem');
-						$currentOpenContent.slideUp(function() {
-							$(this).removeClass('gridder-show');
-						});
-						$nextCard.addClass('selectedItem');
-						$nextCardContent.addClass('gridder-show').slideDown();
-					}
-				}
+	/**
+	 * Close the given card and call the callback function
+	 *
+	 * @param {jQuery} $element
+	 * @param {function} callback
+	 * @returns {boolean}
+	 */
+	CardLayout.closeCard = function($element, callback) {
+		if (CardLayout.transitionInProgress) {
+			return false;
+		}
+		CardLayout.transitionInProgress = true;
+		var $contentContainer = $element.next();
+		$element.removeClass('selectedItem');
+		$contentContainer.slideUp(function() {
+			$contentContainer.removeClass('gridder-show');
+			CardLayout.transitionInProgress = false;
+			if (typeof callback === 'function') {
+				callback();
+			}
+			CardLayout.checkNavigationButtons();
+		});
+	};
+
+	/**
+	 * Find the next card and open it, if it exists
+	 */
+	CardLayout.openNextCard = function() {
+		var $currentOpenCard = CardLayout.getCurrentOpenCard();
+		var $nextCard = $currentOpenCard.next().next();
+		if ($nextCard.length) {
+			CardLayout.closeCard($currentOpenCard, function() {
+				CardLayout.openCard($nextCard);
 			});
+		}
+	};
 
-			// Close current open card
-			$(document).on('click', '.gridder-close', function() {
-				var $currentOpenContent = $('.gridder-content.gridder-show');
-				if ($currentOpenContent.length > 0) {
-					var $currentOpenCard = $currentOpenContent.prev();
-					$currentOpenCard.removeClass('selectedItem');
-					$currentOpenContent.slideUp(function() {
-						$(this).removeClass('gridder-show');
-					});
-				}
+	/**
+	 * Find the previous card and open it, if it exists
+	 */
+	CardLayout.openPrevCard = function() {
+		var $currentOpenCard = CardLayout.getCurrentOpenCard();
+		var $nextCard = $currentOpenCard.prev().prev();
+		if ($nextCard.length) {
+			CardLayout.closeCard($currentOpenCard, function() {
+				CardLayout.openCard($nextCard);
 			});
 		}
 	};
+
+	/**
+	 * Check the navigation icons and enable/disable the buttons
+	 */
+	CardLayout.checkNavigationButtons = function() {
+		var $currentOpenCard = CardLayout.getCurrentOpenCard();
+		if ($currentOpenCard.length === 0) {
+			$('.gridder-close').addClass('disabled');
+		} else {
+			$('.gridder-close').removeClass('disabled');
+		}
+		if ($currentOpenCard.prev().prev().length === 0) {
+			$('.gridder-nav-prev').addClass('disabled')
+		} else {
+			$('.gridder-nav-prev').removeClass('disabled')
+		}
+		if ($currentOpenCard.next().next().length === 0) {
+			$('.gridder-nav-next').addClass('disabled')
+		} else {
+			$('.gridder-nav-next').removeClass('disabled')
+		}
+	};
+
+	return CardLayout;
 });
-- 
GitLab