Tooltips fix
This commit is contained in:
parent
a1aa2252ba
commit
7720230013
8 changed files with 161 additions and 54 deletions
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div ref="modal" class="modal fade" tabindex="-1">
|
||||
<div id="product-modal" ref="modal" class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-xxl modal-fullscreen-md-down">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header position-relative">
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
:src="`/data/${product.picture}`"
|
||||
:alt="t('products_logo', {'product_name': transField(product, 'name')})"
|
||||
:title="t('products_logo', {'product_name': transField(product, 'name')})"
|
||||
data-bs-toggle="tooltip"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -53,6 +54,7 @@ import DOMPurify from "dompurify";
|
|||
import type { DirectiveBinding, PropType } from "vue";
|
||||
import { defineComponent } from "vue";
|
||||
import ToolboxHelper from "~/classes/ToolboxHelper";
|
||||
import { Tooltips } from "~/vueModules/bsTooltips";
|
||||
|
||||
const saneHtml = {
|
||||
mounted: (el: HTMLElement, binding: DirectiveBinding) => {
|
||||
|
|
@ -85,19 +87,21 @@ export default defineComponent({
|
|||
"closed", "openned"
|
||||
],
|
||||
data(): {
|
||||
modal: Modal;
|
||||
modal: Modal|null;
|
||||
tooltips: Tooltips|null;
|
||||
} {
|
||||
return {
|
||||
modal: {} as Modal
|
||||
modal: null,
|
||||
tooltips: null
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show() {
|
||||
this.$nextTick(() => {
|
||||
if(this.show) {
|
||||
this.modal.show();
|
||||
} else if(this.modal.hide) {
|
||||
this.modal.hide();
|
||||
this.modal?.show();
|
||||
} else {
|
||||
this.modal?.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -106,18 +110,19 @@ export default defineComponent({
|
|||
this.$nextTick(() => {
|
||||
const modal = this.$refs.modal as HTMLElement;
|
||||
modal.addEventListener("shown.bs.modal", () => {
|
||||
this.tooltips = Tooltips.make({type:"parent", parentSelector: "#product-modal"});
|
||||
this.$emit("openned");
|
||||
});
|
||||
modal.addEventListener("hidden.bs.modal", () => {
|
||||
this.tooltips?.closeBootstrapTooltip();
|
||||
this.$emit("closed");
|
||||
});
|
||||
this.modal = Modal.getOrCreateInstance(modal);
|
||||
});
|
||||
},
|
||||
beforeUnmount() {
|
||||
if(this.modal.hide) {
|
||||
this.modal.hide();
|
||||
}
|
||||
this.tooltips?.closeBootstrapTooltip();
|
||||
this.modal?.hide();
|
||||
},
|
||||
methods: {
|
||||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="container justify-content-center d-flex flex-column">
|
||||
<div id="product-list-component" class="container justify-content-center d-flex flex-column">
|
||||
<div v-if="range.products" ref="rangeList" class="row justify-content-around">
|
||||
<div
|
||||
v-for="(productPair, productIndex) of chunkInefficient(range.products, 2)"
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
<button
|
||||
class="d-inline-block btn bg-body position-relative"
|
||||
:title="t('more_about_this_product')"
|
||||
data-bs-toggle="tooltip"
|
||||
@click.stop="showProduct(product, $event)"
|
||||
>
|
||||
<div class="container-fluid">
|
||||
|
|
@ -26,7 +27,6 @@
|
|||
class="img-thumbnail"
|
||||
:src="`/data/${product.picture}`"
|
||||
:alt="t('products_logo', {'product_name': transField(product, 'name')})"
|
||||
:title="t('products_logo', {'product_name': transField(product, 'name')})"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -69,7 +69,7 @@ import type { DirectiveBinding } from "vue";
|
|||
import { defineComponent } from "vue";
|
||||
import { useRoute, type RouteLocationNormalizedLoaded } from "vue-router";
|
||||
import ToolboxHelper from "~/classes/ToolboxHelper";
|
||||
import bsTooltips from "~/vueModules/bsTooltips";
|
||||
import { Tooltips } from "~/vueModules/bsTooltips";
|
||||
|
||||
const saneHtml = {
|
||||
mounted: (el: HTMLElement, binding: DirectiveBinding) => {
|
||||
|
|
@ -97,10 +97,12 @@ export default defineComponent({
|
|||
data(): {
|
||||
route: RouteLocationNormalizedLoaded;
|
||||
displayShelves: boolean;
|
||||
tooltips: Tooltips|null;
|
||||
} {
|
||||
return {
|
||||
route: useRoute(),
|
||||
displayShelves: this.range.shelf
|
||||
displayShelves: this.range.shelf,
|
||||
tooltips: null
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -109,9 +111,12 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(bsTooltips.methods.initTooltips);
|
||||
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: "#product-list-component"});});
|
||||
this.$nextTick(this.applySameHeight);
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.tooltips?.closeBootstrapTooltip();
|
||||
},
|
||||
methods: {
|
||||
chunkInefficient(products: Array<TypeProduct>, chunkSize: number):Array<Array<TypeProduct>> {
|
||||
const out:Array<Array<TypeProduct>> = [];
|
||||
|
|
@ -144,6 +149,7 @@ export default defineComponent({
|
|||
return Object.fromEntries(out.entries());
|
||||
},
|
||||
showProduct(product: TypeProduct, $event: Event) {
|
||||
this.tooltips?.refreshTooltips();
|
||||
const el = $event.target as HTMLButtonElement;
|
||||
el.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ import { useRoute, type RouteLocationNormalizedLoaded } from "vue-router";
|
|||
import ToolboxHelper from "~/classes/ToolboxHelper";
|
||||
import type { appInfo } from "~/electron/main";
|
||||
import { useAppStore } from "~/stores/useAppStore";
|
||||
import bsTooltips from "~/vueModules/bsTooltips";
|
||||
import { Tooltips } from "~/vueModules/bsTooltips";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AppFooter",
|
||||
|
|
@ -108,6 +108,7 @@ export default defineComponent({
|
|||
modules: Array<{
|
||||
name: string;
|
||||
}>;
|
||||
tooltips: Tooltips|null;
|
||||
} {
|
||||
return {
|
||||
locale: "",
|
||||
|
|
@ -121,6 +122,7 @@ export default defineComponent({
|
|||
settings: {} as TypeSettings,
|
||||
brands: [],
|
||||
modules: [Scrollbar],
|
||||
tooltips: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -147,7 +149,10 @@ export default defineComponent({
|
|||
this.locale = locale;
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => bsTooltips.methods.initTooltips());
|
||||
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: "#footer"});});
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.tooltips?.closeBootstrapTooltip();
|
||||
},
|
||||
methods: {
|
||||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ import { defineComponent } from "vue";
|
|||
import type { RouteLocationNormalizedLoaded } from "vue-router";
|
||||
import ToolboxHelper from "~/classes/ToolboxHelper";
|
||||
import { useAppStore } from "~/stores/useAppStore";
|
||||
import bsTooltips from "~/vueModules/bsTooltips";
|
||||
import { Tooltips } from "~/vueModules/bsTooltips";
|
||||
|
||||
type LocaleParams = {
|
||||
iso: string,
|
||||
|
|
@ -125,6 +125,7 @@ export default defineComponent({
|
|||
locales: Array<LocaleParams>,
|
||||
locale: string;
|
||||
route: RouteLocationNormalizedLoaded;
|
||||
tooltips: Tooltips|null;
|
||||
} {
|
||||
return {
|
||||
versions: window.versions,
|
||||
|
|
@ -132,6 +133,7 @@ export default defineComponent({
|
|||
locales: [],
|
||||
locale: "",
|
||||
route: useRoute(),
|
||||
tooltips: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -167,7 +169,10 @@ export default defineComponent({
|
|||
});
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => bsTooltips.methods.initTooltips());
|
||||
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: "#top-navbar"});});
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.tooltips?.closeBootstrapTooltip();
|
||||
},
|
||||
methods: {
|
||||
t(text: string, params: Record<string,string> = {}, localeToUse: string|null = null): string {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ import type AppState from "~/classes/AppState";
|
|||
import Toast, { ToastTypeEnum } from "~/classes/Toast";
|
||||
import ToolboxHelper from "~/classes/ToolboxHelper";
|
||||
import { useAppStore } from "~/stores/useAppStore";
|
||||
import bsTooltips from "~/vueModules/bsTooltips";
|
||||
import { Tooltips } from "~/vueModules/bsTooltips";
|
||||
|
||||
export default defineComponent({
|
||||
name: "BrandShow",
|
||||
|
|
@ -82,6 +82,7 @@ export default defineComponent({
|
|||
animateIndex: number|null;
|
||||
animations: Array<string>;
|
||||
displayShelves: boolean;
|
||||
tooltips: Tooltips|null;
|
||||
} {
|
||||
return {
|
||||
appState: {} as AppState,
|
||||
|
|
@ -90,7 +91,8 @@ export default defineComponent({
|
|||
animateTimeout: undefined,
|
||||
animateIndex: null,
|
||||
animations: ["heartBeat", "tada", "shakeX", "rubberBand"],
|
||||
displayShelves: false
|
||||
displayShelves: false,
|
||||
tooltips: null
|
||||
};
|
||||
},
|
||||
beforeMount() {
|
||||
|
|
@ -113,7 +115,7 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => bsTooltips.methods.initTooltips());
|
||||
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: ".page-brands-show"});});
|
||||
|
||||
// * ANIMATIONS
|
||||
clearTimeout(this.animateTimeout);
|
||||
|
|
@ -130,6 +132,7 @@ export default defineComponent({
|
|||
});
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.tooltips?.closeBootstrapTooltip();
|
||||
clearTimeout(this.animateTimeout);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -38,10 +38,6 @@
|
|||
'color': getContrastYIQ(brand.color),
|
||||
'background-color': brand.color
|
||||
}"
|
||||
role="button"
|
||||
:title="t('view_brand_ranges', {'brand_name': transField(brand, 'name')})"
|
||||
data-bs-toggle="tooltip"
|
||||
@click="gotoBrand(brand)"
|
||||
>
|
||||
{{ transField(brand, 'name') }}
|
||||
</span>
|
||||
|
|
@ -62,7 +58,7 @@ import { defineComponent } from "vue";
|
|||
import type AppState from "~/classes/AppState";
|
||||
import ToolboxHelper from "~/classes/ToolboxHelper";
|
||||
import { useAppStore } from "~/stores/useAppStore";
|
||||
import bsTooltips from "~/vueModules/bsTooltips";
|
||||
import { Tooltips } from "~/vueModules/bsTooltips";
|
||||
|
||||
export default defineComponent({
|
||||
name: "HomePage",
|
||||
|
|
@ -71,16 +67,18 @@ export default defineComponent({
|
|||
animateTimeout: NodeJS.Timeout|undefined;
|
||||
animateIndex: number|null;
|
||||
animations: Array<string>;
|
||||
tooltips: Tooltips|null;
|
||||
} {
|
||||
return {
|
||||
appState: {} as AppState,
|
||||
animateTimeout: undefined,
|
||||
animateIndex: null,
|
||||
animations: ["heartBeat", "tada", "shakeX", "rubberBand"]
|
||||
animations: ["heartBeat", "tada", "shakeX", "rubberBand"],
|
||||
tooltips: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => bsTooltips.methods.initTooltips());
|
||||
this.$nextTick(() => {this.tooltips = Tooltips.make({type:"parent", parentSelector: ".page-home"});});
|
||||
this.appState = useAppStore().data;
|
||||
|
||||
// * ANIMATIONS
|
||||
|
|
@ -98,6 +96,7 @@ export default defineComponent({
|
|||
});
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.tooltips?.closeBootstrapTooltip();
|
||||
clearTimeout(this.animateTimeout);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import Toast, { ToastTypeEnum } from "~/classes/Toast";
|
|||
import ToolboxHelper from "~/classes/ToolboxHelper";
|
||||
import ProductDescriptionModalVue from "~/components/ProductDescriptionModal.vue";
|
||||
import ProductListVue from "~/components/ProductList.vue";
|
||||
import bsTooltips from "~/vueModules/bsTooltips";
|
||||
|
||||
const saneHtml = {
|
||||
mounted: (el: HTMLElement, binding: DirectiveBinding) => {
|
||||
|
|
@ -56,9 +55,6 @@ export default defineComponent({
|
|||
}
|
||||
this.range = range;
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => bsTooltips.methods.initTooltips());
|
||||
},
|
||||
methods: {
|
||||
t(text: string, params: Record<string, string> = {}, localeToUse: string | null = null): string {
|
||||
return ToolboxHelper.trans(text, params, localeToUse);
|
||||
|
|
|
|||
|
|
@ -1,26 +1,114 @@
|
|||
import { Tooltip } from "bootstrap";
|
||||
|
||||
let tooltips: Array<Tooltip> = [];
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
initTooltips() {
|
||||
// Disable tooltips on reboot.
|
||||
tooltips.forEach((tooltip) => {
|
||||
tooltip.disable();
|
||||
tooltip.hide();
|
||||
});
|
||||
tooltips = [].slice
|
||||
.call(document.querySelectorAll("[data-bs-toggle=\"tooltip\"]"))
|
||||
.map(function (tooltipTriggerEl) {
|
||||
return new Tooltip(tooltipTriggerEl, {
|
||||
customClass: "large-tooltip",
|
||||
delay: {
|
||||
show: 1250,
|
||||
hide: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
type ConstructorTypeParent = "parent";
|
||||
type ConstructorTypeDom = "dom";
|
||||
|
||||
interface ParentSelectorTooltips {
|
||||
type: ConstructorTypeParent
|
||||
/** The parent element that contains Dom elements for which tooltips shall be created. */
|
||||
parentSelector: string;
|
||||
}
|
||||
|
||||
interface DomProvidedTooltips {
|
||||
type: ConstructorTypeDom;
|
||||
/** Dom elements for which tooltips shall be created. */
|
||||
elements: HTMLElement | NodeListOf<HTMLElement>;
|
||||
}
|
||||
|
||||
interface TooltipsOptions {
|
||||
/** Tooltip options. */
|
||||
options?: Partial<Tooltip.Options>|null|undefined;
|
||||
}
|
||||
|
||||
export type TooltipsConstructor = TooltipsOptions & (ParentSelectorTooltips|DomProvidedTooltips);
|
||||
|
||||
export class Tooltips {
|
||||
/** BS tooltips instances */
|
||||
private tooltips: Array<Tooltip> = [];
|
||||
|
||||
/** The parent element that contains Dom elements for which tooltips shall be created. */
|
||||
private parentSelector: string | null = null;
|
||||
|
||||
/** Dom elements for which tooltips shall be created. */
|
||||
private elements: Array<HTMLElement> = [];
|
||||
|
||||
/** Tooltip default options. */
|
||||
private static defaultOptions: Partial<Tooltip.Options> = {
|
||||
delay: {
|
||||
show: 1250,
|
||||
hide: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/** Tooltip options. */
|
||||
private options: Partial<Tooltip.Options> = {};
|
||||
|
||||
/**
|
||||
* @param parentSelector
|
||||
* @param options Tooltip options.
|
||||
*/
|
||||
constructor(params: TooltipsConstructor) {
|
||||
if (params.type === "parent") {
|
||||
this.parentSelectorConstructor(params);
|
||||
}
|
||||
if (params.type === "dom") {
|
||||
this.domPrividedTooltipsContructor(params);
|
||||
}
|
||||
}
|
||||
|
||||
public static make(params: TooltipsConstructor = { type: "parent", parentSelector: "body"}
|
||||
) {
|
||||
const fullParams = { ...{ type: "parent", options: {} }, ...params };
|
||||
return new Tooltips(fullParams);
|
||||
}
|
||||
|
||||
private parentSelectorConstructor({ parentSelector, options }: TooltipsOptions & ParentSelectorTooltips) {
|
||||
this.parentSelector = parentSelector;
|
||||
this.options = { ...Tooltips.defaultOptions, ...options };
|
||||
this.initTooltips();
|
||||
}
|
||||
|
||||
private domPrividedTooltipsContructor({ elements, options }: TooltipsOptions & DomProvidedTooltips) {
|
||||
if (elements instanceof HTMLElement) {
|
||||
this.elements = [elements];
|
||||
} else {
|
||||
this.elements = Array.from(elements);
|
||||
}
|
||||
this.options = { ...Tooltips.defaultOptions, ...options };
|
||||
this.initTooltips();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all Bootstrap tooltips and reinstanciate them.
|
||||
*/
|
||||
public refreshTooltips(): void {
|
||||
this.closeBootstrapTooltip();
|
||||
this.initTooltips();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all Bootstrap tooltips for ever.
|
||||
*/
|
||||
public closeBootstrapTooltip(): void {
|
||||
this.tooltips.forEach((tooltip) => {
|
||||
tooltip.hide();
|
||||
// * Prevent pending tooltips beeing shown after we asked to hide them
|
||||
tooltip.disable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize tooltips
|
||||
*/
|
||||
private initTooltips() {
|
||||
this.closeBootstrapTooltip();
|
||||
/** data-bs-toggle tooltips elements */
|
||||
const elements = this.parentSelector ? [].slice
|
||||
.call(document.querySelectorAll(`${this.parentSelector} [data-bs-toggle="tooltip"]`)) :
|
||||
this.elements;
|
||||
this.tooltips = elements.map((tooltipTriggerEl) => {
|
||||
return new Tooltip(tooltipTriggerEl, this.options);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue