diff options
author | Hsieh Chin Fan <pham@topo.tw> | 2024-09-28 17:47:52 +0800 |
---|---|---|
committer | Hsieh Chin Fan <pham@topo.tw> | 2024-09-28 17:47:52 +0800 |
commit | 933eba7dc3bdc979fefadd47388b20b8360e1d6b (patch) | |
tree | 9b88908d88a025aaaa1d70306afde8e49fedab27 /src/Layout.mjs | |
parent | 5a64dfc8bb8169e72b7c1164f18c6912e9e3576e (diff) |
style: prettier
Diffstat (limited to 'src/Layout.mjs')
-rw-r--r-- | src/Layout.mjs | 240 |
1 files changed, 120 insertions, 120 deletions
diff --git a/src/Layout.mjs b/src/Layout.mjs index abefd4d..9cf2ab9 100644 --- a/src/Layout.mjs +++ b/src/Layout.mjs | |||
@@ -1,208 +1,208 @@ | |||
1 | import PlainDraggable from 'plain-draggable' | 1 | import PlainDraggable from "plain-draggable"; |
2 | import { onRemove, animateRectTransition } from './utils' | 2 | import { onRemove, animateRectTransition } from "./utils"; |
3 | 3 | ||
4 | export class Layout { | 4 | export class Layout { |
5 | constructor(options = {}) { | 5 | constructor(options = {}) { |
6 | if (!options.name) throw Error("Layout name is not given") | 6 | if (!options.name) throw Error("Layout name is not given"); |
7 | this.name = options.name | 7 | this.name = options.name; |
8 | this.enterHandler = options.enterHandler | 8 | this.enterHandler = options.enterHandler; |
9 | this.leaveHandler = options.leaveHandler | 9 | this.leaveHandler = options.leaveHandler; |
10 | } | 10 | } |
11 | valueOf = () => this.name | 11 | valueOf = () => this.name; |
12 | } | 12 | } |
13 | 13 | ||
14 | export class SideBySide extends Layout { | 14 | export class SideBySide extends Layout { |
15 | name = "side-by-side" | 15 | name = "side-by-side"; |
16 | 16 | ||
17 | enterHandler = ({ container, htmlHolder, showcase }) => { | 17 | enterHandler = ({ container, htmlHolder, showcase }) => { |
18 | const bar = document.createElement('div') | 18 | const bar = document.createElement("div"); |
19 | bar.className = 'bar' | 19 | bar.className = "bar"; |
20 | bar.innerHTML = '<div class="bar-handle"></div>' | 20 | bar.innerHTML = '<div class="bar-handle"></div>'; |
21 | const handle = bar.querySelector('.bar-handle') | 21 | const handle = bar.querySelector(".bar-handle"); |
22 | container.appendChild(bar) | 22 | container.appendChild(bar); |
23 | 23 | ||
24 | // Resize views by value | 24 | // Resize views by value |
25 | const resizeByLeft = (left) => { | 25 | const resizeByLeft = left => { |
26 | htmlHolder.style.width = (left) + "px" | 26 | htmlHolder.style.width = left + "px"; |
27 | showcase.style.width = (parseFloat(getComputedStyle(container).width) - left) + "px" | 27 | showcase.style.width = |
28 | } | 28 | parseFloat(getComputedStyle(container).width) - left + "px"; |
29 | }; | ||
29 | 30 | ||
30 | const draggable = new PlainDraggable(bar, { | 31 | const draggable = new PlainDraggable(bar, { |
31 | handle: handle, | 32 | handle: handle, |
32 | containment: { left: '25%', top: 0, right: '75%', height: 0 }, | 33 | containment: { left: "25%", top: 0, right: "75%", height: 0 }, |
33 | }) | 34 | }); |
34 | draggable.draggableCursor = "grab" | 35 | draggable.draggableCursor = "grab"; |
35 | 36 | ||
36 | draggable.onDrag = (pos) => { | 37 | draggable.onDrag = pos => { |
37 | handle.style.transform = 'unset' | 38 | handle.style.transform = "unset"; |
38 | resizeByLeft(pos.left) | 39 | resizeByLeft(pos.left); |
39 | } | 40 | }; |
40 | draggable.onDragEnd = (_) => { | 41 | draggable.onDragEnd = _ => { |
41 | handle.removeAttribute('style') | 42 | handle.removeAttribute("style"); |
42 | } | 43 | }; |
43 | 44 | ||
44 | onRemove(bar, () => draggable.remove()) | 45 | onRemove(bar, () => draggable.remove()); |
45 | } | 46 | }; |
46 | 47 | ||
47 | leaveHandler = ({ container }) => { | 48 | leaveHandler = ({ container }) => { |
48 | container.querySelector('.bar')?.remove() | 49 | container.querySelector(".bar")?.remove(); |
49 | } | 50 | }; |
50 | } | 51 | } |
51 | 52 | ||
52 | export class Overlay extends Layout { | 53 | export class Overlay extends Layout { |
53 | name = "overlay" | 54 | name = "overlay"; |
54 | 55 | ||
55 | saveLeftTopAsData = (element) => { | 56 | saveLeftTopAsData = element => { |
56 | const { left, top } = element.getBoundingClientRect() | 57 | const { left, top } = element.getBoundingClientRect(); |
57 | element.setAttribute('data-left', left) | 58 | element.setAttribute("data-left", left); |
58 | element.setAttribute('data-top', top) | 59 | element.setAttribute("data-top", top); |
59 | } | 60 | }; |
60 | 61 | ||
61 | addDraggable = (element) => { | 62 | addDraggable = element => { |
62 | // Make sure current element always on top | 63 | // Make sure current element always on top |
63 | const siblings = Array.from(element.parentElement?.querySelectorAll(':scope > *') ?? []) | 64 | const siblings = Array.from( |
64 | let popTimer = null | 65 | element.parentElement?.querySelectorAll(":scope > *") ?? [], |
66 | ); | ||
67 | let popTimer = null; | ||
65 | element.onmouseover = () => { | 68 | element.onmouseover = () => { |
66 | popTimer = setTimeout(() => { | 69 | popTimer = setTimeout(() => { |
67 | siblings.forEach(e => e.style.removeProperty('z-index')) | 70 | siblings.forEach(e => e.style.removeProperty("z-index")); |
68 | element.style.zIndex = '9001' | 71 | element.style.zIndex = "9001"; |
69 | }, 200) | 72 | }, 200); |
70 | } | 73 | }; |
71 | element.onmouseout = () => { | 74 | element.onmouseout = () => { |
72 | clearTimeout(popTimer) | 75 | clearTimeout(popTimer); |
73 | } | 76 | }; |
74 | 77 | ||
75 | // Add draggable part | 78 | // Add draggable part |
76 | const draggablePart = document.createElement('div') | 79 | const draggablePart = document.createElement("div"); |
77 | element.appendChild(draggablePart) | 80 | element.appendChild(draggablePart); |
78 | draggablePart.className = 'draggable-part' | 81 | draggablePart.className = "draggable-part"; |
79 | draggablePart.innerHTML = '<div class="handle">\u2630</div>' | 82 | draggablePart.innerHTML = '<div class="handle">\u2630</div>'; |
80 | 83 | ||
81 | // Add draggable instance | 84 | // Add draggable instance |
82 | const { left, top } = element.getBoundingClientRect() | 85 | const { left, top } = element.getBoundingClientRect(); |
83 | const draggable = new PlainDraggable(element, { | 86 | const draggable = new PlainDraggable(element, { |
84 | top: top, | 87 | top: top, |
85 | left: left, | 88 | left: left, |
86 | handle: draggablePart, | 89 | handle: draggablePart, |
87 | snap: { x: { step: 20 }, y: { step: 20 } }, | 90 | snap: { x: { step: 20 }, y: { step: 20 } }, |
88 | }) | 91 | }); |
89 | 92 | ||
90 | // FIXME use pure CSS to hide utils | 93 | // FIXME use pure CSS to hide utils |
91 | const utils = element.querySelector('.utils') | 94 | const utils = element.querySelector(".utils"); |
92 | draggable.onDragStart = () => { | 95 | draggable.onDragStart = () => { |
93 | utils.style.display = 'none' | 96 | utils.style.display = "none"; |
94 | element.classList.add('drag') | 97 | element.classList.add("drag"); |
95 | } | 98 | }; |
96 | 99 | ||
97 | draggable.onDragEnd = () => { | 100 | draggable.onDragEnd = () => { |
98 | utils.style = '' | 101 | utils.style = ""; |
99 | element.classList.remove('drag') | 102 | element.classList.remove("drag"); |
100 | element.style.zIndex = '9000' | 103 | element.style.zIndex = "9000"; |
101 | } | 104 | }; |
102 | 105 | ||
103 | // Reposition draggable instance when resized | 106 | // Reposition draggable instance when resized |
104 | new ResizeObserver(() => { | 107 | new ResizeObserver(() => { |
105 | try { | 108 | try { |
106 | draggable.position(); | 109 | draggable.position(); |
107 | } catch (_) { | 110 | } catch (_) { |
108 | null | 111 | null; |
109 | } | 112 | } |
110 | }).observe(element); | 113 | }).observe(element); |
111 | 114 | ||
112 | // Callback for remove | 115 | // Callback for remove |
113 | onRemove(element, () => { | 116 | onRemove(element, () => { |
114 | draggable.remove() | 117 | draggable.remove(); |
115 | }) | 118 | }); |
116 | } | 119 | }; |
117 | 120 | ||
118 | enterHandler = ({ htmlHolder, blocks }) => { | 121 | enterHandler = ({ htmlHolder, blocks }) => { |
119 | // FIXME It is weird rect from this method and this scope are different... | 122 | // FIXME It is weird rect from this method and this scope are different... |
120 | blocks.forEach(this.saveLeftTopAsData) | 123 | blocks.forEach(this.saveLeftTopAsData); |
121 | 124 | ||
122 | // Create draggable blocks and set each position by previous one | 125 | // Create draggable blocks and set each position by previous one |
123 | let [left, top] = [20, 20] | 126 | let [left, top] = [20, 20]; |
124 | blocks.forEach(block => { | 127 | blocks.forEach(block => { |
125 | const originLeft = Number(block.getAttribute('data-left')) | 128 | const originLeft = Number(block.getAttribute("data-left")); |
126 | const originTop = Number(block.getAttribute('data-top')) | 129 | const originTop = Number(block.getAttribute("data-top")); |
127 | 130 | ||
128 | // Create draggable block | 131 | // Create draggable block |
129 | const wrapper = document.createElement('div') | 132 | const wrapper = document.createElement("div"); |
130 | wrapper.classList.add('draggable-block') | 133 | wrapper.classList.add("draggable-block"); |
131 | wrapper.innerHTML = ` | 134 | wrapper.innerHTML = ` |
132 | <div class="utils"> | 135 | <div class="utils"> |
133 | <div id="close">\u274C</div> | 136 | <div id="close">\u274C</div> |
134 | <div id="plus-font-size" ">\u2795</div> | 137 | <div id="plus-font-size" ">\u2795</div> |
135 | <div id="minus-font-size">\u2796</div> | 138 | <div id="minus-font-size">\u2796</div> |
136 | </div> | 139 | </div> |
137 | ` | 140 | `; |
138 | wrapper.title = 'Middle-click to hide block' | 141 | wrapper.title = "Middle-click to hide block"; |
139 | wrapper.onmouseup = (e) => { | 142 | wrapper.onmouseup = e => { |
140 | // Hide block with middle click | 143 | // Hide block with middle click |
141 | if (e.button === 1) { | 144 | if (e.button === 1) { |
142 | wrapper.classList.add('hide') | 145 | wrapper.classList.add("hide"); |
143 | } | 146 | } |
144 | } | 147 | }; |
145 | 148 | ||
146 | // Set DOMRect for wrapper | 149 | // Set DOMRect for wrapper |
147 | wrapper.appendChild(block) | 150 | wrapper.appendChild(block); |
148 | wrapper.style.left = left + "px" | 151 | wrapper.style.left = left + "px"; |
149 | wrapper.style.top = top + "px" | 152 | wrapper.style.top = top + "px"; |
150 | htmlHolder.appendChild(wrapper) | 153 | htmlHolder.appendChild(wrapper); |
151 | const { width } = wrapper.getBoundingClientRect() | 154 | const { width } = wrapper.getBoundingClientRect(); |
152 | left += width + 30 | 155 | left += width + 30; |
153 | if (left > window.innerWidth) { | 156 | if (left > window.innerWidth) { |
154 | top += 200 | 157 | top += 200; |
155 | left = left % window.innerWidth | 158 | left = left % window.innerWidth; |
156 | } | 159 | } |
157 | 160 | ||
158 | // Animation for DOMRect | 161 | // Animation for DOMRect |
159 | animateRectTransition( | 162 | animateRectTransition( |
160 | wrapper, | 163 | wrapper, |
161 | { left: originLeft, top: originTop }, | 164 | { left: originLeft, top: originTop }, |
162 | { resume: true, duration: 300 } | 165 | { resume: true, duration: 300 }, |
163 | ) | 166 | ).finished.finally(() => this.addDraggable(wrapper)); |
164 | .finished | ||
165 | .finally(() => this.addDraggable(wrapper)) | ||
166 | 167 | ||
167 | // Trivial case: | 168 | // Trivial case: |
168 | // This hack make sure utils remains at the same place even when wrapper resized | 169 | // This hack make sure utils remains at the same place even when wrapper resized |
169 | // Prevent DOMRect changes when user clicking plus/minus button many times | 170 | // Prevent DOMRect changes when user clicking plus/minus button many times |
170 | const utils = wrapper.querySelector('.utils') | 171 | const utils = wrapper.querySelector(".utils"); |
171 | utils.onmouseover = () => { | 172 | utils.onmouseover = () => { |
172 | const { left, top } = utils.getBoundingClientRect() | 173 | const { left, top } = utils.getBoundingClientRect(); |
173 | utils.style.cssText = `visibility: visible; z-index: 9000; position: fixed; transition: unset; left: ${left}px; top: ${top}px;` | 174 | utils.style.cssText = `visibility: visible; z-index: 9000; position: fixed; transition: unset; left: ${left}px; top: ${top}px;`; |
174 | document.body.appendChild(utils) | 175 | document.body.appendChild(utils); |
175 | } | 176 | }; |
176 | utils.onmouseout = () => { | 177 | utils.onmouseout = () => { |
177 | wrapper.appendChild(utils) | 178 | wrapper.appendChild(utils); |
178 | utils.removeAttribute('style') | 179 | utils.removeAttribute("style"); |
179 | } | 180 | }; |
180 | 181 | ||
181 | // Close button | 182 | // Close button |
182 | wrapper.querySelector('#close').onclick = () => { | 183 | wrapper.querySelector("#close").onclick = () => { |
183 | wrapper.classList.add('hide') | 184 | wrapper.classList.add("hide"); |
184 | utils.removeAttribute('style') | 185 | utils.removeAttribute("style"); |
185 | } | 186 | }; |
186 | // Plus/Minus font-size of content | 187 | // Plus/Minus font-size of content |
187 | wrapper.querySelector('#plus-font-size').onclick = () => { | 188 | wrapper.querySelector("#plus-font-size").onclick = () => { |
188 | const fontSize = parseFloat(getComputedStyle(block).fontSize) / 16 | 189 | const fontSize = parseFloat(getComputedStyle(block).fontSize) / 16; |
189 | block.style.fontSize = `${fontSize + 0.2}rem` | 190 | block.style.fontSize = `${fontSize + 0.2}rem`; |
190 | } | 191 | }; |
191 | wrapper.querySelector('#minus-font-size').onclick = () => { | 192 | wrapper.querySelector("#minus-font-size").onclick = () => { |
192 | const fontSize = parseFloat(getComputedStyle(block).fontSize) / 16 | 193 | const fontSize = parseFloat(getComputedStyle(block).fontSize) / 16; |
193 | block.style.fontSize = `${fontSize - 0.2}rem` | 194 | block.style.fontSize = `${fontSize - 0.2}rem`; |
194 | } | 195 | }; |
195 | }) | 196 | }); |
196 | } | 197 | }; |
197 | 198 | ||
198 | leaveHandler = ({ htmlHolder, blocks }) => { | 199 | leaveHandler = ({ htmlHolder, blocks }) => { |
199 | const resumeFromDraggable = (block) => { | 200 | const resumeFromDraggable = block => { |
200 | const draggableContainer = block.closest('.draggable-block') | 201 | const draggableContainer = block.closest(".draggable-block"); |
201 | if (!draggableContainer) return | 202 | if (!draggableContainer) return; |
202 | htmlHolder.appendChild(block) | 203 | htmlHolder.appendChild(block); |
203 | draggableContainer.remove() | 204 | draggableContainer.remove(); |
204 | } | 205 | }; |
205 | blocks.forEach(resumeFromDraggable) | 206 | blocks.forEach(resumeFromDraggable); |
206 | } | 207 | }; |
207 | } | 208 | } |
208 | |||