mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 16:36:37 +02:00
Merge branch 'MDL-74822-master' of https://github.com/HuongNV13/moodle
This commit is contained in:
commit
401fc00245
4 changed files with 135 additions and 6 deletions
2
admin/tool/usertours/amd/build/tour.min.js
vendored
2
admin/tool/usertours/amd/build/tour.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -44,7 +44,7 @@ import {prefetchStrings} from 'core/prefetch';
|
||||||
* @constant
|
* @constant
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
const MINSPACING = 50;
|
const MINSPACING = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user tour.
|
* A user tour.
|
||||||
|
@ -83,6 +83,12 @@ const Tour = class {
|
||||||
// Apply configuration.
|
// Apply configuration.
|
||||||
this.configure.apply(this, arguments);
|
this.configure.apply(this, arguments);
|
||||||
|
|
||||||
|
// Unset recalculate state.
|
||||||
|
this.possitionNeedToBeRecalculated = false;
|
||||||
|
|
||||||
|
// Unset recalculate count.
|
||||||
|
this.recalculatedNo = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.storage = window.sessionStorage;
|
this.storage = window.sessionStorage;
|
||||||
this.storageKey = 'tourstate_' + this.tourName;
|
this.storageKey = 'tourstate_' + this.tourName;
|
||||||
|
@ -396,6 +402,11 @@ const Tour = class {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the CSS styles are allowed on the browser or not.
|
||||||
|
if (!this.isCSSAllowed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let target = this.getStepTarget(stepConfig);
|
let target = this.getStepTarget(stepConfig);
|
||||||
if (target && target.length && target.is(':visible')) {
|
if (target && target.length && target.is(':visible')) {
|
||||||
// Without a target, there can be no step.
|
// Without a target, there can be no step.
|
||||||
|
@ -405,6 +416,22 @@ const Tour = class {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the browser actually allow CSS styles?
|
||||||
|
*
|
||||||
|
* @returns {boolean} True if the browser is allowing CSS styles
|
||||||
|
*/
|
||||||
|
isCSSAllowed() {
|
||||||
|
const testCSSElement = document.createElement('div');
|
||||||
|
testCSSElement.classList.add('hide');
|
||||||
|
document.body.appendChild(testCSSElement);
|
||||||
|
const styles = window.getComputedStyle(testCSSElement);
|
||||||
|
const isAllowed = styles.display === 'none';
|
||||||
|
testCSSElement.remove();
|
||||||
|
|
||||||
|
return isAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go to the next step in the tour.
|
* Go to the next step in the tour.
|
||||||
*
|
*
|
||||||
|
@ -924,6 +951,7 @@ const Tour = class {
|
||||||
// Configure ARIA attributes on the target.
|
// Configure ARIA attributes on the target.
|
||||||
let target = this.getStepTarget(stepConfig);
|
let target = this.getStepTarget(stepConfig);
|
||||||
if (target) {
|
if (target) {
|
||||||
|
target.data('original-tabindex', target.attr('tabindex'));
|
||||||
if (!target.attr('tabindex')) {
|
if (!target.attr('tabindex')) {
|
||||||
target.attr('tabindex', 0);
|
target.attr('tabindex', 0);
|
||||||
}
|
}
|
||||||
|
@ -1150,6 +1178,12 @@ const Tour = class {
|
||||||
|
|
||||||
if (target.data('original-tabindex')) {
|
if (target.data('original-tabindex')) {
|
||||||
target.attr('tabindex', target.data('tabindex'));
|
target.attr('tabindex', target.data('tabindex'));
|
||||||
|
} else {
|
||||||
|
// If the target does not have the tabindex attribute at the beginning. We need to remove it.
|
||||||
|
// We should wait a little here before removing the attribute to prevent the browser from adding it again.
|
||||||
|
window.setTimeout(() => {
|
||||||
|
target.removeAttr('tabindex');
|
||||||
|
}, 400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1296,6 +1330,7 @@ const Tour = class {
|
||||||
*/
|
*/
|
||||||
positionStep(stepConfig) {
|
positionStep(stepConfig) {
|
||||||
let content = this.currentStepNode;
|
let content = this.currentStepNode;
|
||||||
|
let thisT = this;
|
||||||
if (!content || !content.length) {
|
if (!content || !content.length) {
|
||||||
// Unable to find the step node.
|
// Unable to find the step node.
|
||||||
return this;
|
return this;
|
||||||
|
@ -1335,9 +1370,15 @@ const Tour = class {
|
||||||
},
|
},
|
||||||
onCreate: function(data) {
|
onCreate: function(data) {
|
||||||
recalculateArrowPosition(data);
|
recalculateArrowPosition(data);
|
||||||
|
recalculateStepPosition(data);
|
||||||
},
|
},
|
||||||
onUpdate: function(data) {
|
onUpdate: function(data) {
|
||||||
recalculateArrowPosition(data);
|
recalculateArrowPosition(data);
|
||||||
|
if (thisT.possitionNeedToBeRecalculated) {
|
||||||
|
thisT.recalculatedNo++;
|
||||||
|
thisT.possitionNeedToBeRecalculated = false;
|
||||||
|
recalculateStepPosition(data);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1387,6 +1428,90 @@ const Tour = class {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const recalculateStepPosition = function(data) {
|
||||||
|
const placement = data.placement.split('-')[0];
|
||||||
|
const isVertical = ['left', 'right'].indexOf(placement) !== -1;
|
||||||
|
const popperElement = $(data.instance.popper);
|
||||||
|
const targetElement = $(data.instance.reference);
|
||||||
|
const arrowElement = popperElement.find('[data-role="arrow"]');
|
||||||
|
const stepElement = popperElement.find('[data-role="flexitour-step"]');
|
||||||
|
const viewportHeight = $(window).height();
|
||||||
|
const viewportWidth = $(window).width();
|
||||||
|
const arrowHeight = parseFloat(arrowElement.outerHeight(true));
|
||||||
|
const popperHeight = parseFloat(popperElement.outerHeight(true));
|
||||||
|
const targetHeight = parseFloat(targetElement.outerHeight(true));
|
||||||
|
const arrowWidth = parseFloat(arrowElement.outerWidth(true));
|
||||||
|
const popperWidth = parseFloat(popperElement.outerWidth(true));
|
||||||
|
const targetWidth = parseFloat(targetElement.outerWidth(true));
|
||||||
|
let maxHeight;
|
||||||
|
|
||||||
|
if (thisT.recalculatedNo > 1) {
|
||||||
|
// The current screen is too small, and cannot fit with the original placement.
|
||||||
|
// We should set the placement to auto so the PopperJS can calculate the perfect placement.
|
||||||
|
thisT.currentStepPopper.options.placement = isVertical ? 'auto-left' : 'auto-bottom';
|
||||||
|
}
|
||||||
|
if (thisT.recalculatedNo > 2) {
|
||||||
|
// Return here to prevent recursive calling.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVertical) {
|
||||||
|
// Find the best place to put the tour: Left of right.
|
||||||
|
const leftSpace = targetElement.offset().left > 0 ? targetElement.offset().left : 0;
|
||||||
|
const rightSpace = viewportWidth - leftSpace - targetWidth;
|
||||||
|
const remainingSpace = leftSpace >= rightSpace ? leftSpace : rightSpace;
|
||||||
|
maxHeight = viewportHeight - MINSPACING * 2;
|
||||||
|
if (remainingSpace < (popperWidth + arrowWidth)) {
|
||||||
|
const maxWidth = remainingSpace - MINSPACING - arrowWidth;
|
||||||
|
if (maxWidth > 0) {
|
||||||
|
popperElement.css({
|
||||||
|
'max-width': maxWidth + 'px',
|
||||||
|
});
|
||||||
|
// Not enough space, flag true to make Popper to recalculate the position.
|
||||||
|
thisT.possitionNeedToBeRecalculated = true;
|
||||||
|
}
|
||||||
|
} else if (maxHeight < popperHeight) {
|
||||||
|
// Check if the Popper's height can fit the viewport height or not.
|
||||||
|
// If not, set the correct max-height value for the Popper element.
|
||||||
|
popperElement.css({
|
||||||
|
'max-height': maxHeight + 'px',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Find the best place to put the tour: Top of bottom.
|
||||||
|
const topSpace = targetElement.offset().top > 0 ? targetElement.offset().top : 0;
|
||||||
|
const bottomSpace = viewportHeight - topSpace - targetHeight;
|
||||||
|
const remainingSpace = topSpace >= bottomSpace ? topSpace : bottomSpace;
|
||||||
|
maxHeight = remainingSpace - MINSPACING - arrowHeight;
|
||||||
|
if (remainingSpace < (popperHeight + arrowHeight)) {
|
||||||
|
// Not enough space, flag true to make Popper to recalculate the position.
|
||||||
|
thisT.possitionNeedToBeRecalculated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the Popper's height can fit the viewport height or not.
|
||||||
|
// If not, set the correct max-height value for the body.
|
||||||
|
const currentStepBody = stepElement.find('[data-placeholder="body"]').first();
|
||||||
|
const headerEle = stepElement.find('.modal-header').first();
|
||||||
|
const footerEle = stepElement.find('.modal-footer').first();
|
||||||
|
const headerHeight = headerEle.outerHeight(true) ?? 0;
|
||||||
|
const footerHeight = footerEle.outerHeight(true) ?? 0;
|
||||||
|
maxHeight = maxHeight - headerHeight - footerHeight;
|
||||||
|
if (maxHeight > 0) {
|
||||||
|
headerEle.removeClass('minimal');
|
||||||
|
footerEle.removeClass('minimal');
|
||||||
|
currentStepBody.css({
|
||||||
|
'max-height': maxHeight + 'px',
|
||||||
|
'overflow': 'auto',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
headerEle.addClass('minimal');
|
||||||
|
footerEle.addClass('minimal');
|
||||||
|
}
|
||||||
|
// Call the Popper update method to update the position.
|
||||||
|
thisT.currentStepPopper.update();
|
||||||
|
};
|
||||||
|
|
||||||
let background = $('[data-flexitour="step-background"]');
|
let background = $('[data-flexitour="step-background"]');
|
||||||
if (background.length) {
|
if (background.length) {
|
||||||
target = background;
|
target = background;
|
||||||
|
@ -1503,9 +1628,7 @@ const Tour = class {
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetPosition = this.calculatePosition(targetNode);
|
let targetPosition = this.calculatePosition(targetNode);
|
||||||
if (targetPosition === 'fixed') {
|
if (targetPosition === 'absolute') {
|
||||||
background.css('top', 0);
|
|
||||||
} else if (targetPosition === 'absolute') {
|
|
||||||
background.css('position', 'fixed');
|
background.css('position', 'fixed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,12 @@ span[data-flexitour="container"] .modal-dialog .modal-content .modal-header {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span[data-flexitour="container"] .modal-dialog .modal-content .modal-header.minimal,
|
||||||
|
span[data-flexitour="container"] .modal-dialog .modal-content .modal-footer.minimal {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
span[data-flexitour="container"] .modal-dialog .modal-content .modal-footer {
|
span[data-flexitour="container"] .modal-dialog .modal-content .modal-footer {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue