FEATURE: unified popover implementation (#7244)
This commit is contained in:
parent
4a1096f14a
commit
8fb63b2706
|
@ -4,10 +4,6 @@ import { exportEntity } from "discourse/lib/export-csv";
|
|||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
import { SCHEMA_VERSION, default as Report } from "admin/models/report";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import {
|
||||
registerHoverTooltip,
|
||||
unregisterHoverTooltip
|
||||
} from "discourse/lib/tooltip";
|
||||
|
||||
const TABLE_OPTIONS = {
|
||||
perPage: 8,
|
||||
|
@ -102,18 +98,6 @@ export default Ember.Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
didRender() {
|
||||
this._super(...arguments);
|
||||
|
||||
registerHoverTooltip($(".info[data-tooltip]"));
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
unregisterHoverTooltip($(".info[data-tooltip]"));
|
||||
},
|
||||
|
||||
showError: Ember.computed.or(
|
||||
"showTimeoutError",
|
||||
"showExceptionError",
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { showPopover, hidePopover } from "discourse/lib/d-popover";
|
||||
|
||||
const SELECTORS =
|
||||
"[data-html-popover],[data-tooltip],[data-popover],[data-html-tooltip]";
|
||||
|
||||
export default {
|
||||
name: "d-popover",
|
||||
|
||||
initialize() {
|
||||
$("#main").on("click.d-popover mouseenter.d-popover", SELECTORS, event =>
|
||||
showPopover(event)
|
||||
);
|
||||
|
||||
$("#main").on("mouseleave.d-popover", SELECTORS, event =>
|
||||
hidePopover(event)
|
||||
);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,173 @@
|
|||
import { siteDir } from "discourse/lib/text-direction";
|
||||
|
||||
const D_POPOVER_ID = "d-popover";
|
||||
|
||||
const D_POPOVER_TEMPLATE = `
|
||||
<div id="${D_POPOVER_ID}" class="is-under">
|
||||
<div class="d-popover-arrow d-popover-top-arrow"></div>
|
||||
<div class="d-popover-content">
|
||||
<div class="spinner small"></div>
|
||||
</div>
|
||||
<div class="d-popover-arrow d-popover-bottom-arrow"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const D_ARROW_HEIGHT = 10;
|
||||
|
||||
const D_HORIZONTAL_MARGIN = 5;
|
||||
|
||||
export function hidePopover() {
|
||||
getPopover()
|
||||
.fadeOut()
|
||||
.remove();
|
||||
|
||||
return getPopover();
|
||||
}
|
||||
|
||||
export function showPopover(event, options = {}) {
|
||||
const $enteredElement = $(event.currentTarget);
|
||||
|
||||
if (isRetina()) {
|
||||
getPopover().addClass("retina");
|
||||
}
|
||||
|
||||
if (!getPopover().length) {
|
||||
$("body").append($(D_POPOVER_TEMPLATE));
|
||||
}
|
||||
|
||||
setPopoverHtmlContent($enteredElement, options.htmlContent);
|
||||
setPopoverTextContent($enteredElement, options.textContent);
|
||||
|
||||
getPopover().fadeIn();
|
||||
|
||||
positionPopover($enteredElement);
|
||||
|
||||
return {
|
||||
html: content => replaceHtmlContent($enteredElement, content),
|
||||
text: content => replaceTextContent($enteredElement, content),
|
||||
hide: hidePopover
|
||||
};
|
||||
}
|
||||
|
||||
function setPopoverHtmlContent($enteredElement, content) {
|
||||
content =
|
||||
content ||
|
||||
$enteredElement.attr("data-html-popover") ||
|
||||
$enteredElement.attr("data-html-tooltip");
|
||||
|
||||
replaceHtmlContent($enteredElement, content);
|
||||
}
|
||||
|
||||
function setPopoverTextContent($enteredElement, content) {
|
||||
content =
|
||||
content ||
|
||||
$enteredElement.attr("data-popover") ||
|
||||
$enteredElement.attr("data-tooltip");
|
||||
|
||||
replaceTextContent($enteredElement, content);
|
||||
}
|
||||
|
||||
function replaceTextContent($enteredElement, content) {
|
||||
if (content) {
|
||||
getPopover()
|
||||
.find(".d-popover-content")
|
||||
.text(content);
|
||||
window.requestAnimationFrame(() => positionPopover($enteredElement));
|
||||
}
|
||||
}
|
||||
|
||||
function replaceHtmlContent($enteredElement, content) {
|
||||
if (content) {
|
||||
getPopover()
|
||||
.find(".d-popover-content")
|
||||
.html(content);
|
||||
window.requestAnimationFrame(() => positionPopover($enteredElement));
|
||||
}
|
||||
}
|
||||
|
||||
function positionPopover($element) {
|
||||
const $popover = getPopover();
|
||||
$popover.removeClass("is-above is-under is-left-aligned is-right-aligned");
|
||||
|
||||
const $dHeader = $(".d-header");
|
||||
const windowRect = {
|
||||
left: 0,
|
||||
top: $dHeader.length ? $dHeader[0].getBoundingClientRect().bottom : 0,
|
||||
width: $(window).width(),
|
||||
height: $(window).height()
|
||||
};
|
||||
|
||||
const popoverRect = {
|
||||
width: $popover.width(),
|
||||
height: $popover.height(),
|
||||
left: null,
|
||||
right: null
|
||||
};
|
||||
|
||||
if (popoverRect.width > windowRect.width - D_HORIZONTAL_MARGIN * 2) {
|
||||
popoverRect.width = windowRect.width - D_HORIZONTAL_MARGIN * 2;
|
||||
$popover.width(popoverRect.width);
|
||||
}
|
||||
|
||||
const targetRect = $element[0].getBoundingClientRect();
|
||||
const underSpace = windowRect.height - targetRect.bottom - D_ARROW_HEIGHT;
|
||||
const topSpace = targetRect.top - windowRect.top - D_ARROW_HEIGHT;
|
||||
|
||||
if (
|
||||
underSpace > popoverRect.height + D_HORIZONTAL_MARGIN ||
|
||||
underSpace > topSpace
|
||||
) {
|
||||
$popover
|
||||
.css("top", targetRect.bottom + window.pageYOffset + D_ARROW_HEIGHT)
|
||||
.addClass("is-under");
|
||||
} else {
|
||||
$popover
|
||||
.css(
|
||||
"top",
|
||||
targetRect.top +
|
||||
window.pageYOffset -
|
||||
popoverRect.height -
|
||||
D_ARROW_HEIGHT
|
||||
)
|
||||
.addClass("is-above");
|
||||
}
|
||||
|
||||
const leftSpace = targetRect.left + targetRect.width / 2;
|
||||
|
||||
if (siteDir() === "ltr") {
|
||||
if (leftSpace > popoverRect.width / 2 + D_HORIZONTAL_MARGIN) {
|
||||
popoverRect.left = leftSpace - popoverRect.width / 2;
|
||||
$popover.css("left", popoverRect.left);
|
||||
} else {
|
||||
popoverRect.left = D_HORIZONTAL_MARGIN;
|
||||
$popover.css("left", popoverRect.left).addClass("is-left-aligned");
|
||||
}
|
||||
} else {
|
||||
const rightSpace = windowRect.width - targetRect.right;
|
||||
|
||||
if (rightSpace > popoverRect.width / 2 + D_HORIZONTAL_MARGIN) {
|
||||
popoverRect.left = leftSpace - popoverRect.width / 2;
|
||||
$popover.css("left", popoverRect.left);
|
||||
} else {
|
||||
popoverRect.left =
|
||||
windowRect.width - popoverRect.width - D_HORIZONTAL_MARGIN * 2;
|
||||
$popover.css("left", popoverRect.left).addClass("is-right-aligned");
|
||||
}
|
||||
}
|
||||
|
||||
let arrowPosition;
|
||||
if (siteDir() === "ltr") {
|
||||
arrowPosition = Math.abs(targetRect.left - popoverRect.left);
|
||||
} else {
|
||||
arrowPosition = targetRect.left - popoverRect.left + targetRect.width / 2;
|
||||
}
|
||||
$popover.find(".d-popover-arrow").css("left", arrowPosition);
|
||||
}
|
||||
|
||||
function isRetina() {
|
||||
return window.devicePixelRatio && window.devicePixelRatio > 1;
|
||||
}
|
||||
|
||||
function getPopover() {
|
||||
return $(document.getElementById(D_POPOVER_ID));
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
||||
const fadeSpeed = 300;
|
||||
|
@ -77,12 +78,16 @@ export function hideTooltip() {
|
|||
}
|
||||
|
||||
export function registerTooltip(jqueryContext) {
|
||||
deprecated("tooltip is getting deprecated. Use d-popover instead");
|
||||
|
||||
if (jqueryContext.length) {
|
||||
jqueryContext.off("click").on("click", event => showTooltip(event));
|
||||
}
|
||||
}
|
||||
|
||||
export function registerHoverTooltip(jqueryContext) {
|
||||
deprecated("tooltip is getting deprecated. Use d-popover instead");
|
||||
|
||||
if (jqueryContext.length) {
|
||||
jqueryContext
|
||||
.off("mouseenter mouseleave click")
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
$d-popover-background: $secondary;
|
||||
$d-popover-border: $primary-medium;
|
||||
|
||||
@-webkit-keyframes popoverFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes popoverFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#d-popover {
|
||||
background-color: $d-popover-background;
|
||||
position: absolute;
|
||||
z-index: z("tooltip");
|
||||
border-color: $d-popover-border;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
max-width: 300px;
|
||||
-webkit-animation: popoverFadeIn 0.5s;
|
||||
animation: popoverFadeIn 0.5s;
|
||||
background-clip: padding-box;
|
||||
display: block;
|
||||
box-shadow: shadow("dropdown");
|
||||
border-radius: 2px;
|
||||
|
||||
&.is-under {
|
||||
margin-top: 0px;
|
||||
|
||||
.d-popover-top-arrow {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.d-popover-bottom-arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-above {
|
||||
margin-top: 0px;
|
||||
|
||||
.d-popover-bottom-arrow {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.d-popover-top-arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.retina {
|
||||
border-width: 0.5px;
|
||||
}
|
||||
|
||||
.d-popover-content {
|
||||
padding: 1em;
|
||||
font-size: $font-down-1;
|
||||
overflow-wrap: break-word;
|
||||
-webkit-animation: popoverFadeIn 0.5s;
|
||||
animation: popoverFadeIn 0.5s;
|
||||
}
|
||||
|
||||
.d-popover-arrow {
|
||||
border-style: solid;
|
||||
color: transparent;
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: calc(z("tooltip") - 100);
|
||||
}
|
||||
|
||||
.d-popover-top-arrow {
|
||||
border-color: transparent transparent $d-popover-border;
|
||||
top: 8px;
|
||||
transform: translate(0, -15px);
|
||||
border-width: 0 8px 8px;
|
||||
|
||||
&:after {
|
||||
border-color: transparent transparent $d-popover-background;
|
||||
border-style: solid;
|
||||
border-width: 0 7px 7px;
|
||||
bottom: -8px;
|
||||
margin-left: -7px;
|
||||
position: absolute;
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
.d-popover-bottom-arrow {
|
||||
border-color: $d-popover-border transparent transparent;
|
||||
top: calc(100% + 16px);
|
||||
transform: translate(0, -16px);
|
||||
border-width: 8px 8px 0;
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
border-color: $d-popover-background transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 7px 7px 0;
|
||||
bottom: 2px;
|
||||
transform: translate(-7px, 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { registerTooltip } from "discourse/lib/tooltip";
|
||||
|
||||
function initializeDiscourseLocalDates(api) {
|
||||
api.decorateCooked($elem => {
|
||||
$(".discourse-local-date", $elem).applyLocalDates();
|
||||
registerTooltip($(".discourse-local-date", $elem));
|
||||
});
|
||||
|
||||
api.addToolbarPopupMenuOptionsCallback(() => {
|
||||
|
|
Loading…
Reference in New Issue