menu-support-fims 제거

main
이범준 6 months ago
parent ab99620021
commit 3bd0574964

@ -16,21 +16,23 @@
<!-- Core JS for base -->
<script src="<c:url value="/resources/sneat/libs/jstree/jstree.js?${ver}"/>"></script>
<!-- Core support -->
<script src="<c:url value="/resources/js/base/menu-support.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/jstree-support.js?${ver}"/>"></script>
<!-- base -->
<script src="<c:url value="/resources/js/base/base.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/dataset.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/upload-support.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/code.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/code-support.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/menu.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/menu-support.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/actionGroup.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/user.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/base/authority.js?${ver}"/>"></script>
<script src="<c:url value="/resources/js/fims/menu-support-fims.js?${ver}"/>"></script>
<script src="<c:url value='/resources/sneat/libs/jquery-sticky/jquery-sticky.js' />"></script>
<!-- 데이트픽커 -->
<script src="<c:url value="/resources/sneat/libs/bootstrap-datepicker/bootstrap-datepicker.js?${ver}"/>"></script>

@ -487,8 +487,9 @@ $("#fastTerm--top").onEnterPress(fnGlobalFastSearch);
function fnGlobalFastSearch(){
var integrationSearchMenuNum = "17";
closeTab(integrationSearchMenuNum);
var url = $("#menus").find("li[data-key='"+integrationSearchMenuNum+"'] a").attr("onclick").split("'")[1];
mainTabs.close(url);
var itegrationSearchMenu = $("#menus").find("li[data-key='"+integrationSearchMenuNum+"'] a")[0];
@ -496,9 +497,9 @@ function fnGlobalFastSearch(){
var fastTerm = $("#fastTerm--top").val();
var fastBy = $("#fastBy--top").val();
openMenu(itegrationSearchMenu, "?fastBy="+fastBy+"&fastTerm="+fastTerm);
openMenu(url+"?fastBy="+fastBy+"&fastTerm="+fastTerm);
} else {
openMenu(itegrationSearchMenu);
openMenu(url);
}
}

@ -29,10 +29,12 @@ function fnHome(){
}
let userMenus = ${userMenus};
let menuSupport = new MenuSupport("#layout-menu");
function setUserMenus(menus) {
let menuSupport = new FimsMenuSupport("#layout-menu").setMenuInfo(menus).setActive(wctx.current());
menuSupport.setMenuInfo(menus).setActive(wctx.current());
let currentMenu = menuSupport.getMenu(wctx.current());
if (currentMenu)
setPageTitle(currentMenu.name);
}
setUserMenus(userMenus);

