|
3 | 3 | // SPDX-License-Identifier: MIT |
4 | 4 |
|
5 | 5 | ;(function () { |
6 | | - const osName = __TEMPLATE_os_name__ |
7 | | - |
8 | 6 | //-----------------------// |
9 | 7 | // drag on mousedown and maximize on double click on Windows and Linux |
10 | | - // while macOS macos maximization should be on mouseup and if the mouse |
| 8 | + // while macOS maximization should be on mouseup and if the mouse |
11 | 9 | // moves after the double click, it should be cancelled (see https://github.com/tauri-apps/tauri/issues/8306) |
12 | 10 | //-----------------------// |
13 | 11 | const TAURI_DRAG_REGION_ATTR = 'data-tauri-drag-region' |
14 | 12 |
|
| 13 | + function isClickableElement(el) { |
| 14 | + const tag = el.tagName && el.tagName.toLowerCase() |
| 15 | + |
| 16 | + return ( |
| 17 | + tag === 'a' |
| 18 | + || tag === 'button' |
| 19 | + || tag === 'input' |
| 20 | + || tag === 'select' |
| 21 | + || tag === 'textarea' |
| 22 | + || tag === 'label' |
| 23 | + || tag === 'summary' |
| 24 | + || (el.hasAttribute('contenteditable') |
| 25 | + && el.getAttribute('contenteditable') !== 'false') |
| 26 | + || (el.hasAttribute('tabindex') && el.getAttribute('tabindex') !== '-1') |
| 27 | + ) |
| 28 | + } |
| 29 | + |
| 30 | + // Walk the composed path from target upward. If a clickable element or a |
| 31 | + // data-tauri-drag-region="false" element is encountered, return false (don't drag). |
| 32 | + // Otherwise return true. |
| 33 | + // |
| 34 | + // Supported values for data-tauri-drag-region: |
| 35 | + // (bare / no value) → self: only direct clicks on this element trigger drag |
| 36 | + // "deep" → deep: clicks anywhere in the subtree trigger drag |
| 37 | + // "false" → disabled: drag is blocked here (and for ancestors) |
| 38 | + function isDragRegion(composedPath) { |
| 39 | + for (const el of composedPath) { |
| 40 | + if (!(el instanceof HTMLElement)) continue |
| 41 | + |
| 42 | + // if we hit a clickable element or a disabled drag region, don't drag |
| 43 | + if ( |
| 44 | + isClickableElement(el) |
| 45 | + || el.getAttribute(TAURI_DRAG_REGION_ATTR) === 'false' |
| 46 | + ) { |
| 47 | + return false |
| 48 | + } |
| 49 | + |
| 50 | + const attr = el.getAttribute(TAURI_DRAG_REGION_ATTR) |
| 51 | + if (attr !== null) { |
| 52 | + // deep: the whole subtree is a drag region |
| 53 | + if (attr === 'deep') return true |
| 54 | + // bare (or any unrecognized value): self-only |
| 55 | + if (el === composedPath[0]) return true |
| 56 | + // click was on a child of a self-only region — stop walking, don't drag |
| 57 | + return false |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | + return false |
| 62 | + } |
| 63 | + |
| 64 | + const osName = __TEMPLATE_os_name__ |
| 65 | + |
15 | 66 | // initial mousedown position for macOS |
16 | 67 | let initialX = 0 |
17 | 68 | let initialY = 0 |
18 | 69 |
|
19 | 70 | document.addEventListener('mousedown', (e) => { |
20 | | - const attr = e.target.getAttribute(TAURI_DRAG_REGION_ATTR) |
21 | 71 | if ( |
22 | | - // element has the magic data attribute |
23 | | - attr !== null |
24 | | - // and not false |
25 | | - && attr !== 'false' |
26 | | - // and was left mouse button |
27 | | - && e.button === 0 |
| 72 | + // was left mouse button |
| 73 | + e.button === 0 |
28 | 74 | // and was normal click to drag or double click to maximize |
29 | 75 | && (e.detail === 1 || e.detail === 2) |
| 76 | + // and is drag region |
| 77 | + && isDragRegion(e.composedPath()) |
30 | 78 | ) { |
31 | 79 | // macOS maximization happens on `mouseup`, |
32 | 80 | // so we save needed state and early return |
|
48 | 96 | window.__TAURI_INTERNALS__.invoke('plugin:window|' + cmd) |
49 | 97 | } |
50 | 98 | }) |
| 99 | + |
51 | 100 | // on macOS we maximize on mouseup instead, to match the system behavior where maximization can be canceled |
52 | 101 | // if the mouse moves outside the data-tauri-drag-region |
53 | 102 | if (osName === 'macos') { |
54 | 103 | document.addEventListener('mouseup', (e) => { |
55 | | - const attr = e.target.getAttribute(TAURI_DRAG_REGION_ATTR) |
56 | 104 | if ( |
57 | | - // element has the magic data attribute |
58 | | - attr !== null |
59 | | - // and not false |
60 | | - && attr !== 'false' |
61 | | - // and was left mouse button |
62 | | - && e.button === 0 |
| 105 | + // was left mouse button |
| 106 | + e.button === 0 |
63 | 107 | // and was double click |
64 | 108 | && e.detail === 2 |
65 | 109 | // and the cursor hasn't moved from initial mousedown |
66 | 110 | && e.clientX === initialX |
67 | 111 | && e.clientY === initialY |
| 112 | + // and the event path contains a drag region (with no clickable element in between) |
| 113 | + && isDragRegion(e.composedPath()) |
68 | 114 | ) { |
69 | 115 | window.__TAURI_INTERNALS__.invoke( |
70 | 116 | 'plugin:window|internal_toggle_maximize' |
|
0 commit comments