// module stub to store common functions for ui editors 'use strict'; restoreDefaultEvents(); // apply default viewbox events on load // restore default viewbox events function restoreDefaultEvents() { svg.call(zoom); viewbox.style('cursor', 'default').on('.drag', null).on('click', clicked).on('touchmove mousemove', moved); legend.call(d3.drag().on('start', dragLegendBox)); } // on viewbox click event - run function based on target function clicked() { const el = d3.event.target; if (!el || !el.parentElement || !el.parentElement.parentElement) return; const parent = el.parentElement, grand = parent.parentElement, great = grand.parentElement; const p = d3.mouse(this); const i = findCell(p[0], p[1]); if (grand.id === 'emblems') editEmblem(); else if (parent.id === 'rivers') editRiver(); else if (grand.id === 'routes') editRoute(); else if (el.tagName === 'tspan' && grand.parentNode.parentNode.id === 'labels') editLabel(); else if (grand.id === 'burgLabels') editBurg(); else if (grand.id === 'burgIcons') editBurg(); else if (parent.id === 'ice') editIce(); else if (parent.id === 'terrain') editReliefIcon(); else if (parent.id === 'markers') editMarker(); else if (grand.id === 'coastline') editCoastline(); else if (great.id === 'armies') editRegiment(); else if (pack.cells.t[i] === 1) { const node = document.getElementById('island_' + pack.cells.f[i]); editCoastline(node); } else if (grand.id === 'lakes') editLake(); } // clear elSelected variable function unselect() { restoreDefaultEvents(); if (!elSelected) return; elSelected.call(d3.drag().on('drag', null)).attr('class', null); debug.selectAll('*').remove(); viewbox.style('cursor', 'default'); elSelected = null; } // close all dialogs except stated function closeDialogs(except = '#except') { $('.dialog:visible') .not(except) .each(function () { $(this).dialog('close'); }); } // move brush radius circle function moveCircle(x, y, r = 20) { let circle = document.getElementById('brushCircle'); if (!circle) { const html = ``; document.getElementById('debug').insertAdjacentHTML('afterBegin', html); } else { circle.setAttribute('cx', x); circle.setAttribute('cy', y); circle.setAttribute('r', r); } } function removeCircle() { if (document.getElementById('brushCircle')) document.getElementById('brushCircle').remove(); } // get browser-defined fit-content function fitContent() { return !window.chrome ? '-moz-max-content' : 'fit-content'; } // apply sorting behaviour for lines on Editor header click document.querySelectorAll('.sortable').forEach(function (e) { e.addEventListener('click', function (e) { sortLines(this); }); }); function sortLines(header) { const type = header.classList.contains('alphabetically') ? 'name' : 'number'; let order = header.className.includes('-down') ? '-up' : '-down'; if (!header.className.includes('icon-sort') && type === 'name') order = '-up'; const headers = header.parentNode; headers.querySelectorAll('div.sortable').forEach((e) => { e.classList.forEach((c) => { if (c.includes('icon-sort')) e.classList.remove(c); }); }); header.classList.add('icon-sort-' + type + order); applySorting(headers); } function applySorting(headers) { const header = headers.querySelector("div[class*='icon-sort']"); if (!header) return; const sortby = header.dataset.sortby; const name = header.classList.contains('alphabetically'); const desc = header.className.includes('-down') ? -1 : 1; const list = headers.nextElementSibling; const lines = Array.from(list.children); lines .sort((a, b) => { const an = name ? a.dataset[sortby] : +a.dataset[sortby]; const bn = name ? b.dataset[sortby] : +b.dataset[sortby]; return (an > bn ? 1 : an < bn ? -1 : 0) * desc; }) .forEach((line) => list.appendChild(line)); } function confirmationDialog(options) { const { title = 'Confirm action', message = 'Are you sure you want to continue?
The action cannot be reverted', cancel = 'Cancel', confirm = 'Continue', onCancel = () => {}, onConfirm = () => {} } = options; alertMessage.innerHTML = message; $('#alert').dialog({ resizable: false, title, buttons: { [confirm]: function () { onConfirm(); $(this).dialog('close'); }, [cancel]: function () { onCancel(); $(this).dialog('close'); } } }); } function addBurg(point) { const cells = pack.cells; const x = rn(point[0], 2), y = rn(point[1], 2); const cell = findCell(x, point[1]); const i = pack.burgs.length; const culture = cells.culture[cell]; const name = Names.getCulture(culture); const state = cells.state[cell]; const feature = cells.f[cell]; const temple = pack.states[state].form === 'Theocracy'; const population = Math.max((cells.s[cell] + cells.road[cell]) / 3 + i / 1000 + (cell % 100) / 1000, 0.1); const type = BurgsAndStates.getType(cell, false); // generate emblem const coa = COA.generate(pack.states[state].coa, 0.25, null, type); coa.shield = COA.getShield(culture, state); COArenderer.add('burg', i, coa, x, y); pack.burgs.push({name, cell, x, y, state, i, culture, feature, capital: 0, port: 0, temple, population, coa, type}); cells.burg[cell] = i; const townSize = burgIcons.select('#towns').attr('size') || 0.5; burgIcons .select('#towns') .append('circle') .attr('id', 'burg' + i) .attr('data-id', i) .attr('cx', x) .attr('cy', y) .attr('r', townSize); burgLabels .select('#towns') .append('text') .attr('id', 'burgLabel' + i) .attr('data-id', i) .attr('x', x) .attr('y', y) .attr('dy', `${townSize * -1.5}px`) .text(name); BurgsAndStates.defineBurgFeatures(pack.burgs[i]); return i; } function moveBurgToGroup(id, g) { const label = document.querySelector("#burgLabels [data-id='" + id + "']"); const icon = document.querySelector("#burgIcons [data-id='" + id + "']"); const anchor = document.querySelector("#anchors [data-id='" + id + "']"); if (!label || !icon) { ERROR && console.error('Cannot find label or icon elements'); return; } document.querySelector('#burgLabels > #' + g).appendChild(label); document.querySelector('#burgIcons > #' + g).appendChild(icon); const iconSize = icon.parentNode.getAttribute('size'); icon.setAttribute('r', iconSize); label.setAttribute('dy', `${iconSize * -1.5}px`); if (anchor) { document.querySelector('#anchors > #' + g).appendChild(anchor); const anchorSize = +anchor.parentNode.getAttribute('size'); anchor.setAttribute('width', anchorSize); anchor.setAttribute('height', anchorSize); anchor.setAttribute('x', rn(pack.burgs[id].x - anchorSize * 0.47, 2)); anchor.setAttribute('y', rn(pack.burgs[id].y - anchorSize * 0.47, 2)); } } function removeBurg(id) { const label = document.querySelector("#burgLabels [data-id='" + id + "']"); const icon = document.querySelector("#burgIcons [data-id='" + id + "']"); const anchor = document.querySelector("#anchors [data-id='" + id + "']"); if (label) label.remove(); if (icon) icon.remove(); if (anchor) anchor.remove(); const cells = pack.cells, burg = pack.burgs[id]; burg.removed = true; cells.burg[burg.cell] = 0; if (burg.coa) { const coaId = 'burgCOA' + id; if (document.getElementById(coaId)) document.getElementById(coaId).remove(); emblems.select(`#burgEmblems > use[data-i='${id}']`).remove(); delete burg.coa; // remove to save data } } function toggleCapital(burg) { const state = pack.burgs[burg].state; if (!state) { tip('Neutral lands cannot have a capital', false, 'error'); return; } if (pack.burgs[burg].capital) { tip('To change capital please assign a capital status to another burg of this state', false, 'error'); return; } const old = pack.states[state].capital; // change statuses pack.states[state].capital = burg; pack.states[state].center = pack.burgs[burg].cell; pack.burgs[burg].capital = 1; pack.burgs[old].capital = 0; moveBurgToGroup(burg, 'cities'); moveBurgToGroup(old, 'towns'); } function togglePort(burg) { const anchor = document.querySelector("#anchors [data-id='" + burg + "']"); if (anchor) anchor.remove(); const b = pack.burgs[burg]; if (b.port) { b.port = 0; return; } // not a port anymore const haven = pack.cells.haven[b.cell]; const port = haven ? pack.cells.f[haven] : -1; if (!haven) tip("Port haven is not found, system won't be able to make a searoute", false, 'warn'); b.port = port; const g = b.capital ? 'cities' : 'towns'; const group = anchors.select('g#' + g); const size = +group.attr('size'); group .append('use') .attr('xlink:href', '#icon-anchor') .attr('data-id', burg) .attr('x', rn(b.x - size * 0.47, 2)) .attr('y', rn(b.y - size * 0.47, 2)) .attr('width', size) .attr('height', size); } function toggleBurgLock(burg) { const b = pack.burgs[burg]; b.lock = b.lock ? 0 : 1; } function showBurgLockTip(burg) { const b = pack.burgs[burg]; if (b.lock) { tip('Click to unlock burg and allow it to be change by regeneration tools'); } else { tip('Click to lock burg and prevent changes by regeneration tools'); } } // draw legend box function drawLegend(name, data) { legend.selectAll('*').remove(); // fully redraw every time legend.attr('data', data.join('|')); // store data const itemsInCol = +styleLegendColItems.value; const fontSize = +legend.attr('font-size'); const backClr = styleLegendBack.value; const opacity = +styleLegendOpacity.value; const lineHeight = Math.round(fontSize * 1.7); const colorBoxSize = Math.round(fontSize / 1.7); const colOffset = fontSize; const vOffset = fontSize / 2; // append items const boxes = legend.append('g').attr('stroke-width', 0.5).attr('stroke', '#111111').attr('stroke-dasharray', 'none'); const labels = legend.append('g').attr('fill', '#000000').attr('stroke', 'none'); const columns = Math.ceil(data.length / itemsInCol); for (let column = 0, i = 0; column < columns; column++) { const linesInColumn = Math.ceil(data.length / columns); const offset = column ? colOffset * 2 + legend.node().getBBox().width : colOffset; for (let l = 0; l < linesInColumn && data[i]; l++, i++) { boxes .append('rect') .attr('fill', data[i][1]) .attr('x', offset) .attr('y', lineHeight + l * lineHeight + vOffset) .attr('width', colorBoxSize) .attr('height', colorBoxSize); labels .append('text') .text(data[i][2]) .attr('x', offset + colorBoxSize * 1.6) .attr('y', fontSize / 1.6 + lineHeight + l * lineHeight + vOffset); } } // append label const offset = colOffset + legend.node().getBBox().width / 2; labels .append('text') .attr('text-anchor', 'middle') .attr('font-weight', 'bold') .attr('font-size', '1.2em') .attr('id', 'legendLabel') .text(name) .attr('x', offset) .attr('y', fontSize * 1.1 + vOffset / 2); // append box const bbox = legend.node().getBBox(); const width = bbox.width + colOffset * 2; const height = bbox.height + colOffset / 2 + vOffset; legend.insert('rect', ':first-child').attr('id', 'legendBox').attr('x', 0).attr('y', 0).attr('width', width).attr('height', height).attr('fill', backClr).attr('fill-opacity', opacity); fitLegendBox(); } // fit Legend box to canvas size function fitLegendBox() { if (!legend.selectAll('*').size()) return; const px = isNaN(+legend.attr('data-x')) ? 99 : legend.attr('data-x') / 100; const py = isNaN(+legend.attr('data-y')) ? 93 : legend.attr('data-y') / 100; const bbox = legend.node().getBBox(); const x = rn(svgWidth * px - bbox.width), y = rn(svgHeight * py - bbox.height); legend.attr('transform', `translate(${x},${y})`); } // draw legend with the same data, but using different settings function redrawLegend() { if (!legend.select('rect').size()) return; const name = legend.select('#legendLabel').text(); const data = legend .attr('data') .split('|') .map((l) => l.split(',')); drawLegend(name, data); } function dragLegendBox() { const tr = parseTransform(this.getAttribute('transform')); const x = +tr[0] - d3.event.x, y = +tr[1] - d3.event.y; const bbox = legend.node().getBBox(); d3.event.on('drag', function () { const px = rn(((x + d3.event.x + bbox.width) / svgWidth) * 100, 2); const py = rn(((y + d3.event.y + bbox.height) / svgHeight) * 100, 2); const transform = `translate(${x + d3.event.x},${y + d3.event.y})`; legend.attr('transform', transform).attr('data-x', px).attr('data-y', py); }); } function clearLegend() { legend.selectAll('*').remove(); legend.attr('data', null); } // draw color (fill) picker function createPicker(hatching) { const COLORS_IN_ROW = 14; const pos = () => tip('Drag to change the picker position'); const cl = () => tip('Click to close the picker'); const closePicker = () => container.remove(); const container = d3.select('body').append('svg').attr('id', 'pickerContainer').attr('width', '100%').attr('height', '100%'); container.append('rect').attr('width', '100%').attr('height', '100%').attr('opacity', 0).on('mousemove', cl).on('click', closePicker); const picker = container .append('g') .attr('id', 'picker') .call( d3 .drag() .filter(() => event.target.tagName !== 'INPUT') .on('start', dragPicker) ); const controls = picker.append('g').attr('id', 'pickerControls'); const h = controls.append('g'); h.append('text').attr('x', 4).attr('y', 14).text('H:'); h.append('line').attr('x1', 18).attr('y1', 10).attr('x2', 107).attr('y2', 10); h.append('circle').attr('cx', 75).attr('cy', 10).attr('r', 5).attr('id', 'pickerH'); h.on('mousemove', () => tip('Set palette hue')); const s = controls.append('g'); s.append('text').attr('x', 113).attr('y', 14).text('S:'); s.append('line').attr('x1', 124).attr('y1', 10).attr('x2', 206).attr('y2', 10); s.append('circle').attr('cx', 181.4).attr('cy', 10).attr('r', 5).attr('id', 'pickerS'); s.on('mousemove', () => tip('Set palette saturation')); const l = controls.append('g'); l.append('text').attr('x', 213).attr('y', 14).text('L:'); l.append('line').attr('x1', 226).attr('y1', 10).attr('x2', 306).attr('y2', 10); l.append('circle').attr('cx', 282).attr('cy', 10).attr('r', 5).attr('id', 'pickerL'); l.on('mousemove', () => tip('Set palette lightness')); controls.selectAll('line').on('click', clickPickerControl); controls.selectAll('circle').call(d3.drag().on('start', dragPickerControl)); const spaces = picker .append('foreignObject') .attr('id', 'pickerSpaces') .attr('x', 4) .attr('y', 20) .attr('width', 303) .attr('height', 20) .on('mousemove', () => tip('Color value in different color spaces. Edit to change')); const html = ` `; spaces.node().insertAdjacentHTML('beforeend', html); spaces.selectAll('input').on('change', changePickerSpace); const colors = picker.append('g').attr('id', 'pickerColors').attr('stroke', '#333333'); const clr = d3.range(COLORS_IN_ROW).map((i) => d3.hsl((i / COLORS_IN_ROW) * 360, 0.7, 0.7).hex()); clr.forEach(function (d, i) { colors .append('rect') .attr('id', 'picker_' + d) .attr('fill', d) .attr('class', i ? '' : 'selected') .attr('x', i * 22 + 4) .attr('y', 40) .attr('width', 16) .attr('height', 16); }); colors .selectAll('rect') .on('click', pickerFillClicked) .on('mousemove', () => tip('Click to fill with the color')); if (hatching) { const hatches = picker.append('g').attr('id', 'pickerHatches').attr('stroke', '#333333'); d3.selectAll('g#hatching > pattern').each(function (d, i) { hatches .append('rect') .attr('id', 'picker_' + this.id) .attr('fill', 'url(#' + this.id + ')') .attr('x', i * 22 + 4) .attr('y', 61) .attr('width', 16) .attr('height', 16); }); hatches .selectAll('rect') .on('click', pickerFillClicked) .on('mousemove', () => tip('Click to fill with the hatching')); } // append box const bbox = picker.node().getBBox(); const width = bbox.width + 8; const height = bbox.height + 9; picker.insert('rect', ':first-child').attr('x', 0).attr('y', 0).attr('width', width).attr('height', height).attr('fill', '#ffffff').attr('stroke', '#5d4651').on('mousemove', pos); picker.insert('text', ':first-child').attr('x', 291).attr('y', -10).attr('id', 'pickerCloseText').text('✕'); picker.insert('rect', ':first-child').attr('x', 288).attr('y', -21).attr('id', 'pickerCloseRect').attr('width', 14).attr('height', 14).on('mousemove', cl).on('click', closePicker); picker.insert('text', ':first-child').attr('x', 12).attr('y', -10).attr('id', 'pickerLabel').text('Color Picker').on('mousemove', pos); picker.insert('rect', ':first-child').attr('x', 0).attr('y', -30).attr('width', width).attr('height', 30).attr('id', 'pickerHeader').on('mousemove', pos); picker.attr('transform', `translate(${(svgWidth - width) / 2},${(svgHeight - height) / 2})`); } function updateSelectedRect(fill) { document.getElementById('picker').querySelector('rect.selected').classList.remove('selected'); document .getElementById('picker') .querySelector("rect[fill='" + fill.toLowerCase() + "']") .classList.add('selected'); } function updateSpaces() { // hsl const h = getPickerControl(pickerH, 360); const s = getPickerControl(pickerS, 1); const l = getPickerControl(pickerL, 1); pickerHSL_H.value = rn(h); pickerHSL_S.value = rn(s * 100); // multiplied by 100 pickerHSL_L.value = rn(l * 100); // multiplied by 100 // rgb const rgb = d3.color(d3.hsl(h, s, l)); pickerRGB_R.value = rgb.r; pickerRGB_G.value = rgb.g; pickerRGB_B.value = rgb.b; // hex pickerHEX.value = rgb.hex(); } function updatePickerColors() { const colors = d3.select('#picker > #pickerColors').selectAll('rect'); const number = colors.size(); const h = getPickerControl(pickerH, 360); const s = getPickerControl(pickerS, 1); const l = getPickerControl(pickerL, 1); colors.each(function (d, i) { const clr = d3.hsl((i / number) * 180 + h, s, l).hex(); this.setAttribute('id', 'picker_' + clr); this.setAttribute('fill', clr); }); } function openPicker(fill, callback, options = {allowHatching: true}) { createPicker(options.allowHatching); if (fill[0] === '#') { const hsl = d3.hsl(fill); if (!isNaN(hsl.h)) setPickerControl(pickerH, hsl.h, 360); if (!isNaN(hsl.s)) setPickerControl(pickerS, hsl.s, 1); if (!isNaN(hsl.l)) setPickerControl(pickerL, hsl.l, 1); updateSpaces(); updatePickerColors(); } updateSelectedRect(fill); openPicker.updateFill = function () { const selected = document.getElementById('picker').querySelector('rect.selected'); if (!selected) return; callback(selected.getAttribute('fill')); }; } function setPickerControl(control, value, max) { const min = +control.previousSibling.getAttribute('x1'); const delta = +control.previousSibling.getAttribute('x2') - min; const percent = value / max; control.setAttribute('cx', min + delta * percent); } function getPickerControl(control, max) { const min = +control.previousSibling.getAttribute('x1'); const delta = +control.previousSibling.getAttribute('x2') - min; const current = +control.getAttribute('cx') - min; return (current / delta) * max; } function dragPicker() { const tr = parseTransform(this.getAttribute('transform')); const x = +tr[0] - d3.event.x, y = +tr[1] - d3.event.y; const picker = d3.select('#picker'); const bbox = picker.node().getBBox(); d3.event.on('drag', function () { const px = rn(((x + d3.event.x + bbox.width) / svgWidth) * 100, 2); const py = rn(((y + d3.event.y + bbox.height) / svgHeight) * 100, 2); const transform = `translate(${x + d3.event.x},${y + d3.event.y})`; picker.attr('transform', transform).attr('data-x', px).attr('data-y', py); }); } function pickerFillClicked() { const fill = this.getAttribute('fill'); updateSelectedRect(fill); openPicker.updateFill(); const hsl = d3.hsl(fill); if (isNaN(hsl.h)) return; // not a color setPickerControl(pickerH, hsl.h, 360); updateSpaces(); } function clickPickerControl() { const min = this.getScreenCTM().e; this.nextSibling.setAttribute('cx', d3.event.x - min); updateSpaces(); updatePickerColors(); openPicker.updateFill(); } function dragPickerControl() { const min = +this.previousSibling.getAttribute('x1'); const max = +this.previousSibling.getAttribute('x2'); d3.event.on('drag', function () { const x = Math.max(Math.min(d3.event.x, max), min); this.setAttribute('cx', x); updateSpaces(); updatePickerColors(); openPicker.updateFill(); }); } function changePickerSpace() { const valid = this.checkValidity(); if (!valid) { tip('You must provide a correct value', false, 'error'); return; } const space = this.dataset.space; const i = Array.from(this.parentNode.querySelectorAll('input')).map((input) => input.value); // inputs const fill = space === 'hex' ? d3.rgb(this.value) : space === 'rgb' ? d3.rgb(i[0], i[1], i[2]) : d3.hsl(i[0], i[1] / 100, i[2] / 100); const hsl = d3.hsl(fill); if (isNaN(hsl.l)) { tip('You must provide a correct value', false, 'error'); return; } if (!isNaN(hsl.h)) setPickerControl(pickerH, hsl.h, 360); if (!isNaN(hsl.s)) setPickerControl(pickerS, hsl.s, 1); if (!isNaN(hsl.l)) setPickerControl(pickerL, hsl.l, 1); updateSpaces(); updatePickerColors(); openPicker.updateFill(); } // add fogging function fog(id, path) { if (defs.select('#fog #' + id).size()) return; const fadeIn = d3.transition().duration(2000).ease(d3.easeSinInOut); if (defs.select('#fog path').size()) { defs.select('#fog').append('path').attr('d', path).attr('id', id).attr('opacity', 0).transition(fadeIn).attr('opacity', 1); } else { defs.select('#fog').append('path').attr('d', path).attr('id', id).attr('opacity', 1); const opacity = fogging.attr('opacity'); fogging.style('display', 'block').attr('opacity', 0).transition(fadeIn).attr('opacity', opacity); } } // remove fogging function unfog(id) { let el = defs.select('#fog #' + id); if (!id || !el.size()) el = defs.select('#fog').selectAll('path'); el.remove(); if (!defs.selectAll('#fog path').size()) fogging.style('display', 'none'); } function getFileName(dataType) { const formatTime = (time) => (time < 10 ? '0' + time : time); const name = mapName.value; const type = dataType ? dataType + ' ' : ''; const date = new Date(); const year = date.getFullYear(); const month = formatTime(date.getMonth() + 1); const day = formatTime(date.getDate()); const hour = formatTime(date.getHours()); const minutes = formatTime(date.getMinutes()); const dateString = [year, month, day, hour, minutes].join('-'); return name + ' ' + type + dateString; } function downloadFile(data, name, type = 'text/plain') { const dataBlob = new Blob([data], {type}); const url = window.URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.download = name; link.href = url; link.click(); window.setTimeout(() => window.URL.revokeObjectURL(url), 2000); } function uploadFile(el, callback) { const fileReader = new FileReader(); fileReader.readAsText(el.files[0], 'UTF-8'); el.value = ''; fileReader.onload = (loaded) => callback(loaded.target.result); } function highlightElement(element) { if (debug.select('.highlighted').size()) return; // allow only 1 highlight element simultaniosly const box = element.getBBox(); const transform = element.getAttribute('transform') || null; const enter = d3.transition().duration(1000).ease(d3.easeBounceOut); const exit = d3.transition().duration(500).ease(d3.easeLinear); const highlight = debug.append('rect').attr('x', box.x).attr('y', box.y).attr('width', box.width).attr('height', box.height).attr('transform', transform); highlight.classed('highlighted', 1).transition(enter).style('outline-offset', '0px').transition(exit).style('outline-color', 'transparent').delay(1000).remove(); const tr = parseTransform(transform); let x = box.x + box.width / 2; if (tr[0]) x += tr[0]; let y = box.y + box.height / 2; if (tr[1]) y += tr[1]; zoomTo(x, y, scale > 2 ? scale : 3, 1600); } function selectIcon(initial, callback) { if (!callback) return; $('#iconSelector').dialog(); const table = document.getElementById('iconTable'); const input = document.getElementById('iconInput'); input.value = initial; if (!table.innerHTML) { const icons = [ '⚔️', '🏹', '🐴', '💣', '🌊', '🎯', '⚓', '🔮', '📯', '⚒️', '🛡️', '👑', '⚜️', '☠️', '🎆', '🗡️', '🔪', '⛏️', '🔥', '🩸', '💧', '🐾', '🎪', '🏰', '🏯', '⛓️', '❤️', '💘', '💜', '📜', '🔔', '🔱', '💎', '🌈', '🌠', '✨', '💥', '☀️', '🌙', '⚡', '❄️', '♨️', '🎲', '🚨', '🌉', '🗻', '🌋', '🧱', '⚖️', '✂️', '🎵', '👗', '🎻', '🎨', '🎭', '⛲', '💉', '📖', '📕', '🎁', '💍', '⏳', '🕸️', '⚗️', '☣️', '☢️', '🔰', '🎖️', '🚩', '🏳️', '🏴', '💪', '✊', '👊', '🤜', '🤝', '🙏', '🧙', '🧙‍♀️', '💂', '🤴', '🧛', '🧟', '🧞', '🧝', '👼', '👻', '👺', '👹', '🦄', '🐲', '🐉', '🐎', '🦓', '🐺', '🦊', '🐱', '🐈', '🦁', '🐯', '🐅', '🐆', '🐕', '🦌', '🐵', '🐒', '🦍', '🦅', '🕊️', '🐓', '🦇', '🦜', '🐦', '🦉', '🐮', '🐄', '🐂', '🐃', '🐷', '🐖', '🐗', '🐏', '🐑', '🐐', '🐫', '🦒', '🐘', '🦏', '🐭', '🐁', '🐀', '🐹', '🐰', '🐇', '🦔', '🐸', '🐊', '🐢', '🦎', '🐍', '🐳', '🐬', '🦈', '🐠', '🐙', '🦑', '🐌', '🦋', '🐜', '🐝', '🐞', '🦗', '🕷️', '🦂', '🦀', '🌳', '🌲', '🎄', '🌴', '🍂', '🍁', '🌵', '☘️', '🍀', '🌿', '🌱', '🌾', '🍄', '🌽', '🌸', '🌹', '🌻', '🍒', '🍏', '🍇', '🍉', '🍅', '🍓', '🥔', '🥕', '🥩', '🍗', '🍞', '🍻', '🍺', '🍲', '🍷' ]; let row = ''; for (let i = 0; i < icons.length; i++) { if (i % 17 === 0) row = table.insertRow((i / 17) | 0); const cell = row.insertCell(i % 17); cell.innerHTML = icons[i]; } } table.onclick = (e) => { if (e.target.tagName === 'TD') { input.value = e.target.innerHTML; callback(input.value); } }; table.onmouseover = (e) => { if (e.target.tagName === 'TD') tip(`Click to select ${e.target.innerHTML} icon`); }; $('#iconSelector').dialog({ width: fitContent(), title: 'Select Icon', buttons: { Apply: function () { callback(input.value || '⠀'); $(this).dialog('close'); }, Close: function () { callback(initial); $(this).dialog('close'); } } }); } // Calls the refresh for all currently open editors function refreshAllEditors() { if (document.getElementById('culturesEditorRefresh').offsetParent) culturesEditorRefresh.click(); if (document.getElementById('biomesEditorRefresh').offsetParent) biomesEditorRefresh.click(); if (document.getElementById('diplomacyEditorRefresh').offsetParent) diplomacyEditorRefresh.click(); if (document.getElementById('provincesEditorRefresh').offsetParent) provincesEditorRefresh.click(); if (document.getElementById('religionsEditorRefresh').offsetParent) religionsEditorRefresh.click(); if (document.getElementById('statesEditorRefresh').offsetParent) statesEditorRefresh.click(); if (document.getElementById('zonesEditorRefresh').offsetParent) zonesEditorRefresh.click(); if (document.getElementById('resourcesEditorRefresh').offsetParent) resourcesEditorRefresh.click(); }