FEATURE: unified popover implementation (#7244)

This commit is contained in:
Joffrey JAFFEUX 2019-03-26 15:43:27 +01:00 committed by GitHub
parent 4a1096f14a
commit 8fb63b2706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 310 additions and 18 deletions

View File

@ -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",

View File

@ -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)
);
}
};

View File

@ -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));
}

View File

@ -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")

View File

@ -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);
}
}
}

View File

@ -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(() => {