framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
256 lines (224 loc) • 7.46 kB
JavaScript
import $ from 'dom7';
import Utils from '../../utils/utils';
import Support from '../../utils/support';
import Framework7Class from '../../utils/class';
class Tooltip extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const tooltip = this;
const defaults = Utils.extend({}, app.params.tooltip);
// Extend defaults with modules params
tooltip.useModulesParams(defaults);
tooltip.params = Utils.extend(defaults, params);
const { targetEl } = tooltip.params;
if (!targetEl) return tooltip;
const $targetEl = $(targetEl);
if ($targetEl.length === 0) return tooltip;
if ($targetEl[0].f7Tooltip) return $targetEl[0].f7Tooltip;
const $el = $(tooltip.render()).eq(0);
Utils.extend(tooltip, {
app,
$targetEl,
targetEl: $targetEl && $targetEl[0],
$el,
el: $el && $el[0],
text: tooltip.params.text || '',
visible: false,
opened: false,
});
$targetEl[0].f7Tooltip = tooltip;
const touchesStart = {};
let isTouched;
function handleTouchStart(e) {
if (isTouched) return;
isTouched = true;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
tooltip.show(this);
}
function handleTouchMove(e) {
if (!isTouched) return;
const x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
const distance = (
((x - touchesStart.x) ** 2)
+ ((y - touchesStart.y) ** 2)
) ** 0.5;
if (distance > 50) {
isTouched = false;
tooltip.hide();
}
}
function handleTouchEnd() {
if (!isTouched) return;
isTouched = false;
tooltip.hide();
}
function handleMouseEnter() {
tooltip.show(this);
}
function handleMouseLeave() {
tooltip.hide();
}
function handleTransitionEnd() {
if (!$el.hasClass('tooltip-in')) {
$el.removeClass('tooltip-out').remove();
}
}
tooltip.attachEvents = function attachEvents() {
$el.on('transitionend', handleTransitionEnd);
if (Support.touch) {
const passive = Support.passiveListener ? { passive: true } : false;
$targetEl.on(app.touchEvents.start, handleTouchStart, passive);
app.on('touchmove', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
} else {
$targetEl.on('mouseenter', handleMouseEnter);
$targetEl.on('mouseleave', handleMouseLeave);
}
};
tooltip.detachEvents = function detachEvents() {
$el.off('transitionend', handleTransitionEnd);
if (Support.touch) {
const passive = Support.passiveListener ? { passive: true } : false;
$targetEl.off(app.touchEvents.start, handleTouchStart, passive);
app.off('touchmove', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
} else {
$targetEl.off('mouseenter', handleMouseEnter);
$targetEl.off('mouseleave', handleMouseLeave);
}
};
// Install Modules
tooltip.useModules();
tooltip.init();
return tooltip;
}
position(targetEl) {
const tooltip = this;
const { $el, app } = tooltip;
$el.css({ left: '', top: '' });
const $targetEl = $(targetEl || tooltip.targetEl);
const [width, height] = [$el.width(), $el.height()];
$el.css({ left: '', top: '' });
let targetWidth;
let targetHeight;
let targetOffsetLeft;
let targetOffsetTop;
if ($targetEl && $targetEl.length > 0) {
targetWidth = $targetEl.outerWidth();
targetHeight = $targetEl.outerHeight();
const targetOffset = $targetEl.offset();
targetOffsetLeft = targetOffset.left - app.left;
targetOffsetTop = targetOffset.top - app.top;
const targetParentPage = $targetEl.parents('.page');
if (targetParentPage.length > 0) {
targetOffsetTop -= targetParentPage[0].scrollTop;
}
}
let [left, top] = [0, 0, 0];
// Top Position
let position = 'top';
if (height < targetOffsetTop) {
// On top
top = targetOffsetTop - height;
} else if (height < app.height - targetOffsetTop - targetHeight) {
// On bottom
position = 'bottom';
top = targetOffsetTop + targetHeight;
} else {
// On middle
position = 'middle';
top = ((targetHeight / 2) + targetOffsetTop) - (height / 2);
if (top <= 0) {
top = 8;
} else if (top + height >= app.height) {
top = app.height - height - 8;
}
}
// Horizontal Position
if (position === 'top' || position === 'bottom') {
left = ((targetWidth / 2) + targetOffsetLeft) - (width / 2);
if (left < 8) left = 8;
if (left + width > app.width) left = app.width - width - 8;
if (left < 0) left = 0;
} else if (position === 'middle') {
left = targetOffsetLeft - width;
if (left < 8 || (left + width > app.width)) {
if (left < 8) left = targetOffsetLeft + targetWidth;
if (left + width > app.width) left = app.width - width - 8;
}
}
// Apply Styles
$el.css({ top: `${top}px`, left: `${left}px` });
}
show(aroundEl) {
const tooltip = this;
const { app, $el, $targetEl } = tooltip;
app.root.append($el);
tooltip.position(aroundEl);
const $aroundEl = $(aroundEl);
tooltip.visible = true;
tooltip.opened = true;
$targetEl.trigger('tooltip:show', tooltip);
$el.trigger('tooltip:show', tooltip);
if ($aroundEl.length && $aroundEl[0] !== $targetEl[0]) {
$aroundEl.trigger('tooltip:show', tooltip);
}
tooltip.emit('local::show tooltipShow', tooltip);
$el.removeClass('tooltip-out').addClass('tooltip-in');
return tooltip;
}
hide() {
const tooltip = this;
const { $el, $targetEl } = tooltip;
tooltip.visible = false;
tooltip.opened = false;
$targetEl.trigger('tooltip:hide', tooltip);
$el.trigger('tooltip:hide', tooltip);
tooltip.emit('local::hide tooltipHide', tooltip);
$el.addClass('tooltip-out').removeClass('tooltip-in');
return tooltip;
}
render() {
const tooltip = this;
if (tooltip.params.render) return tooltip.params.render.call(tooltip, tooltip);
const { cssClass, text } = tooltip.params;
return `
<div class="tooltip ${cssClass || ''}">
<div class="tooltip-content">${text || ''}</div>
</div>
`.trim();
}
setText(newText) {
const tooltip = this;
if (typeof newText === 'undefined') {
return tooltip;
}
tooltip.params.text = newText;
tooltip.text = newText;
if (tooltip.$el) {
tooltip.$el.children('.tooltip-content').html(newText);
}
if (tooltip.opened) {
tooltip.position();
}
return tooltip;
}
init() {
const tooltip = this;
tooltip.attachEvents();
}
destroy() {
const tooltip = this;
if (!tooltip.$targetEl || tooltip.destroyed) return;
tooltip.$targetEl.trigger('tooltip:beforedestroy', tooltip);
tooltip.emit('local::beforeDestroy tooltipBeforeDestroy', tooltip);
tooltip.$el.remove();
delete tooltip.$targetEl[0].f7Tooltip;
tooltip.detachEvents();
Utils.deleteProps(tooltip);
tooltip.destroyed = true;
}
}
export default Tooltip;