|
87 | 87 | } |
88 | 88 | }; |
89 | 89 |
|
| 90 | + const constrainPosition = (btn, x, y) => { |
| 91 | + const rect = btn.getBoundingClientRect(); |
| 92 | + const viewport = { w: window.innerWidth, h: window.innerHeight }; |
| 93 | + |
| 94 | + const maxX = viewport.w - rect.width; |
| 95 | + const maxY = viewport.h - rect.height; |
| 96 | + |
| 97 | + return { |
| 98 | + x: getMin(x, 0, maxX), |
| 99 | + y: getMin(y, 0, maxY) |
| 100 | + }; |
| 101 | + }; |
| 102 | + |
90 | 103 | const applyButtonPosition = (btn, x, y) => { |
91 | 104 | btn.style.position = 'fixed'; |
92 | 105 | btn.style.right = 'auto'; |
|
212 | 225 | }; |
213 | 226 |
|
214 | 227 | const setupDrag = (btn) => { |
| 228 | + const rect = btn.getBoundingClientRect(); |
| 229 | + const startPos = constrainPosition(btn, rect.left, Math.max(0, rect.top - 50)); |
| 230 | + applyButtonPosition(btn, startPos.x, startPos.y); |
| 231 | + |
215 | 232 | const saved = readSavedPosition(); |
216 | 233 | if (saved) { |
217 | | - applyButtonPosition(btn, saved.x, saved.y); |
| 234 | + const constrained = constrainPosition(btn, saved.x, saved.y); |
| 235 | + applyButtonPosition(btn, constrained.x, constrained.y); |
218 | 236 | } |
219 | 237 |
|
220 | 238 | let dragActive = false; |
|
271 | 289 |
|
272 | 290 | moved = true; |
273 | 291 |
|
274 | | - const maxLeft = window.innerWidth - btn.offsetWidth; |
275 | | - const maxTop = window.innerHeight - btn.offsetHeight; |
276 | | - |
277 | | - const x = getMin(originLeft + dragX, 0, maxLeft); |
278 | | - const y = getMin(originTop + dragY, 0, maxTop); |
279 | | - |
280 | | - applyButtonPosition(btn, x, y); |
| 292 | + const constrained = constrainPosition(btn, originLeft + dragX, originTop + dragY); |
| 293 | + applyButtonPosition(btn, constrained.x, constrained.y); |
281 | 294 | }); |
282 | 295 |
|
283 | 296 | document.addEventListener('mouseup', () => { |
|
295 | 308 | clickBlockOnce = true; |
296 | 309 |
|
297 | 310 | const r = btn.getBoundingClientRect(); |
298 | | - savePosition(r.left, r.top); |
| 311 | + const finalPos = constrainPosition(btn, r.left, r.top); |
| 312 | + applyButtonPosition(btn, finalPos.x, finalPos.y); |
| 313 | + savePosition(finalPos.x, finalPos.y); |
| 314 | + }); |
| 315 | + }; |
| 316 | + |
| 317 | + |
| 318 | + const observeButtonClasses = (btn) => { |
| 319 | + const observer = new MutationObserver((mutations) => { |
| 320 | + if (!btn.classList.contains('hidden')) { |
| 321 | + const rect = btn.getBoundingClientRect(); |
| 322 | + const constrained = constrainPosition(btn, rect.left, rect.top); |
| 323 | + |
| 324 | + if (Math.abs(rect.left - constrained.x) > 1 || Math.abs(rect.top - constrained.y) > 1) { |
| 325 | + applyButtonPosition(btn, constrained.x - 15, constrained.y); |
| 326 | + savePosition(constrained.x, constrained.y); |
| 327 | + } |
| 328 | + } |
| 329 | + }) |
| 330 | + |
| 331 | + observer.observe(btn, { |
| 332 | + attributes: true, |
| 333 | + attributeFilter: ['class'] |
299 | 334 | }); |
300 | 335 | }; |
301 | 336 |
|
302 | 337 | const boot = (btn) => { |
303 | 338 | setupDrag(btn); |
| 339 | + observeButtonClasses(btn); |
304 | 340 |
|
305 | 341 | const windowElement = getWindowEl(); |
306 | 342 | if (windowElement) { |
|
318 | 354 | } else { |
319 | 355 | start(); |
320 | 356 | } |
| 357 | + |
| 358 | + window.addEventListener('resize', () => { |
| 359 | + const btn = getButtonEl(); |
| 360 | + if (btn && isButtonVisible(btn)) { |
| 361 | + const rect = btn.getBoundingClientRect(); |
| 362 | + const constrained = constrainPosition(btn, rect.left, rect.top); |
| 363 | + if (Math.abs(rect.left - constrained.x) > 1 || Math.abs(rect.top - constrained.y) > 1) { |
| 364 | + applyButtonPosition(btn, constrained.x, constrained.y); |
| 365 | + savePosition(constrained.x, constrained.y); |
| 366 | + } |
| 367 | + } |
| 368 | + }); |
321 | 369 | </script> |
322 | 370 | <script> |
323 | 371 | const TARGET_IFRAME_ID = 'gitbook-widget-iframe'; |
|
0 commit comments