From df05993d2034e485bee984e9e4eff8d5eeab3eea Mon Sep 17 00:00:00 2001 From: Vincent Vanwaelscappel Date: Thu, 26 Sep 2019 14:39:54 +0200 Subject: [PATCH] fix #3054 @7 --- images/interface.svg | 11 + js/libs/fluidbook/fluidbook.links.js | 326 +-------------- js/libs/fluidbook/fluidbook.share.js | 81 ++-- .../fluidbook/links/fluidbook.links.zoom.js | 379 ++++++++++++++++++ style/fluidbook.less | 144 ++++--- 5 files changed, 546 insertions(+), 395 deletions(-) create mode 100644 js/libs/fluidbook/links/fluidbook.links.zoom.js diff --git a/images/interface.svg b/images/interface.svg index aa0b0aeb..e80f8558 100644 --- a/images/interface.svg +++ b/images/interface.svg @@ -24,6 +24,17 @@ + + + + +
'); - - $(document).on('click', '.zoomPopup', function (e) { - e.preventDefault(); - $this.zoomLink(this); - return false; - }); $(document).on('mouseenter', '#links a.image_rollover', function () { var id = $(this).closest('[data-id]').data('id'); @@ -52,23 +49,11 @@ FluidbookLinks.prototype = { $this.rolloverLeave(iid); }); - $(this.fluidbook).on('fluidbook.zoom.in.end', function () { - $this.zoomLinkReset(true); - return true; - }); - - $(this.fluidbook).on('fluidbook.resize.orientation', function () { - $this.zoomLinkReset(true); - }); $(this.fluidbook).on('fluidbook.resize', function () { $this.resize(); }); - $(document).on('click', '#zoomPopupOverlay, .zoomPopupWrapper, .zoomPopupClose', function (e) { - $this.zoomLinkReset(); - return false; - }); $(document).on('click', 'a', function () { if ($(this).is('#wopen')) { @@ -140,7 +125,7 @@ FluidbookLinks.prototype = { // Ensure that mobile menu closes if it is open $this.fluidbook.nav.closeMenu(); - if (action == 'share') { + if (action === 'share') { // Let share class handle this return true; } @@ -149,7 +134,7 @@ FluidbookLinks.prototype = { action = map[action]; } - if (action == 'chapters' && extra) { + if (action === 'chapters' && extra) { window.location.hash = '#/chapters/' + extra; return false; } @@ -249,7 +234,7 @@ FluidbookLinks.prototype = { }, animateContentLink: function (link) { - link=$(link); + link = $(link); var linkElement = $(link).get(0); var animation = link.data('animation'); if (animation.type === undefined || animation.type === '') { @@ -497,301 +482,6 @@ FluidbookLinks.prototype = { }, delay + additionalDelay); }, - zoomLink: function (link) { - - var $this = this, - $link = $(link), - links = [], - zoomMargin = 50, - zoomZonesGap = 30, // Space between grouped zoom links - gapsTotal, - availableWidth = $(window).width() - (2 * zoomMargin), - availableHeight = $(window).height() - (2 * zoomMargin), - maxZoom = parseFloat($(link).data('maxzoom')) || 2; - - // If the interface is zoomed in, we must zoom out first - if (this.fluidbook.zoom.zoom > 1) { - - // Zoom out - this.fluidbook.zoom.resetZoom(); - - // Wait for clickZoom out to finish before trying again to open zoom link - $(this.fluidbook).one('fluidbook.zoom.out.end', function () { - $this.zoomLink(link); - }); - - return false; - } - - // Add clicked zoom link to the collection - links.push($link); - - // If there is a zoom group, we need to find the other zone it is linked to - // For now, only 2 zones maximum can be linked together so if we have more - // than one group (eg. for a shared zone), we should treat it as a standalone - // zone when clicked. - if ($link.data('group-count') == 1) { - // Find other zones in the same group - var $others = $('.zoom-group-' + $link.data('group')).not('#' + $link.attr('id')); - - if ($others.length >= 1) { - links.push($others.first()); // Take the first because we only support 1 linked zone currently - } - } - - //=============== - - // Calculate space taken by between blocks (always 1 less gap than total blocks) - gapsTotal = (links.length - 1) * zoomZonesGap; - - // Calculate positions and scaling for all zoomLink blocks - // First, calculate stacked height of all zoomLink blocks - var stackedHeight = gapsTotal + links.reduce(function (sum, zoomLink) { - return sum + (zoomLink.data('height') * maxZoom); - }, 0); - - // Calculate side-by-side width of all zoomLink blocks - var sideBySideWidth = gapsTotal + links.reduce(function (sum, zoomLink) { - return sum + (zoomLink.data('width') * maxZoom); - }, 0); - - // Find widest element in collection - var widestLink = links.reduce(function (maxWidth, zoomLink) { - var width = (zoomLink.data('width') * maxZoom); - return (width > maxWidth) ? width : maxWidth; - }, 0); - - // Find tallest element in collection - var tallestLink = links.reduce(function (maxHeight, zoomLink) { - var height = (zoomLink.data('height') * maxZoom); - return (height > maxHeight) ? height : maxHeight; - }, 0); - - // Compare scaling required for each layout of blocks - var stackedScale = Math.min(availableHeight / stackedHeight, availableWidth / widestLink, 1), - sideBySideScale = Math.min(availableHeight / tallestLink, availableWidth / sideBySideWidth, 1), - groupScale = (stackedScale > sideBySideScale) ? stackedScale : sideBySideScale, - layout = (stackedScale > sideBySideScale) ? 'stacked' : 'side-by-side'; - - // Apply scaling for the group so it is accounted for in later calculations - stackedHeight *= groupScale; - sideBySideWidth *= groupScale; - - // Sort links so they are displayed in a natural order when zooming - // When stacked: highest link on page will come first - // When side-by-side: leftmost link on page will come first - links.sort(function (a, b) { - if (layout == 'stacked') { - return a.data('y') - b.data('y'); // Lowest Y co-ordinates first - } else { - return a.offset().left - b.offset().left; // Lowest X co-ordinates first - } - }); - - - links.forEach(function (zoomLink, index) { - // console.log(index, 'Found link with ID: ' + zoomLink.attr('id')); - - var zoomID = zoomLink.attr('id'), - $groupWrapper = $('#zoomPopupGroupWrapper'); - - // Add holder for each zoom zone - $groupWrapper.append(''); - - var z = $('#zoomPopup_' + zoomID), - box = zoomLink[0].getBoundingClientRect(), // Should return full values without rounding - parent = zoomLink.closest('.link'), - baseWidth = parseInt(zoomLink.data('width')), // Width of the original link from the editor - baseHeight = parseInt(zoomLink.data('height')), // Height of the original link from the editor - maxZoom = parseFloat(zoomLink.data('maxzoom')) || 2, // The default value for this should match that of the compiler in zoomLink::generateImage() - zoomX, - zoomY, - zoomWidth, - zoomHeight, - zoomScale; - - if ($(parent).length == 0) { - return; - } - - var linkId = $(parent).attr('id').split('_', 2)[1]; - var zoomImage = 'data/links/zoom_' + linkId + '.jpg'; - - // TODO: In the compiler we should look at generating higher-res images to cater for hiDPI displays - // TODO: It should be clearer what the sizes in the link editor really mean - due to screen size and scaling, a 100x100 link could appear as 150x150 in the player so if it we set a max zoom level of 2, it will only appear at 200x200, which is not much bigger than the embedded size. It's hard to handle max zoom levels while also working with a player that always scales the content to fit the screen. The most pragmatic approach probably is to generate higher res images. - - - // Due to the scaling done by the Fluidbook interface, the actual link size is likely to be different - // to the original link editor width and height. Since the zoom image is generated based on the link editor - // dimensions multiplied by the max zoom level, we need to be able to take that into account so we don't exceed - // the resolution of the image in the popup. We can't use the fluidbook.resize.bookScale variable because it - // measures the scaling of the high-res images. Instead, we work out the relative scaling by taking the - // link editor width (baseWidth) and comparing it to the actual link width. - //maxZoom = maxZoom / (box.width / baseWidth); // Adjusted maxZoom level... - - // Apply any necessary group scaling to the individual element... - baseHeight *= groupScale; - baseWidth *= groupScale; - - // Then calculate best scale factor to fit and also to honour the maxZoom level - zoomScale = Math.min((availableWidth / baseWidth), (availableHeight / baseHeight), maxZoom); - - // Dimensions of the final popup - zoomWidth = baseWidth * zoomScale; - zoomHeight = baseHeight * zoomScale; - - // Max zoom of first clicked link - var firstMaxZoom = parseFloat(links[0].data('maxzoom')) || 2; - - //========= - // Position elements based on the layout - // There are two possible layouts: stacked or side-by-side - if (layout == 'stacked') { - - $groupWrapper.addClass('layout-stacked'); - - // Calculate translate co-ordinates so image is centred correctly - // Values are rounded so we don't end up with image being positioned between pixels, which causes blurring - zoomX = Math.round((availableWidth / 2) - parent.offset().left - (zoomWidth / 2) + zoomMargin); - - // Y position of first block (so both blocks are vertically centred) - var groupY = Math.round((availableHeight - stackedHeight) / 2); - - // If this is the first / only block, use calculated groupY position - if (index == 0) { - zoomY = groupY - parent.offset().top + zoomMargin; - - // Otherwise, calculate Y position based on first element position - } else { - zoomY = Math.round(groupY + links[0].data('height') * firstMaxZoom * groupScale + zoomZonesGap + zoomMargin - parent.offset().top); - } - } else { - // Side-by-side layout - $groupWrapper.addClass('layout-side-by-side'); - - // Vertically centre each block - zoomY = Math.round((availableHeight / 2) - parent.offset().top - (zoomHeight / 2) + zoomMargin); - - // X position of first block (so both blocks are horizontally centred) - var groupX = Math.round((availableWidth - sideBySideWidth) / 2); - - // If this is the first / only block, use calculated groupX position - if (index == 0) { - zoomX = groupX - parent.offset().left + zoomMargin; - - // Otherwise, calculate X position based on first element position - } else { - zoomX = Math.round(groupX + (links[0].data('width') * firstMaxZoom * groupScale) + zoomZonesGap + zoomMargin - parent.offset().left); - } - } - - // Keep starting scale with zoom element so it can be used when zooming back out - z.data('starting-scale', box.width / zoomWidth); - - // Initial position of the zoom box - should sit over the link and match - // size and position so that the element appears to zoom from the link - z.css({ - transform: 'translateX(0) translateY(0) scale(' + z.data('starting-scale') + ')', - width: zoomWidth, - height: zoomHeight, - left: Math.round(box.left), - top: Math.round(box.top) - }); - - // Load image before running zoom up animation - this.fluidbook.displayLoader(); - loadImage(zoomImage, function (img) { - - // Image is set as a background for better scaling / fitting via CSS - z.css('background-image', 'url(' + img.src + ')'); - this.fluidbook.hideLoader(); - z.show(); - $this.showOverlay(); - - // Trigger zoom up animation just after showing zoom element - setTimeout(function () { - z.css({ - boxShadow: '0 0 100px rgba(0,0,0,0.3)', - transform: 'translateX(' + zoomX + 'px) translateY(' + zoomY + 'px) scale(1)' - }); - }, 50); - - // Hide close button initially so it only shows when zoom finishes. - $('.zoomPopupClose').css('opacity', 0); - - $this.fluidbook.stats.track(2, $this.fluidbook.currentPage); - - // Display close button after zoom animation has finished - setTimeout(function () { - $('.zoomPopupClose').css('opacity', 1); - }, 500); - }); - - }); - }, - - zoomLinkClose: function (immediate) { - return this.zoomLinkReset(immediate); - }, - - zoomLinkReset: function (immediate) { - - var $this = this; - - if ($('.zoomPopupWrapper:visible').length == 0) { - return; - } - - if (immediate == undefined) { - immediate = false; - } - - var $wrapper = $('#zoomPopupGroupWrapper'); - - // Close each popup that is open - $wrapper.find('.zoomPopupWrapper').each(function () { - var z = $(this); - z.find('.zoomPopupClose').css('opacity', '0'); - - if (immediate) { - $('.zoomPopupWrapper').hide(); - $this.hideOverlay(1); - } - - z.css({ - transform: 'translate(0,0) scale(' + z.data('starting-scale') + ')', - boxShadow: '0 0 0 rgba(0,0,0,0.3)', - }); - }); - - // Hide popup after transition completes - // ToDo: use CSS transition end event to do this without needing a timeout value (or use Web Animation API) - // ToDo: see https://davidwalsh.name/css-animation-callback - this.hideOverlay(500); - setTimeout(function () { - $('.zoomPopupWrapper').hide(); - $wrapper.html(''); // Empty group wrapper - $wrapper.removeClass(); // Remove all classes (stacked / side-by-side layout) - }, 500); - - return false; - }, - - hideOverlay: function (delay) { - if (delay == undefined) { - delay = 500; - } - $("#zoomPopupOverlay").css('opacity', 0); - setTimeout(function () { - $("#zoomPopupOverlay").hide(); - }, delay); - }, - showOverlay: function () { - $("#zoomPopupOverlay").css('opacity', 0).show(); - setTimeout(function () { - $("#zoomPopupOverlay").css('opacity', 1) - }, 10) - }, triggerLinkById: function (id) { var a = $('.link[data-id="' + id + '"] a:eq(0)'); a.get(0).click(); diff --git a/js/libs/fluidbook/fluidbook.share.js b/js/libs/fluidbook/fluidbook.share.js index 4359abed..4a52d696 100644 --- a/js/libs/fluidbook/fluidbook.share.js +++ b/js/libs/fluidbook/fluidbook.share.js @@ -9,14 +9,16 @@ function FluidbookShare(fluidbook) { if (url === undefined || url === null || url === 'undefined') { url = ''; } - $this[f](url); + var context = $(this).data('context') === null ? 'publication' : $(this).data('context'); + + $this[f](url, context); $(this).closest('.mview').find('.back').click(); return false; }); } $(document).on('click touchend', '[data-action="share"]', function () { - $this.fluidbook.menu.openView("share", $(this).data('extra')); + $this.fluidbook.menu.openView("share", $(this).data('extra'), $(this).data('context')); return false; }); @@ -63,7 +65,6 @@ FluidbookShare.prototype = { }, getShareURL: function (url) { - if (url == undefined || url == 'undefined' || url == null || url == false) { url = ''; } @@ -103,20 +104,28 @@ FluidbookShare.prototype = { return this.fluidbook.datas.title; }, - getEmailSubject: function () { - if (this.fluidbook.datas.email_title == '') { - return this.fluidbook.datas.title; + getEmailSubject: function (context) { + if (context === 'publication') { + if (this.fluidbook.datas.email_title === '') { + return this.fluidbook.datas.title; + } + return this.fluidbook.datas.email_title; + } else if (context === 'product') { + return this.fluidbook.datas.product_email_title; } - return this.fluidbook.datas.email_title; }, - getEmailBody: function (url) { + getEmailBody: function (url, context) { var body; var u = this.getShareURL(url); - if (this.fluidbook.datas.email_body == '') { - body = this.fluidbook.l10n.__('Veuillez cliquer sur le lien suivant pour ouvrir %title%\\n%link%'); - } else { - body = this.fluidbook.datas.email_body; + if (context === 'publication') { + if (this.fluidbook.datas.email_body === '') { + body = this.fluidbook.l10n.__('Veuillez cliquer sur le lien suivant pour ouvrir %title%\\n%link%'); + } else { + body = this.fluidbook.datas.email_body; + } + } else if (context === 'product') { + body = this.fluidbook.datas.product_email_body; } body = body.trim(); body = body.replace(/\%title\%/g, this.fluidbook.datas.title); @@ -137,12 +146,12 @@ FluidbookShare.prototype = { return this.fluidbook.datas.seoArticles[title]; }, - getShareLinks: function (hideLabels, url) { + getShareLinks: function (hideLabels, url, context) { var shareLinks = {}, shareHTML = ''; - if (url == undefined || url == 'undefined') { - url == ''; + if (url === undefined || url === null || url === 'undefined') { + url = ''; } hideLabels = hideLabels || false; @@ -172,7 +181,7 @@ FluidbookShare.prototype = { // Generate links for (var shareType in shareLinks) { if (shareLinks.hasOwnProperty(shareType)) { // Ensure we don't get inherited properties - shareHTML += '
  • '; + $groupWrapper.append('
    ' + menu + '
    '); + $groupWrapper.append('' + getSpriteIcon('interface-close') + ''); + } + + var z = $('#zoomPopup_' + zoomID), + box = zoomLink[0].getBoundingClientRect(), // Should return full values without rounding + parent = zoomLink.closest('.link'), + baseWidth = parseInt(zoomLink.data('width')), // Width of the original link from the editor + baseHeight = parseInt(zoomLink.data('height')), // Height of the original link from the editor + maxZoom = parseFloat(zoomLink.data('maxzoom')) || 2, // The default value for this should match that of the compiler in zoomLink::generateImage() + zoomX, + zoomY, + zoomWidth, + zoomHeight, + zoomScale; + + if ($(parent).length === 0) { + return; + } + + var linkId = $(parent).attr('id').split('_', 2)[1]; + var zoomImage = 'data/links/zoom_' + linkId + '.jpg'; + + // TODO: In the compiler we should look at generating higher-res images to cater for hiDPI displays + // TODO: It should be clearer what the sizes in the link editor really mean - due to screen size and scaling, a 100x100 link could appear as 150x150 in the player so if it we set a max zoom level of 2, it will only appear at 200x200, which is not much bigger than the embedded size. It's hard to handle max zoom levels while also working with a player that always scales the content to fit the screen. The most pragmatic approach probably is to generate higher res images. + + + // Due to the scaling done by the Fluidbook interface, the actual link size is likely to be different + // to the original link editor width and height. Since the zoom image is generated based on the link editor + // dimensions multiplied by the max zoom level, we need to be able to take that into account so we don't exceed + // the resolution of the image in the popup. We can't use the fluidbook.resize.bookScale variable because it + // measures the scaling of the high-res images. Instead, we work out the relative scaling by taking the + // link editor width (baseWidth) and comparing it to the actual link width. + //maxZoom = maxZoom / (box.width / baseWidth); // Adjusted maxZoom level... + + // Apply any necessary group scaling to the individual element... + baseHeight *= groupScale; + baseWidth *= groupScale; + + // Then calculate best scale factor to fit and also to honour the maxZoom level + zoomScale = Math.min((availableWidth / baseWidth), (availableHeight / baseHeight), maxZoom); + + // Dimensions of the final popup + zoomWidth = baseWidth * zoomScale; + zoomHeight = baseHeight * zoomScale; + + // Max zoom of first clicked link + var firstMaxZoom = parseFloat(links[0].data('maxzoom')) || 2; + + //========= + // Position elements based on the layout + // There are two possible layouts: stacked or side-by-side + if (layout === 'stacked') { + + $groupWrapper.addClass('layout-stacked'); + + // Calculate translate co-ordinates so image is centred correctly + // Values are rounded so we don't end up with image being positioned between pixels, which causes blurring + zoomX = Math.round((availableWidth / 2) - parent.offset().left - (zoomWidth / 2) + zoomMargin); + + // Y position of first block (so both blocks are vertically centred) + var groupY = Math.round((availableHeight - stackedHeight) / 2); + + // If this is the first / only block, use calculated groupY position + if (index === 0) { + zoomY = groupY - parent.offset().top + zoomMargin; + + // Otherwise, calculate Y position based on first element position + } else { + zoomY = Math.round(groupY + links[0].data('height') * firstMaxZoom * groupScale + zoomZonesGap + zoomMargin - parent.offset().top); + } + } else { + // Side-by-side layout + $groupWrapper.addClass('layout-side-by-side'); + + // Vertically centre each block + zoomY = Math.round((availableHeight / 2) - parent.offset().top - (zoomHeight / 2) + zoomMargin); + + // X position of first block (so both blocks are horizontally centred) + var groupX = Math.round((availableWidth - sideBySideWidth) / 2); + + // If this is the first / only block, use calculated groupX position + if (index === 0) { + zoomX = groupX - parent.offset().left + zoomMargin; + + // Otherwise, calculate X position based on first element position + } else { + zoomX = Math.round(groupX + (links[0].data('width') * firstMaxZoom * groupScale) + zoomZonesGap + zoomMargin - parent.offset().left); + } + } + + // Keep starting scale with zoom element so it can be used when zooming back out + z.data('starting-scale', box.width / zoomWidth); + + // Initial position of the zoom box - should sit over the link and match + // size and position so that the element appears to zoom from the link + z.css({ + transform: 'translateX(0) translateY(0) scale(' + z.data('starting-scale') + ')', + width: zoomWidth, + height: zoomHeight, + left: Math.round(box.left), + top: Math.round(box.top) + }); + + // Load image before running zoom up animation + this.fluidbook.displayLoader(); + loadImage(zoomImage, function (img) { + + // Image is set as a background for better scaling / fitting via CSS + z.css('background-image', 'url(' + img.src + ')'); + $this.fluidbook.hideLoader(); + z.show(); + $this.showOverlay(); + + // Trigger zoom up animation just after showing zoom element + setTimeout(function () { + z.css({ + boxShadow: '0 0 100px rgba(0,0,0,0.3)', + transform: 'translateX(' + zoomX + 'px) translateY(' + zoomY + 'px) scale(1)' + }); + + setTimeout(function () { + $this.resizeZoomLinkBackground(true); + }, 600); + + }, 50); + + + $this.fluidbook.stats.track(2, $this.fluidbook.currentPage); + }); + + }); + }, + + resizeZoomLinkBackground: function (show) { + var top, left, bottom, right, width, height, padding; + + var wrappers = $('.zoomPopupWrapper'); + if ($('html').hasClass('menu-burger')) { + top = 0; + left = 0; + width = this.fluidbook.resize.ww; + height = this.fluidbook.resize.hh; + } else if (wrappers.length === 1) { + var box = $(wrappers).get(0).getBoundingClientRect(); + top = box.top; + left = box.left; + width = box.width; + height = box.height; + } else { + top = Number.MAX_VALUE; + left = Number.MAX_VALUE; + bottom = Number.MIN_VALUE; + right = Number.MIN_VALUE; + wrappers.each(function () { + var box = $(this).get(0).getBoundingClientRect(); + top = Math.min(top, box.top); + left = Math.min(left, box.left); + right = Math.max(right, box.right); + bottom = Math.max(bottom, box.bottom); + }); + padding = 20; + width = right - left + 2 * padding; + height = bottom - top + 2 * padding; + top -= padding; + left -= padding; + } + + $("#zoomPopupBackground").css({left: left, top: top, width: width, height: height, opacity: show ? 1 : 0}); + }, + + zoomLinkClose: function (immediate) { + return this.zoomLinkReset(immediate); + }, + + zoomLinkReset: function (immediate) { + + var $this = this; + + if ($('.zoomPopupWrapper:visible').length === 0) { + return; + } + + if (immediate === undefined) { + immediate = false; + } + + var $wrapper = $('#zoomPopupGroupWrapper'); + + // Close each popup that is open + $wrapper.find('.zoomPopupWrapper').each(function () { + var z = $(this); + z.find('.zoomPopupClose').css('opacity', '0'); + + if (immediate) { + $('.zoomPopupWrapper').hide(); + $this.hideOverlay(1); + } + + z.css({ + transform: 'translate(0,0) scale(' + z.data('starting-scale') + ')', + boxShadow: '0 0 0 rgba(0,0,0,0.3)', + }); + }); + + this.resizeZoomLinkBackground(0); + + // Hide popup after transition completes + // ToDo: use CSS transition end event to do this without needing a timeout value (or use Web Animation API) + // ToDo: see https://davidwalsh.name/css-animation-callback + this.hideOverlay(500); + setTimeout(function () { + $('.zoomPopupWrapper').hide(); + $wrapper.html(''); // Empty group wrapper + $wrapper.removeClass(); // Remove all classes (stacked / side-by-side layout) + }, 500); + + return false; + }, + + hideOverlay: function (delay) { + if (delay === undefined) { + delay = 500; + } + $("#zoomPopupOverlay").css('opacity', 0); + setTimeout(function () { + $("#zoomPopupOverlay").hide(); + }, delay); + }, + showOverlay: function () { + $("#zoomPopupOverlay").css('opacity', 0).show(); + setTimeout(function () { + $("#zoomPopupOverlay").css('opacity', 1) + }, 10) + }, +}; \ No newline at end of file diff --git a/style/fluidbook.less b/style/fluidbook.less index 0d916a00..c9c719a2 100644 --- a/style/fluidbook.less +++ b/style/fluidbook.less @@ -2804,35 +2804,112 @@ ul.chapters { z-index: 100; display: none; .overlayBackground(); + + .menu-burger & { + background-color: @menu-background; + } } -// Depending on the layout, hide one of the close buttons -// We need to define both first and last rules in case there is only one zoom zone -// In this case, the last written rule will apply -#zoomPopupGroupWrapper { - &.layout-stacked { - .zoomPopupWrapper:last-of-type .zoomPopupClose { - display: none; - } +.zoomPopupWrapper, .zoomPopupClose, #zoomPopupBackground .bg { + cursor: zoom-out !important; // Needed for close link, otherwise pointer cursor is used +} - .zoomPopupWrapper:first-of-type .zoomPopupClose { - display: block; - } +#zoomPopupBackground { + position: absolute; + z-index: 100; + opacity: 0; + transition: opacity 150ms; + + .bg { + background-color: @menu-background; + width: 100%; + height: 100%; } - &.layout-side-by-side { - .zoomPopupWrapper:first-of-type .zoomPopupClose { - display: none; + #zoomPopupMenu { + position: absolute; + right: 0; + bottom: -40px; + color: @menu-text; + + .menu-burger & { + right: auto; + bottom: 0; + left: 50%; + transform: translateX(-50%); + white-space: nowrap; } - .zoomPopupWrapper:last-of-type .zoomPopupClose { - display: block; + .button { + margin-left: 3px; + height: 40px; + display: inline-block; + padding: 7px 17px 7px 7px; + background-color: @menu-button-background; + width: auto; + white-space: nowrap; + + .menu-burger & { + padding: 10px 20px 10px 10px; + height: 60px; + } + + .svg-icon { + height: 25px; + + .menu-burger & { + height: 40px; + } + } + + &.nolabel { + padding-right: 7px; + width: 40px; + + .menu-burger & { + padding-right: 10px; + width: 60px; + } + } + + span { + text-transform: uppercase; + margin-left: 20px; + position: relative; + top: -5px; + + .menu-burger & { + font-size: 20px; + top: -13px; + } + } } } } -.zoomPopupWrapper, .zoomPopupClose { - cursor: zoom-out !important; // Needed for close link, otherwise pointer cursor is used +.zoomPopupClose { + @zoom-close-button-size: 60px; + + position: absolute; + top: 0; + right: 0; + width: @zoom-close-button-size; + height: @zoom-close-button-size; + padding: unit((@zoom-close-button-size/30)*11, px); + z-index: 103; + background-color: @menu-button-background; + color: @menu-text; + opacity: 1; + transition: opacity 500ms; + + .svg-icon { + display: block; // Needed for proper positioning in centre of square + } + + .rtl & { + right: auto; + left: 0; + } } .zoomPopupWrapper { @@ -2841,17 +2918,11 @@ ul.chapters { background-repeat: no-repeat; background-position: center; background-size: cover; - transition: all 0.5s ease-in-out; + transition: all 0.5s; transform-origin: 0 0; position: absolute; z-index: 101; - &:hover { - .zoomPopupClose { - opacity: 1; - } - } - img { position: absolute; top: 0; @@ -2862,30 +2933,7 @@ ul.chapters { z-index: 102; } - .zoomPopupClose { - @zoom-close-button-size: 30px; - position: absolute; - top: 0; - right: -@zoom-close-button-size; - width: @zoom-close-button-size; - height: @zoom-close-button-size; - padding: 11px; - z-index: 103; - background-color: @menu-button-background; - color: @menu-text; - opacity: 1; - transition: opacity 250ms; - - .svg-icon { - display: block; // Needed for proper positioning in centre of square - } - - .rtl & { - right: auto; - left: 0; - } - } } @import "lib/perfect-scrollbar.less"; -- 2.39.5