Merge branch 'MDL-83005-404' of https://github.com/davewoloszyn/moodle into MOODLE_404_STABLE

This commit is contained in:
Shamim Rezaie
2024-12-23 06:03:11 +11:00
7 changed files with 157 additions and 245 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+151 -187
View File
@@ -47,6 +47,7 @@ import PendingPromise from 'core/pending';
* @type {number}
*/
const MINSPACING = 10;
const BUFFER = 10;
/**
* A user tour.
@@ -805,21 +806,8 @@ const Tour = class {
if (this.isStepActuallyVisible(stepConfig)) {
let targetNode = this.getStepTarget(stepConfig);
if (targetNode.parents('[data-usertour="scroller"]').length) {
animationTarget = targetNode.parents('[data-usertour="scroller"]');
}
targetNode.data('flexitour', 'target');
let zIndex = this.calculateZIndex(targetNode);
if (zIndex) {
stepConfig.zIndex = zIndex + 1;
}
if (stepConfig.zIndex) {
currentStepNode.css('zIndex', stepConfig.zIndex + 1);
}
// Add the backdrop.
this.positionBackdrop(stepConfig);
@@ -1209,9 +1197,8 @@ const Tour = class {
this.currentStepConfig = null;
}
// Remove the backdrop features.
$('[data-flexitour="step-background"]').remove();
$('[data-flexitour="step-backdrop"]').removeAttr('data-flexitour');
// Remove the highlight attribute when the hide occurs.
$('[data-flexitour="highlight"]').removeAttr('data-flexitour');
const backdrop = $('[data-flexitour="backdrop"]');
if (backdrop.length) {
@@ -1274,6 +1261,25 @@ const Tour = class {
return $(this.currentStepNode);
}
/**
* Check whether the target node has a fixed position, or is nested within one.
*
* @param {Object} targetNode The target element to check.
* @return {Boolean} Return true if fixed position found.
*/
hasFixedPosition = (targetNode) => {
let currentElement = targetNode[0];
while (currentElement) {
const computedStyle = window.getComputedStyle(currentElement);
if (computedStyle.position === 'fixed') {
return true;
}
currentElement = currentElement.parentElement;
}
return false;
};
/**
* Calculate scrollTop.
*
@@ -1291,7 +1297,9 @@ const Tour = class {
}
let scrollTop = scrollParent.scrollTop();
if (stepConfig.placement === 'top') {
if (this.hasFixedPosition(targetNode)) {
// Target must be in a fixed or custom position. No need to modify the scrollTop.
} else if (stepConfig.placement === 'top') {
// If the placement is top, center scroll at the top of the target.
scrollTop = targetNode.offset().top - (viewportHeight / 2);
} else if (stepConfig.placement === 'bottom') {
@@ -1381,6 +1389,12 @@ const Tour = class {
break;
}
let offset = '0';
if (stepConfig.backdrop) {
// Offset the arrow so that it points to the cut-out in the backdrop.
offset = `-${BUFFER}, ${BUFFER}`;
}
let target = this.getStepTarget(stepConfig);
var config = {
placement: stepConfig.placement + '-start',
@@ -1392,6 +1406,9 @@ const Tour = class {
arrow: {
element: '[data-role="arrow"]',
},
offset: {
offset: offset
}
},
onCreate: function(data) {
recalculateArrowPosition(data);
@@ -1404,6 +1421,8 @@ const Tour = class {
thisT.possitionNeedToBeRecalculated = false;
recalculateStepPosition(data);
}
// Reset backdrop position when things update.
thisT.recalculateBackdropPosition(stepConfig);
},
};
@@ -1537,7 +1556,7 @@ const Tour = class {
thisT.currentStepPopper.update();
};
let background = $('[data-flexitour="step-background"]');
let background = $('[data-flexitour="highlight"]');
if (background.length) {
target = background;
}
@@ -1556,23 +1575,37 @@ const Tour = class {
* @return {String} The placement after recalculate
*/
recalculatePlacement(stepConfig) {
const buffer = 10;
const arrowWidth = 16;
let target = this.getStepTarget(stepConfig);
let widthContent = this.currentStepNode.width() + arrowWidth;
let targetOffsetLeft = target.offset().left - buffer;
let targetOffsetRight = target.offset().left + target.width() + buffer;
let targetOffsetLeft = target.offset().left - BUFFER;
let targetOffsetRight = target.offset().left + target.width() + BUFFER;
let placement = stepConfig.placement;
if (['left', 'right'].indexOf(placement) !== -1) {
if ((targetOffsetLeft < (widthContent + buffer)) &&
((targetOffsetRight + widthContent + buffer) > document.documentElement.clientWidth)) {
if ((targetOffsetLeft < (widthContent + BUFFER)) &&
((targetOffsetRight + widthContent + BUFFER) > document.documentElement.clientWidth)) {
placement = 'top';
}
}
return placement;
}
/**
* Recaculate where the backdrop and its cut-out should be.
*
* This is needed when highlighted elements are off the page.
* This can be called on update to recalculate it all.
*
* @method recalculateBackdropPosition
* @param {Object} stepConfig The step configuration of the step
*/
recalculateBackdropPosition(stepConfig) {
if (stepConfig.backdrop) {
this.positionBackdrop(stepConfig);
}
}
/**
* Add the backdrop.
*
@@ -1584,194 +1617,125 @@ const Tour = class {
positionBackdrop(stepConfig) {
if (stepConfig.backdrop) {
this.currentStepConfig.hasBackdrop = true;
let backdrop = $('<div data-flexitour="backdrop"></div>');
if (stepConfig.zIndex) {
if (stepConfig.attachPoint === 'append') {
stepConfig.attachTo.append(backdrop);
} else {
backdrop.insertAfter(stepConfig.attachTo);
}
} else {
// Position our backdrop above everything else.
let backdrop = $('div[data-flexitour="backdrop"]');
if (!backdrop.length) {
backdrop = $('<div data-flexitour="backdrop"></div>');
$('body').append(backdrop);
}
if (this.isStepActuallyVisible(stepConfig)) {
// The step has a visible target.
// Punch a hole through the backdrop.
let background = $('[data-flexitour="step-background"]');
if (!background.length) {
background = $('<div data-flexitour="step-background"></div>');
}
let targetNode = this.getStepTarget(stepConfig);
targetNode.attr('data-flexitour', 'highlight');
let buffer = 10;
let distanceFromTop = targetNode[0].getBoundingClientRect().top;
let relativeTop = targetNode.offset().top - distanceFromTop;
let colorNode = targetNode;
if (buffer) {
colorNode = $('body');
}
/*
Draw a clip-path that makes the backdrop a window.
The clip-path is drawn with x/y coordinates in the following sequence.
let drawertop = 0;
1--------------------------------------------------2
11 |
| |
| 8-----------------------------7 |
| | | |
| | | |
| | | |
10-------9 | |
5--------------------------------------6 |
| |
| |
4--------------------------------------------------3
*/
// These values will help us draw the backdrop.
const viewportHeight = $(window).height();
const viewportWidth = $(window).width();
const elementWidth = targetNode.outerWidth() + (BUFFER * 2);
let elementHeight = targetNode.outerHeight() + (BUFFER * 2);
const elementLeft = targetNode.offset().left - BUFFER;
let elementTop = targetNode.offset().top - BUFFER - relativeTop;
// Check the amount of navbar overlap the highlight element has.
// We will adjust the backdrop shape to compensate for the fixed navbar.
let navbarOverlap = 0;
if (targetNode.parents('[data-usertour="scroller"]').length) {
// Determine the navbar height.
const scrollerElement = targetNode.parents('[data-usertour="scroller"]');
const navigationBuffer = scrollerElement.offset().top;
if (scrollerElement.scrollTop() >= navigationBuffer) {
drawertop = scrollerElement.scrollTop() - navigationBuffer;
background.css({
position: 'fixed'
});
}
const navbarHeight = scrollerElement.offset().top;
navbarOverlap = Math.max(Math.ceil(navbarHeight - elementTop), 0);
elementTop = elementTop + navbarOverlap;
elementHeight = elementHeight - navbarOverlap;
}
background.css({
width: targetNode.outerWidth() + buffer + buffer,
height: targetNode.outerHeight() + buffer + buffer,
left: targetNode.offset().left - buffer,
top: targetNode.offset().top + drawertop - buffer,
backgroundColor: this.calculateInherittedBackgroundColor(colorNode),
});
if (targetNode.offset().left < buffer) {
background.css({
width: targetNode.outerWidth() + targetNode.offset().left + buffer,
left: targetNode.offset().left,
});
}
if ((targetNode.offset().top + drawertop) < buffer) {
background.css({
height: targetNode.outerHeight() + targetNode.offset().top + buffer,
top: targetNode.offset().top,
});
}
let targetRadius = targetNode.css('borderRadius');
if (targetRadius && targetRadius !== $('body').css('borderRadius')) {
background.css('borderRadius', targetRadius);
}
let targetPosition = this.calculatePosition(targetNode);
if (targetPosition === 'absolute') {
background.css('position', 'fixed');
}
let fader = background.clone();
fader.css({
backgroundColor: backdrop.css('backgroundColor'),
opacity: backdrop.css('opacity'),
});
fader.attr('data-flexitour', 'step-background-fader');
if (!stepConfig.zIndex) {
let targetClone = targetNode.clone();
background.append(targetClone.first());
$('body').append(fader);
$('body').append(background);
} else {
if (stepConfig.attachPoint === 'append') {
stepConfig.attachTo.append(background);
// Check if the step container is in the 'top' position.
// We will re-anchor the step container to the shifted backdrop edge as opposed to the actual element.
if (this.currentStepNode && this.currentStepNode.length) {
const xPlacement = this.currentStepNode[0].getAttribute('x-placement');
if (xPlacement === 'top-start') {
this.currentStepNode[0].style.top = `${navbarOverlap}px`;
} else {
fader.insertAfter(stepConfig.attachTo);
background.insertAfter(stepConfig.attachTo);
this.currentStepNode[0].style.top = '0px';
}
}
// Add the backdrop data to the actual target.
// This is the part which actually does the work.
targetNode.attr('data-flexitour', 'step-backdrop');
let backdropPath = document.querySelector('div[data-flexitour="backdrop"]');
const radius = 10;
if (stepConfig.zIndex) {
backdrop.css('zIndex', stepConfig.zIndex);
background.css('zIndex', stepConfig.zIndex + 1);
targetNode.css('zIndex', stepConfig.zIndex + 2);
}
const bottomRight = {
'x1': elementLeft + elementWidth - radius,
'y1': elementTop + elementHeight,
'x2': elementLeft + elementWidth,
'y2': elementTop + elementHeight - radius,
};
fader.fadeOut('2000', function() {
$(this).remove();
});
const topRight = {
'x1': elementLeft + elementWidth,
'y1': elementTop + radius,
'x2': elementLeft + elementWidth - radius,
'y2': elementTop,
};
const topLeft = {
'x1': elementLeft + radius,
'y1': elementTop,
'x2': elementLeft,
'y2': elementTop + radius,
};
const bottomLeft = {
'x1': elementLeft,
'y1': elementTop + elementHeight - radius,
'x2': elementLeft + radius,
'y2': elementTop + elementHeight,
};
// L = line.
// C = Bezier curve.
// Z = Close path.
backdropPath.style.clipPath = `path('M 0 0 \
L ${viewportWidth} 0 \
L ${viewportWidth} ${viewportHeight} \
L 0 ${viewportHeight} \
L 0 ${elementTop + elementHeight} \
L ${bottomRight.x1} ${bottomRight.y1} \
C ${bottomRight.x1} ${bottomRight.y1} ${bottomRight.x2} ${bottomRight.y1} ${bottomRight.x2} ${bottomRight.y2} \
L ${topRight.x1} ${topRight.y1} \
C ${topRight.x1} ${topRight.y1} ${topRight.x1} ${topRight.y2} ${topRight.x2} ${topRight.y2} \
L ${topLeft.x1} ${topLeft.y1} \
C ${topLeft.x1} ${topLeft.y1} ${topLeft.x2} ${topLeft.y1} ${topLeft.x2} ${topLeft.y2} \
L ${bottomLeft.x1} ${bottomLeft.y1} \
C ${bottomLeft.x1} ${bottomLeft.y1} ${bottomLeft.x1} ${bottomLeft.y2} ${bottomLeft.x2} ${bottomLeft.y2} \
L 0 ${elementTop + elementHeight} \
Z'
)`;
}
}
return this;
}
/**
* Calculate the inheritted z-index.
*
* @method calculateZIndex
* @param {jQuery} elem The element to calculate z-index for
* @return {Number} Calculated z-index
*/
calculateZIndex(elem) {
elem = $(elem);
if (this.requireDefaultTourZindex(elem)) {
return 0;
}
while (elem.length && elem[0] !== document) {
// Ignore z-index if position is set to a value where z-index is ignored by the browser
// This makes behavior of this function consistent across browsers
// WebKit always returns auto if the element is positioned.
let position = elem.css("position");
if (position === "absolute" || position === "fixed") {
// IE returns 0 when zIndex is not specified
// other browsers return a string
// we ignore the case of nested elements with an explicit value of 0
// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
let value = parseInt(elem.css("zIndex"), 10);
if (!isNaN(value) && value !== 0) {
return value;
}
}
elem = elem.parent();
}
return 0;
}
/**
* Check if the element require the default tour z-index.
*
* Some page elements have fixed z-index. However, their weight is not enough to cover
* other page elements like the top navbar or a sticky footer so they use the default
* tour z-index instead.
*
* @param {jQuery} elem the page element to highlight
* @return {Boolean} true if the element requires the default tour z-index instead of the calculated one
*/
requireDefaultTourZindex(elem) {
if (elem.parents('[data-region="fixed-drawer"]').length !== 0) {
return true;
}
return false;
}
/**
* Calculate the inheritted background colour.
*
* @method calculateInherittedBackgroundColor
* @param {jQuery} elem The element to calculate colour for
* @return {String} Calculated background colour
*/
calculateInherittedBackgroundColor(elem) {
// Use a fake node to compare each element against.
let fakeNode = $('<div>').hide();
$('body').append(fakeNode);
let fakeElemColor = fakeNode.css('backgroundColor');
fakeNode.remove();
elem = $(elem);
while (elem.length && elem[0] !== document) {
let color = elem.css('backgroundColor');
if (color !== fakeElemColor) {
return color;
}
elem = elem.parent();
}
return null;
}
/**
* Calculate the inheritted position.
*
-13
View File
@@ -33,19 +33,6 @@ span[data-flexitour="container"].orphan div[data-role="arrow"] {
display: none;
}
body div[data-flexitour="step-background-fader"],
body div[data-flexitour="step-background"] {
position: absolute;
background: inherit;
background-image: none;
}
div[data-flexitour="step-background-fader"],
[data-flexitour="step-backdrop"] > td,
[data-flexitour="step-backdrop"] {
position: relative;
}
span[data-flexitour="container"].orphan div[data-role="arrow"] {
display: none;
}
+2 -17
View File
@@ -1,11 +1,9 @@
/**
* Tour step must sit above all other UI components.
* The backdrop is the lowest point in the tour.
* Everything else is in the container, and the target background should be at the same z-index.
* ----- moodle
* ---- step backdrop
* --- step container
* --- step target background
*/
$flexitour-base-zindex: 1040;
@@ -18,24 +16,11 @@ div[data-flexitour="backdrop"] {
z-index: #{$flexitour-base-zindex};
}
// The step-background is used to highlight the region targetted in the step.
div[data-flexitour="step-background-fader"],
div[data-flexitour="step-background"] {
@include border-radius($border-radius-lg);
// The step container, and the target background should be at the same z-index.
padding: 10px;
span[data-flexitour="container"] {
// The step container, needs to be higher than the backdrop.
z-index: ($flexitour-base-zindex + 1);
}
span[data-flexitour="container"],
div[data-flexitour="step-background-fader"],
[data-flexitour="step-backdrop"] > td,
[data-flexitour="step-backdrop"] {
// The step container, and the target background should be at the same z-index.
z-index: ($flexitour-base-zindex + 2);
}
span[data-flexitour="container"] {
.modal-dialog {
/**
+1 -13
View File
@@ -36648,11 +36648,9 @@ body {
/**
* Tour step must sit above all other UI components.
* The backdrop is the lowest point in the tour.
* Everything else is in the container, and the target background should be at the same z-index.
* ----- moodle
* ---- step backdrop
* --- step container
* --- step target background
*/
div[data-flexitour=backdrop] {
background-color: #000;
@@ -36660,20 +36658,10 @@ div[data-flexitour=backdrop] {
z-index: 1040;
}
div[data-flexitour=step-background-fader],
div[data-flexitour=step-background] {
border-radius: 0.6rem;
padding: 10px;
span[data-flexitour=container] {
z-index: 1041;
}
span[data-flexitour=container],
div[data-flexitour=step-background-fader],
[data-flexitour=step-backdrop] > td,
[data-flexitour=step-backdrop] {
z-index: 1042;
}
span[data-flexitour=container] .modal-dialog {
/**
* Remove all margins to:
+1 -13
View File
@@ -36582,11 +36582,9 @@ body {
/**
* Tour step must sit above all other UI components.
* The backdrop is the lowest point in the tour.
* Everything else is in the container, and the target background should be at the same z-index.
* ----- moodle
* ---- step backdrop
* --- step container
* --- step target background
*/
div[data-flexitour=backdrop] {
background-color: #000;
@@ -36594,20 +36592,10 @@ div[data-flexitour=backdrop] {
z-index: 1040;
}
div[data-flexitour=step-background-fader],
div[data-flexitour=step-background] {
border-radius: 0.3rem;
padding: 10px;
span[data-flexitour=container] {
z-index: 1041;
}
span[data-flexitour=container],
div[data-flexitour=step-background-fader],
[data-flexitour=step-backdrop] > td,
[data-flexitour=step-backdrop] {
z-index: 1042;
}
span[data-flexitour=container] .modal-dialog {
/**
* Remove all margins to: