From f4fe9ff6c1ce2811fe9aa0272333b4732a6ebcdc Mon Sep 17 00:00:00 2001 From: Hsieh Chin Fan Date: Mon, 30 Sep 2024 17:59:05 +0800 Subject: refactor: move menu feature from editor to dumbymap --- src/MenuItem.mjs | 5 +++- src/css/dumbymap.css | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/css/index.css | 67 -------------------------------------------------- src/dumbymap.mjs | 51 ++++++++++++++++++++++++++++++++++++++ src/editor.mjs | 34 -------------------------- 5 files changed, 123 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs index f4cd518..74138ec 100644 --- a/src/MenuItem.mjs +++ b/src/MenuItem.mjs @@ -89,7 +89,10 @@ export const pickLayoutItem = dumbymap => items: [ new Item({ text: 'EDIT', - onclick: () => document.body.setAttribute('data-mode', 'editing'), + onclick: () => + dumbymap.container + .closest('.playground') + .setAttribute('data-mode', 'editing'), }).element, ...dumbymap.layouts.map( layout => diff --git a/src/css/dumbymap.css b/src/css/dumbymap.css index f6275ab..822353f 100644 --- a/src/css/dumbymap.css +++ b/src/css/dumbymap.css @@ -226,7 +226,7 @@ root { padding: 0; position: relative; - overflow-x: auto; + overflow: visible; &::after { content: 'Layout: ' attr(data-layout); @@ -609,3 +609,70 @@ root { .bold-options { font-weight: bold; } + +.menu { + display: none; + width: fit-content; + + position: absolute; + z-index: 9999; + + border: 2px solid gray; + border-radius: 6px; + + background: white; + min-width: 10rem; + max-height: 40vh; + overflow-y: scroll; +} + +.menu-item { + display: flex; + box-sizing: border-box; + justify-content: space-between; + padding: 0.5rem; + + z-index: 9999; + + border: 2px solid transparent; + border-radius: 5px; + + cursor: pointer; + text-wrap: nowrap; + + &:hover { + background: rgb(226 232 240); + } + + .info { + padding-inline: 1em; + + color: steelblue; + font-weight: bold; + } +} + +.folder::after { + content: '⏵'; +} + +.sub-menu { + overflow: scroll; + width: fit-content; + + position: absolute; + z-index: 100; + + border: 2px solid gray; + border-radius: 6px; + + background: white; + min-width: 6rem; + max-height: 40vh; + + .menu-item { + margin: 0 auto; + padding-inline: 0.5em; + min-width: 5em; + } +} diff --git a/src/css/index.css b/src/css/index.css index 069bf85..b13a45d 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -104,22 +104,6 @@ body { } } -#menu { - display: none; - width: fit-content; - - position: absolute; - z-index: 9999; - - border: 2px solid gray; - border-radius: 6px; - - background: white; - min-width: 10rem; - max-height: 40vh; - overflow-y: scroll; -} - .container__suggestion { display: flex; overflow: hidden; @@ -161,54 +145,3 @@ body { } } } - -.menu-item { - display: flex; - box-sizing: border-box; - justify-content: space-between; - padding: 0.5rem; - - z-index: 9999; - - border: 2px solid transparent; - border-radius: 5px; - - cursor: pointer; - text-wrap: nowrap; - - &:hover { - background: rgb(226 232 240); - } - - .info { - padding-inline: 1em; - - color: steelblue; - font-weight: bold; - } -} - -.folder::after { - content: '⏵'; -} - -.sub-menu { - overflow: scroll; - width: fit-content; - - position: absolute; - z-index: 100; - - border: 2px solid gray; - border-radius: 6px; - - background: white; - min-width: 6rem; - max-height: 40vh; - - .menu-item { - margin: 0 auto; - padding-inline: 0.5em; - min-width: 5em; - } -} diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index 67376c7..d365712 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs @@ -8,6 +8,7 @@ import { renderWith, defaultAliases, parseConfigsFromYaml } from 'mapclay'; import { onRemove, animateRectTransition, throttle } from './utils'; import { Layout, SideBySide, Overlay } from './Layout'; import * as utils from './dumbyUtils'; +import * as menuItem from './MenuItem'; const docLinkSelector = 'a[href^="#"][title^="=>"]'; const geoLinkSelector = 'a[href^="geo:"]'; @@ -520,7 +521,57 @@ export const generateMaps = (container, { delay, mapCallback }) => { clearTimeout(timer); }); }); + // }}} + + // Menu {{{ + const menu = document.createElement('div'); + menu.className = 'menu'; + menu.onclick = () => (menu.style.display = 'none'); + new MutationObserver(() => { + if (menu.style.display === 'none') { + menu.style.cssText = ''; + menu.replaceChildren(); + } + }).observe(menu, { + attributes: true, + attributeFilter: ['style'], + }); + container.appendChild(menu); + + // Menu Items + container.oncontextmenu = e => { + const selection = document.getSelection(); + const range = selection.getRangeAt(0); + if (selection) { + e.preventDefault(); + menu.innerHTML = ''; + const addGeoLink = new menuItem.GeoLink({ range }); + menu.appendChild(addGeoLink.createElement()); + } + menu.style.cssText = `overflow: visible; display: block; left: ${e.clientX + 10}px; top: ${e.clientY + 5}px;`; + menu.appendChild(menuItem.modal); + menu.appendChild(menuItem.pickMapItem(dumbymap)); + menu.appendChild(menuItem.pickBlockItem(dumbymap)); + menu.appendChild(menuItem.pickLayoutItem(dumbymap)); + }; + // Remove menu when click outside + const actionOutsideMenu = e => { + if (menu.style.display === 'none') return; + const rect = menu.getBoundingClientRect(); + if ( + e.clientX < rect.left || + e.clientX > rect.left + rect.width || + e.clientY < rect.top || + e.clientY > rect.top + rect.height + ) { + menu.style.display = 'none'; + } + }; + document.addEventListener('click', actionOutsideMenu); + onRemove(htmlHolder, () => + document.removeEventListener('click', actionOutsideMenu), + ); //}}} return Object.seal(dumbymap); }; diff --git a/src/editor.mjs b/src/editor.mjs index 9946686..760e2e1 100644 --- a/src/editor.mjs +++ b/src/editor.mjs @@ -660,40 +660,6 @@ layoutObserver.observe(HtmlContainer, { attributeFilter: ['data-layout'], attributeOldValue: true, }); -// }}} -// ContextMenu {{{ -document.oncontextmenu = e => { - if (cm.hasFocus()) return; - - const selection = document.getSelection(); - const range = selection.getRangeAt(0); - if (selection) { - e.preventDefault(); - menu.innerHTML = ''; - const addGeoLink = new menuItem.GeoLink({ range }); - menu.appendChild(addGeoLink.createElement()); - } - menu.style.cssText = `overflow: visible; display: block; left: ${e.clientX + 10}px; top: ${e.clientY + 5}px;`; - menu.appendChild(menuItem.pickMapItem(dumbymap)); - menu.appendChild(menuItem.pickBlockItem(dumbymap)); - menu.appendChild(menuItem.pickLayoutItem(dumbymap)); -}; - -const actionOutsideMenu = e => { - if (menu.style.display === 'none' || cm.hasFocus()) return; - const rect = menu.getBoundingClientRect(); - if ( - e.clientX < rect.left || - e.clientX > rect.left + rect.width || - e.clientY < rect.top || - e.clientY > rect.top + rect.height - ) { - menu.style.display = 'none'; - } -}; - -document.addEventListener('click', actionOutsideMenu); - // }}} // vim: sw=2 ts=2 foldmethod=marker foldmarker={{{,}}} -- cgit v1.2.3-70-g09d2