From 5262676e0e501332f79c0f36d2a063290212b2f8 Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Wed, 12 Feb 2020 19:22:40 +0200 Subject: [PATCH] rewrite popover because v-tooltip is slow as heck --- src/App.js | 4 +- src/App.vue | 1 + src/components/extra_buttons/extra_buttons.js | 3 + .../extra_buttons/extra_buttons.vue | 14 +- src/components/popover/popover.js | 113 ++++++++++ src/components/popover/popover.vue | 195 ++++++++++++++++++ src/components/popover/popover_target.js | 23 +++ src/components/popover/popover_target.vue | 25 +++ src/components/popper/popper.scss | 147 ------------- .../status_popover/status_popover.js | 3 +- .../status_popover/status_popover.vue | 22 +- src/main.js | 4 +- src/modules/popover.js | 31 +++ 13 files changed, 417 insertions(+), 168 deletions(-) create mode 100644 src/components/popover/popover.js create mode 100644 src/components/popover/popover.vue create mode 100644 src/components/popover/popover_target.js create mode 100644 src/components/popover/popover_target.vue create mode 100644 src/modules/popover.js diff --git a/src/App.js b/src/App.js index 61b5eec1..041e131a 100644 --- a/src/App.js +++ b/src/App.js @@ -12,6 +12,7 @@ import MobilePostStatusButton from './components/mobile_post_status_button/mobil import MobileNav from './components/mobile_nav/mobile_nav.vue' import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue' import PostStatusModal from './components/post_status_modal/post_status_modal.vue' +import PopoverTarget from './components/popover/popover_target.vue' import { windowWidth } from './services/window_utils/window_utils' export default { @@ -30,7 +31,8 @@ export default { MobilePostStatusButton, MobileNav, UserReportingModal, - PostStatusModal + PostStatusModal, + PopoverTarget }, data: () => ({ mobileActivePanel: 'timeline', diff --git a/src/App.vue b/src/App.vue index 1b1c2648..de15802f 100644 --- a/src/App.vue +++ b/src/App.vue @@ -123,6 +123,7 @@ + diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js index 5ac73e97..37485383 100644 --- a/src/components/extra_buttons/extra_buttons.js +++ b/src/components/extra_buttons/extra_buttons.js @@ -1,5 +1,8 @@ +import Popover from '../popover/popover.vue' + const ExtraButtons = { props: [ 'status' ], + components: { Popover }, methods: { deleteStatus () { const confirmed = window.confirm(this.$t('status.delete_confirm')) diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index 746f1c91..3f003425 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -1,11 +1,11 @@ @@ -59,6 +59,10 @@ @import '../../_variables.scss'; @import '../popper/popper.scss'; +.dropdown-menu { + flex-shrink: 0; +} + .icon-ellipsis { cursor: pointer; diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js new file mode 100644 index 00000000..4ee08323 --- /dev/null +++ b/src/components/popover/popover.js @@ -0,0 +1,113 @@ + +const Popover = { + name: 'Popover', + props: [ + 'trigger', + 'placement', + 'show' + ], + data () { + return { + hidden: true, + styles: { opacity: 0 } + } + }, + computed: { + display () { + return !this.hidden + } + }, + methods: { + /* + registerPopover (e) { + if (!this.targetId) { + this.$store.dispatch('registerPopover', e.target).then(id => this.targetId = id) + } + }, + unregisterPopover () { + if (this.targetId) { + this.$store.dispatch('unregisterPopover', this.targetId) + this.targetId = null + } + }, + */ + showPopover () { + this.hidden = false + this.$nextTick(function () { + if (this.hidden) return { opacity: 0 } + + const anchorEl = this.$refs.trigger || this.$el + console.log(anchorEl) + const screenBox = anchorEl.getBoundingClientRect() + const origin = { x: screenBox.left + screenBox.width * 0.5, y: screenBox.top} + const content = this.$refs.content + let horizOffset = 0 + + if ((origin.x - content.offsetWidth * 0.5) < 25) { + horizOffset += -(origin.x - content.offsetWidth * 0.5) + 25 + } + + console.log((origin.x + content.offsetWidth * 0.5), (window.innerWidth - 25)) + if ((origin.x + content.offsetWidth * 0.5) > window.innerWidth - 25) { + horizOffset -= (origin.x + content.offsetWidth * 0.5) - (window.innerWidth - 25) + } + // Default to whatever user wished with placement prop + let usingTop = this.placement !== 'bottom' + + // Handle special cases, first force to displaying on top if there's not space on bottom, + // regardless of what placement value was. Then check if there's not space on top, and + // force to bottom, again regardless of what placement value was. + if (origin.y + content.offsetHeight > (window.innerHeight - 25)) usingTop = true + if (origin.y - content.offsetHeight < 50) usingTop = false + + const vertAlign = usingTop ? + { + bottom: `${anchorEl.offsetHeight}px` + } : + { + top: `${anchorEl.offsetHeight}px` + } + this.styles = { + opacity: '100%', + left: `${(anchorEl.offsetLeft + anchorEl.offsetWidth * 0.5) - content.offsetWidth * 0.5 + horizOffset}px`, + ...vertAlign + } + }) + }, + hidePopover () { + this.hidden = true + this.styles = { opacity: 0 } + }, + onMouseenter (e) { + console.log(this.trigger) + if (this.trigger === 'hover') this.showPopover() + }, + onMouseleave (e) { + if (this.trigger === 'hover') this.hidePopover() + }, + onClick (e) { + if (this.trigger === 'click') { + if (this.hidden) { + this.showPopover() + } else { + this.hidePopover() + } + } + }, + onClickOutside (e) { + if (this.hidden) return + if (this.$el.contains(e.target)) return + console.log(e.target) + this.hidePopover() + } + }, + created () { + document.addEventListener("click", this.onClickOutside) + }, + destroyed () { + document.removeEventListener("click", this.onClickOutside) + this.hidePopover() + } +} + +export default Popover diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue new file mode 100644 index 00000000..273a0a69 --- /dev/null +++ b/src/components/popover/popover.vue @@ -0,0 +1,195 @@ + + + @@ -29,11 +25,11 @@