1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-23 23:54:10 +02:00

fix(frontend): ウィンドウのドラッグ・サイズ変更のポインターをキャプチャするように (#17159)

* fix(frontend): ウィンドウのドラッグ・サイズ変更のポインターをキャプチャするように

* Update Changelog

* fix
This commit is contained in:
かっこかり
2026-02-16 19:23:30 +09:00
committed by GitHub
parent b5121dc70e
commit 41620600cc
2 changed files with 74 additions and 42 deletions

View File

@@ -27,6 +27,7 @@
- Fix: mCaptchaが正しく動作しない問題を修正 - Fix: mCaptchaが正しく動作しない問題を修正
- Fix: 非ログイン時にリバーシの対局が表示されない問題を修正 - Fix: 非ログイン時にリバーシの対局が表示されない問題を修正
- Fix: ノートの詳細表示でリアクションが全件表示されない問題を修正 - Fix: ノートの詳細表示でリアクションが全件表示されない問題を修正
- Fix: 動画埋め込みプレイヤーなどの一部ウィンドウで、ウィンドウのサイズ変更や移動が正常に行えない問題を修正
- Fix: 画像エフェクトの修正 - Fix: 画像エフェクトの修正
- 塗りつぶし・モザイク・ぼかしエフェクトを回転させると歪む問題を修正 - 塗りつぶし・モザイク・ぼかしエフェクトを回転させると歪む問題を修正
- モザイクの格子のサイズが画像の縦横比によって長方形となる問題を修正 - モザイクの格子のサイズが画像の縦横比によって長方形となる問題を修正

View File

@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<button v-for="button in buttonsLeft" v-tooltip="button.title" class="_button" :class="[$style.headerButton, { [$style.highlighted]: button.highlighted }]" @click="button.onClick"><i :class="button.icon"></i></button> <button v-for="button in buttonsLeft" v-tooltip="button.title" class="_button" :class="[$style.headerButton, { [$style.highlighted]: button.highlighted }]" @click="button.onClick"><i :class="button.icon"></i></button>
</template> </template>
</span> </span>
<span :class="$style.headerTitle" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown"> <span :class="$style.headerTitle" @pointerdown.prevent="onHeaderPointerdown">
<slot name="header"></slot> <slot name="header"></slot>
</span> </span>
<span :class="$style.headerRight"> <span :class="$style.headerRight">
@@ -39,14 +39,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
<template v-if="canResize && !minimized"> <template v-if="canResize && !minimized">
<div :class="$style.handleTop" @mousedown.prevent="onTopHandleMousedown"></div> <div :class="$style.handleTop" @pointerdown.prevent="onTopHandlePointerdown"></div>
<div :class="$style.handleRight" @mousedown.prevent="onRightHandleMousedown"></div> <div :class="$style.handleRight" @pointerdown.prevent="onRightHandlePointerdown"></div>
<div :class="$style.handleBottom" @mousedown.prevent="onBottomHandleMousedown"></div> <div :class="$style.handleBottom" @pointerdown.prevent="onBottomHandlePointerdown"></div>
<div :class="$style.handleLeft" @mousedown.prevent="onLeftHandleMousedown"></div> <div :class="$style.handleLeft" @pointerdown.prevent="onLeftHandlePointerdown"></div>
<div :class="$style.handleTopLeft" @mousedown.prevent="onTopLeftHandleMousedown"></div> <div :class="$style.handleTopLeft" @pointerdown.prevent="onTopLeftHandlePointerdown"></div>
<div :class="$style.handleTopRight" @mousedown.prevent="onTopRightHandleMousedown"></div> <div :class="$style.handleTopRight" @pointerdown.prevent="onTopRightHandlePointerdown"></div>
<div :class="$style.handleBottomRight" @mousedown.prevent="onBottomRightHandleMousedown"></div> <div :class="$style.handleBottomRight" @pointerdown.prevent="onBottomRightHandlePointerdown"></div>
<div :class="$style.handleBottomLeft" @mousedown.prevent="onBottomLeftHandleMousedown"></div> <div :class="$style.handleBottomLeft" @pointerdown.prevent="onBottomLeftHandlePointerdown"></div>
</template> </template>
</div> </div>
</Transition> </Transition>
@@ -70,20 +70,39 @@ type WindowButton = {
const minHeight = 50; const minHeight = 50;
const minWidth = 250; const minWidth = 250;
function dragListen(fn: (ev: MouseEvent | TouchEvent) => void) { function dragListen(fn: (ev: PointerEvent) => void) {
window.addEventListener('mousemove', fn); window.addEventListener('pointermove', fn);
window.addEventListener('touchmove', fn); const clear = () => {
window.addEventListener('mouseleave', dragClear.bind(null, fn)); dragClear(fn);
window.addEventListener('mouseup', dragClear.bind(null, fn)); };
window.addEventListener('touchend', dragClear.bind(null, fn)); window.addEventListener('pointerup', clear, { once: true });
window.addEventListener('pointercancel', clear, { once: true });
window.addEventListener('blur', clear, { once: true });
} }
function dragClear(fn: (ev: MouseEvent | TouchEvent) => void) { function dragClear(fn: (ev: PointerEvent) => void) {
window.removeEventListener('mousemove', fn); window.removeEventListener('pointermove', fn);
window.removeEventListener('touchmove', fn); }
window.removeEventListener('mouseleave', dragClear as any);
window.removeEventListener('mouseup', dragClear as any); function capturePointer(evt: PointerEvent) {
window.removeEventListener('touchend', dragClear as any); const target = evt.currentTarget;
if (!(target instanceof HTMLElement)) return;
if (!target.setPointerCapture) return;
try {
target.setPointerCapture(evt.pointerId);
} catch {
return;
}
const release = () => {
if (target.hasPointerCapture(evt.pointerId)) {
target.releasePointerCapture(evt.pointerId);
}
};
window.addEventListener('pointerup', release, { once: true });
window.addEventListener('pointercancel', release, { once: true });
} }
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
@@ -209,15 +228,17 @@ function onDblClick() {
} }
} }
function getPositionX(event: MouseEvent | TouchEvent) { function getPositionX(event: PointerEvent) {
return 'touches' in event && event.touches.length > 0 ? event.touches[0].clientX : 'clientX' in event ? event.clientX : 0; return event.clientX;
} }
function getPositionY(event: MouseEvent | TouchEvent) { function getPositionY(event: PointerEvent) {
return 'touches' in event && event.touches.length > 0 ? event.touches[0].clientY : 'clientY' in event ? event.clientY : 0; return event.clientY;
} }
function onHeaderMousedown(evt: MouseEvent | TouchEvent) { function onHeaderPointerdown(evt: PointerEvent) {
capturePointer(evt);
// 右クリックはコンテキストメニューを開こうとした可能性が高いため無視 // 右クリックはコンテキストメニューを開こうとした可能性が高いため無視
if ('button' in evt && evt.button === 2) return; if ('button' in evt && evt.button === 2) return;
@@ -289,7 +310,9 @@ function onHeaderMousedown(evt: MouseEvent | TouchEvent) {
} }
// 上ハンドル掴み時 // 上ハンドル掴み時
function onTopHandleMousedown(evt: MouseEvent | TouchEvent) { function onTopHandlePointerdown(evt: PointerEvent) {
capturePointer(evt);
const main = rootEl.value; const main = rootEl.value;
// どういうわけかnullになることがある // どういうわけかnullになることがある
if (main == null) return; if (main == null) return;
@@ -317,7 +340,9 @@ function onTopHandleMousedown(evt: MouseEvent | TouchEvent) {
} }
// 右ハンドル掴み時 // 右ハンドル掴み時
function onRightHandleMousedown(evt: MouseEvent | TouchEvent) { function onRightHandlePointerdown(evt: PointerEvent) {
capturePointer(evt);
const main = rootEl.value; const main = rootEl.value;
if (main == null) return; if (main == null) return;
@@ -342,7 +367,9 @@ function onRightHandleMousedown(evt: MouseEvent | TouchEvent) {
} }
// 下ハンドル掴み時 // 下ハンドル掴み時
function onBottomHandleMousedown(evt: MouseEvent | TouchEvent) { function onBottomHandlePointerdown(evt: PointerEvent) {
capturePointer(evt);
const main = rootEl.value; const main = rootEl.value;
if (main == null) return; if (main == null) return;
@@ -367,7 +394,9 @@ function onBottomHandleMousedown(evt: MouseEvent | TouchEvent) {
} }
// 左ハンドル掴み時 // 左ハンドル掴み時
function onLeftHandleMousedown(evt: MouseEvent | TouchEvent) { function onLeftHandlePointerdown(evt: PointerEvent) {
capturePointer(evt);
const main = rootEl.value; const main = rootEl.value;
if (main == null) return; if (main == null) return;
@@ -394,27 +423,27 @@ function onLeftHandleMousedown(evt: MouseEvent | TouchEvent) {
} }
// 左上ハンドル掴み時 // 左上ハンドル掴み時
function onTopLeftHandleMousedown(evt: MouseEvent | TouchEvent) { function onTopLeftHandlePointerdown(evt: PointerEvent) {
onTopHandleMousedown(evt); onTopHandlePointerdown(evt);
onLeftHandleMousedown(evt); onLeftHandlePointerdown(evt);
} }
// 右上ハンドル掴み時 // 右上ハンドル掴み時
function onTopRightHandleMousedown(evt: MouseEvent | TouchEvent) { function onTopRightHandlePointerdown(evt: PointerEvent) {
onTopHandleMousedown(evt); onTopHandlePointerdown(evt);
onRightHandleMousedown(evt); onRightHandlePointerdown(evt);
} }
// 右下ハンドル掴み時 // 右下ハンドル掴み時
function onBottomRightHandleMousedown(evt: MouseEvent | TouchEvent) { function onBottomRightHandlePointerdown(evt: PointerEvent) {
onBottomHandleMousedown(evt); onBottomHandlePointerdown(evt);
onRightHandleMousedown(evt); onRightHandlePointerdown(evt);
} }
// 左下ハンドル掴み時 // 左下ハンドル掴み時
function onBottomLeftHandleMousedown(evt: MouseEvent | TouchEvent) { function onBottomLeftHandlePointerdown(evt: PointerEvent) {
onBottomHandleMousedown(evt); onBottomHandlePointerdown(evt);
onLeftHandleMousedown(evt); onLeftHandlePointerdown(evt);
} }
// 高さを適用 // 高さを適用
@@ -566,6 +595,7 @@ defineExpose({
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
cursor: move; cursor: move;
touch-action: none;
} }
.content { .content {
@@ -579,6 +609,7 @@ $handleSize: 8px;
.handle { .handle {
position: absolute; position: absolute;
touch-action: none;
} }
.handleTop { .handleTop {