ide-assi 0.443.0 → 0.445.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.cjs.js +880 -616
- package/dist/bundle.esm.js +880 -616
- package/dist/components/ideAssi.js +40 -2
- package/dist/components/ideDiff.js +2 -2
- package/package.json +1 -1
- package/src/components/ideAssi.js +40 -2
- package/src/components/ideDiff.js +2 -2
- package/src/components/ideDiff.js.bak +0 -141
- package/src/components/ideDiff.js.bak2 +0 -725
package/dist/bundle.esm.js
CHANGED
|
@@ -10973,6 +10973,7 @@ class ninegrid {
|
|
|
10973
10973
|
ROW_MOVED : "rowmoved",
|
|
10974
10974
|
//CAN_FIXED_CHANGE : "canfixedchange",
|
|
10975
10975
|
//FIXED_CHANGED : "fixedchanged",
|
|
10976
|
+
TAB_LOAD : "tabload",
|
|
10976
10977
|
};
|
|
10977
10978
|
|
|
10978
10979
|
static BAND = {
|
|
@@ -119282,7 +119283,21 @@ class NineGridContainer extends HTMLElement
|
|
|
119282
119283
|
|
|
119283
119284
|
//export { NineGridContainer };
|
|
119284
119285
|
|
|
119285
|
-
customElements.define("nine-grid", NineGridContainer);
|
|
119286
|
+
customElements.define("nine-grid", NineGridContainer);
|
|
119287
|
+
|
|
119288
|
+
class NineGridSourceContainer extends NineGridContainer
|
|
119289
|
+
{
|
|
119290
|
+
constructor() {
|
|
119291
|
+
|
|
119292
|
+
super();
|
|
119293
|
+
}
|
|
119294
|
+
|
|
119295
|
+
connectedCallback() {
|
|
119296
|
+
super.connectedCallback();
|
|
119297
|
+
};
|
|
119298
|
+
}
|
|
119299
|
+
|
|
119300
|
+
customElements.define("ng-source", NineGridSourceContainer);
|
|
119286
119301
|
|
|
119287
119302
|
class nxDialog extends HTMLElement
|
|
119288
119303
|
{
|
|
@@ -119422,76 +119437,6 @@ class nxDialog extends HTMLElement
|
|
|
119422
119437
|
|
|
119423
119438
|
customElements.define("nx-dialog", nxDialog);
|
|
119424
119439
|
|
|
119425
|
-
class nxDiv extends HTMLElement {
|
|
119426
|
-
constructor() {
|
|
119427
|
-
super();
|
|
119428
|
-
this.attachShadow({ mode: "open" });
|
|
119429
|
-
this.isCollapsed = false; // 검색 박스 상태 (true: 축소됨, false: 확장됨)
|
|
119430
|
-
}
|
|
119431
|
-
|
|
119432
|
-
connectedCallback() {
|
|
119433
|
-
this.#init();
|
|
119434
|
-
}
|
|
119435
|
-
|
|
119436
|
-
getJsonData = () => {
|
|
119437
|
-
const parent = this.shadowRoot.querySelector(".search-content");
|
|
119438
|
-
const elements = parent.querySelectorAll("[id]");
|
|
119439
|
-
const jsonData = {};
|
|
119440
|
-
|
|
119441
|
-
elements.forEach(element => {
|
|
119442
|
-
if (element.tagName === "INPUT" || element.tagName === "TEXTAREA" || element.tagName === "SELECT") {
|
|
119443
|
-
jsonData[element.id] = element.value;
|
|
119444
|
-
} else {
|
|
119445
|
-
jsonData[element.id] = element.textContent.trim();
|
|
119446
|
-
}
|
|
119447
|
-
});
|
|
119448
|
-
|
|
119449
|
-
return jsonData;
|
|
119450
|
-
};
|
|
119451
|
-
|
|
119452
|
-
getSearchOptions = () => {
|
|
119453
|
-
|
|
119454
|
-
};
|
|
119455
|
-
|
|
119456
|
-
#init = () => {
|
|
119457
|
-
const contents = this.innerHTML.trim();
|
|
119458
|
-
this.innerHTML = ""; // 기존 내부 HTML 제거
|
|
119459
|
-
|
|
119460
|
-
const htmlTmpl = document.createElement("template");
|
|
119461
|
-
htmlTmpl.innerHTML = `
|
|
119462
|
-
<style>
|
|
119463
|
-
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxDiv.css";
|
|
119464
|
-
${ninegrid.getCustomPath(this,"nxDiv.css")}
|
|
119465
|
-
|
|
119466
|
-
:host {
|
|
119467
|
-
}
|
|
119468
|
-
</style>
|
|
119469
|
-
|
|
119470
|
-
<div class="search-container">
|
|
119471
|
-
<span class="toggle-icon"></span>
|
|
119472
|
-
<div class="search-content">${contents}</div>
|
|
119473
|
-
</div>
|
|
119474
|
-
`;
|
|
119475
|
-
|
|
119476
|
-
this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
|
|
119477
|
-
|
|
119478
|
-
this.#setupToggle();
|
|
119479
|
-
}
|
|
119480
|
-
|
|
119481
|
-
#setupToggle = () => {
|
|
119482
|
-
const toggleIcon = this.shadowRoot.querySelector(".toggle-icon");
|
|
119483
|
-
const searchContainer = this.shadowRoot.querySelector(".search-container");
|
|
119484
|
-
|
|
119485
|
-
toggleIcon.addEventListener("click", () => {
|
|
119486
|
-
this.isCollapsed = !this.isCollapsed;
|
|
119487
|
-
//toggleIcon.innerHTML = this.isCollapsed ? "" : "X";
|
|
119488
|
-
searchContainer.classList.toggle("collapse", this.isCollapsed);
|
|
119489
|
-
});
|
|
119490
|
-
}
|
|
119491
|
-
}
|
|
119492
|
-
|
|
119493
|
-
customElements.define("nx-div", nxDiv);
|
|
119494
|
-
|
|
119495
119440
|
class nxI18nExt extends HTMLElement
|
|
119496
119441
|
{
|
|
119497
119442
|
#enableHtml;
|
|
@@ -120119,6 +120064,20 @@ class nxSideMenu extends HTMLElement
|
|
|
120119
120064
|
ninegrid.waitForInnerHTML(this)
|
|
120120
120065
|
.then(() => this.#init())
|
|
120121
120066
|
.catch(error => console.error(error));
|
|
120067
|
+
|
|
120068
|
+
setTimeout(() => {
|
|
120069
|
+
if (!ninegrid.querySelector("nx-side-menu-item.active", this.shadowRoot)) {
|
|
120070
|
+
const rawUrl = window.location.href; // 전체 URL
|
|
120071
|
+
const parsedUrl = new URL(rawUrl); // URL 객체로 파싱
|
|
120072
|
+
const href = parsedUrl.pathname; // 👉 경로만 추출
|
|
120073
|
+
|
|
120074
|
+
const el = ninegrid.querySelector(`nx-side-menu-item[href="${href}"]`, this.shadowRoot);
|
|
120075
|
+
if (el) {
|
|
120076
|
+
el.classList.add("active");
|
|
120077
|
+
}
|
|
120078
|
+
}
|
|
120079
|
+
}, 300);
|
|
120080
|
+
|
|
120122
120081
|
};
|
|
120123
120082
|
|
|
120124
120083
|
expand = () => {
|
|
@@ -120650,203 +120609,6 @@ class nxSpan extends HTMLElement
|
|
|
120650
120609
|
|
|
120651
120610
|
customElements.define("nx-span", nxSpan);
|
|
120652
120611
|
|
|
120653
|
-
class nxTab extends HTMLElement {
|
|
120654
|
-
constructor() {
|
|
120655
|
-
super();
|
|
120656
|
-
this.attachShadow({ mode: 'open' });
|
|
120657
|
-
|
|
120658
|
-
this.shadowRoot.innerHTML = `
|
|
120659
|
-
<style>
|
|
120660
|
-
:host(.theme-1) {
|
|
120661
|
-
.tabs {
|
|
120662
|
-
--border-bottom: 1px solid #eee;
|
|
120663
|
-
gap: 3px;
|
|
120664
|
-
}
|
|
120665
|
-
.tab-button {
|
|
120666
|
-
color: #666;
|
|
120667
|
-
font-weight: 500;
|
|
120668
|
-
transform: translateY(1px);
|
|
120669
|
-
z-index: 1;
|
|
120670
|
-
--border-bottom: 1px solid #ccc;
|
|
120671
|
-
}
|
|
120672
|
-
.tab-button.active {
|
|
120673
|
-
color: #666;
|
|
120674
|
-
font-weight: 700;
|
|
120675
|
-
border-bottom: 1px solid white;
|
|
120676
|
-
}
|
|
120677
|
-
.tab-pages {
|
|
120678
|
-
border: 1px solid #ccc;
|
|
120679
|
-
}
|
|
120680
|
-
}
|
|
120681
|
-
|
|
120682
|
-
:host(.theme-2) {
|
|
120683
|
-
.tabs {
|
|
120684
|
-
border-bottom: 1px solid #eee;
|
|
120685
|
-
gap: 40px;
|
|
120686
|
-
}
|
|
120687
|
-
.tab-button {
|
|
120688
|
-
color: #666;
|
|
120689
|
-
font-weight: 500;
|
|
120690
|
-
border: none;
|
|
120691
|
-
}
|
|
120692
|
-
.tab-button.active {
|
|
120693
|
-
color: green;
|
|
120694
|
-
font-weight: 700;
|
|
120695
|
-
border-bottom: 3px solid green;
|
|
120696
|
-
}
|
|
120697
|
-
}
|
|
120698
|
-
|
|
120699
|
-
.tabs {
|
|
120700
|
-
display: flex;
|
|
120701
|
-
cursor: pointer;
|
|
120702
|
-
|
|
120703
|
-
}
|
|
120704
|
-
.tab-button {
|
|
120705
|
-
padding: 8px;
|
|
120706
|
-
border: 1px solid #ccc;
|
|
120707
|
-
text-align: center;
|
|
120708
|
-
outline: 0;
|
|
120709
|
-
}
|
|
120710
|
-
.tab-button:hover {
|
|
120711
|
-
--filter: brightness(80%);
|
|
120712
|
-
}
|
|
120713
|
-
.tab-pages {
|
|
120714
|
-
position: relative;
|
|
120715
|
-
width: 100%;
|
|
120716
|
-
overflow: hidden;
|
|
120717
|
-
transition: height 0.5s ease-in-out;
|
|
120718
|
-
}
|
|
120719
|
-
.tab-page {
|
|
120720
|
-
position: absolute;
|
|
120721
|
-
width: 100%;
|
|
120722
|
-
top: 0;
|
|
120723
|
-
transition: left 0.5s ease-in-out;
|
|
120724
|
-
padding: 20px;
|
|
120725
|
-
box-sizing: border-box;
|
|
120726
|
-
white-space: nowrap;
|
|
120727
|
-
overflow: hidden;
|
|
120728
|
-
text-overflow: ellipsis;
|
|
120729
|
-
text-align: left;
|
|
120730
|
-
}
|
|
120731
|
-
.tab-page.active {
|
|
120732
|
-
left: 0;
|
|
120733
|
-
}
|
|
120734
|
-
.tab-page.exit-left {
|
|
120735
|
-
left: -100%;
|
|
120736
|
-
}
|
|
120737
|
-
.tab-page.exit-right {
|
|
120738
|
-
left: 100%;
|
|
120739
|
-
}
|
|
120740
|
-
</style>
|
|
120741
|
-
<div class="tabs"></div>
|
|
120742
|
-
<div class="tab-pages"></div>
|
|
120743
|
-
`;
|
|
120744
|
-
|
|
120745
|
-
//console.log(this.shadowRoot.querySelector('.tab-page'));
|
|
120746
|
-
//this.shadowRoot.querySelector('.tab-pages').style.height = this.shadowRoot.querySelector('.tab-page').style.height;
|
|
120747
|
-
|
|
120748
|
-
this.switchTabHandler = this.#switchTab.bind(this);
|
|
120749
|
-
}
|
|
120750
|
-
|
|
120751
|
-
connectedCallback() {
|
|
120752
|
-
this.classList.add(this.getAttribute("theme") || "theme-1");
|
|
120753
|
-
this.#renderTabs();
|
|
120754
|
-
this.shadowRoot.querySelectorAll('.tab-button').forEach(tab => {
|
|
120755
|
-
tab.addEventListener('click', this.switchTabHandler);
|
|
120756
|
-
});
|
|
120757
|
-
|
|
120758
|
-
const firstTab = this.shadowRoot.querySelector('.tab-button');
|
|
120759
|
-
const firstContent = this.shadowRoot.querySelector('.tab-page');
|
|
120760
|
-
if (firstTab && firstContent) {
|
|
120761
|
-
firstTab.classList.add('active');
|
|
120762
|
-
firstContent.classList.add('active');
|
|
120763
|
-
setTimeout(() => {
|
|
120764
|
-
this.shadowRoot.querySelector('.tab-pages').style.height = `${firstContent.scrollHeight}px`;
|
|
120765
|
-
}, 100);
|
|
120766
|
-
//this.shadowRoot.querySelector('.tab-pages').style.height = `${firstContent.scrollHeight}px`;
|
|
120767
|
-
|
|
120768
|
-
console.log(firstContent.style.height, firstContent.scrollHeight);
|
|
120769
|
-
}
|
|
120770
|
-
|
|
120771
|
-
this.shadowRoot.querySelectorAll('.tab-page:not(.active)').forEach(el => { el.classList.add('exit-right'); });
|
|
120772
|
-
}
|
|
120773
|
-
|
|
120774
|
-
#renderTabs() {
|
|
120775
|
-
const tabs = this.shadowRoot.querySelector('.tabs');
|
|
120776
|
-
const contents = this.shadowRoot.querySelector('.tab-pages');
|
|
120777
|
-
const tabItems = this.querySelectorAll('nx-tab-page');
|
|
120778
|
-
|
|
120779
|
-
tabItems.forEach((item, index) => {
|
|
120780
|
-
const tab = document.createElement('div');
|
|
120781
|
-
tab.classList.add('tab-button');
|
|
120782
|
-
tab.textContent = item.getAttribute('caption');
|
|
120783
|
-
tab.setAttribute('data-target', `content${index}`);
|
|
120784
|
-
tabs.appendChild(tab);
|
|
120785
|
-
|
|
120786
|
-
const content = document.createElement('div');
|
|
120787
|
-
content.id = `content${index}`;
|
|
120788
|
-
content.classList.add('tab-page');
|
|
120789
|
-
content.innerHTML = item.innerHTML;
|
|
120790
|
-
contents.appendChild(content);
|
|
120791
|
-
});
|
|
120792
|
-
|
|
120793
|
-
tabItems.forEach((item) => {
|
|
120794
|
-
item.remove();
|
|
120795
|
-
});
|
|
120796
|
-
}
|
|
120797
|
-
|
|
120798
|
-
#switchTab(event) {
|
|
120799
|
-
const target = event.target;
|
|
120800
|
-
if (!target.classList.contains('tab-button')) return;
|
|
120801
|
-
|
|
120802
|
-
const targetId = target.getAttribute('data-target');
|
|
120803
|
-
const activeTab = this.shadowRoot.querySelector('.tab-button.active');
|
|
120804
|
-
const activeContent = this.shadowRoot.querySelector('.tab-page.active');
|
|
120805
|
-
const newContent = this.shadowRoot.getElementById(targetId);
|
|
120806
|
-
|
|
120807
|
-
if (activeTab === target) return; // 현재 탭을 클릭했을 때 아무런 변화가 없도록 함
|
|
120808
|
-
|
|
120809
|
-
if (activeTab && activeContent) {
|
|
120810
|
-
activeTab.classList.remove('active');
|
|
120811
|
-
activeContent.classList.remove('active','exit-left','exit-right');
|
|
120812
|
-
//newContent.classList.remove('exit-left','exit-right');
|
|
120813
|
-
activeContent.style.left = '';
|
|
120814
|
-
|
|
120815
|
-
if (activeTab.compareDocumentPosition(target) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
120816
|
-
activeContent.classList.add('exit-left');
|
|
120817
|
-
} else {
|
|
120818
|
-
activeContent.classList.add('exit-right');
|
|
120819
|
-
}
|
|
120820
|
-
//console.log(index);
|
|
120821
|
-
//if (index == 1) return;
|
|
120822
|
-
|
|
120823
|
-
newContent.classList.add('active');
|
|
120824
|
-
newContent.style.left = '';
|
|
120825
|
-
|
|
120826
|
-
newContent.classList.remove('exit-left','exit-right');
|
|
120827
|
-
}
|
|
120828
|
-
|
|
120829
|
-
target.classList.add('active');
|
|
120830
|
-
//newContent.classList.add('active');
|
|
120831
|
-
this.shadowRoot.querySelector('.tab-pages').style.height = `${newContent.scrollHeight}px`;
|
|
120832
|
-
|
|
120833
|
-
//console.log(newContent.style.height, newContent.scrollHeight);
|
|
120834
|
-
}
|
|
120835
|
-
}
|
|
120836
|
-
|
|
120837
|
-
class nxTabPage extends HTMLElement {
|
|
120838
|
-
constructor() {
|
|
120839
|
-
super();
|
|
120840
|
-
}
|
|
120841
|
-
|
|
120842
|
-
connectedCallback() {
|
|
120843
|
-
this.caption = this.getAttribute('caption');
|
|
120844
|
-
}
|
|
120845
|
-
}
|
|
120846
|
-
|
|
120847
|
-
customElements.define('nx-tab', nxTab);
|
|
120848
|
-
customElements.define('nx-tab-page', nxTabPage);
|
|
120849
|
-
|
|
120850
120612
|
class nxTest1 extends HTMLElement
|
|
120851
120613
|
{
|
|
120852
120614
|
constructor() {
|
|
@@ -121031,6 +120793,704 @@ Array.prototype.nineBinarySearch = function(target)
|
|
|
121031
120793
|
return -1;
|
|
121032
120794
|
};
|
|
121033
120795
|
|
|
120796
|
+
class nxDiv extends HTMLElement {
|
|
120797
|
+
constructor() {
|
|
120798
|
+
super();
|
|
120799
|
+
this.attachShadow({ mode: "open" });
|
|
120800
|
+
this.isCollapsed = false; // 검색 박스 상태 (true: 축소됨, false: 확장됨)
|
|
120801
|
+
}
|
|
120802
|
+
|
|
120803
|
+
connectedCallback() {
|
|
120804
|
+
this.#init();
|
|
120805
|
+
}
|
|
120806
|
+
|
|
120807
|
+
getJsonData = () => {
|
|
120808
|
+
const parent = this.shadowRoot.querySelector(".search-content");
|
|
120809
|
+
const elements = parent.querySelectorAll("[id]");
|
|
120810
|
+
const jsonData = {};
|
|
120811
|
+
|
|
120812
|
+
elements.forEach(element => {
|
|
120813
|
+
if (element.tagName === "INPUT" || element.tagName === "TEXTAREA" || element.tagName === "SELECT") {
|
|
120814
|
+
jsonData[element.id] = element.value;
|
|
120815
|
+
} else {
|
|
120816
|
+
jsonData[element.id] = element.textContent.trim();
|
|
120817
|
+
}
|
|
120818
|
+
});
|
|
120819
|
+
|
|
120820
|
+
return jsonData;
|
|
120821
|
+
};
|
|
120822
|
+
|
|
120823
|
+
getSearchOptions = () => {
|
|
120824
|
+
|
|
120825
|
+
};
|
|
120826
|
+
|
|
120827
|
+
#init = () => {
|
|
120828
|
+
const contents = this.innerHTML.trim();
|
|
120829
|
+
this.innerHTML = ""; // 기존 내부 HTML 제거
|
|
120830
|
+
|
|
120831
|
+
const htmlTmpl = document.createElement("template");
|
|
120832
|
+
htmlTmpl.innerHTML = `
|
|
120833
|
+
<style>
|
|
120834
|
+
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxDiv.css";
|
|
120835
|
+
${ninegrid.getCustomPath(this,"nxDiv.css")}
|
|
120836
|
+
</style>
|
|
120837
|
+
|
|
120838
|
+
<div class="search-container">
|
|
120839
|
+
<span class="toggle-icon"></span>
|
|
120840
|
+
<div class="search-content">${contents}</div>
|
|
120841
|
+
</div>
|
|
120842
|
+
`;
|
|
120843
|
+
|
|
120844
|
+
this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
|
|
120845
|
+
|
|
120846
|
+
this.#setupToggle();
|
|
120847
|
+
}
|
|
120848
|
+
|
|
120849
|
+
#setupToggle = () => {
|
|
120850
|
+
const toggleIcon = this.shadowRoot.querySelector(".toggle-icon");
|
|
120851
|
+
const searchContainer = this.shadowRoot.querySelector(".search-container");
|
|
120852
|
+
|
|
120853
|
+
toggleIcon.addEventListener("click", () => {
|
|
120854
|
+
this.isCollapsed = !this.isCollapsed;
|
|
120855
|
+
//toggleIcon.innerHTML = this.isCollapsed ? "" : "X";
|
|
120856
|
+
searchContainer.classList.toggle("collapse", this.isCollapsed);
|
|
120857
|
+
});
|
|
120858
|
+
}
|
|
120859
|
+
}
|
|
120860
|
+
|
|
120861
|
+
customElements.define("nx-div", nxDiv);
|
|
120862
|
+
|
|
120863
|
+
class nxCollapse extends HTMLElement {
|
|
120864
|
+
#target;
|
|
120865
|
+
#targetPrevDisplay;
|
|
120866
|
+
|
|
120867
|
+
constructor() {
|
|
120868
|
+
super();
|
|
120869
|
+
this.attachShadow({ mode: "open" });
|
|
120870
|
+
}
|
|
120871
|
+
|
|
120872
|
+
connectedCallback() {
|
|
120873
|
+
const targetSelector = this.getAttribute("target");
|
|
120874
|
+
this.#target = ninegrid.querySelector(targetSelector);
|
|
120875
|
+
//if (!this.#target) return;
|
|
120876
|
+
|
|
120877
|
+
this.#init();
|
|
120878
|
+
}
|
|
120879
|
+
|
|
120880
|
+
#init = () => {
|
|
120881
|
+
this.innerHTML.trim();
|
|
120882
|
+
this.innerHTML = ""; // 기존 내부 HTML 제거
|
|
120883
|
+
|
|
120884
|
+
const htmlTmpl = document.createElement("template");
|
|
120885
|
+
htmlTmpl.innerHTML = `
|
|
120886
|
+
<style>
|
|
120887
|
+
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxCollapse.css";
|
|
120888
|
+
${ninegrid.getCustomPath(this,"nxCollapse.css")}
|
|
120889
|
+
</style>
|
|
120890
|
+
|
|
120891
|
+
<button></button>
|
|
120892
|
+
`;
|
|
120893
|
+
|
|
120894
|
+
this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
|
|
120895
|
+
|
|
120896
|
+
if (this.#target && this.#target) {
|
|
120897
|
+
const collapseBtn = document.createElement("span");
|
|
120898
|
+
collapseBtn.className = "collapse-toggle";
|
|
120899
|
+
|
|
120900
|
+
const shadowRoot = this.#target.shadowRoot;
|
|
120901
|
+
(shadowRoot || this.#target).appendChild(collapseBtn);
|
|
120902
|
+
|
|
120903
|
+
const style = document.createElement("style");
|
|
120904
|
+
style.textContent = `
|
|
120905
|
+
span.collapse-toggle {
|
|
120906
|
+
position: absolute;
|
|
120907
|
+
top: 0;
|
|
120908
|
+
right: 0;
|
|
120909
|
+
cursor: pointer;
|
|
120910
|
+
width: 16px;
|
|
120911
|
+
height: 16px;
|
|
120912
|
+
border: none;
|
|
120913
|
+
transition: all 0.3s ease;
|
|
120914
|
+
background-repeat: no-repeat;
|
|
120915
|
+
background-position: center;
|
|
120916
|
+
background-size: auto;
|
|
120917
|
+
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="darkgray" class="bi bi-box-arrow-in-up-right" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M6.364 13.5a.5.5 0 0 0 .5.5H13.5a1.5 1.5 0 0 0 1.5-1.5v-10A1.5 1.5 0 0 0 13.5 1h-10A1.5 1.5 0 0 0 2 2.5v6.636a.5.5 0 1 0 1 0V2.5a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 .5.5v10a.5.5 0 0 1-.5.5H6.864a.5.5 0 0 0-.5.5"/><path fill-rule="evenodd" d="M11 5.5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793l-8.147 8.146a.5.5 0 0 0 .708.708L10 6.707V10.5a.5.5 0 0 0 1 0z"/></svg>');
|
|
120918
|
+
}
|
|
120919
|
+
|
|
120920
|
+
span.collapse-toggle:hover {
|
|
120921
|
+
background-color: rgba(60, 60, 60, 0.1);
|
|
120922
|
+
box-shadow: 0 0 6px rgba(60, 60, 60, 0.4);
|
|
120923
|
+
transform: scale(1.2); /* 살짝 확대 */
|
|
120924
|
+
}
|
|
120925
|
+
|
|
120926
|
+
${shadowRoot ? ":host(.nx-collapse)" : ".nx-collapse"} {
|
|
120927
|
+
animation: collapseShrink 0.7s ease forwards;
|
|
120928
|
+
pointer-events: none; /* 클릭 방지 */
|
|
120929
|
+
}
|
|
120930
|
+
|
|
120931
|
+
${shadowRoot ? ":host(.nx-expand)" : ".nx-expand"} {
|
|
120932
|
+
animation: expandShrink 0.6s ease forwards;
|
|
120933
|
+
pointer-events: none; /* 클릭 방지 */
|
|
120934
|
+
}
|
|
120935
|
+
|
|
120936
|
+
@keyframes collapseShrink {
|
|
120937
|
+
0% {
|
|
120938
|
+
opacity: 1;
|
|
120939
|
+
transform: scale(1);
|
|
120940
|
+
transform-origin: top right;
|
|
120941
|
+
}
|
|
120942
|
+
100% {
|
|
120943
|
+
opacity: 0;
|
|
120944
|
+
transform: scale(0);
|
|
120945
|
+
transform-origin: top right;
|
|
120946
|
+
}
|
|
120947
|
+
}
|
|
120948
|
+
|
|
120949
|
+
@keyframes expandShrink {
|
|
120950
|
+
0% {
|
|
120951
|
+
opacity: 0;
|
|
120952
|
+
transform: scale(0.5);
|
|
120953
|
+
transform-origin: top right;
|
|
120954
|
+
}
|
|
120955
|
+
100% {
|
|
120956
|
+
opacity: 1;
|
|
120957
|
+
transform: scale(1);
|
|
120958
|
+
transform-origin: top right;
|
|
120959
|
+
}
|
|
120960
|
+
}
|
|
120961
|
+
`;
|
|
120962
|
+
|
|
120963
|
+
(shadowRoot || this.#target).appendChild(style);
|
|
120964
|
+
|
|
120965
|
+
// collapse 시 target 숨기고 복원 버튼 등장
|
|
120966
|
+
collapseBtn.addEventListener("click", () => {
|
|
120967
|
+
// fade-out 클래스 먼저 넣고 → 일정 시간 후 display: none
|
|
120968
|
+
// STEP 1: 복원 버튼 애니메이션 시작 (살짝 빠르게 먼저 등장)
|
|
120969
|
+
this.#target.classList.add("nx-collapse");
|
|
120970
|
+
|
|
120971
|
+
setTimeout(() => {
|
|
120972
|
+
// STEP 2: target이 줄어드는 shrinking 애니메이션 시작
|
|
120973
|
+
//this.style.display = "inline-block";
|
|
120974
|
+
this.classList.add("nx-collapse");
|
|
120975
|
+
}, 100); // appearing 시작 후 100ms 딜레이로 target 축소 시작
|
|
120976
|
+
|
|
120977
|
+
setTimeout(() => {
|
|
120978
|
+
// STEP 3: 실제 target 숨기기
|
|
120979
|
+
this.#targetPrevDisplay = this.#target.style.display;
|
|
120980
|
+
this.#target.style.display = "none";
|
|
120981
|
+
}, 500); // shrinking 애니메이션이 끝나고 실제 제거
|
|
120982
|
+
});
|
|
120983
|
+
}
|
|
120984
|
+
|
|
120985
|
+
// 복원 시 target 보이고 복원 버튼 사라짐
|
|
120986
|
+
/**
|
|
120987
|
+
this.shadowRoot.querySelector("button").addEventListener("click", () => {
|
|
120988
|
+
this.#target.classList.remove("nx-collapse");
|
|
120989
|
+
this.classList.remove("nx-collapse");
|
|
120990
|
+
|
|
120991
|
+
this.#target.style.display = this.#targetPrevDisplay;
|
|
120992
|
+
this.style.display = "none";
|
|
120993
|
+
}); */
|
|
120994
|
+
|
|
120995
|
+
this.shadowRoot.querySelector("button").addEventListener("click", () => {
|
|
120996
|
+
// STEP 1: 복원 대상에 애니메이션 클래스 부여
|
|
120997
|
+
this.#target.style.display = this.#targetPrevDisplay;
|
|
120998
|
+
this.#target.classList.remove("nx-collapse");
|
|
120999
|
+
this.#target.classList.add("nx-expand"); // expandReveal 적용
|
|
121000
|
+
|
|
121001
|
+
setTimeout(() => {
|
|
121002
|
+
// STEP 2: target이 줄어드는 shrinking 애니메이션 시작
|
|
121003
|
+
this.classList.remove("nx-collapse");
|
|
121004
|
+
//this.style.display = "inline-block";
|
|
121005
|
+
this.classList.add("nx-expand");
|
|
121006
|
+
}, 100); // appearing 시작 후 100ms 딜레이로 target 축소 시작
|
|
121007
|
+
|
|
121008
|
+
|
|
121009
|
+
setTimeout(() => {
|
|
121010
|
+
// STEP 2: 실제 화면에 표시
|
|
121011
|
+
|
|
121012
|
+
//this.style.display = "none"; // 복원 버튼은 사라짐
|
|
121013
|
+
|
|
121014
|
+
// STEP 3: 애니메이션이 끝난 후 pointer-events 복구 (선택적)
|
|
121015
|
+
this.#target.classList.remove("nx-expand");
|
|
121016
|
+
this.classList.remove("nx-expand");
|
|
121017
|
+
//this.#target.style.pointerEvents = "auto";
|
|
121018
|
+
}, 600); // 애니메이션과 동일한 시간
|
|
121019
|
+
});
|
|
121020
|
+
|
|
121021
|
+
}
|
|
121022
|
+
}
|
|
121023
|
+
|
|
121024
|
+
customElements.define("nx-collapse", nxCollapse);
|
|
121025
|
+
|
|
121026
|
+
class nxTab extends HTMLElement {
|
|
121027
|
+
constructor() {
|
|
121028
|
+
super();
|
|
121029
|
+
this.attachShadow({ mode: 'open' });
|
|
121030
|
+
|
|
121031
|
+
this.shadowRoot.innerHTML = `
|
|
121032
|
+
<style>
|
|
121033
|
+
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxTab.css";
|
|
121034
|
+
${ninegrid.getCustomPath(this,"nxTab.css")}
|
|
121035
|
+
</style>
|
|
121036
|
+
|
|
121037
|
+
<div class="tabs"></div>
|
|
121038
|
+
<div class="tab-pages"></div>
|
|
121039
|
+
`;
|
|
121040
|
+
|
|
121041
|
+
//console.log(this.shadowRoot.querySelector('.tab-page'));
|
|
121042
|
+
//this.shadowRoot.querySelector('.tab-pages').style.height = this.shadowRoot.querySelector('.tab-page').style.height;
|
|
121043
|
+
|
|
121044
|
+
this.switchTabHandler = this.#switchTab.bind(this);
|
|
121045
|
+
}
|
|
121046
|
+
|
|
121047
|
+
connectedCallback() {
|
|
121048
|
+
this.#init();
|
|
121049
|
+
this.dispatchEvent(new CustomEvent(ninegrid.EVENT.TAB_LOAD, { bubbles: true, detail: {} }));
|
|
121050
|
+
}
|
|
121051
|
+
|
|
121052
|
+
#renderTabs() {
|
|
121053
|
+
const tabs = this.shadowRoot.querySelector('.tabs');
|
|
121054
|
+
const contents = this.shadowRoot.querySelector('.tab-pages');
|
|
121055
|
+
const tabItems = this.querySelectorAll('nx-tab-page');
|
|
121056
|
+
|
|
121057
|
+
tabItems.forEach((item, index) => {
|
|
121058
|
+
const tab = document.createElement('div');
|
|
121059
|
+
tab.classList.add('tab-button');
|
|
121060
|
+
tab.textContent = item.getAttribute('caption');
|
|
121061
|
+
tab.setAttribute('data-target', `content${index}`);
|
|
121062
|
+
tabs.appendChild(tab);
|
|
121063
|
+
|
|
121064
|
+
const content = document.createElement('div');
|
|
121065
|
+
content.id = `content${index}`;
|
|
121066
|
+
content.classList.add('tab-page');
|
|
121067
|
+
content.innerHTML = item.innerHTML;
|
|
121068
|
+
contents.appendChild(content);
|
|
121069
|
+
});
|
|
121070
|
+
|
|
121071
|
+
tabItems.forEach((item) => {
|
|
121072
|
+
item.remove();
|
|
121073
|
+
});
|
|
121074
|
+
}
|
|
121075
|
+
|
|
121076
|
+
#switchTab(event) {
|
|
121077
|
+
const target = event.target;
|
|
121078
|
+
if (!target.classList.contains('tab-button')) return;
|
|
121079
|
+
|
|
121080
|
+
const targetId = target.getAttribute('data-target');
|
|
121081
|
+
const activeTab = this.shadowRoot.querySelector('.tab-button.active');
|
|
121082
|
+
const activeContent = this.shadowRoot.querySelector('.tab-page.active');
|
|
121083
|
+
const newContent = this.shadowRoot.getElementById(targetId);
|
|
121084
|
+
|
|
121085
|
+
if (activeTab === target) return; // 현재 탭을 클릭했을 때 아무런 변화가 없도록 함
|
|
121086
|
+
|
|
121087
|
+
if (activeTab && activeContent) {
|
|
121088
|
+
activeTab.classList.remove('active');
|
|
121089
|
+
activeContent.classList.remove('active','exit-left','exit-right');
|
|
121090
|
+
//newContent.classList.remove('exit-left','exit-right');
|
|
121091
|
+
activeContent.style.left = '';
|
|
121092
|
+
|
|
121093
|
+
if (activeTab.compareDocumentPosition(target) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
121094
|
+
activeContent.classList.add('exit-left');
|
|
121095
|
+
} else {
|
|
121096
|
+
activeContent.classList.add('exit-right');
|
|
121097
|
+
}
|
|
121098
|
+
//console.log(index);
|
|
121099
|
+
//if (index == 1) return;
|
|
121100
|
+
|
|
121101
|
+
newContent.classList.add('active');
|
|
121102
|
+
newContent.style.left = '';
|
|
121103
|
+
|
|
121104
|
+
newContent.classList.remove('exit-left','exit-right');
|
|
121105
|
+
}
|
|
121106
|
+
|
|
121107
|
+
target.classList.add('active');
|
|
121108
|
+
//newContent.classList.add('active');
|
|
121109
|
+
this.shadowRoot.querySelector('.tab-pages').style.height = `${newContent.scrollHeight}px`;
|
|
121110
|
+
|
|
121111
|
+
//console.log(newContent.style.height, newContent.scrollHeight);
|
|
121112
|
+
};
|
|
121113
|
+
|
|
121114
|
+
#init = () => {
|
|
121115
|
+
|
|
121116
|
+
this.classList.add(this.getAttribute("theme") || "theme-1");
|
|
121117
|
+
this.#renderTabs();
|
|
121118
|
+
this.shadowRoot.querySelectorAll('.tab-button').forEach(tab => {
|
|
121119
|
+
tab.addEventListener('click', this.switchTabHandler);
|
|
121120
|
+
});
|
|
121121
|
+
|
|
121122
|
+
const firstTab = this.shadowRoot.querySelector('.tab-button');
|
|
121123
|
+
const firstContent = this.shadowRoot.querySelector('.tab-page');
|
|
121124
|
+
if (firstTab && firstContent) {
|
|
121125
|
+
firstTab.classList.add('active');
|
|
121126
|
+
firstContent.classList.add('active');
|
|
121127
|
+
setTimeout(() => {
|
|
121128
|
+
this.shadowRoot.querySelector('.tab-pages').style.height = `${firstContent.scrollHeight}px`;
|
|
121129
|
+
}, 100);
|
|
121130
|
+
//this.shadowRoot.querySelector('.tab-pages').style.height = `${firstContent.scrollHeight}px`;
|
|
121131
|
+
|
|
121132
|
+
console.log(firstContent.style.height, firstContent.scrollHeight);
|
|
121133
|
+
}
|
|
121134
|
+
|
|
121135
|
+
this.shadowRoot.querySelectorAll('.tab-page:not(.active)').forEach(el => { el.classList.add('exit-right'); });
|
|
121136
|
+
|
|
121137
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
121138
|
+
const activeContent = this.shadowRoot.querySelector('.tab-page.active');
|
|
121139
|
+
if (activeContent) {
|
|
121140
|
+
this.shadowRoot.querySelector('.tab-pages').style.height = `${activeContent.scrollHeight}px`;
|
|
121141
|
+
}
|
|
121142
|
+
});
|
|
121143
|
+
|
|
121144
|
+
const activeContent = this.shadowRoot.querySelector('.tab-page.active');
|
|
121145
|
+
if (activeContent) resizeObserver.observe(activeContent);
|
|
121146
|
+
};
|
|
121147
|
+
}
|
|
121148
|
+
|
|
121149
|
+
class nxTabPage extends HTMLElement {
|
|
121150
|
+
constructor() {
|
|
121151
|
+
super();
|
|
121152
|
+
}
|
|
121153
|
+
|
|
121154
|
+
connectedCallback() {
|
|
121155
|
+
this.caption = this.getAttribute('caption');
|
|
121156
|
+
}
|
|
121157
|
+
}
|
|
121158
|
+
|
|
121159
|
+
customElements.define('nx-tab', nxTab);
|
|
121160
|
+
customElements.define('nx-tab-page', nxTabPage);
|
|
121161
|
+
|
|
121162
|
+
class nxSplitter extends HTMLElement {
|
|
121163
|
+
#mode;
|
|
121164
|
+
|
|
121165
|
+
constructor() {
|
|
121166
|
+
super();
|
|
121167
|
+
this.attachShadow({ mode: "open" });
|
|
121168
|
+
}
|
|
121169
|
+
|
|
121170
|
+
connectedCallback() {
|
|
121171
|
+
this.#init();
|
|
121172
|
+
}
|
|
121173
|
+
|
|
121174
|
+
#detectMode = (el) => {
|
|
121175
|
+
const prev = el.previousElementSibling;
|
|
121176
|
+
const next = el.nextElementSibling;
|
|
121177
|
+
|
|
121178
|
+
const prevRect = prev?.getBoundingClientRect();
|
|
121179
|
+
const nextRect = next?.getBoundingClientRect();
|
|
121180
|
+
|
|
121181
|
+
this.#mode = (!prevRect || !nextRect) || (Math.abs(prevRect.top - nextRect.top) < 5) ? "h" : "v";
|
|
121182
|
+
};
|
|
121183
|
+
|
|
121184
|
+
#startDrag = (e) => {
|
|
121185
|
+
e.preventDefault();
|
|
121186
|
+
e.stopPropagation();
|
|
121187
|
+
|
|
121188
|
+
const splitterRect = this.getBoundingClientRect();
|
|
121189
|
+
const isHorizontal = this.#mode === "h";
|
|
121190
|
+
|
|
121191
|
+
const clickOffset = isHorizontal
|
|
121192
|
+
? e.clientX - splitterRect.left
|
|
121193
|
+
: e.clientY - splitterRect.top;
|
|
121194
|
+
|
|
121195
|
+
const dragBar = document.createElement("div");
|
|
121196
|
+
dragBar.className = `nx-splitter-drag-bar-${this.#mode}`;
|
|
121197
|
+
|
|
121198
|
+
Object.assign(dragBar.style, {
|
|
121199
|
+
position: "absolute",
|
|
121200
|
+
zIndex: "999",
|
|
121201
|
+
background: "#666",
|
|
121202
|
+
opacity: "0.6",
|
|
121203
|
+
pointerEvents: "none"
|
|
121204
|
+
});
|
|
121205
|
+
|
|
121206
|
+
const root = this.getRootNode({ composed: true });
|
|
121207
|
+
const parent = root instanceof ShadowRoot ? root.host : this.parentElement;
|
|
121208
|
+
|
|
121209
|
+
const prev = this.previousElementSibling;
|
|
121210
|
+
const next = this.nextElementSibling;
|
|
121211
|
+
|
|
121212
|
+
if (!parent || !prev || !next) {
|
|
121213
|
+
console.warn("Spliter's parent or siblings not found.");
|
|
121214
|
+
return;
|
|
121215
|
+
}
|
|
121216
|
+
|
|
121217
|
+
(parent.shadowRoot || parent).appendChild(dragBar);
|
|
121218
|
+
|
|
121219
|
+
const dragBarOffsetParent = dragBar.offsetParent;
|
|
121220
|
+
|
|
121221
|
+
if (!dragBarOffsetParent) {
|
|
121222
|
+
console.error("dragBar's offsetParent could not be determined. Ensure parent or an ancestor has a position property (e.g., relative).");
|
|
121223
|
+
dragBar.remove();
|
|
121224
|
+
return;
|
|
121225
|
+
}
|
|
121226
|
+
|
|
121227
|
+
const dragBarOffsetParentRect = dragBarOffsetParent.getBoundingClientRect();
|
|
121228
|
+
const prevRect = prev.getBoundingClientRect();
|
|
121229
|
+
const nextRect = next.getBoundingClientRect();
|
|
121230
|
+
|
|
121231
|
+
let initialPosInOffsetParent;
|
|
121232
|
+
if (isHorizontal) {
|
|
121233
|
+
initialPosInOffsetParent = e.clientX - dragBarOffsetParentRect.left;
|
|
121234
|
+
dragBar.style.top = "0";
|
|
121235
|
+
dragBar.style.left = `${initialPosInOffsetParent}px`;
|
|
121236
|
+
dragBar.style.width = "1px";
|
|
121237
|
+
dragBar.style.height = "100%";
|
|
121238
|
+
} else {
|
|
121239
|
+
initialPosInOffsetParent = e.clientY - dragBarOffsetParentRect.top;
|
|
121240
|
+
dragBar.style.left = "0";
|
|
121241
|
+
dragBar.style.top = `${initialPosInOffsetParent}px`;
|
|
121242
|
+
dragBar.style.height = "1px";
|
|
121243
|
+
dragBar.style.width = "100%";
|
|
121244
|
+
}
|
|
121245
|
+
|
|
121246
|
+
const minLimit = isHorizontal
|
|
121247
|
+
? prevRect.left - dragBarOffsetParentRect.left
|
|
121248
|
+
: prevRect.top - dragBarOffsetParentRect.top;
|
|
121249
|
+
const maxLimit = isHorizontal
|
|
121250
|
+
? nextRect.right - dragBarOffsetParentRect.left
|
|
121251
|
+
: nextRect.bottom - dragBarOffsetParentRect.top;
|
|
121252
|
+
|
|
121253
|
+
|
|
121254
|
+
const onMove = moveEvent => {
|
|
121255
|
+
const clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;
|
|
121256
|
+
const currentPosInOffsetParent = isHorizontal
|
|
121257
|
+
? clientPos - dragBarOffsetParentRect.left
|
|
121258
|
+
: clientPos - dragBarOffsetParentRect.top;
|
|
121259
|
+
|
|
121260
|
+
const clampedPos = Math.max(minLimit, Math.min(currentPosInOffsetParent, maxLimit));
|
|
121261
|
+
|
|
121262
|
+
if (isHorizontal) {
|
|
121263
|
+
dragBar.style.left = `${clampedPos}px`;
|
|
121264
|
+
} else {
|
|
121265
|
+
dragBar.style.top = `${clampedPos}px`;
|
|
121266
|
+
}
|
|
121267
|
+
|
|
121268
|
+
console.log(clampedPos);
|
|
121269
|
+
};
|
|
121270
|
+
|
|
121271
|
+
const onUp = (upEvent) => {
|
|
121272
|
+
window.removeEventListener("mousemove", onMove);
|
|
121273
|
+
window.removeEventListener("mouseup", onUp);
|
|
121274
|
+
dragBar.remove();
|
|
121275
|
+
|
|
121276
|
+
const finalDragBarPosInOffsetParent = isHorizontal
|
|
121277
|
+
? parseFloat(dragBar.style.left)
|
|
121278
|
+
: parseFloat(dragBar.style.top);
|
|
121279
|
+
|
|
121280
|
+
// ⭐⭐ offsetParentTotalSize 변수를 여기서 정의합니다 ⭐⭐
|
|
121281
|
+
const offsetParentTotalSize = isHorizontal
|
|
121282
|
+
? dragBarOffsetParentRect.width
|
|
121283
|
+
: dragBarOffsetParentRect.height;
|
|
121284
|
+
|
|
121285
|
+
const splitterThickness = isHorizontal ? splitterRect.width : splitterRect.height;
|
|
121286
|
+
|
|
121287
|
+
// prev의 시작점 (offsetParent 기준)
|
|
121288
|
+
const prevStartPosInOffsetParent = isHorizontal
|
|
121289
|
+
? prevRect.left - dragBarOffsetParentRect.left
|
|
121290
|
+
: prevRect.top - dragBarOffsetParentRect.top;
|
|
121291
|
+
|
|
121292
|
+
// prev의 새로운 크기 (dragBar의 왼쪽 위치 - prev의 왼쪽 위치)
|
|
121293
|
+
let finalPrevSize = finalDragBarPosInOffsetParent - prevStartPosInOffsetParent;
|
|
121294
|
+
|
|
121295
|
+
// next의 새로운 크기 (offsetParent의 전체 크기 - prev 크기 - 스플리터 두께)
|
|
121296
|
+
// 이 방법이 전체 공간을 정확히 채우면서 오차를 마지막 패널에 몰아넣는 데 더 견고합니다.
|
|
121297
|
+
const MIN_PANEL_SIZE_PX = 1;
|
|
121298
|
+
finalPrevSize = Math.max(MIN_PANEL_SIZE_PX, finalPrevSize) - clickOffset;
|
|
121299
|
+
let finalNextSize = Math.max(MIN_PANEL_SIZE_PX, offsetParentTotalSize - finalPrevSize - splitterThickness);
|
|
121300
|
+
|
|
121301
|
+
// flex 속성 저장 및 복원
|
|
121302
|
+
const originalPrevFlex = prev.style.flex;
|
|
121303
|
+
const originalNextFlex = next.style.flex;
|
|
121304
|
+
|
|
121305
|
+
// 드래그 중에는 flex를 "none"으로 설정하여 직접 크기 조절
|
|
121306
|
+
prev.style.flex = "none";
|
|
121307
|
+
next.style.flex = "none";
|
|
121308
|
+
|
|
121309
|
+
console.log(finalPrevSize, finalNextSize, offsetParentTotalSize);
|
|
121310
|
+
|
|
121311
|
+
if (isHorizontal) {
|
|
121312
|
+
prev.style.width = `${finalPrevSize}px`;
|
|
121313
|
+
next.style.width = `${finalNextSize}px`;
|
|
121314
|
+
} else {
|
|
121315
|
+
prev.style.height = `${finalPrevSize}px`;
|
|
121316
|
+
next.style.height = `${finalNextSize}px`;
|
|
121317
|
+
}
|
|
121318
|
+
|
|
121319
|
+
// 작업 완료 후 원래 flex 값으로 복원
|
|
121320
|
+
prev.style.flex = originalPrevFlex;
|
|
121321
|
+
next.style.flex = originalNextFlex;
|
|
121322
|
+
};
|
|
121323
|
+
|
|
121324
|
+
window.addEventListener("mousemove", onMove);
|
|
121325
|
+
window.addEventListener("mouseup", onUp);
|
|
121326
|
+
};
|
|
121327
|
+
|
|
121328
|
+
|
|
121329
|
+
#init = () => {
|
|
121330
|
+
this.#detectMode(this);
|
|
121331
|
+
|
|
121332
|
+
this.classList.add(this.#mode);
|
|
121333
|
+
|
|
121334
|
+
const contents = this.innerHTML.trim();
|
|
121335
|
+
const gripClass = `grip-${this.#mode}`;
|
|
121336
|
+
const gripTmpl = (contents === "") ? `<div class="${gripClass}"></div>`: `<div class="${gripClass}"></div><div class="inner-container">${contents}</div><div class="${gripClass}"></div>`;
|
|
121337
|
+
|
|
121338
|
+
this.innerHTML = "";
|
|
121339
|
+
const htmlTmpl = document.createElement("template");
|
|
121340
|
+
htmlTmpl.innerHTML = `
|
|
121341
|
+
<style>
|
|
121342
|
+
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxSplitter.css";
|
|
121343
|
+
${ninegrid.getCustomPath(this,"nxSplitter.css")}
|
|
121344
|
+
</style>
|
|
121345
|
+
|
|
121346
|
+
${gripTmpl}
|
|
121347
|
+
`;
|
|
121348
|
+
|
|
121349
|
+
this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
|
|
121350
|
+
|
|
121351
|
+
this.shadowRoot.querySelectorAll(".grip-h,.grip-v").forEach(el => {
|
|
121352
|
+
el.addEventListener("mousedown", e => this.#startDrag(e));
|
|
121353
|
+
});
|
|
121354
|
+
|
|
121355
|
+
this.#prepareLayout();
|
|
121356
|
+
|
|
121357
|
+
window.addEventListener("resize", () => this.#prepareLayout());
|
|
121358
|
+
};
|
|
121359
|
+
|
|
121360
|
+
#isLastSplitter = () => {
|
|
121361
|
+
const parent = this.parentElement;
|
|
121362
|
+
if (!parent) return false;
|
|
121363
|
+
|
|
121364
|
+
const allSplitters = [...parent.querySelectorAll("nx-splitter")];
|
|
121365
|
+
return allSplitters.at(-1) === this;
|
|
121366
|
+
};
|
|
121367
|
+
|
|
121368
|
+
#getSiblingSizeSum = () => {
|
|
121369
|
+
const parent = this.parentElement;
|
|
121370
|
+
if (!parent) return 0;
|
|
121371
|
+
|
|
121372
|
+
const isHorizontal = this.#mode === "h";
|
|
121373
|
+
|
|
121374
|
+
return Array.from(parent.children).reduce((sum, el) => {
|
|
121375
|
+
const size = isHorizontal ? el.offsetWidth : el.offsetHeight;
|
|
121376
|
+
return sum + size;
|
|
121377
|
+
}, 0);
|
|
121378
|
+
};
|
|
121379
|
+
|
|
121380
|
+
|
|
121381
|
+
#prepareLayout = () => {
|
|
121382
|
+
|
|
121383
|
+
const isHorizontal = this.#mode === "h";
|
|
121384
|
+
const prev = this.previousElementSibling;
|
|
121385
|
+
const next = this.nextElementSibling;
|
|
121386
|
+
const parent = this.parentElement;
|
|
121387
|
+
if (!prev || !next || !parent) return;
|
|
121388
|
+
|
|
121389
|
+
const currentTotal = this.#getSiblingSizeSum();
|
|
121390
|
+
const nextTotal = isHorizontal
|
|
121391
|
+
? parent.getBoundingClientRect().width
|
|
121392
|
+
: parent.getBoundingClientRect().height;
|
|
121393
|
+
|
|
121394
|
+
const prevSize = isHorizontal ? prev.offsetWidth : prev.offsetHeight;
|
|
121395
|
+
const nextSize = isHorizontal ? next.offsetWidth : next.offsetHeight;
|
|
121396
|
+
|
|
121397
|
+
const newPrevSize = nextTotal * prevSize / currentTotal;
|
|
121398
|
+
const newNextSize = nextTotal * nextSize / currentTotal;
|
|
121399
|
+
|
|
121400
|
+
|
|
121401
|
+
if (isHorizontal) {
|
|
121402
|
+
prev.style.width = `${newPrevSize}px`;
|
|
121403
|
+
|
|
121404
|
+
if (this.#isLastSplitter()) {
|
|
121405
|
+
next.style.width = `${newNextSize}px`;
|
|
121406
|
+
}
|
|
121407
|
+
} else {
|
|
121408
|
+
prev.style.height = `${newPrevSize}px`;
|
|
121409
|
+
|
|
121410
|
+
if (this.#isLastSplitter()) {
|
|
121411
|
+
next.style.height = `${newNextSize}px`;
|
|
121412
|
+
}
|
|
121413
|
+
}
|
|
121414
|
+
};
|
|
121415
|
+
|
|
121416
|
+
}
|
|
121417
|
+
|
|
121418
|
+
customElements.define("nx-splitter", nxSplitter);
|
|
121419
|
+
|
|
121420
|
+
class nxForm extends HTMLElement {
|
|
121421
|
+
#mode;
|
|
121422
|
+
|
|
121423
|
+
constructor() {
|
|
121424
|
+
super();
|
|
121425
|
+
this.attachShadow({ mode: "open" });
|
|
121426
|
+
}
|
|
121427
|
+
|
|
121428
|
+
connectedCallback() {
|
|
121429
|
+
this.#init();
|
|
121430
|
+
}
|
|
121431
|
+
|
|
121432
|
+
getData_BAK = () => {
|
|
121433
|
+
const jsonData = {};
|
|
121434
|
+
|
|
121435
|
+
this.shadowRoot.querySelectorAll("[id]").forEach(el => {
|
|
121436
|
+
if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
|
|
121437
|
+
jsonData[el.id] = el.value;
|
|
121438
|
+
} else {
|
|
121439
|
+
jsonData[el.id] = el.textContent.trim();
|
|
121440
|
+
}
|
|
121441
|
+
});
|
|
121442
|
+
|
|
121443
|
+
return jsonData;
|
|
121444
|
+
};
|
|
121445
|
+
|
|
121446
|
+
getData = () => {
|
|
121447
|
+
const jsonData = {};
|
|
121448
|
+
|
|
121449
|
+
this.shadowRoot.querySelectorAll("input, textarea, select, [id], [name]").forEach(el => {
|
|
121450
|
+
const key = el.id || el.name; // id가 있으면 우선, 없으면 name 사용
|
|
121451
|
+
if (!key) return; // id도 name도 없으면 건너뛰기
|
|
121452
|
+
|
|
121453
|
+
const value = (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT")
|
|
121454
|
+
? el.value
|
|
121455
|
+
: el.textContent.trim();
|
|
121456
|
+
|
|
121457
|
+
// 중복 키를 대비한 배열 처리
|
|
121458
|
+
if (jsonData[key]) {
|
|
121459
|
+
if (!Array.isArray(jsonData[key])) {
|
|
121460
|
+
jsonData[key] = [jsonData[key]];
|
|
121461
|
+
}
|
|
121462
|
+
jsonData[key].push(value);
|
|
121463
|
+
} else {
|
|
121464
|
+
jsonData[key] = value;
|
|
121465
|
+
}
|
|
121466
|
+
});
|
|
121467
|
+
|
|
121468
|
+
return jsonData;
|
|
121469
|
+
};
|
|
121470
|
+
|
|
121471
|
+
|
|
121472
|
+
#init = () => {
|
|
121473
|
+
|
|
121474
|
+
const contents = this.innerHTML.trim();
|
|
121475
|
+
|
|
121476
|
+
this.innerHTML = ""; // 기존 내부 HTML 제거
|
|
121477
|
+
const htmlTmpl = document.createElement("template");
|
|
121478
|
+
htmlTmpl.innerHTML = `
|
|
121479
|
+
<style>
|
|
121480
|
+
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxForm.css";
|
|
121481
|
+
${ninegrid.getCustomPath(this,"nxForm.css")}
|
|
121482
|
+
</style>
|
|
121483
|
+
|
|
121484
|
+
${contents}
|
|
121485
|
+
`;
|
|
121486
|
+
|
|
121487
|
+
this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
|
|
121488
|
+
};
|
|
121489
|
+
|
|
121490
|
+
}
|
|
121491
|
+
|
|
121492
|
+
customElements.define("nx-form", nxForm);
|
|
121493
|
+
|
|
121034
121494
|
class aiSettings extends HTMLElement
|
|
121035
121495
|
{
|
|
121036
121496
|
constructor() {
|
|
@@ -121405,6 +121865,80 @@ class aiMyMessage extends HTMLElement
|
|
|
121405
121865
|
};
|
|
121406
121866
|
}
|
|
121407
121867
|
|
|
121868
|
+
// aiProgressMessage 클래스 정의
|
|
121869
|
+
class aiProgressMessage extends HTMLElement {
|
|
121870
|
+
#progressData = []; // 진행 상태 데이터를 저장할 배열
|
|
121871
|
+
#progressElements = new Map(); // 각 진행 단계의 DOM 요소를 저장할 Map
|
|
121872
|
+
|
|
121873
|
+
constructor() {
|
|
121874
|
+
super();
|
|
121875
|
+
this.attachShadow({ mode: 'open' });
|
|
121876
|
+
}
|
|
121877
|
+
|
|
121878
|
+
connectedCallback() {
|
|
121879
|
+
this.shadowRoot.innerHTML = `
|
|
121880
|
+
<style>
|
|
121881
|
+
@import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ai.css";
|
|
121882
|
+
${ninegrid.getCustomPath(this, "ai.css")}
|
|
121883
|
+
</style>
|
|
121884
|
+
<div class="chat-message progress-message">
|
|
121885
|
+
<ul class="progress-list"></ul>
|
|
121886
|
+
</div>
|
|
121887
|
+
`;
|
|
121888
|
+
}
|
|
121889
|
+
|
|
121890
|
+
/**
|
|
121891
|
+
* 진행 상태 데이터를 초기화하고 화면에 표시합니다.
|
|
121892
|
+
* @param {Array<Object>} data - [{id: 'step1', message: '분석중입니다...', completedMessage: '분석이 완료되었습니다.'}, ...]
|
|
121893
|
+
*/
|
|
121894
|
+
initialize(data) {
|
|
121895
|
+
this.#progressData = data.map(item => ({ ...item, status: 'pending' })); // 초기 상태는 'pending'
|
|
121896
|
+
this.#renderProgress();
|
|
121897
|
+
}
|
|
121898
|
+
|
|
121899
|
+
/**
|
|
121900
|
+
* 특정 단계의 진행 상태를 업데이트합니다.
|
|
121901
|
+
* @param {string} id - 업데이트할 단계의 고유 ID
|
|
121902
|
+
* @param {string} status - 'completed' 또는 'pending'
|
|
121903
|
+
*/
|
|
121904
|
+
updateProgress(id, status) {
|
|
121905
|
+
const itemIndex = this.#progressData.findIndex(item => item.id === id);
|
|
121906
|
+
if (itemIndex > -1) {
|
|
121907
|
+
this.#progressData[itemIndex].status = status;
|
|
121908
|
+
this.#updateProgressItem(this.#progressData[itemIndex]);
|
|
121909
|
+
}
|
|
121910
|
+
}
|
|
121911
|
+
|
|
121912
|
+
#renderProgress() {
|
|
121913
|
+
const progressList = this.shadowRoot.querySelector(".progress-list");
|
|
121914
|
+
progressList.innerHTML = ''; // 기존 목록 초기화
|
|
121915
|
+
this.#progressElements.clear(); // 기존 요소 Map 초기화
|
|
121916
|
+
|
|
121917
|
+
this.#progressData.forEach((item, index) => {
|
|
121918
|
+
const li = document.createElement("li");
|
|
121919
|
+
li.setAttribute("data-id", item.id);
|
|
121920
|
+
li.classList.add("progress-item", item.status);
|
|
121921
|
+
li.innerHTML = `
|
|
121922
|
+
<span class="icon"></span>
|
|
121923
|
+
<span class="text">${item.message}</span>
|
|
121924
|
+
`;
|
|
121925
|
+
progressList.appendChild(li);
|
|
121926
|
+
this.#progressElements.set(item.id, li); // DOM 요소 참조 저장
|
|
121927
|
+
});
|
|
121928
|
+
}
|
|
121929
|
+
|
|
121930
|
+
#updateProgressItem(item) {
|
|
121931
|
+
const li = this.#progressElements.get(item.id);
|
|
121932
|
+
if (li) {
|
|
121933
|
+
li.classList.remove('pending', 'completed'); // 기존 클래스 제거
|
|
121934
|
+
li.classList.add(item.status); // 새 상태 클래스 추가
|
|
121935
|
+
li.querySelector(".text").textContent = item.status === 'completed' ? item.completedMessage : item.message;
|
|
121936
|
+
}
|
|
121937
|
+
}
|
|
121938
|
+
}
|
|
121939
|
+
|
|
121940
|
+
|
|
121941
|
+
|
|
121408
121942
|
class aiChat extends HTMLElement
|
|
121409
121943
|
{
|
|
121410
121944
|
constructor() {
|
|
@@ -121475,11 +122009,47 @@ class aiChat extends HTMLElement
|
|
|
121475
122009
|
el.scrollIntoView({ behavior: "smooth", block: "end" });
|
|
121476
122010
|
}, 200);
|
|
121477
122011
|
};
|
|
122012
|
+
|
|
122013
|
+
/**
|
|
122014
|
+
* 챗 메시지를 추가합니다.
|
|
122015
|
+
* @param {string} sender - 메시지 발신자 ('me', 'ing', 'ai', 'progress')
|
|
122016
|
+
* @param {string} message - 메시지 내용 (progress 타입의 경우 사용되지 않음)
|
|
122017
|
+
* @param {Array<Object>} info - nine-grid 정보 (ai 타입에만 해당)
|
|
122018
|
+
* @param {Array<Object>} data - nine-grid 데이터 (ai 타입에만 해당)
|
|
122019
|
+
* @param {Array<string>|string} unique - nine-grid 고유 키 (ai 타입에만 해당)
|
|
122020
|
+
* @param {Array<Object>} progressData - aiProgressMessage의 초기 진행 데이터 (progress 타입에만 해당)
|
|
122021
|
+
* @returns {HTMLElement|null} 생성된 메시지 엘리먼트 (특히 aiProgressMessage의 경우 업데이트를 위해 반환)
|
|
122022
|
+
*/
|
|
122023
|
+
addProgress = (progressData = null) => { // progressData 파라미터 추가
|
|
122024
|
+
|
|
122025
|
+
const target = this.shadowRoot.querySelector(".chat-body");
|
|
122026
|
+
|
|
122027
|
+
this.shadowRoot.querySelectorAll("nx-ai-ing-message").forEach(el => {
|
|
122028
|
+
el.remove();
|
|
122029
|
+
});
|
|
122030
|
+
|
|
122031
|
+
let el = document.createElement("nx-ai-progress-message");
|
|
122032
|
+
if (progressData) {
|
|
122033
|
+
el.initialize(progressData); // progressData로 초기화
|
|
122034
|
+
}
|
|
122035
|
+
target.appendChild(el);
|
|
122036
|
+
|
|
122037
|
+
setTimeout(() => {
|
|
122038
|
+
if (el) { // el이 null이 아닐 때만 scrollIntoView 호출
|
|
122039
|
+
el.scrollIntoView({ behavior: "smooth", block: "end" });
|
|
122040
|
+
}
|
|
122041
|
+
}, 200);
|
|
122042
|
+
|
|
122043
|
+
return el; // 생성된 엘리먼트를 반환
|
|
122044
|
+
};
|
|
121478
122045
|
}
|
|
121479
122046
|
|
|
122047
|
+
|
|
122048
|
+
|
|
121480
122049
|
customElements.define("nx-ai-message", aiMessage);
|
|
121481
122050
|
customElements.define("nx-ai-ing-message", aiIngMessage);
|
|
121482
122051
|
customElements.define("nx-ai-my-message", aiMyMessage);
|
|
122052
|
+
customElements.define("nx-ai-progress-message", aiProgressMessage);
|
|
121483
122053
|
customElements.define("nx-ai-chat", aiChat);
|
|
121484
122054
|
|
|
121485
122055
|
/**
|
|
@@ -201847,351 +202417,6 @@ class IdeAssi extends HTMLElement
|
|
|
201847
202417
|
//this.shadowRoot.querySelector('ide-diff-popup').remove();
|
|
201848
202418
|
|
|
201849
202419
|
this.shadowRoot.appendChild(document.createElement('ide-diff-popup'));
|
|
201850
|
-
|
|
201851
|
-
//setTimeout(() => {
|
|
201852
|
-
let src1 = `
|
|
201853
|
-
import React, { useRef, useEffect } from "react" adfa;
|
|
201854
|
-
import { api, ai } from "ide-assi";
|
|
201855
|
-
import ninegrid from "ninegrid2";
|
|
201856
|
-
|
|
201857
|
-
const DocManager = () => {
|
|
201858
|
-
const tabRef = useRef(null);
|
|
201859
|
-
const gridRef = useRef(null);
|
|
201860
|
-
|
|
201861
|
-
const selectList = async (params) => {
|
|
201862
|
-
if (!gridRef.current) return;
|
|
201863
|
-
gridRef.current.classList.add("loading");
|
|
201864
|
-
api.post(\`/api/tmpl-a/doc-manager/selectList\`, params).then((res) => {
|
|
201865
|
-
gridRef.current.data.source = res.list;
|
|
201866
|
-
});
|
|
201867
|
-
};
|
|
201868
|
-
|
|
201869
|
-
const handleNaturalLanguageSearch = async () => {
|
|
201870
|
-
const searchTextElement = ninegrid.querySelector("#searchText", tabRef.current);
|
|
201871
|
-
const searchText = searchTextElement ? searchTextElement.value : "";
|
|
201872
|
-
|
|
201873
|
-
if (!gridRef.current) return;
|
|
201874
|
-
gridRef.current.classList.add("loading");
|
|
201875
|
-
|
|
201876
|
-
let params = {};
|
|
201877
|
-
if (searchText) {
|
|
201878
|
-
params = {
|
|
201879
|
-
_whereClause: await ai.generateWhereCause(
|
|
201880
|
-
"tmpla/DocManagerMapper.xml",
|
|
201881
|
-
"selectList",
|
|
201882
|
-
searchText,
|
|
201883
|
-
import.meta.env.VITE_GEMINI_API_KEY
|
|
201884
|
-
),
|
|
201885
|
-
};
|
|
201886
|
-
}
|
|
201887
|
-
selectList(params);
|
|
201888
|
-
};
|
|
201889
|
-
|
|
201890
|
-
const handleClassicSearch = () => {
|
|
201891
|
-
if (!gridRef.current) return;
|
|
201892
|
-
gridRef.current.classList.add("loading");
|
|
201893
|
-
|
|
201894
|
-
const form2Element = ninegrid.querySelector(".form2", tabRef.current);
|
|
201895
|
-
const params = form2Element ? form2Element.getData() : {};
|
|
201896
|
-
selectList(params);
|
|
201897
|
-
};
|
|
201898
|
-
|
|
201899
|
-
useEffect(() => {
|
|
201900
|
-
selectList({});
|
|
201901
|
-
|
|
201902
|
-
const searchTextElement = ninegrid.querySelector("#searchText", tabRef.current);
|
|
201903
|
-
const searchButton = ninegrid.querySelector(".search", tabRef.current);
|
|
201904
|
-
|
|
201905
|
-
const handleKeyDown = (e) => {
|
|
201906
|
-
if (e.key === "Enter" && !e.isComposing) {
|
|
201907
|
-
handleNaturalLanguageSearch();
|
|
201908
|
-
}
|
|
201909
|
-
};
|
|
201910
|
-
|
|
201911
|
-
const handleClick = () => {
|
|
201912
|
-
handleClassicSearch();
|
|
201913
|
-
};
|
|
201914
|
-
|
|
201915
|
-
if (searchTextElement) {
|
|
201916
|
-
searchTextElement.addEventListener("keydown", handleKeyDown);
|
|
201917
|
-
}
|
|
201918
|
-
if (searchButton) {
|
|
201919
|
-
searchButton.addEventListener("click", handleClick);
|
|
201920
|
-
}
|
|
201921
|
-
|
|
201922
|
-
return () => {
|
|
201923
|
-
if (searchTextElement) {
|
|
201924
|
-
searchTextElement.removeEventListener("keydown", handleKeyDown);
|
|
201925
|
-
}
|
|
201926
|
-
if (searchButton) {
|
|
201927
|
-
searchButton.removeEventListener("click", handleClick);
|
|
201928
|
-
}
|
|
201929
|
-
};
|
|
201930
|
-
}, []);
|
|
201931
|
-
|
|
201932
|
-
return (
|
|
201933
|
-
<div className="wrapper">
|
|
201934
|
-
<nx-collapse target="nx-tab" className="search-collapse"></nx-collapse>
|
|
201935
|
-
<div className="list-wrapper">
|
|
201936
|
-
<nx-tab theme="theme-3" ref={tabRef}>
|
|
201937
|
-
<nx-tab-page caption="자연어 검색">
|
|
201938
|
-
<nx-form className="form1">
|
|
201939
|
-
<input
|
|
201940
|
-
type="text"
|
|
201941
|
-
id="searchText"
|
|
201942
|
-
name="searchText"
|
|
201943
|
-
placeholder="자연어 검색어를 입력하세요 (ex: 작성자가 홍길동인 데이타를 찾아줘)"
|
|
201944
|
-
/>
|
|
201945
|
-
</nx-form>
|
|
201946
|
-
</nx-tab-page>
|
|
201947
|
-
<nx-tab-page caption="클래식 검색">
|
|
201948
|
-
<nx-form className="form2">
|
|
201949
|
-
<label>문서명: <input type="text" name="docNm" /></label>
|
|
201950
|
-
<label>매출액:
|
|
201951
|
-
<input type="number" name="minAmt" placeholder="최소" /> ~
|
|
201952
|
-
<input type="number" name="maxAmt" placeholder="최대" />
|
|
201953
|
-
</label>
|
|
201954
|
-
</nx-form>
|
|
201955
|
-
<button className="search">검색</button>
|
|
201956
|
-
</nx-tab-page>
|
|
201957
|
-
</nx-tab>
|
|
201958
|
-
|
|
201959
|
-
<div className="grid-wrapper">
|
|
201960
|
-
<nine-grid
|
|
201961
|
-
ref={gridRef}
|
|
201962
|
-
caption="문서관리"
|
|
201963
|
-
select-type="row"
|
|
201964
|
-
show-title-bar="true"
|
|
201965
|
-
show-menu-icon="true"
|
|
201966
|
-
show-status-bar="true"
|
|
201967
|
-
enable-fixed-col="true"
|
|
201968
|
-
row-resizable="false"
|
|
201969
|
-
col-movable="true"
|
|
201970
|
-
>
|
|
201971
|
-
<table>
|
|
201972
|
-
<colgroup>
|
|
201973
|
-
<col width="50" fixed="left" background-color="gray" />
|
|
201974
|
-
<col width="100" />
|
|
201975
|
-
<col width="100" />
|
|
201976
|
-
<col width="200" />
|
|
201977
|
-
<col width="120" />
|
|
201978
|
-
<col width="100" />
|
|
201979
|
-
<col width="150" />
|
|
201980
|
-
<col width="150" />
|
|
201981
|
-
</colgroup>
|
|
201982
|
-
<thead>
|
|
201983
|
-
<tr>
|
|
201984
|
-
<th>No.</th>
|
|
201985
|
-
<th>최종수정자</th>
|
|
201986
|
-
<th>문서ID</th>
|
|
201987
|
-
<th>문서명</th>
|
|
201988
|
-
<th>매출액</th>
|
|
201989
|
-
<th>최초등록자</th>
|
|
201990
|
-
<th>최초등록일</th>
|
|
201991
|
-
<th>최종수정일</th>
|
|
201992
|
-
</tr>
|
|
201993
|
-
</thead>
|
|
201994
|
-
<tbody>
|
|
201995
|
-
<tr>
|
|
201996
|
-
<th><ng-row-indicator /></th>
|
|
201997
|
-
<td data-bind="updateUser" text-align="center"></td>
|
|
201998
|
-
<td data-bind="docId" text-align="center"></td>
|
|
201999
|
-
<td data-bind="docNm" text-align="left"></td>
|
|
202000
|
-
<td
|
|
202001
|
-
data-bind="amt"
|
|
202002
|
-
data-expr="data.amt.toLocaleString()"
|
|
202003
|
-
text-align="right"
|
|
202004
|
-
show-icon="true"
|
|
202005
|
-
icon-type="sphere"
|
|
202006
|
-
icon-color="data.amt >= 2000 ? 'red' : 'gray'"
|
|
202007
|
-
></td>
|
|
202008
|
-
<td data-bind="insertUser" text-align="center"></td>
|
|
202009
|
-
<td data-bind="insertDt" text-align="center"></td>
|
|
202010
|
-
<td data-bind="updateDt" text-align="center"></td>
|
|
202011
|
-
</tr>
|
|
202012
|
-
</tbody>
|
|
202013
|
-
</table>
|
|
202014
|
-
</nine-grid>
|
|
202015
|
-
</div>
|
|
202016
|
-
</div>
|
|
202017
|
-
</div>
|
|
202018
|
-
);
|
|
202019
|
-
};
|
|
202020
|
-
|
|
202021
|
-
export default DocManager;
|
|
202022
|
-
`;
|
|
202023
|
-
|
|
202024
|
-
let src2 = `
|
|
202025
|
-
import React, { useRef, useEffect } from "react";
|
|
202026
|
-
import { api, ai } from "ide-assi";
|
|
202027
|
-
import ninegrid from "ninegrid2";
|
|
202028
|
-
|
|
202029
|
-
const DocManager = () => {
|
|
202030
|
-
const tabRef = useRef(null);
|
|
202031
|
-
const gridRef = useRef(null);
|
|
202032
|
-
|
|
202033
|
-
const selectList = async (params) => {
|
|
202034
|
-
if (!gridRef.current) return;
|
|
202035
|
-
gridRef.current.classList.add("loading");
|
|
202036
|
-
api.post(\`/api/tmpl-a/doc-manager/selectList\`, params).then((res) => {
|
|
202037
|
-
gridRef.current.data.source = res.list;
|
|
202038
|
-
});
|
|
202039
|
-
};
|
|
202040
|
-
|
|
202041
|
-
const handleNaturalLanguageSearch = async () => {
|
|
202042
|
-
const searchTextElement = ninegrid.querySelector("#searchText", tabRef.current);
|
|
202043
|
-
const searchText = searchTextElement ? searchTextElement.value : "";
|
|
202044
|
-
|
|
202045
|
-
if (!gridRef.current) return;
|
|
202046
|
-
gridRef.current.classList.add("loading");
|
|
202047
|
-
|
|
202048
|
-
let params = {};
|
|
202049
|
-
if (searchText) {
|
|
202050
|
-
params = {
|
|
202051
|
-
_whereClause: await ai.generateWhereCause(
|
|
202052
|
-
"tmpla/DocManagerMapper.xml",
|
|
202053
|
-
"selectList",
|
|
202054
|
-
searchText,
|
|
202055
|
-
import.meta.env.VITE_GEMINI_API_KEY
|
|
202056
|
-
),
|
|
202057
|
-
};
|
|
202058
|
-
}
|
|
202059
|
-
selectList(params);
|
|
202060
|
-
};
|
|
202061
|
-
|
|
202062
|
-
const handleClassicSearch = () => {
|
|
202063
|
-
if (!gridRef.current) return;
|
|
202064
|
-
gridRef.current.classList.add("loading");
|
|
202065
|
-
|
|
202066
|
-
const form2Element = ninegrid.querySelector(".form2", tabRef.current);
|
|
202067
|
-
const params = form2Element ? form2Element.getData() : {};
|
|
202068
|
-
selectList(params);
|
|
202069
|
-
};
|
|
202070
|
-
|
|
202071
|
-
useEffect(() => {
|
|
202072
|
-
selectList({});
|
|
202073
|
-
|
|
202074
|
-
const searchTextElement = ninegrid.querySelector("#searchText", tabRef.current);
|
|
202075
|
-
const searchButton = ninegrid.querySelector(".search", tabRef.current);
|
|
202076
|
-
|
|
202077
|
-
const handleKeyDown = (e) => {
|
|
202078
|
-
if (e.key === "Enter" && !e.isComposing) {
|
|
202079
|
-
handleNaturalLanguageSearch();
|
|
202080
|
-
}
|
|
202081
|
-
};
|
|
202082
|
-
|
|
202083
|
-
const handleClick = () => {
|
|
202084
|
-
handleClassicSearch();
|
|
202085
|
-
};
|
|
202086
|
-
|
|
202087
|
-
if (searchTextElement) {
|
|
202088
|
-
searchTextElement.addEventListener("keydown", handleKeyDown);
|
|
202089
|
-
}
|
|
202090
|
-
if (searchButton) {
|
|
202091
|
-
searchButton.addEventListener("click", handleClick);
|
|
202092
|
-
}
|
|
202093
|
-
|
|
202094
|
-
return () => {
|
|
202095
|
-
if (searchTextElement) {
|
|
202096
|
-
searchTextElement.removeEventListener("keydown", handleKeyDown);
|
|
202097
|
-
}
|
|
202098
|
-
if (searchButton) {
|
|
202099
|
-
searchButton.removeEventListener("click", handleClick);
|
|
202100
|
-
}
|
|
202101
|
-
};
|
|
202102
|
-
}, []);
|
|
202103
|
-
|
|
202104
|
-
return (
|
|
202105
|
-
<div className="wrapper">
|
|
202106
|
-
<nx-collapse target="nx-tab" className="search-collapse"></nx-collapse>
|
|
202107
|
-
<div className="list-wrapper">
|
|
202108
|
-
<nx-tab theme="theme-3" ref={tabRef}>
|
|
202109
|
-
<nx-tab-page caption="자연어 검색">
|
|
202110
|
-
<nx-form className="form1">
|
|
202111
|
-
<input
|
|
202112
|
-
type="text"
|
|
202113
|
-
id="searchText"
|
|
202114
|
-
name="searchText"
|
|
202115
|
-
placeholder="자연어 검색어를 입력하세요 (ex: 작성자가 홍길동인 데이타를 찾아줘)"
|
|
202116
|
-
/>
|
|
202117
|
-
</nx-form>
|
|
202118
|
-
</nx-tab-page>
|
|
202119
|
-
<nx-tab-page caption="클래식 검색">
|
|
202120
|
-
<nx-form className="form2">
|
|
202121
|
-
<label>문서명: <input type="text" name="docNm" /></label>
|
|
202122
|
-
<label>매출액:
|
|
202123
|
-
<input type="number" name="minAmt" placeholder="최소" /> ~
|
|
202124
|
-
<input type="number" name="maxAmt" placeholder="최대" />
|
|
202125
|
-
</label>
|
|
202126
|
-
</nx-form>
|
|
202127
|
-
<button className="search">검색</button>
|
|
202128
|
-
</nx-tab-page>
|
|
202129
|
-
</nx-tab>
|
|
202130
|
-
|
|
202131
|
-
<div className="grid-wrapper">
|
|
202132
|
-
<nine-grid
|
|
202133
|
-
ref={gridRef}
|
|
202134
|
-
caption="매출 문서 관리"
|
|
202135
|
-
select-type="row"
|
|
202136
|
-
show-title-bar="true"
|
|
202137
|
-
show-menu-icon="true"
|
|
202138
|
-
show-status-bar="true"
|
|
202139
|
-
enable-fixed-col="true"
|
|
202140
|
-
row-resizable="false"
|
|
202141
|
-
col-movable="true"
|
|
202142
|
-
>
|
|
202143
|
-
<table>
|
|
202144
|
-
<colgroup>
|
|
202145
|
-
<col width="50" fixed="left" background-color="gray" />
|
|
202146
|
-
<col width="100" />
|
|
202147
|
-
<col width="120" />
|
|
202148
|
-
<col width="100" />
|
|
202149
|
-
<col width="200" />
|
|
202150
|
-
<col width="100" />
|
|
202151
|
-
<col width="150" />
|
|
202152
|
-
<col width="150" />
|
|
202153
|
-
</colgroup>
|
|
202154
|
-
<thead>
|
|
202155
|
-
<tr>
|
|
202156
|
-
<th>No.</th>
|
|
202157
|
-
<th>문서ID</th>
|
|
202158
|
-
<th>매출액</th>
|
|
202159
|
-
<th>최종수정자</th>
|
|
202160
|
-
<th>문서명</th>
|
|
202161
|
-
<th>최초등록자</th>
|
|
202162
|
-
<th>최초등록일</th>
|
|
202163
|
-
<th>최종수정일</th>
|
|
202164
|
-
</tr>
|
|
202165
|
-
</thead>
|
|
202166
|
-
<tbody>
|
|
202167
|
-
<tr>
|
|
202168
|
-
<th><ng-row-indicator /></th>
|
|
202169
|
-
<td data-bind="docId" text-align="center"></td>
|
|
202170
|
-
<td
|
|
202171
|
-
data-bind="amt"
|
|
202172
|
-
data-expr="data.amt.toLocaleString()"
|
|
202173
|
-
text-align="right"
|
|
202174
|
-
show-icon="true"
|
|
202175
|
-
icon-type="sphere"
|
|
202176
|
-
icon-color="data.amt >= 2000 ? 'red' : 'gray'"
|
|
202177
|
-
></td>
|
|
202178
|
-
<td data-bind="updateUser" text-align="center"></td>
|
|
202179
|
-
<td data-bind="docNm" text-align="left"></td>
|
|
202180
|
-
<td data-bind="insertUser" text-align="center"></td>
|
|
202181
|
-
<td data-bind="insertDt" text-align="center"></td>
|
|
202182
|
-
<td data-bind="updateDt" text-align="center"></td>
|
|
202183
|
-
</tr>
|
|
202184
|
-
</tbody>
|
|
202185
|
-
</table>
|
|
202186
|
-
</nine-grid>
|
|
202187
|
-
</div>
|
|
202188
|
-
</div>
|
|
202189
|
-
</div>
|
|
202190
|
-
);
|
|
202191
|
-
};
|
|
202192
|
-
|
|
202193
|
-
export default DocManager1;
|
|
202194
|
-
`;
|
|
202195
202420
|
/**
|
|
202196
202421
|
src1 = `
|
|
202197
202422
|
<tr>
|
|
@@ -202218,9 +202443,48 @@ export default DocManager1;
|
|
|
202218
202443
|
</tr>
|
|
202219
202444
|
`; */
|
|
202220
202445
|
|
|
202221
|
-
this.shadowRoot.querySelector("ide-diff-popup").popup(src1, src2);
|
|
202446
|
+
//this.shadowRoot.querySelector("ide-diff-popup").popup(src1, src2);
|
|
202447
|
+
|
|
202448
|
+
//return;
|
|
202449
|
+
|
|
202450
|
+
|
|
202451
|
+
// 1. 초기 진행 상태 메시지 추가
|
|
202452
|
+
const initialProgressData = [
|
|
202453
|
+
{ id: 'analysis', message: '1. 분석중입니다...', completedMessage: '1-1. 분석이 완료되었습니다.' },
|
|
202454
|
+
{ id: 'design', message: '2. 설계중...', completedMessage: '2-1. 설계가 완료되었습니다.' },
|
|
202455
|
+
{ id: 'development', message: '3. 개발중...', completedMessage: '3-1. 개발이 완료되었습니다.' }
|
|
202456
|
+
];
|
|
202457
|
+
|
|
202458
|
+
// aiChat.add 호출 시, progressData를 마지막 인자로 전달하고 생성된 엘리먼트를 받습니다.
|
|
202459
|
+
const progressMessageInstance = elAiChat.addProgress(initialProgressData);
|
|
202460
|
+
|
|
202461
|
+
// 2. 시간이 지난 후, 특정 단계의 완료를 알림
|
|
202462
|
+
// 예를 들어, 3초 후에 분석 완료
|
|
202463
|
+
setTimeout(() => {
|
|
202464
|
+
if (progressMessageInstance) {
|
|
202465
|
+
progressMessageInstance.updateProgress('analysis', 'completed');
|
|
202466
|
+
console.log("분석 완료 메시지 업데이트");
|
|
202467
|
+
}
|
|
202468
|
+
}, 3000);
|
|
202469
|
+
|
|
202470
|
+
// 예를 들어, 6초 후에 설계 완료
|
|
202471
|
+
setTimeout(() => {
|
|
202472
|
+
if (progressMessageInstance) {
|
|
202473
|
+
progressMessageInstance.updateProgress('design', 'completed');
|
|
202474
|
+
console.log("설계 완료 메시지 업데이트");
|
|
202475
|
+
}
|
|
202476
|
+
}, 6000);
|
|
202477
|
+
|
|
202478
|
+
// 모든 단계가 완료된 후, 일반 AI 메시지 추가 (선택 사항)
|
|
202479
|
+
setTimeout(() => {
|
|
202480
|
+
elAiChat.add("ai", "모든 작업이 성공적으로 완료되었습니다!", [], []);
|
|
202481
|
+
}, 9000);
|
|
202482
|
+
|
|
202483
|
+
|
|
202222
202484
|
|
|
202223
202485
|
return;
|
|
202486
|
+
|
|
202487
|
+
const elAiChat = this.shadowRoot.querySelector("nx-ai-chat");
|
|
202224
202488
|
}
|
|
202225
202489
|
|
|
202226
202490
|
#toggleCollapseHandler = () => {
|
|
@@ -234916,11 +235180,11 @@ class MergeButtonWidget extends WidgetType {
|
|
|
234916
235180
|
if (this.isAsisButton) {
|
|
234917
235181
|
// ASIS (왼쪽) 에디터에 붙는 버튼: AI가 삭제한 것을 '삭제' (ASIS에서 제거)
|
|
234918
235182
|
button.className = "cm-merge-button revert"; // 'revert' 클래스 사용 (빨간색)
|
|
234919
|
-
button.textContent = "삭제"; // 텍스트 변경
|
|
235183
|
+
//button.textContent = "삭제"; // 텍스트 변경
|
|
234920
235184
|
} else {
|
|
234921
235185
|
// TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용' (ASIS에 반영)
|
|
234922
235186
|
button.className = "cm-merge-button accept"; // 'accept' 클래스 사용 (녹색)
|
|
234923
|
-
button.textContent = "← 적용"; // 화살표 방향 변경
|
|
235187
|
+
//button.textContent = "← 적용"; // 화살표 방향 변경
|
|
234924
235188
|
}
|
|
234925
235189
|
|
|
234926
235190
|
// 클릭 이벤트 핸들러
|