MOFA/js/ui.js
익희 김 204aadf2d8 수정
2024-11-29 08:14:01 +09:00

371 lines
13 KiB
JavaScript

function uiGnbHandler() {
/**
* .menu-first-depth, mouseenter일때 함수 작동
* 문서의 header 찾음
* secondDeptSelector의 각 자식요소의 갯수의 max를 받아서
* header에 data-sub에 넣고 이를 css에서 높이 결정을 함
*
*/
const headerSelector = document.getElementsByTagName('header')[0];
const secondDeptSelector = Array.from(headerSelector.getElementsByClassName('menu-second-depth'));
const childrenLengthArray = secondDeptSelector.map((i) => i.children.length);
const maxChildren = Math.max(...childrenLengthArray);
headerSelector.setAttribute('open', 'true');
headerSelector.style.setProperty('--max-length', maxChildren)
secondDeptSelector.forEach(element => {
element.setAttribute('open', 'true');
});
headerSelector.addEventListener('mouseleave', () => {
headerSelector.setAttribute('open', 'false');
secondDeptSelector.forEach(element => {
element.setAttribute('open', 'false');
});
});
}
function uiAttrOpen({ selector, state }) {
if (state === 'set') {
selector.setAttribute('open', '');
} else {
selector.removeAttribute('open');
}
}
function uiTableCollapseHandler(event) {
/**
* 함수는 table > tbody > tr > td > details 위치에 onClick으로 작동해야함
* html ui구조는 table > tbody > tr > td > details > summary 구조
* details 태그의 open 상태에 따라 attribute의 open set 또는 remove
*/
const parentTd = event.target.offsetParent;
const parentTr = parentTd.offsetParent;
const isDetailOpen = parentTd.children[0].open;
parentTr.toggleAttribute('open', !isDetailOpen);
}
function uiTableCollapseAllHandler(event) {
const targetData = event.target.dataset;
const dataSet = targetData.state;
const tbodySelector = document.getElementsByTagName('tbody')[0];
const trSelector = Array.from(tbodySelector.querySelectorAll('tr'));
const trWithDetails = trSelector.filter(tr => tr.querySelector('details'));
trWithDetails.forEach(tr => {
const details = tr.querySelector('details');
if (details) {
dataSet === 'close' ?
(
uiAttrOpen({ selector: tr, state: 'set' }),
uiAttrOpen({ selector: details, state: 'set' }),
event.target.setAttribute('data-state', 'open'),
event.target.textContent = '전체 닫기'
)
: (
uiAttrOpen({ selector: tr, state: 'remove' }),
uiAttrOpen({ selector: details, state: 'remove' }),
event.target.setAttribute('data-state', 'close'),
event.target.textContent = '전체 열기'
)
}
});
}
function uiModalOpenHandler(event) {
const currentTarget = event.target;
const targetModal = currentTarget.offsetParent;
const isOpen = targetModal.dataset.state;
if (isOpen !== undefined && isOpen === 'open') {
targetModal.setAttribute('data-state', 'close');
}
if (isOpen === undefined) {
const getDataSet = currentTarget.dataset.modal;
const modalElement = document.querySelector(`[data-modal="${getDataSet}"].modal`);
if (modalElement) {
modalElement.setAttribute('data-state', 'open');
}
}
}
function uiScrollHandler(event) {
const currentScrollPosition = document.scrollingElement.scrollTop;
const indicatorSelector = document.getElementsByClassName('indicators')[0];
const articles = Array.from(indicatorSelector.getElementsByClassName('editor-article'));
const indicatorLinks = Array.from(document.querySelectorAll('.editor-indicator a'));
articles.forEach((article, index) => {
const articleTop = article.offsetTop;
const articleHeight = article.offsetHeight;
const nextArticleTop = index < articles.length - 1 ? articles[index + 1].offsetTop : document.body.scrollHeight;
if (currentScrollPosition >= articleTop && currentScrollPosition < nextArticleTop) {
indicatorLinks.forEach(link => link.removeAttribute('current'));
const correspondingLink = indicatorLinks.find(link => link.getAttribute('href') === `#${article.id}`);
if (correspondingLink) {
correspondingLink.setAttribute('current', '');
}
}
});
}
function uiDropZoneHandler() {
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const fileList = document.getElementById('fileList');
dropZone.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', uiUpdateFileList);
dropZone.addEventListener('dragover', (event) => {
event.preventDefault();
dropZone.classList.add('hover');
});
dropZone.addEventListener('dragleave', () => dropZone.classList.remove('hover'));
dropZone.addEventListener('drop', (event) => {
event.preventDefault();
dropZone.classList.remove('hover');
const files = Array.from(event.dataTransfer.files);
fileInput.files = new DataTransfer().files;
Array.from(files).forEach(file => fileInput.files = new DataTransfer().files.add(file));
uiUpdateFileList(files);
});
}
function uiUpdateFileList(files = Array.from(fileInput.files)) {
fileList.innerHTML = '';
Array.from(files).forEach(file => {
const listItem = document.createElement('div');
listItem.textContent = `${file.name} - ${Math.round(file.size / 1024)} KB`;
fileList.appendChild(listItem);
});
}
function uiEventCalendarHandler() {
/**
* 주요일정 캘린더 .event-dot 요소 찾아 배열
*
* [HTML영역]
* <div class="event-dot" style="--background-color:..." data-title="..." data-desc="..." />
* 로 되어 있어야함.
* 각 요소 mouseenter가 되었을때 .event-hint 요소 생성
* dataSet의 data-title, data-desc을 가져와서 event-hint 요소에 출력
* style의 --background-color에 색상값을 넣으면 css변수를 이용하여
* event-dot의 동그라미 요소와 event-hint에 같이 색상 출력
*
*/
const eventDotElements = document.querySelectorAll('.event-dot');
eventDotElements.forEach((i) => {
i.addEventListener('mouseenter', (j) => {
const title = j.target.getAttribute('data-title');
const desc = j.target.getAttribute('data-desc');
const hintElement = document.createElement('div');
hintElement.classList.add('event-hint');
hintElement.innerHTML = `
<div>
<p>${title}</p>
<p>${desc}</p>
</div>
`;
j.target.appendChild(hintElement);
});
i.addEventListener('mouseleave', (j) => {
const hintElement = j.target.querySelector('.event-hint');
if (hintElement) {
hintElement.remove();
}
});
});
}
function uiSelectorRenderer(style) {
/**
* <select>...</select> HTML요소를
* <details><summary>...</summary></details>로 변경
* <select>에 disappear 클래스를 추가하여 안보이게 처리함
* 24-11-18 dataSet에 width추가
* 24-11-28 외부 클릭 시 모든 open 속성 제거
*/
const styleClass = style ? style : 'default';
const selectElement = document.querySelectorAll('select');
selectElement.forEach((i, index) => {
i.classList.add('disappear');
i.classList.add(`origin-select-${index}`);
const dataWidth = i.dataset.width ? `${i.dataset.width}px` : 'auto';
const optionsElement = Array.from(i.options);
const element = document.createElement('div');
element.classList.add('render-select');
element.classList.add(styleClass);
element.style.width = dataWidth;
element.innerHTML =
`<details onclick="uiRenderedHandler(event)">` +
`<summary class="render-select-${index}">${optionsElement[0].label}</summary>` +
`<div class="render-options">` +
optionsElement.map((option, index) => {
return `<div data-index="${index}" data-label="${option.label}" data-value="${option.value}">${option.label}</div>`;
}).join('');
+ `</div>`
i.insertAdjacentElement('beforebegin', element);
+ '</details>'
});
document.addEventListener('click', (event) => {
const detailsElements = document.querySelectorAll('details[open]');
detailsElements.forEach((details) => {
if (!details.contains(event.target)) {
details.removeAttribute('open');
}
});
});
}
function uiRenderedHandler(event) {
/**
* uiSelectorRenderer()로 변경된 <details>요소가 변경될때
* <select>의 요소도 같이 변경
* <select>는 onchange메소드가 아닌 onclick메소드로 처리해 줘야함
* 그러면 select의 변경 이벤트를 처리할 수 있음
* ex) X <select onchange="console.log(event)">
* O <select onclick="console.log(event)">
*/
const eventParentElement = event.target.parentElement;
const options = eventParentElement.classList.value;
const isOptions = options === 'render-options';
if (isOptions) {
const eventTargetIndex = event.target.parentNode.parentNode.parentNode.nextSibling.classList.value.split('-')[2];
const eventSibilingSelect = document.querySelector(`.origin-select-${eventTargetIndex}`)
const isDetailElement = event.target.parentElement.parentElement;
const summaryElement = isDetailElement.children[0];
const dataLabel = event.target.dataset.label;
const dataIndex = event.target.dataset.index;
isDetailElement && isDetailElement.removeAttribute('open');
eventSibilingSelect.selectedIndex = dataIndex;
summaryElement.innerHTML = dataLabel;
eventSibilingSelect.click();
}
}
function uiSpinnerSizeHandler(selector, callback) {
const targetElement = document.querySelector(selector);
if (!targetElement) {
return;
}
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
callback();
observer.unobserve(entry.target);
}
});
});
observer.observe(targetElement);
}
function uiCalcSetSpaceHeight(selector) {
const defaultSelector = selector ? selector : '.spinner-wrap';
const windowInnerHeight = window.innerHeight;
const bodyHeight = document.body.clientHeight;
const targetElement = document.querySelector(defaultSelector);
if (!targetElement) {
absoluteFooter.classList.remove('absolute')
return;
}
const remainingHeight = windowInnerHeight - bodyHeight;
if (remainingHeight > 0) {
targetElement.style.height = `${remainingHeight}px`;
const absoluteFooter = document.querySelector('footer');
absoluteFooter.classList.add('absolute')
} else {
targetElement.style.height = 'auto';
}
}
function uiColumnChartRender({ selector, data }) {
am5.ready(function () {
const root = am5.Root.new(selector);
root.setThemes([
am5themes_Animated.new(root)
]);
const chart = root.container.children.push(
am5xy.XYChart.new(root, {
panX: false,
panY: false,
// wheelX: "panX",
// wheelY: "zoomX",
// pinchZoomX: true
})
);
const xAxis = chart.xAxes.push(
am5xy.CategoryAxis.new(root, {
categoryField: "x",
renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 30 }),
tooltip: am5.Tooltip.new(root, {})
})
);
const yAxis = chart.yAxes.push(
am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {
stroke: am5.color('#DCDCDC'),
strokeWidth: 1
})
})
);
const series = chart.series.push(
am5xy.ColumnSeries.new(root, {
name: "sector",
xAxis: xAxis,
yAxis: yAxis,
valueYField: "y",
categoryXField: "x",
// tooltip: am5.Tooltip.new(root, {
// labelText: "{valueY}"
// })
})
);
series.columns.template.setAll({
fill: am5.color("#7292CD"),
stroke: am5.color("#7292CD"),
cornerRadiusTL: 4,
cornerRadiusTR: 4,
width: 38
});
xAxis.data.setAll(data);
series.data.setAll(data);
series.appear(0);
chart.appear(0, 0);
});
}