diff options
| -rw-r--r-- | src/MenuItem.mjs | 36 | ||||
| -rw-r--r-- | src/css/dumbymap.css | 2 | ||||
| -rw-r--r-- | src/dumbyUtils.mjs | 15 | ||||
| -rw-r--r-- | src/dumbymap.mjs | 41 |
4 files changed, 78 insertions, 16 deletions
diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs index 74b01d5..874c829 100644 --- a/src/MenuItem.mjs +++ b/src/MenuItem.mjs | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | import { shiftByWindow } from './utils.mjs' | 1 | import { shiftByWindow } from './utils.mjs' |
| 2 | import * as utils from './dumbyUtils.mjs' | ||
| 2 | 3 | ||
| 3 | /** | 4 | /** |
| 4 | * @typedef {Object} RefLink | 5 | * @typedef {Object} RefLink |
| @@ -426,3 +427,38 @@ export const addRefLink = (cm, refLinks) => | |||
| 426 | }) | 427 | }) |
| 427 | }), | 428 | }), |
| 428 | }) | 429 | }) |
| 430 | |||
| 431 | /** | ||
| 432 | * setGeoLinkTypeItem. | ||
| 433 | * | ||
| 434 | * @param {HTMLAnchorElement} link | ||
| 435 | * @param {String} text | ||
| 436 | * @param {String} type | ||
| 437 | */ | ||
| 438 | export const setGeoLinkTypeItem = ({ link, text, type }) => { | ||
| 439 | const params = new URLSearchParams(link.search) | ||
| 440 | return new Item({ | ||
| 441 | text, | ||
| 442 | onclick: () => { | ||
| 443 | params.set('type', type) | ||
| 444 | link.search = params | ||
| 445 | utils.removeLeaderLines(link) | ||
| 446 | utils.getMarkersFromMaps(link) | ||
| 447 | .forEach(marker => marker.remove()) | ||
| 448 | utils.getMarkersFromMaps(link) | ||
| 449 | }, | ||
| 450 | }) | ||
| 451 | } | ||
| 452 | |||
| 453 | /** | ||
| 454 | * setGeoLinkType. | ||
| 455 | * | ||
| 456 | * @param {HTMLAnchorElement} link | ||
| 457 | */ | ||
| 458 | export const setGeoLinkType = (link) => new Folder({ | ||
| 459 | text: 'Marker Type', | ||
| 460 | items: [ | ||
| 461 | setGeoLinkTypeItem({ link, text: 'Pin', type: 'pin' }), | ||
| 462 | setGeoLinkTypeItem({ link, text: 'Circle', type: 'circle' }), | ||
| 463 | ], | ||
| 464 | }) | ||
diff --git a/src/css/dumbymap.css b/src/css/dumbymap.css index 8dfe90d..8ba0887 100644 --- a/src/css/dumbymap.css +++ b/src/css/dumbymap.css | |||
| @@ -171,7 +171,7 @@ pre:has(.mapclay) { | |||
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | .menu { | 173 | .menu { |
| 174 | display: block; | 174 | display: none; |
| 175 | overflow: visible; | 175 | overflow: visible; |
| 176 | width: fit-content; | 176 | width: fit-content; |
| 177 | min-width: 10rem; | 177 | min-width: 10rem; |
diff --git a/src/dumbyUtils.mjs b/src/dumbyUtils.mjs index 214e44f..8fe23eb 100644 --- a/src/dumbyUtils.mjs +++ b/src/dumbyUtils.mjs | |||
| @@ -93,7 +93,8 @@ export function removeBlockFocus () { | |||
| 93 | * @param {HTMLAnchorElement} link | 93 | * @param {HTMLAnchorElement} link |
| 94 | * @return {HTMLElement[]} markers | 94 | * @return {HTMLElement[]} markers |
| 95 | */ | 95 | */ |
| 96 | const getMarkersFromMaps = link => { | 96 | export const getMarkersFromMaps = link => { |
| 97 | const params = new URLSearchParams(link.search) | ||
| 97 | const maps = Array.from( | 98 | const maps = Array.from( |
| 98 | link.closest('.Dumby') | 99 | link.closest('.Dumby') |
| 99 | .querySelectorAll('.mapclay[data-render="fulfilled"]'), | 100 | .querySelectorAll('.mapclay[data-render="fulfilled"]'), |
| @@ -107,7 +108,7 @@ const getMarkersFromMaps = link => { | |||
| 107 | const marker = map.querySelector(`.marker[data-xy="${lonLat}"]`) ?? | 108 | const marker = map.querySelector(`.marker[data-xy="${lonLat}"]`) ?? |
| 108 | renderer.addMarker({ | 109 | renderer.addMarker({ |
| 109 | xy: lonLat, | 110 | xy: lonLat, |
| 110 | type: link.type, | 111 | type: params.get('type') ?? null, |
| 111 | }) | 112 | }) |
| 112 | marker.dataset.xy = lonLat | 113 | marker.dataset.xy = lonLat |
| 113 | marker.title = new URLSearchParams(link.search).get('xy') ?? lonLat | 114 | marker.title = new URLSearchParams(link.search).get('xy') ?? lonLat |
| @@ -167,7 +168,6 @@ export const createGeoLink = (link) => { | |||
| 167 | link.classList.remove('not-geolink') | 168 | link.classList.remove('not-geolink') |
| 168 | // TODO refactor as data attribute | 169 | // TODO refactor as data attribute |
| 169 | link.targets = params.get('id')?.split(',') ?? null | 170 | link.targets = params.get('id')?.split(',') ?? null |
| 170 | link.type = params.get('type') ?? null | ||
| 171 | link.title = 'Left-Click to move Camera, Middle-Click to clean anchor' | 171 | link.title = 'Left-Click to move Camera, Middle-Click to clean anchor' |
| 172 | 172 | ||
| 173 | link.lines = [] | 173 | link.lines = [] |
| @@ -385,7 +385,7 @@ export const dragForAnchor = (container, range, endOfLeaderLine) => { | |||
| 385 | container.classList.add('dragging-geolink') | 385 | container.classList.add('dragging-geolink') |
| 386 | const geoLink = document.createElement('a') | 386 | const geoLink = document.createElement('a') |
| 387 | geoLink.textContent = range.toString() | 387 | geoLink.textContent = range.toString() |
| 388 | geoLink.classList.add('with-leader-line', 'geolink', 'drag') | 388 | geoLink.classList.add('with-leader-line', 'geolink', 'drag', 'from-text') |
| 389 | 389 | ||
| 390 | // Replace current content with link | 390 | // Replace current content with link |
| 391 | const originContent = range.cloneContents() | 391 | const originContent = range.cloneContents() |
| @@ -439,6 +439,11 @@ export const dragForAnchor = (container, range, endOfLeaderLine) => { | |||
| 439 | } | 439 | } |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | /** | ||
| 443 | * addGeoSchemeByText. | ||
| 444 | * | ||
| 445 | * @param {Node} node | ||
| 446 | */ | ||
| 442 | export const addGeoSchemeByText = async (node) => { | 447 | export const addGeoSchemeByText = async (node) => { |
| 443 | const digit = '[\\d\\uFF10-\\uFF19]' | 448 | const digit = '[\\d\\uFF10-\\uFF19]' |
| 444 | const decimal = '[.\\uFF0E]' | 449 | const decimal = '[.\\uFF0E]' |
| @@ -451,7 +456,7 @@ export const addGeoSchemeByText = async (node) => { | |||
| 451 | if (Date.parse(match.at(0) + ' 1990')) return null | 456 | if (Date.parse(match.at(0) + ' 1990')) return null |
| 452 | 457 | ||
| 453 | const a = document.createElement('a') | 458 | const a = document.createElement('a') |
| 454 | a.className = 'not-geolink' | 459 | a.className = 'not-geolink from-text' |
| 455 | a.href = `geo:0,0?xy=${x},${y}` | 460 | a.href = `geo:0,0?xy=${x},${y}` |
| 456 | a.textContent = match.at(0) | 461 | a.textContent = match.at(0) |
| 457 | return a | 462 | return a |
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index 8b9a2a6..4d6657f 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs | |||
| @@ -527,25 +527,46 @@ export const generateMaps = (container, { | |||
| 527 | 527 | ||
| 528 | /** MENU: Menu Items for Context Menu */ | 528 | /** MENU: Menu Items for Context Menu */ |
| 529 | container.oncontextmenu = e => { | 529 | container.oncontextmenu = e => { |
| 530 | container.querySelectorAll('.dumby-menu').forEach(m => m.remove()) | ||
| 530 | const map = e.target.closest('.mapclay') | 531 | const map = e.target.closest('.mapclay') |
| 531 | const block = e.target.closest('.dumby-block') | 532 | const block = e.target.closest('.dumby-block') |
| 532 | if (!block && !map) return | 533 | const geoLink = e.target.closest('.geolink') |
| 534 | if (!block && !map && !geoLink) return | ||
| 533 | e.preventDefault() | 535 | e.preventDefault() |
| 534 | 536 | ||
| 535 | /** MENU: Prepare Context Menu */ | 537 | // Add menu element |
| 536 | const menu = document.createElement('div') | 538 | const menu = document.createElement('div') |
| 537 | menu.classList.add('menu', 'dumby-menu') | 539 | menu.classList.add('menu', 'dumby-menu') |
| 538 | menu.onclick = (e) => { | 540 | menu.onclick = (e) => { |
| 539 | const keepMenu = e.target.closest('.keep-menu') || e.target.classList.contains('.keep-menu') | 541 | if (e.target.closest('.keep-menu')) return |
| 540 | if (keepMenu) return | ||
| 541 | |||
| 542 | menu.remove() | 542 | menu.remove() |
| 543 | } | 543 | } |
| 544 | container.body.appendChild(menu) | 544 | container.appendChild(menu) |
| 545 | 545 | new MutationObserver(() => { | |
| 546 | menu.replaceChildren() | 546 | menu.style.display = 'block' |
| 547 | menu.style.display = 'block' | 547 | menu.style.left = (e.clientX - menu.offsetParent.offsetLeft + 10) + 'px' |
| 548 | menu.style.cssText = `left: ${e.clientX - menu.offsetParent.offsetLeft + 10}px; top: ${e.clientY - menu.offsetParent.offsetTop + 5}px;` | 548 | menu.style.top = (e.clientY - menu.offsetParent.offsetTop + 5) + 'px' |
| 549 | clearTimeout(menu.timer) | ||
| 550 | }).observe(menu, { childList: true }) | ||
| 551 | menu.timer = setTimeout(() => menu.remove(), 100) | ||
| 552 | |||
| 553 | // Menu Items for GeoLink | ||
| 554 | if (geoLink) { | ||
| 555 | if (geoLink.classList.contains('from-text')) { | ||
| 556 | menu.appendChild(new menuItem.Item({ | ||
| 557 | text: 'Delete', | ||
| 558 | onclick: () => { | ||
| 559 | utils.getMarkersFromMaps(geoLink) | ||
| 560 | .forEach(m => m.remove()) | ||
| 561 | geoLink.replaceWith( | ||
| 562 | document.createTextNode(geoLink.textContent), | ||
| 563 | ) | ||
| 564 | }, | ||
| 565 | })) | ||
| 566 | } | ||
| 567 | menu.appendChild(menuItem.setGeoLinkType(geoLink)) | ||
| 568 | return | ||
| 569 | } | ||
| 549 | 570 | ||
| 550 | // Menu Items for map | 571 | // Menu Items for map |
| 551 | if (map?.renderer?.results) { | 572 | if (map?.renderer?.results) { |