From 2e5b283faa98e6f5ec650911879aeb99fe0fe5d2 Mon Sep 17 00:00:00 2001 From: Stephen Cameron Date: Tue, 10 Oct 2017 18:07:29 +0200 Subject: [PATCH] Refactor helpView, add proper support for interface scaling and fix numerous display bugs. Done #1736 @6.25 --- js/libs/fluidbook/fluidbook.help.js | 184 ++++++++++++-------------- js/libs/fluidbook/fluidbook.resize.js | 2 +- style/fluidbook.less | 69 +++------- style/mmenu/mmenu.less | 13 +- 4 files changed, 117 insertions(+), 151 deletions(-) diff --git a/js/libs/fluidbook/fluidbook.help.js b/js/libs/fluidbook/fluidbook.help.js index ee4b6121..489268ae 100644 --- a/js/libs/fluidbook/fluidbook.help.js +++ b/js/libs/fluidbook/fluidbook.help.js @@ -43,12 +43,6 @@ FluidbookHelp.prototype = { // Icons help += '
'; - // var scale = $("#horizontalNav").transform('scaleX'); - // $("#horizontalNav").transform({ - // scale: [1, 1] - // }, { - // preserve: true - // }); var tooltipSelector = '#horizontalNav a[data-tooltip]'; @@ -203,88 +197,64 @@ FluidbookHelp.prototype = { // ToDo: access variables from fluidbook.resize.* if they're not passed to the function. So resize function can be called directly... - var $this = this; - var menuHeightScaled = (this.fluidbook.datas.menuHeight) * navScale; + var $this = this, + dir = this.fluidbook.l10n.dir, + menuHeightScaled = (this.fluidbook.datas.menuHeight) * navScale, + arrow = $('#interface #next').get(0).getBoundingClientRect(), // Used for calculating offsets for both #next & #previous + nextTop, + firstTop; + + // The arrow element contains both arrows in a single image + // so we calculate the top position of the labels by percentage + nextTop = Math.round(arrow.top + arrow.height * 0.35); + firstTop = Math.round(arrow.top + arrow.height * 0.71); + + // Navigation arrow labels + this.view.find('.previous, .next').css({ + top: nextTop + }); + this.view.find('.first, .last').css({ + top: firstTop + }); - // this.view.css({ - // width: ww, - // minHeight: hh - menuHeightScaled, - // top: menuHeightScaled - // }); + // Labels are swapped for RTL documents + var prevPosition = (dir == 'ltr') ? {left: Math.round(arrow.width)} : {right: Math.round(arrow.width)}, + nextPosition = (dir == 'ltr') ? {right: Math.round(arrow.width)} : {left: Math.round(arrow.width)}; + this.view.find('.previous, .first').css(prevPosition); + this.view.find('.next, .last').css(nextPosition); - // Navigation arrows - this.interfaceTop = (hh - 100 * interfaceScale) / 2 + 30 * interfaceScale; - this.view.find('.next, .previous, .first, .last').css({ - top: this.interfaceTop - }); // Slider label var positionSliderLabel = function () { var sliderHelp = $this.view.find('.slider'); var sliderCursor = $('#slidercursor .visible'); sliderHelp.css({ - bottom: (hh - sliderCursor.offset().top) * navScale, - left: sliderCursor.offset().left + (sliderCursor.width() / 2 * navScale), - transformOrigin: '0 0' + bottom: Math.round(hh - sliderCursor.offset().top), + left: Math.round(sliderCursor.offset().left + (sliderCursor.width() / 2)), + transformOrigin: 'left bottom' }); }; positionSliderLabel(); // Run immediately setTimeout(positionSliderLabel, 250); // delay slightly to make sure co-ordinates are correct this.view.find('#icons').css({ - 'top': menuHeightScaled, - 'transform': 'scale('+ navScale +')', - 'transformOrigin': '0 100%' + top: menuHeightScaled, + transform: 'scale('+ navScale +')' }); $("#helpView #icons").css({ fontSize: (14 / navScale) * interfaceScale }); - // $("#helpView .illustration").transform({ - // scale: [interfaceScale, interfaceScale], - // origin: ['50%', '50%'] - // }); - this.view.find('.illustration').css({ transform: 'translate(-50%, -50%) scale('+ interfaceScale +')' }); - // ToDo: refactor bookmarkLabel code so that a scale transform can be applied without messing up positioning (wrap all 3 elements in a div? Handle RTL differences) - $("#helpView .interface").find('> div').transform({ scale: [interfaceScale, interfaceScale] }) - // ToDo: refactor this and try to move transform-origins to CSS. Make sure that .first and .last label positions factor in interfaceScale - - $("#helpView .interface").find('.last').transform({ - origin: ['100%', '100%'] - }, { - preserve: true - }); - - $("#helpView .interface").find('.first').transform({ - origin: ['0%', '100%'] - }, { - preserve: true - }); - - $("#helpView .interface").find('.next').transform({ - origin: ['100%', '0%'] - }, { - preserve: true - }); - - - $("#helpView .interface").find('.previous').transform({ - origin: ['0%', '0%'] - }, { - preserve: true - }); - - //this.view.find('.illustration').css('margin-top', (hh - 200 * interfaceScale) / 2); }, clearTimeout: function() { clearTimeout(this.autoTimeout); @@ -313,11 +283,6 @@ FluidbookHelp.prototype = { baseElement = $('#links .bookmark.' + side), // Original element used to provide position and sizing for overlay html = ''; - // Don't show the label if there's no space for it (ie. the side doesn't exist in this view) - // if ((isFirst && side == firstMissing) || (isLast && side == lastMissing)) { - // return ''; - // } - // If bookmark icon isn't present on the side we want, it means that we're on // the first/last page and that side is missing so we can't display the help if (baseElement.length == 0) { @@ -326,61 +291,76 @@ FluidbookHelp.prototype = { // Get the offset and dimensions of the element, taking into account the scaling var box = baseElement[0].getBoundingClientRect(), - circleExtra = 20, // How much bigger the circle should be around the bookmark icon + circleExtra = 20 * this.fluidbook.resize.interfaceScale, // How much bigger the circle should be around the bookmark icon lineLength = 30; // Length of the line to the label text + // The bookmark icon sits inside a circle that is slightly bigger so in order to make the icon sit exactly + // on the corner of the page, we must offset the difference added by the larger wrapping circle. + var circleOffset = circleExtra / 2; + // Build a HTML string via jQuery with all the styling // Bookmark icon: - html += $('
').css({ - 'position': 'absolute', - 'display': 'block', - 'top': Math.round(box.top), - 'left': Math.round(box.left), - 'width': Math.round(box.width), - 'height': Math.round(box.height), - 'backgroundImage': baseElement.css('backgroundImage').replace('off.svg', 'on.svg'), // Show the "on" state if not already set - 'backgroundSize': 'contain' + var icon = $('
').css({ + width: Math.round(box.width), + height: Math.round(box.height), + margin: Math.round(circleOffset), // Centre inside circle + backgroundSize: 'contain', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundImage: baseElement.css('backgroundImage').replace('off.svg', 'on.svg') // Show the "on" state if not already set })[0].outerHTML; // Circle around the icon - slightly bigger - html += $('
').css({ - 'position': 'absolute', - 'display': 'block', - 'top': Math.round(box.top - circleExtra / 2), - 'left': Math.round(box.left - circleExtra / 2), - 'width': Math.round(box.width + circleExtra), - 'height': Math.round(box.height + circleExtra), - 'borderRadius': '50%', - 'border': '1px solid' + html += $('
' + icon + '
').css({ + width: Math.round(box.width + circleExtra), + height: Math.round(box.height + circleExtra), + borderRadius: '50%', + border: '1px solid' })[0].outerHTML; - // The line and text need to be positioned differently depending on which side the icon is on - var lineLeft = (side == 'left') ? Math.round(box.left + box.width + circleExtra / 2) : Math.round(box.left - circleExtra / 2 - lineLength), - labelLeft = (side == 'left') ? Math.round(box.left + box.width + circleExtra / 2 + lineLength + 10) : Math.round(box.left - circleExtra / 2 - lineLength - 10), - labelTransform = (side == 'left') ? 'translateY(-50%)' : 'translateY(-50%) translateX(-100%)'; // TranslateX -100% since we don't know how long the text is - // Line to text html += $('
').css({ - 'position': 'absolute', - 'display': 'block', - 'top': Math.round(box.top + box.height / 2), - 'left': lineLeft, - 'width': lineLength, - 'height': 0, - 'borderBottom': '1px solid', + width: lineLength, + height: 0, + borderBottom: '1px solid', })[0].outerHTML; // Help text label html += $('
'+ this.fluidbook.l10n.__('add / remove bookmark') +'
').css({ - 'position': 'absolute', - 'display': 'block', - 'top': Math.round(box.top + box.height / 2), - 'left': labelLeft, - 'transform': labelTransform, - 'whiteSpace': 'nowrap' + whiteSpace: 'nowrap', + padding: '0 0.5em' // Ensure spacing around text regardless which side the line is on })[0].outerHTML; - return html; + + // Wrapper with positioning and layout switched depending on the side + var wrapperCSS = { // Shared properties + display: 'flex', + alignItems: 'center', + position: 'absolute', + top: Math.round(box.top - circleOffset) + }, + wrapperLayout; + + if (side == 'left') { + wrapperLayout = { + left: Math.round(box.left - circleOffset), + transformOrigin: 'left top', + flexDirection: 'row' // Flexbox direction controls order of elements (icon, line, label) + }; + } else { + wrapperLayout = { + right: Math.round(this.fluidbook.resize.ww - box.left - box.width - circleOffset), + transformOrigin: 'right top', + flexDirection: 'row-reverse' // Reverse order of elements for right hand page + } + } + + var wrapper = $('
' + html + '
') + .css( + $.extend(wrapperCSS, wrapperLayout) // Merge all properties + )[0].outerHTML + + return wrapper; } }; diff --git a/js/libs/fluidbook/fluidbook.resize.js b/js/libs/fluidbook/fluidbook.resize.js index c5be9aeb..f5da7ab6 100644 --- a/js/libs/fluidbook/fluidbook.resize.js +++ b/js/libs/fluidbook/fluidbook.resize.js @@ -164,7 +164,7 @@ FluidbookResize.prototype = { bottom: audioButtonPosition }); - $("#logo,footer,#searchHints").transform({ + $("#logo,footer,#searchHints,#menuOpener").transform({ scale: navScale }); diff --git a/style/fluidbook.less b/style/fluidbook.less index 2bab7a46..969f5ff7 100644 --- a/style/fluidbook.less +++ b/style/fluidbook.less @@ -1502,21 +1502,26 @@ ul.chapters.shareList a.level0 .svg-icon { } } -.ltr #helpView .interface .next, -.ltr #helpView .interface .last, -.rtl #helpView .interface .first, -.rtl #helpView .interface .previous { - text-align: right; - right: 40px; - top: 340px; -} +#helpView { + .next, .last, .previous, .first { + margin-top: -0.5em; + line-height: 1; + } + + .next, .last { + transform-origin: right; + + .rtl & { + transform-origin: left; + } + } -&.sharp { - .ltr #helpView .interface .next, - .ltr #helpView .interface .last, - .rtl #helpView .interface .first, - .rtl #helpView .interface .previous { - right: 53px; + .previous, .first { + transform-origin: left; + + .rtl & { + transform-origin: right; + } } } @@ -1527,29 +1532,12 @@ ul.chapters.shareList a.level0 .svg-icon { content: '------------'; width: 100px; border-bottom: 1px solid #fff; - margin: 0 10px; + margin-left: 10px; position: relative; top: -0.5em; color: transparent; } -.rtl #helpView .interface .next, -.rtl #helpView .interface .last, -.ltr #helpView .interface .first, -.ltr #helpView .interface .previous { - left: 40px; - top: 340px; -} - -.sharp { - .rtl #helpView .interface .next, - .rtl #helpView .interface .last, - .ltr #helpView .interface .first, - .ltr #helpView .interface .previous { - left: 57px; - } -} - .rtl #helpView .interface .next:before, .rtl #helpView .interface .last:before, .ltr #helpView .interface .first:before, @@ -1557,27 +1545,14 @@ ul.chapters.shareList a.level0 .svg-icon { content: '------------'; width: 100px; border-bottom: 1px solid #fff; - margin: 0 10px; + margin-right: 10px; position: relative; top: -0.5em; color: transparent; } -#helpView .interface .first, -#helpView .interface .last { - margin-top: 43px; - - .sharp & { - margin-top: 40px; - } -} - -#helpView .interface .next, -#helpView .interface .previous { - margin-top: -5px; -} -#helpView .interface div { +#helpView .interface > div { position: absolute; direction: ltr; } diff --git a/style/mmenu/mmenu.less b/style/mmenu/mmenu.less index bb96c617..0a29f4ad 100644 --- a/style/mmenu/mmenu.less +++ b/style/mmenu/mmenu.less @@ -94,6 +94,10 @@ html.mm-opening .mm-menu.mm-opened[class*=mm-pagedim] ~ #mm-blocker { } } + .mm-navbar .mm-title { + padding: 0 !important; + } + //> a { // vertical-align: top; // display: inline-block; @@ -102,6 +106,12 @@ html.mm-opening .mm-menu.mm-opened[class*=mm-pagedim] ~ #mm-blocker { #menuOpener { display: none; + color: @icon-color; + + // Change colour when help view is open + .help & { + color: #ccc; + } @media all and (max-width: @menu-breakpoint) { position: absolute; @@ -110,7 +120,6 @@ html.mm-opening .mm-menu.mm-opened[class*=mm-pagedim] ~ #mm-blocker { height: 100%; font-size: 16px; line-height: 1; - color: @icon-color; display: flex; align-items: center; } @@ -120,6 +129,7 @@ html.mm-opening .mm-menu.mm-opened[class*=mm-pagedim] ~ #mm-blocker { left: 9px; right: auto; flex-direction: row; + transform-origin: left top; } // Positioning for right-to-left Fluidbooks + inverted menu on LTR @@ -127,6 +137,7 @@ html.mm-opening .mm-menu.mm-opened[class*=mm-pagedim] ~ #mm-blocker { right: 9px; left: auto; flex-direction: row-reverse; // Swap text and icon positions + transform-origin: right top; } .label { -- 2.39.5