diff --git a/src/app/components/panels/TreePanel.ts b/src/app/components/panels/TreePanel.ts index ffc9bcfd..62124004 100644 --- a/src/app/components/panels/TreePanel.ts +++ b/src/app/components/panels/TreePanel.ts @@ -7,36 +7,6 @@ import { renderHtml } from '../../hooks/renderHtml'; import config from '../../../config.json' import { BiomeNoisePreview } from '../../preview/BiomeNoisePreview'; -const createPopupIcon = (type: string, icon: keyof typeof Octicon, popup: string) => { - const div = document.createElement('div') - div.className = `node-icon ${type}` - div.addEventListener('click', evt => { - div.getElementsByTagName('span')[0].classList.add('show') - document.body.addEventListener('click', evt => { - div.getElementsByTagName('span')[0].classList.remove('show') - }, { capture: true, once: true }) - }) - div.insertAdjacentHTML('beforeend', `${popup}${Octicon[icon]}`) - return div -} - -const treeViewObserver = (el: Element) => { - el.querySelectorAll('.node[data-help]').forEach(e => { - e.querySelector('.node-header')?.appendChild( - createPopupIcon('node-help', 'info', e.getAttribute('data-help') ?? '')) - }) - el.querySelectorAll('.node[data-error]').forEach(e => { - e.querySelector('.node-header')?.appendChild( - createPopupIcon('node-error', 'issue_opened', e.getAttribute('data-error') ?? '')) - }) - el.querySelectorAll('.collapse.closed, button.add').forEach(e => { - e.insertAdjacentHTML('afterbegin', Octicon.plus_circle) - }) - el.querySelectorAll('.collapse.open, button.remove').forEach(e => { - e.insertAdjacentHTML('afterbegin', Octicon.trashcan) - }) -} - export const TreePanel = (view: View, model: DataModel) => { const getContent = () => { if (App.loaded.get()) { @@ -53,30 +23,26 @@ export const TreePanel = (view: View, model: DataModel) => { } return '
' } - const mountContent = (el: Element) => { - view.mount(el, getContent(), false) - treeViewObserver(el) - } const tree = view.register(el => { App.loaded.watchRun((value) => { if (!value) { // If loading is taking more than 100 ms, show spinner new Promise(r => setTimeout(r, 100)).then(() => { if (!App.loaded.get()) { - mountContent(el) + view.mount(el, getContent(), false) } }) } else { - mountContent(el) + view.mount(el, getContent(), false) } }) model.addListener({ invalidated() { - mountContent(el) + view.mount(el, getContent(), false) } }) ;(Previews.biome_noise as BiomeNoisePreview).biomeColors.watch(() => { - mountContent(el) + view.mount(el, getContent(), false) }, 'tree-panel') }) return `
diff --git a/src/app/hooks/renderHtml.ts b/src/app/hooks/renderHtml.ts index 50a56db9..6de177e6 100644 --- a/src/app/hooks/renderHtml.ts +++ b/src/app/hooks/renderHtml.ts @@ -3,6 +3,7 @@ import { locale, segmentedLocale } from '../Locales' import { Mounter } from '../views/View' import { hexId, htmlEncode } from '../Utils' import { suffixInjector } from './suffixInjector' +import { Octicon } from '../components/Octicon' /** * Secondary model used to remember the keys of a map @@ -69,7 +70,7 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { if (!Array.isArray(value)) value = [] path.model.set(path, [...value, children.default()]) }) - const suffix = `` + const suffix = `` let body = '' if (Array.isArray(value)) { @@ -78,12 +79,14 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { const childPath = path.push(index).contextPush('entry') const category = children.category(childPath) const [cPrefix, cSuffix, cBody] = children.hook(this, childPath, childValue, mounter) - return `
+ return `
- + ${cPrefix} ${cSuffix} + ${error(childPath, mounter)} + ${help(childPath, mounter)}
${cBody ? `
${cBody}
` : ''}
` @@ -91,7 +94,7 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { if (value.length > 2) { body += `
- +
` } @@ -106,7 +109,7 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { path.model.set(path.push(key), children.default()) }) const keyRendered = keys.hook(this, keyPath, keyPath.get() ?? '', mounter) - const suffix = keyRendered[1] + `` + const suffix = keyRendered[1] + `` let body = '' if (typeof value === 'object' && value !== undefined) { body = Object.keys(value) @@ -115,12 +118,14 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { const childPath = path.modelPush(key) const category = children.category(childPath) const [cPrefix, cSuffix, cBody] = children.hook(this, childPath, value[key], mounter) - return `
+ return `
- + ${cPrefix} ${cSuffix} + ${error(childPath, mounter)} + ${help(childPath, mounter)}
${cBody ? `
${cBody}
` : ''}
` @@ -149,9 +154,9 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { let prefix = '' if (node.optional()) { if (value === undefined) { - prefix = `` + prefix = `` } else { - prefix = `` + prefix = `` } } let suffix = node.hook(suffixInjector, path, mounter) || '' @@ -166,11 +171,13 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = { const childPath = getChildModelPath(path, k) const category = field.category(childPath) const [cPrefix, cSuffix, cBody] = field.hook(this, childPath, value[k], mounter) - return `
+ return `
${cPrefix} ${cSuffix} + ${error(childPath, mounter)} + ${help(childPath, mounter)}
${cBody ? `
${cBody}
` : ''}
` @@ -253,14 +260,26 @@ function pathLocale(path: Path, params?: string[]): string { ?? path.getContext()[path.getContext().length - 1] ?? '' } -function error(p: ModelPath, exact = true) { - const errors = p.model.errors.get(p, exact) +function error(p: ModelPath, mounter: Mounter) { + const errors = p.model.errors.get(p, true) if (errors.length === 0) return '' - return `data-error="${htmlEncode(locale(errors[0].error, errors[0].params))}"` + return popupIcon('node-error', 'issue_opened', htmlEncode(locale(errors[0].error, errors[0].params)), mounter) } -function help(path: ModelPath) { +function help(path: ModelPath, mounter: Mounter) { const message = segmentedLocale(path.contextPush('help').getContext(), [], 6) if (message === undefined) return '' - return `data-help="${htmlEncode(message)}"` + return popupIcon('node-help', 'info', htmlEncode(message), mounter) +} + +const popupIcon = (type: string, icon: keyof typeof Octicon, popup: string, mounter: Mounter) => { + const onClick = mounter.onClick(el => { + el.getElementsByTagName('span')[0].classList.add('show') + document.body.addEventListener('click', () => { + el.getElementsByTagName('span')[0].classList.remove('show') + }, { capture: true, once: true }) + }) + return `
+ ${popup}${Octicon[icon]} +
` }