@ -4,32 +4,37 @@
<body>
<div class="layout-wrapper layout-content-navbar">
<div class="layout-container">
<jsp:include page="/WEB-INF/jsp/include/userMenus.jsp" />
<div class="layout-page">
<jsp:include page="/WEB-INF/jsp/include/top.jsp" />
<jsp:include page="/WEB-INF/jsp/include/top.jsp" />
<div class="layout-page">
<div class="content-wrapper mt-2">
<jsp:include page="/WEB-INF/jsp/include/userMenus.jsp" />
<div class="content-body menu-aware">
<div class="sticky-wrapper">
<ul id="menu-tabs" class="nav nav-tabs sticky-element" role="tablist"
style="--bs-nav-link-padding-y: .125rem; background-image: linear-gradient(#8AB9DB, whitesmoke);">
</ul>
</div>
<template id="main-tab">
<li class="nav-item" role="presentation">
<div class="nav-link border-bottom-0" data-bs-toggle="tab" data-bs-target="{tab-target}"
role="tab" aria-controls="{index}" tabindex="-1">
<span onclick="openMenu('{url}');" class="w-px-150 text-truncate">{name}</span>
<span onclick="mainTabs.close('{url}')" class="ms-2">&times;</span>
</div>
</li>
</template>
<div id="main-tab-content" class="tab-content shadowed">
<div id="dashboard" class="tab-pane fade" role="tabpanel">
<jsp:include page="/WEB-INF/jsp/include/dashboard.jsp" />
</div>
</div>
<template id="tab-pane">
<div id="{index}" class="tab-pane fade" role="tabpanel">{inner-content}</div>
</template>
</div>
</div>
<div id="tabsForInnerPage" class="nav-align-top mt-2">
<ul class="nav nav-tabs nav-tabs-ifr">
<li id="li-dashboard" class="nav-item" role="presentation">
<button type="button" data-bs-toggle="tab" data-bs-target="#tab-dashboard"
class="nav-link nav-link-closeable ps-2 active" aria-selected="true" role="tab">
<span class="w-px-150 text-truncate">대시보드</span>
</button>
</li>
</ul>
</div>
<div id="innerPageTabContents" class="tab-content">
<div id="tab-dashboard" class="tab-pane active show" role="tabpanel">
<div id="divdashboard">
<div class="content-wrapper">
<div class="container-xxl flex-grow-1 container-p-y d-flex flex-column align-items-center">
<jsp:include page="/WEB-INF/jsp/include/dashboard.jsp" />
</div>
</div>
</div>
</div>
</div>
<jsp:include page="/WEB-INF/jsp/include/bottom.jsp" />
</div>
</div>
@ -59,6 +64,82 @@
</c:set>
<script>
let sticky = {id: -1, index: "dashboard", name: "대시보드", url: "/dashboard.do", parentID: null, description: "대시보드"},
mainTabs = new TabControl({
sticky: sticky,
getMenu: (url) => menuSupport.getMenu(url),
onDatasetChange: tabs => {
let template = document.getElementById("main-tab").innerHTML,
toTab = (tmpl, item) => tmpl.replace(/{tab-target}/gi, "#" + "{index}"),
tags = mainTabs.inStrings(template, toTab);
document.getElementById("menu-tabs").innerHTML = tags.join("");
$("#menu-tabs .nav-item").eq(0).find("span.ms-2").remove();
//$("#menu-tabs .nav-item").hover(
//function() {
//let span = $(this).find("span.ms-2");
//if (span.attr("onclick").includes(sticky.url)) return;
//span.show();
//},
//function() {
//$(this).find("span.ms-2").hide();
//}
//);
},
onCurrentChange: tab => {
if (!tab.data) return;
let url = tab.data.url;
menuSupport.setActive(url);
document.querySelector("#menu-tabs li span[onclick=\"openMenu('" + url + "');\"]").click();
let currentPane = document.querySelector("#" + tab.data.index);
if (!currentPane) {
let template = document.getElementById("tab-pane").innerHTML,
html = tab.inString(template);
if (tab.data.content) {
html = html.replace(/{inner-content}/, tab.data.content);
delete tab.data.content;
$("#main-tab-content").append(html);
}
}
document.querySelectorAll("#main-tab-content > div.tab-pane")
.forEach(tabPane => {
let current = tab.data.index == tabPane.getAttribute("id");
if (current)
tabPane.classList.add("show", "active");
else
tabPane.classList.remove("show", "active");
});
},
onRemove: tabs => {
let mainTab = document.querySelector("#main-tab-content");
tabs.forEach(tab => {
let tabPane = document.querySelector("#" + tab.data.index);
if (!tabPane) return;
mainTab.removeChild(tabPane);
delete tabPane;
});
mainTabs.onDatasetChange();
}
});
function openMenu(url) {
mainTabs.open(url)
}
$(".sticky-element").sticky({
topSpacing: $(".nav-bar").height() + 1,
width: "100%",
zIndex: 9
});
const FETCH_XXS = 10;
const FETCH_XS = 30;
const FETCH_SM = 50;
@ -236,6 +317,8 @@
$(function(){
${onload}
mainTabs.getTab(sticky.url);
fnGetAllTask()
.then(() => { return fnCheckSggTask(); })
.then(() => { return fnGetSysLinkInfo(); })

@ -4,20 +4,27 @@ class MenuSupport {
/** MenuSupport .
* @param selector {string} 메뉴를 담을 컨테이너에 대한 css selector
*/
constructor(selector) {
this._container = document.querySelector(this._selector = selector);
constructor(conf) {
conf = conf || {};
this._selector = ifEmpty(conf.selector, "#menus");
this._containerSelector = ifEmpty(conf.containerSelector, "#layout-menu");
this._container = document.querySelector(this._containerSelector);
let onclick = conf.onclick || (menu => 'onclick="openMenu(\'{url}\')" '.replace(/{url}/gi, wctx.url(menu.url)));
this._onclick = (menu => menu && menu.url ? onclick(menu) : "");
this._horizontal = this._container && this._container.classList.contains('menu-horizontal');
this._orientation = this._horizontal ? "horizontal" : "vertical";
this._template = this._orientation + "-menu-template";
this._menuItem = '<li data-key="{menuID}" class="menu-item"><a href="{url}" class="menu-link{toggle}"><i class="menu-icon tf-icons bx bx-layout"></i><div data-i18n="{menuName}">{menuName}</div></a>{menuSub}</li>';
this._menuItem = '<li data-key="{menuID}" class="menu-item" title="{title}"><a {onclick}class="menu-link{toggle}"><i class="menu-icon tf-icons {imageConf}"></i><div data-i18n="{menuName}">{menuName}</div></a>{menuSub}</li>';
this._menuSub = '<ul class="menu-sub">{children}</ul>';
this._menus = [];
this._init();
}
/** .
* @param menus {array} 메뉴 정보 배열<br />
* 메뉴 정보의 레이아웃은 다음과 같다.<br />
* {"id":메뉴 아이디, "name":"메뉴 이름", "url":"실행 url", "parentID":"상위 메뉴 아이디", "description":"메뉴 설명", "imagePath":"이미지 경로", "displayWindow":"표시 창", "children":[하위 메뉴 배열]}
* {"id":메뉴 아이디, "name":"메뉴 이름", "url":"실행 url", "parentID":"상위 메뉴 아이디", "description":"메뉴 설명", "imageConf":"이미지 설정", "displayWindow":"표시 창", "children":[하위 메뉴 배열]}
* @returns MenuSupport
*/
setMenuInfo(menus) {
@ -37,7 +44,9 @@ class MenuSupport {
let tag = this._menuItem
.replace(/{menuID}/gi, menu.id)
.replace(/{menuName}/gi, menu.name)
.replace(/{url}/gi, !menu.url ? "javascript:void(0);" : wctx.url(menu.url));
.replace(/{onclick}/gi, this._onclick(menu))
.replace(/{title}/gi, (menu.description || ""))
.replace(/{imageConf}/gi, (menu.imageConf || "bx bx-layout"));
let parent = menu.children && menu.children.length > 0;
tag = tag.replace(/{toggle}/gi, !parent ? "" : " menu-toggle");
if (!parent)
@ -47,40 +56,47 @@ class MenuSupport {
return tag.replace(/{menuSub}/gi, this._menuSub.replace(/{children}/gi, children));
}
let tags = (menus || []).map(menu => menuItemTag(menu));
document.querySelector("#menus").innerHTML = tags.join("");
document.querySelector(this._selector).innerHTML = tags.join("");
return this._init();
}
_toggleMenuAwares(collapse) {
document.querySelectorAll(".menu-aware").forEach(menuAware => menuAware.style.width = collapse ? "calc(100% - 5.25rem)" : "");
}
_init() {
document.querySelectorAll(this._selector).forEach(element => {
let menu = new Menu(element, {
orientation: this._orientation,
closeChildren: this._horizontal,
showDropdownOnHover: localStorage.getItem('templateCustomizer-' + this._template + '--ShowDropdownOnHover')
? localStorage.getItem('templateCustomizer-' + this._template + '--ShowDropdownOnHover') === 'true'
: window.templateCustomizer !== undefined
? window.templateCustomizer.settings.defaultShowDropdownOnHover
: true
});
window.Helpers.scrollToActive(false); //animate = false
window.Helpers.mainMenu = menu;
});
let menu = new Menu(this._container, {
orientation: this._orientation,
closeChildren: this._horizontal,
showDropdownOnHover: localStorage.getItem('templateCustomizer-' + this._template + '--ShowDropdownOnHover')
? localStorage.getItem('templateCustomizer-' + this._template + '--ShowDropdownOnHover') === 'true'
: window.templateCustomizer !== undefined
? window.templateCustomizer.settings.defaultShowDropdownOnHover
: true
});
window.Helpers.scrollToActive(false); //animate = false
window.Helpers.mainMenu = menu;
//Sets toggler
document.querySelectorAll('.layout-menu-toggle').forEach(item => {
item.addEventListener('click', event => {
event.preventDefault();
window.Helpers.toggleCollapsed();
if (config.enableMenuLocalStorage && !window.Helpers.isSmallScreen()) {
try {
localStorage.setItem(
'templateCustomizer-' + this._template + '--LayoutCollapsed',
String(window.Helpers.isCollapsed())
);
} catch (e) {}
}
});
item.addEventListener('click', event => {
if (event.fired) {
return delete event.fired;
}
event.fired = true;
event.preventDefault();
window.Helpers.toggleCollapsed();
if (config.enableMenuLocalStorage && !window.Helpers.isSmallScreen()) {
try {
localStorage.setItem(
'templateCustomizer-' + this._template + '--LayoutCollapsed',
String(window.Helpers.isCollapsed())
);
} catch (e) {}
}
this._toggleMenuAwares(Helpers.isCollapsed());
});
});
// Display menu toggle (layout-menu-toggle) on hover with delay
let delay = (elem, callback) => {
@ -97,30 +113,59 @@ class MenuSupport {
};
};
if (this._container) {
delay(this._container, () => {
// not for small screen
if (!Helpers.isSmallScreen()) {
document.querySelector('.layout-menu-toggle').classList.add('d-block');
}
});
delay(this._container, () => {
// not for small screen
if (!Helpers.isSmallScreen()) {
document.querySelector('.layout-menu-toggle').classList.add('d-block');
}
});
}
// Detect swipe gesture on the target element and call swipe In
window.Helpers.swipeIn('.drag-target', function (e) {
window.Helpers.setCollapsed(false);
});
// Detect swipe gesture on the target element and call swipe Out
window.Helpers.swipeOut(this._containerSelector, function (e) {
if (window.Helpers.isSmallScreen()) window.Helpers.setCollapsed(true);
});
// Display in main menu when menu scrolls
let menuInnerContainer = document.getElementsByClassName('menu-inner'),
menuInnerShadow = document.getElementsByClassName('menu-inner-shadow')[0];
if (menuInnerContainer.length > 0 && menuInnerShadow) {
menuInnerContainer[0].addEventListener('ps-scroll-y', function () {
if (this.querySelector('.ps__thumb-y').offsetTop) {
menuInnerShadow.style.display = 'block';
} else {
menuInnerShadow.style.display = 'none';
}
});
}
return this;
}
open(url) {
top.document.location.href = url;
}
/** url .
* @param url {string} 메뉴 url
* @returns MenuSupport
*/
setActive(url) {
let menu = this.getMenu(url);
if (!menu) return this;
document
.querySelectorAll(this._selector + " li")
.forEach(li => li.classList.remove("active", "open"));
let a = document.querySelector(this._selector + ' a[href=\"' + wctx.url(url) + '\"]');
let a = document.querySelector(this._selector + " li[data-key=\"" + menu.id + "\"]");
if (!a) return this;
let activate = (e, open) => {
e.classList.add("active");
let p = e.parentNode;
let tag = (p != this._container ? p : null) ? p.tagName : "";
if (!tag) return;
@ -131,7 +176,6 @@ class MenuSupport {
p.classList.add("open");
}
activate(p, true);
};
activate(a);
@ -171,4 +215,93 @@ class MenuSupport {
return getName(menu);
}
}
class TabControl extends Dataset {
constructor(conf) {
if (!conf)
conf = {};
conf.keymapper = info => {
if (!info.index) {
info.index = "ndx-" + new Date().getTime();
}
return info.index;
};
conf.dataGetter = obj => null;
super(conf);
this.sticky = conf.sticky || {};
this.maxCount = conf.maxCount || 8;
this.getMenu = conf.getMenu || ((url) => {throw "getMenu(url) missing"});
}
getTab(by) {
if (by.startsWith("ndx-"))
return this.getData(by, "item");
if (by != this.sticky.url) {
let found = this._items.filter(item => item.data.url == by),
empty = !found || found.length < 1;
if (empty)
return null;
found = found[0];
return !found.unreachable ? found : null;
} else {
let found = this._items.filter(item => item.data.url == this.sticky.url);
if (!found || found.length < 1) {
this.addData([this.sticky]);
}
}
}
open(url) {
if (!url
|| url.startsWith("javascript:void")
|| url == this.sticky.url)
return;
let tab = this.getTab(url);
if (tab)
return this.setCurrent(tab.data.index);
ajax.get({
url: wctx.url(url),
success: resp => {
let menu = this.getMenu(url);
if (!menu)
throw "Menu not found for " + url;
if (this._items.length == this.maxCount) {
let index = isEmpty(this.sticky.url) ? 0 : 1;
this._remove(this._items[index]);
}
menu.content = resp;
this.addData([menu]);
this.open(url);
}
});
}
close(url) {
let removed = this._remove(this.getTab(url));
if (removed)
this.setState();
}
_remove(tab) {
if (!tab || this._items.length < 1)
return false;
let index = this._items.indexOf(tab);
if (index < 0)
return false;
this._items.splice(index, 1);
index = tab.data.index;
delete this._byKeys["key-" + index];
this.onRemove([tab]);
return true;
}
}

@ -1,185 +0,0 @@
/** .
*/
class FimsMenuSupport extends MenuSupport {
constructor(selector) {
super(selector);
this._menuItem = '<li data-key="{menuID}" class="menu-item">'
+'<a data-url="{url}" onclick="openMenu(this)" class="menu-link{toggle}">'
+'<i class="menu-icon tf-icons {imageConf}"></i>'
+'<div data-i18n="{menuName}">{menuName}</div>'
+'</a>'
+'{menuSub}'
+'</li>';
}
setMenuInfo(menus) {
let setParent = menu => {
let children = menu.children || [];
if (children.length < 1) return;
children.forEach(child => {
child.parent = menu;
setParent(child);
});
};
menus.forEach(menu => setParent(menu));
this._menus = menus;
let menuItemTag = menu => {
let tag = this._menuItem
.replace(/{menuID}/gi, menu.id)
.replace(/{menuName}/gi, menu.name)
.replace(/{url}/gi, !menu.url ? "javascript:void(0);" : wctx.url(menu.url))
.replace(/{imageConf}/gi, !menu.imageConf ? "bx bx-layout" : menu.imageConf);
let parent = menu.children && menu.children.length > 0;
tag = tag.replace(/{toggle}/gi, !parent ? "" : " menu-toggle");
if (!parent)
return tag.replace(/{menuSub}/gi, "");
let children = menu.children.map(child => menuItemTag(child)).join("\n\t")
return tag.replace(/{menuSub}/gi, this._menuSub.replace(/{children}/gi, children));
}
let tags = (menus || []).map(menu => menuItemTag(menu));
document.querySelector("#menus").innerHTML = tags.join("");
return this._init();
}
}
/**************************************************************************
* Global Variable
***************************************************************************/
const innerPageMap = {},
openMax = 8;
function openMenu(obj, params) {
let menuUrl = $(obj)[0].dataset.url;
if(menuUrl == "javascript:void(0);"){
return;
}
let menuNm = $(obj).find("div")[0].dataset.i18n;
let dataKey = $(obj).parent()[0].dataset.key;
const OPEN_TAB_CNT = $('div#tabsForInnerPage > ul > li').length;
if(innerPageMap[dataKey]){
// 해당 tab 활성화
$("#tabsForInnerPage").find("ul li button.nav-link").each((idx, data) => {
if(data.dataset.bsTarget == ("#tab-"+dataKey)) {
$(data).tab("show");
}
});
return;
}
if(OPEN_TAB_CNT === openMax){
alert(`메뉴는 최대 ${openMax -1}까지만 열 수 있습니다.`)
return null;
}
let liEl = '<li id="li-'+ dataKey +'" class="nav-item">';
let linkClass = 'nav-link ps-2';
if(dataKey != "dashboard"){
linkClass += ' nav-link-closeable';
}
liEl +='<button type="button" data-bs-toggle="tab" data-bs-target="#tab-'+ dataKey + '" class="' + linkClass + '">'
+ '<span class="w-px-150 text-truncate" title="' + menuNm + '">'
+ menuNm
+ '</span>'
+ '</button>';
if(dataKey != "dashboard"){
liEl += '<button type="button" title="닫기" class="btn btn-close" onclick="closeTab('+ dataKey + ')"></button>'
}
liEl += '</li>';
$('div#tabsForInnerPage ul').append(liEl);
$('div#innerPageTabContents').append('<div id="tab-' + dataKey + '" class="tab-pane"></div>');
if(params != null){
menuUrl = menuUrl + params;
}
let dynamicPage = document.createElement("div");
dynamicPage.setAttribute("id","innerPage-"+dataKey);
;
$("#formForInnerPage").remove();
$("#tab-" + dataKey)[0].appendChild(dynamicPage);
innerPageMap[dataKey] = true;
ajax.request({
type:"POST",
url:menuUrl,
data:{},
success:resp => {
$("#innerPage-"+dataKey).html(resp);
}
});
$("div#tabsForInnerPage ul li button.nav-link").last().tab("show");
}
function closeTab(menuId) {
if(menuId === 'main' || menuId?.id === 'main') return;
const num_tabs = $('div#tabsForInnerPage ul li').length;
// click한 tab
const selIdx = id2Index("div#tabsForInnerPage","tab-"+menuId);
if(selIdx == -1){
return;
}
// active tab
let activeTab = $('div#tabsForInnerPage ul li button.nav-link').filter(".active");
let activeIdx = $('div#tabsForInnerPage ul li button.nav-link').index(activeTab);
if(selIdx === activeIdx) {
if (num_tabs - 1 > activeIdx) {
$('div#tabsForInnerPage ul li button.nav-link').eq(activeIdx + 1).tab("show");
} else {
$('div#tabsForInnerPage ul li button.nav-link').eq(activeIdx - 1).tab("show");
}
}
document.getElementById("tab-"+menuId).remove();
$('#tabsForInnerPage').find('#li-'+menuId).remove();
delete innerPageMap[menuId];
}
function id2Index(tabsId, srcId) {
let index = -1;
const nls = $(tabsId).find("li > button.nav-link");
if(nls.length > 0) {
nls.each((idx, nl) => {
if (nl.dataset.bsTarget.search(srcId) > 0) {
index = idx;
return false;
}
});
}
return index;
}
Loading…
Cancel
Save