summaryrefslogtreecommitdiff
path: root/packages/frontend/src/directives/user-preview.ts
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2022-12-27 14:36:33 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2022-12-27 14:36:33 +0900
commit9384f5399da39e53855beb8e7f8ded1aa56bf72e (patch)
treece5959571a981b9c4047da3c7b3fd080aa44222c /packages/frontend/src/directives/user-preview.ts
parentwip: retention for dashboard (diff)
downloadsharkey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.tar.gz
sharkey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.tar.bz2
sharkey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.zip
rename: client -> frontend
Diffstat (limited to 'packages/frontend/src/directives/user-preview.ts')
-rw-r--r--packages/frontend/src/directives/user-preview.ts118
1 files changed, 118 insertions, 0 deletions
diff --git a/packages/frontend/src/directives/user-preview.ts b/packages/frontend/src/directives/user-preview.ts
new file mode 100644
index 0000000000..ed5f00ca65
--- /dev/null
+++ b/packages/frontend/src/directives/user-preview.ts
@@ -0,0 +1,118 @@
+import { defineAsyncComponent, Directive, ref } from 'vue';
+import autobind from 'autobind-decorator';
+import { popup } from '@/os';
+
+export class UserPreview {
+ private el;
+ private user;
+ private showTimer;
+ private hideTimer;
+ private checkTimer;
+ private promise;
+
+ constructor(el, user) {
+ this.el = el;
+ this.user = user;
+
+ this.attach();
+ }
+
+ @autobind
+ private show() {
+ if (!document.body.contains(this.el)) return;
+ if (this.promise) return;
+
+ const showing = ref(true);
+
+ popup(defineAsyncComponent(() => import('@/components/MkUserPreview.vue')), {
+ showing,
+ q: this.user,
+ source: this.el,
+ }, {
+ mouseover: () => {
+ window.clearTimeout(this.hideTimer);
+ },
+ mouseleave: () => {
+ window.clearTimeout(this.showTimer);
+ this.hideTimer = window.setTimeout(this.close, 500);
+ },
+ }, 'closed');
+
+ this.promise = {
+ cancel: () => {
+ showing.value = false;
+ },
+ };
+
+ this.checkTimer = window.setInterval(() => {
+ if (!document.body.contains(this.el)) {
+ window.clearTimeout(this.showTimer);
+ window.clearTimeout(this.hideTimer);
+ this.close();
+ }
+ }, 1000);
+ }
+
+ @autobind
+ private close() {
+ if (this.promise) {
+ window.clearInterval(this.checkTimer);
+ this.promise.cancel();
+ this.promise = null;
+ }
+ }
+
+ @autobind
+ private onMouseover() {
+ window.clearTimeout(this.showTimer);
+ window.clearTimeout(this.hideTimer);
+ this.showTimer = window.setTimeout(this.show, 500);
+ }
+
+ @autobind
+ private onMouseleave() {
+ window.clearTimeout(this.showTimer);
+ window.clearTimeout(this.hideTimer);
+ this.hideTimer = window.setTimeout(this.close, 500);
+ }
+
+ @autobind
+ private onClick() {
+ window.clearTimeout(this.showTimer);
+ this.close();
+ }
+
+ @autobind
+ public attach() {
+ this.el.addEventListener('mouseover', this.onMouseover);
+ this.el.addEventListener('mouseleave', this.onMouseleave);
+ this.el.addEventListener('click', this.onClick);
+ }
+
+ @autobind
+ public detach() {
+ this.el.removeEventListener('mouseover', this.onMouseover);
+ this.el.removeEventListener('mouseleave', this.onMouseleave);
+ this.el.removeEventListener('click', this.onClick);
+ window.clearInterval(this.checkTimer);
+ }
+}
+
+export default {
+ mounted(el: HTMLElement, binding, vn) {
+ if (binding.value == null) return;
+
+ // TODO: 新たにプロパティを作るのをやめMapを使う
+ // ただメモリ的には↓の方が省メモリかもしれないので検討中
+ const self = (el as any)._userPreviewDirective_ = {} as any;
+
+ self.preview = new UserPreview(el, binding.value);
+ },
+
+ unmounted(el, binding, vn) {
+ if (binding.value == null) return;
+
+ const self = el._userPreviewDirective_;
+ self.preview.detach();
+ },
+} as Directive;