@ninebone/datagrid 0.0.0-stage → 0.0.3
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/LICENSE +21 -0
- package/README.md +108 -2
- package/dist/css/nine-table.css +1713 -0
- package/dist/nine-table.js +4234 -0
- package/dist/nine-table.js.map +1 -0
- package/dist/nine-table.umd.js +223 -0
- package/dist/nine-table.umd.js.map +1 -0
- package/package.json +49 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nine-table.umd.js","names":["traceOrigin","GROUP_IDX","GROUP_IDX","factory","global","exports","start","end","mid","target","elementDebounceState","el","state","pointerEvent","pointerFn","debounceTime","dblClickEvent","dblClickFn","_text","stripHtml","tmp","html","canvas","context","_font","w","h","v","cleanText","metrics","ascent","descent","trace","_ninebone_util","NINE_TABLE","ngRow","#parent","parent","#newrow","ngData","#host","host","#initialize","o","validRecords","#getValidRecords","at","targetRecord","colnm","idx","rowData","rowIndex","colIndex","value","#conv","fields","#defaultHeight","templateElements","#getDefaultMeta","$el","loadData","dataSource","#invalidate","#nextId","rowid","jsonArray","arr","json","#json2Array","#defaultInsert","row","updateState","b","a","rowidx","targetId","item","COL_IDX","oldValue","isSingle","targetArr","result","i","ngDataManager","ds","rowIdx","nRow","#init","#fields","f","found","fieldName","fName","#adjust","map","name","type","rawTables","tbl","fieldType","attr","expr","lastIndex","targetField","NineTableSheets","NineTableSheetsFooter","#render","isMultiSelect","tabItem","index","#switchSheet","updateSplitters","sheets","s","activeSheets","sheet","currentIdx","targetSplitter","tabBar","body","tabItems","sheetElements","tab","isActive","clickedTab","activeTabs","targetSheet","tabsHtml","table","SheetTabItem","Toolbar","#bindEvents","#customContainer","#syncStateFromHost","isSimple","showToolbar","showMenu","caption","titleEl","link","currentCaption","menuBtn","element","text","NineTableHScrollBar","#owner","initWhenReady","#elements","#observeResize","#resizeObserver","#dragging","track","thumb","bodyWidth","tableWidth","needsHScroll","trackWidth","thumbWidth","currentLeft","maxScrollLeft","l","maxThumbLeft","trackBound","targetX","x","delayScroll","#interval1","#interval2","thumbLeft","#thumbMoveTo","pos","currentThumbLeft","clearTimer","evt","e","trackRect","onMouseMove","moveEvent","onMouseUp","NineTableVScrollBar","#sheet","viewRecords","totalCount","scrollHolder","rawContentHeight","MAX_BROWSER_HEIGHT","useScaling","scaleFactor","contentHeight","#getScaleInfo","fixedHeight","bodyHeight","viewHeight","needsVScroll","trackHeight","thumbHeight","currentScrollTop","maxScrollTop","thumbTop","maxThumbTop","#startY","#startThumbTop","deltaY","targetThumbTop","ratio","rowHeight","visibleRowCount","targetRow","clickY","scrollInterval","startContinuousScroll","scrollStep","$firstTr","direction","currentRow","stopContinuousScroll","GROUP_IDX$1","GroupingManager","#groupColumns","#groupMap","groupColumns","sourceTable","$cell","$tr","#isApplying","groupId","rowIds","dataManager","Grouping","validRaw","rawRecords","groupMap","nestedTree","#buildNestedMap","flatResult","renderItems","#flattenTree","counter","isLastLevel","depth","groupKey","subMapOrRecords","mapOrArray","parentId","#collectLeafRowIds","groupRecord","resultArr","#collectLeafRecords","record","remainingCols","records","key","subRecords","subVal","r","RowManager","#initResizeObserver","#templateRowHeights","sum","bodyViewport","#cachedTemplateHeight","#measureAndCacheHeight","#renderAllContainers","#handleScroll","force","#isGrouped","#handleGroupedScroll","scrollTop","templateLength","rawTotalVirtualHeight","totalVirtualHeight","actualScrollTop","maxStartIndex","clampedScrollTop","startIndex","renderOffsetTop","firstTr","#element","currentStartIndex","$tbody","dataIndex","#bindRowData","allRenderItems","totalVirtualCount","bodyContent","getItemHeight","dataRowsHeight","groupHeightsTotal","itemHeights","viewportClientHeight","accumulatedHeight","offsetY","visibleRowsCount","dynamicBuffer","targetStart","targetEnd","renderedItems","container","selector","trs","itemIndex","chunkTrs","virtualIndex","isTrGroup","tr","subIdx","#bindGroupRowData","subRowIndex","matrixRow","indices","allRecords","childrenRecords","customComp","#containerTemplates","tableEl","tbody","templateTrs","#sheetHeight","#isProgrammaticScroll","dataRow","targetScrollTop","rawTargetScrollTop","onRendered","trTemplates","fragment","renderedTrs","computedStyle","#updateRowCount","visibleRows","#BUFFER_ROW_COUNT","groupDepth","#cachedRowCount","#renderRows","#syncRowHeights","targetFixedType","clonedTr","targetTbody","tmpl","leftTable","bodyTable","rightTable","leftRows","bodyRows","rightRows","maxRows","heights","maxHeight","entry","entries","height","TableCompiler","$table","$srcTable","#syncColAttributes","$col","fixed","cols","grid","rowSpan","colSpan","c","CellSelection","#initEvents","sameGroupTrs","t","$td","col","r1","startRow","endRow","r2","c1","startCol","endCol","c2","containers","expanded","loopCount","#getMatrixRow","cell","cellEndRow","cellEndCol","nsR","neR","nsC","neC","#range","mainZone","lastMatrixRow","lastCol","targetCell","allCells","rect","targetTr","CellNavigation","#currentCell","#currentTr","#isCellLeftVisible","#isCellRightVisible","isVisible","#isCellBelowVisible","#isCellAboveVisible","scrollTopIndex","#getVisibleRowCount","currentCell","#findCell","nextCell","#getPreviousCell","#getNextCell","#getUpCell","#getDownCell","#moveCellH","#moveCellV","nextCol","cellCol","cellRect","viewportRect","theadHeight","bodyViewport2","viewportHeight","RESIZE_OFFSET","ColResizer","#panel","#tooltip","#onPointerMove","#onPointerDown","#onDblClick","containerType","firstColgroup","totalWidth","colWidths","colIdx","tables","targetCols","globalColIndex","firstContainer","resolvedContainerType","width","sourceCol","headerPart","offsetX","isLeftEdge","isRightEdge","prevCell","#targetCell","#targetContainerType","#getContainerType","baseColIndex","#targetColIndex","#checkIsAutoFit","#nextColIndex","nextColEl","#nextColStartWidth","targetRect","sheetRect","#startCellWidth","#startLeft","attrW","#startColWidth","#startX","#updatePositions","#onDragMove","#onDragEnd","diff","clientX","isAutoFit","maxDiff","minDiff","currentColWidth","realCellWidth","maxCellWidth","currentCellWidth","sizeBadge","finalWidth","newColWidth","newNextWidth","tbodyCell","extraPadding","fieldIdx","font","headerText","maxTextWidth","val","size","calculatedWidth","ColResizerPanel","#renderer","ColMover","#grip","#indi","root","y","nested","headerCells","hasStrictChildren","isValidGroup","parentGroupRange","subCell","subStart","subSpan","subEnd","isRealGroup","groupRange","#getColGroupRange","origTable","minLeft","maxRight","minTop","maxBottom","targetCells","cCol","cEnd","isGroup","groupWidth","groupHeight","headerContent","clonedCell","style","#checkIsMovable","startX","startY","cancelTimer","#timer","onPointerMovePending","#startDrag","#isDragging","preview","#createGroupHeaderPreview","#sourceCell","#sourceColIndex","#shiftX","bounds","relativeTop","fullHeight","#updateGripPosition","#onPointerUp","#getDeepElementFromPoint","targetColIndex","colMinLeft","colMaxRight","cRect","midX","calculatedTargetCol","indicatorLeft","sourceGroup","movingSpan","sourceRowStart","sourceRowEnd","targetRowStart","targetRowEnd","isRowSpanCompatible","isOutOfBoundsOfParent","pStart","pEnd","isDroppingInsideOtherGroup","spannedCells","sCell","sRowStart","sRowEnd","sStart","sEnd","moveEndCol","isSelfGroup","left","colgroup","targetCol","toColIndex","spanCount","isInRange","fromColIndex","targetViewportCol","fixedType","group","cells","targetRowCell","ColFixManager","baseCol","fixedAttr","targetBoundaryCol","theadTrs","cellBoundaryFound","cEndCol","action","fixType","cIdx","minBaseCol","maxEndCol","rSpan","rIdx","isBroken","isColFixed","NineTableFilterPanel","#closeHandler","#nineTable","#view","#onInput","#onSelectAll","#onOk","#button","filterBtn","panelWidth","top","searchBox","#loadVirtualFilterItems","path","filteredRecords","activeFilters","exprEngine","bindKey","colInfo","exprKey","filterKey","activeSelectedVals","uniqueMap","rawVal","displayVal","uniqueList","valA","valB","numA","numB","selectAllChk","filterRecords","checkedRecords","chk","filterParams","selectedVals","btn","query","data2Idx","matchedValues","isChecked","chkIdx","NineTableFilterButton","#onClick","#columns","seen","uniqueKey","isFiltered","panel","Filtering","#filters","#initFilterPanel","#filterPanel","#isFiltering","#applyFiltering","oFilter","jsonFilter","k","sheetIndex","filterRules","targetKey","allowedValues","isExpr","isPass","recordIdx","allowedSet","Sorting","#handleSort","colName","exprVal","isAsc","isDesc","existingColIndex","m","ruleData","#applySorting","#syncHeaderUI","colRule","asc","SheetView","#cachedVisibleRecords","#viewIndexes","visibleRecords","#convSingle","filterSlot","#sortingColumns","groupResult","columns","rulesWithIdx","rule","idxA","idxB","isEmptyA","isEmptyB","strA","strB","PreCompiler","#ensureColgroup","#ensureThead","#ensureSectionTbodys","#ensureRowIndicator","#normalizeColAttributes","#createColIndicator","#normalizeCollapsibleAttributes","#generateCell","#initColExpanders","#initFilterButtons","#applyInitialCellWidths","thead","firstRow","cnt","td","#numToExcelCol","background","num","headTbody","footTbody","colCount","containerWidth","defaultWidth","widthVal","targetAttributes","autoIdCounter","$tbl","tagName","$datalist","$option","uniqueFuncName","cellType","originalContent","hostFilter","tableFilter","finalFiltering","currentWidth","expandBtn","targetWidth","rows","section","indicatorCell","startColIdx","targetIdx","NineTableSheet","#rowManager","#index","#colResizer","#filtering","#grouping","#colMover","#colFix","#cellSelection","#cellNavigation","#source","attrTrue","sourceTableTrue","#isSimple","#renderSplitContainers","#updateContainerWidths","#adjustOverlay","$thead","$overlay","#autoFit","enable","totalOriginalWidth","colList","collapsedTotalWidth","availableWidth","allocatedTotal","calculatedCols","exactWidth","baseWidth","remainderPixels","uncollapsedCols","finalSumWidth","#syncHeaderAndFooterHeights","#initRowHoverEvent","prefix","firstTable","#createSplitTable","offsetHeight","sheetBottom","tbodyBottom","bodyContainer","scrollLeft","#sorting","leftHeaderRows","bodyHeaderRows","rightHeaderRows","#applyMaxHeights","leftFooterRows","bodyFooterRows","rightFooterRows","activeRowIndex","relatedTarget","LayoutManager","owner","#applyAutoHeight","maxDisplayRows","maxRowHeight","toolbarEl","footerEl","toolbarHeight","footerHeight","calculatedHeight","isAutoHeight","sheetCount","sheetsHtml","className","sheetId","cssImports","ExprEngine","match","trimmedExpr","compiledExpr","evalFn","#exprCache","rowItem","NineTable","#shadowRoot","#dataManager","#templateCnt","#bindDynamicSetters","#layoutManager","#dispatchLoad","checkCount","checkTimer","loadSheetCnt","$sheet","idOrIndex","extractedMethodNames","matches","internalValue","methodName","newValue","fn","BasicCellElement","exprCache","CellElement","#cell","#tr","#attr","button","curRow","renderer","rawRecord","prop","updateRowState","defaultValue","\"display\"","data","cleanExpr","childRecords","funcName","field","acc","EditableCellElement","CellInputText","#target","#initEvent","#maxbyte","maxByteNum","event","CellInputNumber","#onKeyDown","#validate","#max","#min","#scale","str","selectionStart","scale","validKey","isNumKey","CellInputColor","#btn","#dataSource","datalistId","datalist","option","#rendererColor","#isValidColor","g","CellInputDate","#type","formattedVal","d","isValid","#isValidDate","year","month","day","isleap","hour","min","week","CellCheckbox","#label","#trueText","#falseText","#isRadio","trueValue","childHtml","displayText","#enable","#readonly","#visible","CellRadio","#rendererRadio","matchIndex","#radioList","codeVal","#keyName","nameVal","#valueName","label","input","span","CellComboPanel","grd","itemsAttr","fieldKeys","valueName","activeColumnCount","multi","formattedData","keyName","selectedKeys","separator","#isOpen","btnEl","btnRect","panelHeight","upwardTop","#initData","viewContainer","#onClickRow","keyword","CellCombo","#multi","#multiSeparator","#togglePanel","#targetBtn","#getDisplayText","#validateInput","keys","list","CellRenderer","CellButton","#cellButtonClick","customEvent","rawValue","CellRowIndicator","#mainTarget","#subTarget","#statusTarget","displayNum","formattedNum","splitIndex","prefixPart","suffixPart","isSorted","isFitered","ColExpand","singleWidth","currentW","splitWidth","ContextMenu","#tableHost","targetTable","#getTargetSheet","items","activeTableId","activeTable","containerElement","targetTableAttr","rootUl","parsedList","#traverseUl","ulEl","child","spanEl","n","subUl","useDefault","rawItems","customItems","#parseCustomMenuItems","fixManager","#getFixManager","currentFixState","isFixable","isHeaderCell","fixMenuItem","cleanedItems","targetParent","menuItems","#buildMenuItems","#handleMenuClick","#syncMenuStates","isFiltering","autoFit","showTitle","menuId","#onContextMenu","MenuPanel","#onCallback","callback","#appendItems","#bindClickEvents","cellRightX","wrapper","calculatedLeft","calculatedTop","li","condition","sep","parentUl"],"sources":["../src/core/protype.js","../src/external/NoPeer.js","../src/core/constants.js","../src/data/ngData.js","../src/data/ngDataManager.js","../src/data/Fields.js","../src/layout/nine-table-sheets.js","../src/layout/nine-table-sheets-footer.js","../src/layout/nine-table-toolbar.js","../src/layout/nine-table-hscrollbar.js","../src/layout/nine-table-vscrollbar.js","../src/data/Grouping.js","../src/layout/core/RowManager.js","../src/layout/core/TableCompiler.js","../src/cell-manager/CellSelection.js","../src/cell-manager/CellNavigation.js","../src/col/ColResizer.js","../src/col/ColMover.js","../src/col/ColFixManager.js","../src/data/Filtering.js","../src/data/Sorting.js","../src/data/SheetView.js","../src/layout/core/PreCompiler.js","../src/layout/nine-table-sheet.js","../src/layout/core/LayoutManager.js","../src/core/ExprEngine.js","../src/core/nine-table.js","../src/cell/core/BasicCellElement.js","../src/cell/core/CellElement.js","../src/cell/cell-input-text.js","../src/cell/cell-input-number.js","../src/cell/cell-input-color.js","../src/cell/cell-input-date.js","../src/cell/cell-checkbox.js","../src/cell/cell-radio.js","../src/cell/cell-combo-panel.js","../src/cell/cell-combo.js","../src/cell/cell-renderer.js","../src/cell/cell-button.js","../src/cell/cell-row-indicator.js","../src/col/col-expand.js","../src/menu/nine-table-menu.js","../src/menu/nine-table-menu-panel.js"],"sourcesContent":["Array.prototype.nineBinarySearch = function(target) {\n //this.sort((a, b) => { return a > b ? 1 : -1; });\n\n let start = 0;\n let end = this.length - 1;\n let mid;\n\n while (start <= end) {\n mid = parseInt((start + end) / 2);\n\n if (target === this[mid]) {\n return mid;\n } else {\n if (target < this[mid]) {\n end = mid - 1;\n } else {\n start = mid + 1;\n }\n }\n }\n\n return -1;\n};\n\n// 엘리먼트별 디바운스/취소 상태를 격리하기 위한 WeakMap\nconst elementDebounceState = new WeakMap();\n\nHTMLElement.prototype.addDebounseEventListener = function(\n dblClickEvent,\n dblClickFn,\n pointerEvent,\n pointerFn,\n debounceTime = 500\n) {\n const el = this;\n\n if (!elementDebounceState.has(el)) {\n elementDebounceState.set(el, { timer: null, cancelFn: null });\n }\n const state = elementDebounceState.get(el);\n\n // 1. 포인터(다운) 이벤트: 즉시 실행하지 않고 debounceTime 동안 지연시킴\n el.addEventListener(pointerEvent, (e) => {\n e.actualTarget = e.target;\n\n if (state.timer) {\n clearTimeout(state.timer);\n state.timer = null;\n }\n\n // 💡 500ms 동안 대기한 뒤에야 실제 pointerFn이 실행됨\n state.timer = setTimeout(() => {\n state.timer = null;\n state.cancelFn = pointerFn.call(el, e);\n }, debounceTime);\n });\n\n // 2. 더블클릭 이벤트: 대기 시간 내에 들어오면 예약되어 있던 pointerdown 자체를 원천 차단\n el.addEventListener(dblClickEvent, (e) => {\n //trace.log(e);\n if (state.timer) {\n clearTimeout(state.timer);\n state.timer = null; // 💡 pointerdown 실행 예약이 아예 취소됨!\n }\n\n // 혹시 이미 실행되어 버린 경우의 안전장치 롤백\n if (state.cancelFn) {\n state.cancelFn();\n state.cancelFn = null;\n }\n\n dblClickFn.call(el, e);\n });\n};\n\n\nnine.measureTextSize = (_text, _font = '12px sans-serif') => {\n if (typeof _text === 'number') _text = _text + \"\";\n if (!_text) return { width: null, height: null };\n\n // 🎯 브라우저 DOM 파싱을 이용한 완벽한 HTML 태그 제거 함수\n const stripHtml = (html) => {\n const tmp = document.createElement(\"DIV\");\n tmp.innerHTML = html;\n return tmp.textContent || tmp.innerText || \"\";\n };\n\n // 줄바꿈 처리 전 HTML 정제 또는 줄바꿈 단위별 정제\n _text = _text.replaceAll(\"\\n\", \"<br>\");\n\n // 🎯 공용 숨김 캔버스를 querySelector로 찾거나 없으면 생성\n let canvas = document.body.querySelector('canvas#_nine_measure_canvas_');\n if (!canvas) {\n canvas = document.createElement('canvas');\n canvas.id = '_nine_measure_canvas_';\n canvas.style.cssText = 'position: absolute; visibility: hidden; pointer-events: none; left: -9999px;';\n document.body.appendChild(canvas);\n }\n\n const context = canvas.getContext('2d');\n context.font = _font;\n\n let w = 0;\n let h = 0;\n\n for (let v of _text.split(\"<br>\")) {\n // 브라우저 파서로 HTML 태그를 완전히 제거한 순수 텍스트 획득\n const cleanText = stripHtml(v);\n const metrics = context.measureText(cleanText);\n\n //trace.log(cleanText);\n\n w = Math.max(w, metrics.width);\n\n const ascent = metrics.fontBoundingBoxAscent || 10;\n const descent = metrics.fontBoundingBoxDescent || 3;\n h += ascent + descent;\n }\n\n return {\n width: w,\n height: h\n };\n};","import { trace as traceOrigin } from '@ninebone/util';\n\n/**\n// 1. 내부 프라이빗 필드 문제를 피하기 위해 래퍼 객체 생성\nexport const trace = {\n init(prefix, color) {\n // 필요하다면 여기서 초기화 로직 수행 가능\n if (traceOrigin.init) {\n try { traceOrigin.init(prefix, color); } catch (e) {}\n }\n },\n log(...args) {\n return traceOrigin.log(...args);\n },\n warn(...args) {\n return traceOrigin.warn(...args);\n },\n error(...args) {\n return traceOrigin.error(...args);\n }\n};\n\n// 2. 모듈 로드 시점에 네임스페이스 초기화 시도\ntry {\n traceOrigin.init(\"nine-table\", \"green\");\n} catch (e) {}\n*/\n\n\nexport class Trace extends traceOrigin.constructor {\n constructor() {\n super();\n this.init(\"nine-table\", \"green\");\n }\n}\n\nexport const trace = new Trace();\n\n\n//trace.init(\"nine-table\", \"green\");","export const NINE_TABLE = {\n META: {\n INDEX: {\n ROWID: 0,\n FILTER: 1, // 멀티뷰 필터 통과 여부 (true/false)\n GROUP: 2,\n // SELECT: 2,\n // EXPAND: 3\n }\n },\n ROW_STATE: {\n EMPTY: 'EMPTY',\n NORMAL: 'NORMAL',\n INSERT: 'INSERT',\n UPDATE: 'UPDATE',\n DELETE: 'DELETE'\n },\n EVENT: {\n LOAD: \"load\",\n CELL_BUTTON_CLICK: \"cell-button-click\",\n },\n};","import { trace } from \"@nopeer\";\r\nimport { NINE_TABLE } from \"@/core/constants.js\";\r\n\r\nexport class ngRow {\r\n\t#parent;\r\n\t#newrow = -1;\r\n\r\n\tconstructor(parent) {\r\n\t\tthis.#parent = parent;\r\n\t}\r\n\r\n\tget at() {\r\n\t\treturn this.#newrow;\r\n\t}\r\n\tset at(v) {\r\n\t\tthis.#newrow = parseInt(v, 10);\r\n\t}\r\n\r\n\tcount = () => this.#parent.rawRecords.length;\r\n}\r\n\r\nexport class ngData {\r\n\t#host;\r\n\t#parent;\r\n\t#nextId = 0;\r\n\t#defaultHeight = [];\r\n\r\n\tstatic META_INDEX = {\r\n\t\tFILTER: 0, // 멀티뷰 필터 통과 여부 (true/false)\r\n\t\t// ── 추후 확장 예시 ──\r\n\t\t// GROUP: 1,\r\n\t\t// SELECT: 2,\r\n\t\t// EXPAND: 3\r\n\t};\r\n\r\n\t// 🎯 행 상태 정의 상수 내재화\r\n\tstatic ROW_STATE = {\r\n\t\tEMPTY: 'EMPTY',\r\n\t\tNORMAL: 'NORMAL',\r\n\t\tINSERT: 'INSERT',\r\n\t\tUPDATE: 'UPDATE',\r\n\t\tDELETE: 'DELETE'\r\n\t};\r\n\r\n\tconstructor(host, parent) {\r\n\t\tthis.#host = host;\r\n\t\tthis.#parent = parent;\r\n\t\tthis.#initialize();\r\n\t}\r\n\r\n\r\n\r\n\t/**\r\n\t * 🎯 [내부 공통] 삭제되지 않은 유효 레코드 목록 반환 (중복 제거 및 캡슐화)\r\n\t */\r\n\t#getValidRecords = () => {\r\n\t\tconst rawRecords = this.#parent.rawRecords || [];\r\n\t\treturn rawRecords.filter(o => !o.__ng?.deleted);\r\n\t};\r\n\r\n\t/**\r\n\t * 🎯 유효 데이터 행 개수 반환 (속성 및 메서드 형태 모두 지원)\r\n\t */\r\n\tget count() {\r\n\t\treturn this.length;\r\n\t}\r\n\r\n\tcount = () => {\r\n\t\treturn this.length;\r\n\t};\r\n\r\n\t/**\r\n\t * 🎯 [내부 엔진/고성능용] 변환 오버헤드 없이 순수 데이터(v 배열 등) 그대로 반환\r\n\t * - data.getArray() : 유효한 전체 내부 레코드 배열 반환\r\n\t * - data.getArray(at) : 특정 행의 내부 레코드 객체({ v: [...] }) 반환\r\n\t * - data.getArray(at, colnm) : 특정 행의 특정 컬럼 원시 값 반환\r\n\t */\r\n\tgetArray = (at, colnm) => {\r\n\t\tconst validRecords = this.#getValidRecords();\r\n\r\n\t\tif (at === undefined || at === null) {\r\n\t\t\treturn validRecords; // 변환 없이 배열 그대로 반환 (렌더링 최적화)\r\n\t\t}\r\n\r\n\t\tif (at < 0 || at >= validRecords.length) return null;\r\n\r\n\t\tconst targetRecord = validRecords[at];\r\n\r\n\t\tif (colnm != null) {\r\n\t\t\tconst fields = this.getHostFields();\r\n\t\t\tconst idx = fields.indexOf(colnm);\r\n\t\t\treturn (idx >= 0) ? targetRecord.v[idx] : null;\r\n\t\t}\r\n\r\n\t\treturn targetRecord; // { v: [...], __ng: {...} } 원본 형태 반환\r\n\t};\r\n\r\n\tsetArray = (rowIndex, colIndex, value) => {\r\n\t\t//trace.log(rowIndex, colnm, value)\r\n\t\tconst validRecords = this.#getValidRecords();\r\n\t\tconst rowData = validRecords[rowIndex];\r\n\r\n\t\tconst oldValue = rowData.v[colIndex];\r\n\t\tif (oldValue !== value && rowData.__ng.rowState !== ngData.ROW_STATE.INSERT) {\r\n\t\t\t// 변경 전 값 보존 우선 주석처리\r\n\t\t\t//rowData.o[colIndex] = value;\r\n\t\t\trowData.__ng.rowState = ngData.ROW_STATE.UPDATE;\r\n\t\t}\r\n\r\n\t\trowData.v[colIndex] = value;\r\n\t\t//trace.log(rowData, COL_IDX);\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * 🎯 [외부 개발자/비즈니스 로직용] 개발자가 활용하기 편한 JSON 객체 형태로 변환하여 반환\r\n\t * - data.get() : 전체 유효 데이터를 JSON 객체 배열로 변환\r\n\t * - data.get(at) : 특정 행을 JSON 객체로 변환\r\n\t * - data.get(at, colnm) : 특정 컬럼 값 반환\r\n\t */\r\n\tget = (at, colnm) => {\r\n\t\tconst validRecords = this.#getValidRecords();\r\n\r\n\t\tif (at === undefined || at === null) {\r\n\t\t\treturn this.#conv(validRecords);\r\n\t\t}\r\n\r\n\t\tif (at < 0 || at >= validRecords.length) return null;\r\n\r\n\t\tconst targetRecord = validRecords[at];\r\n\t\tconst fields = this.getHostFields();\r\n\r\n\t\tif (colnm != null) {\r\n\t\t\tconst idx = fields.indexOf(colnm);\r\n\t\t\treturn (idx >= 0) ? targetRecord.v[idx] : null;\r\n\t\t}\r\n\r\n\t\treturn this.#conv(targetRecord);\r\n\t};\r\n\r\n\t/**\r\n\t * 🎯 [저장/서버 전송용] 삭제된 행을 포함한 전체 원본 배열 반환\r\n\t */\r\n\tgetAll = () => {\r\n\t\treturn this.#parent.rawRecords || [];\r\n\t};\r\n\r\n\tgetHostFields = () => {\r\n\t\treturn typeof this.#host.fields?.get === 'function' ? this.#host.fields.get() : [];\r\n\t};\r\n\r\n\t#initialize = () => {\r\n\t\tthis.#defaultHeight = [];\r\n\t\tconst templateElements = this.#host.template || [];\r\n\t\tArray.from(templateElements).forEach(el => {\r\n\t\t\tthis.#defaultHeight.push(el.getBoundingClientRect?.().height || 24);\r\n\t\t});\r\n\r\n\t\t(this.#parent.rawRecords || []).forEach(v => {\r\n\t\t\tif (!v.__ng) v.__ng = this.#getDefaultMeta();\r\n\t\t\tv.__ng.height = this.#defaultHeight.slice();\r\n\t\t});\r\n\t};\r\n\r\n\tget source() {\r\n\t\treturn this.#conv(this.#parent.rawRecords);\r\n\t}\r\n\tset source(v) {\r\n\t\tthis.set(v);\r\n\t\t//this.clear();\r\n\t\t//this.add(v, false);\r\n\t}\r\n\r\n\t#invalidate = () => {\r\n\t\tthis.#host.shadowRoot.querySelectorAll(\"nine-table-sheet\").forEach($el => {\r\n\t\t\t$el.invalidate();\r\n\t\t});\r\n\r\n\t\tthis.#host.shadowRoot.querySelector(\"nine-table-sheets-footer\")?.refresh();\r\n\t};\r\n\r\n\tset = (dataSource) => {\r\n\r\n\t\tconst loadData = () => {\r\n\t\t\tthis.#host.loading = true;\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tthis.clear();\r\n\t\t\t\t\tthis.add(dataSource, false);\r\n\t\t\t\t\tthis.#invalidate();\r\n\t\t\t\t} finally {\r\n\t\t\t\t\tthis.#host.loading = false;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (this.#host.loaded) {\r\n\t\t\tloadData();\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.#host.addEventListener(NINE_TABLE.EVENT.LOAD, e => {\r\n\t\t\t\tloadData();\r\n\t\t\t}, { once: true });\r\n\t\t}\r\n\t};\r\n\r\n\tget nextId() {\r\n\t\treturn this.#nextId++;\r\n\t}\r\n\r\n\tget length() {\r\n\t\treturn this.#getValidRecords().length;\r\n\t}\r\n\r\n\tget count() {\r\n\t\treturn this.length;\r\n\t}\r\n\r\n\tgetRowCount() {\r\n\t\treturn this.length;\r\n\t}\r\n\r\n\t#getDefaultMeta = (rowid = 0) => {\r\n\t\treturn {\r\n\t\t\trowState: ngData.ROW_STATE.EMPTY,\r\n\t\t\tdeleted: false,\r\n\t\t\tfiltered: false,\r\n\t\t\theight: this.#defaultHeight.slice(),\r\n\t\t\to: {},\r\n\t\t\tc: {},\r\n\t\t\t__: [0, 0, 0, 0, ngData.ROW_STATE.EMPTY, false, false, true, false, true, true, false, this.#defaultHeight.slice(), -1, {}, {}],\r\n\t\t\t_: [rowid, [], ],\r\n\t\t};\r\n\t};\r\n\r\n\treset = () => {\r\n\t\tthis.#parent.rawRecords = [];\r\n\t\tthis.#invalidate();\r\n\t};\r\n\r\n\tclear = () => {\r\n\t\tthis.#parent.rawRecords = [];\r\n\t\tif (this.#parent.viewRecords?.reset) {\r\n\t\t\tthis.#parent.viewRecords.reset();\r\n\t\t}\r\n\r\n\t\tthis.#nextId = 0;\r\n\r\n\t\tthis.#invalidate();\r\n\t};\r\n\r\n\t#json2Array = (jsonArray) => {\r\n\t\tif (!Array.isArray(jsonArray)) jsonArray = [jsonArray];\r\n\r\n\t\tconst fields = this.getHostFields().length > 0 ? this.getHostFields() : Object.keys(jsonArray[0] || {});\r\n\t\tconst arr = [];\r\n\r\n\t\tjsonArray.forEach(json => {\r\n\t\t\tconst o = { v: [] };\r\n\t\t\tfields.forEach(colnm => {\r\n\t\t\t\to.v.push(json[colnm] !== undefined && json[colnm] !== null ? json[colnm] : \"\");\r\n\t\t\t});\r\n\t\t\tarr.push(o);\r\n\t\t});\r\n\r\n\t\treturn arr;\r\n\t};\r\n\r\n\t#defaultInsert = (arr) => {\r\n\t\tif (!Array.isArray(arr)) arr = [arr];\r\n\t\tarr.forEach(o => {\r\n\t\t\tconst rowid = this.nextId;\r\n\r\n\t\t\to.m = this.#getDefaultMeta(rowid);\r\n\t\t\to.__ng = o.m;\r\n\t\t\to.__ng.rowid = rowid;\r\n\t\t\to.__ng.rowState = ngData.ROW_STATE.INSERT;\r\n\t\t\to.__ng._[0] = rowid;\r\n\t\t});\r\n\t\treturn arr;\r\n\t};\r\n\r\n\tadd = (dataSource, updateState = true) => {\r\n\t\tif (dataSource === undefined) dataSource = {};\r\n\t\tconst arr = this.#json2Array(dataSource);\r\n\r\n\t\tthis.#parent.rawRecords = this.#parent.rawRecords.concat(this.#defaultInsert(arr));\r\n\r\n\t\tconst row = this.count() - 1;\r\n\t\tif (!updateState) {\r\n\t\t\tarr.forEach((_, idx) => {\r\n\t\t\t\tconst target = this.#parent.rawRecords[this.#parent.rawRecords.length - 1 - idx];\r\n\t\t\t\tif (target) target.__ng.rowState = ngData.ROW_STATE.EMPTY;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.#invalidate();\r\n\t\treturn row;\r\n\t};\r\n\r\n\tdelete = (at) => {\r\n\t\tlet arr = [];\r\n\t\tif (Array.isArray(at)) {\r\n\t\t\tarr = at;\r\n\t\t} else if (typeof at === \"undefined\") {\r\n\t\t\tarr = [this.#parent.host.row.at];\r\n\t\t} else {\r\n\t\t\tarr = [parseInt(at, 10)];\r\n\t\t}\r\n\r\n\t\tconst validRecords = this.#getValidRecords();\r\n\r\n\t\tarr.sort((a, b) => b - a).forEach(rowidx => {\r\n\t\t\tif (validRecords[rowidx]) {\r\n\t\t\t\tconst targetId = validRecords[rowidx].__ng.rowid;\r\n\t\t\t\tif (validRecords[rowidx].__ng.rowState === ngData.ROW_STATE.INSERT) {\r\n\t\t\t\t\tthis.#parent.rawRecords = this.#parent.rawRecords.filter(item => item.__ng.rowid !== targetId);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.#parent.rawRecords.forEach(item => {\r\n\t\t\t\t\t\tif (item.__ng.rowid === targetId) {\r\n\t\t\t\t\t\t\titem.__ng.deleted = true;\r\n\t\t\t\t\t\t\titem.__ng.rowState = ngData.ROW_STATE.DELETE;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.#invalidate();\r\n\t};\r\n\r\n\tsetValue = (rowIndex, colnm, value) => {\r\n\t\t//trace.log(rowIndex, colnm, value)\r\n\t\trowIndex = parseInt(rowIndex, 10);\r\n\t\tconst fields = this.getHostFields();\r\n\t\tconst COL_IDX = fields.indexOf(colnm);\r\n\t\tif (COL_IDX < 0) return;\r\n\r\n\t\tconst validRecords = this.#getValidRecords();\r\n\t\tconst rowData = validRecords[rowIndex];\r\n\t\tif (!rowData) return;\r\n\r\n\r\n\r\n\t\tconst oldValue = rowData.v[COL_IDX];\r\n\t\tif (oldValue !== value && rowData.__ng.rowState !== ngData.ROW_STATE.INSERT) {\r\n\t\t\tif (!rowData.__ng.o.hasOwnProperty(colnm)) rowData.__ng.o[colnm] = oldValue;\r\n\t\t\trowData.__ng.rowState = ngData.ROW_STATE.UPDATE;\r\n\t\t}\r\n\r\n\t\trowData.v[COL_IDX] = value;\r\n\t\t//trace.log(rowData, COL_IDX);\r\n\t};\r\n\r\n\t#conv = (arr) => {\r\n\t\tif (!arr) return arr;\r\n\r\n\t\tconst isSingle = !Array.isArray(arr);\r\n\t\tconst targetArr = isSingle ? [arr] : arr;\r\n\t\tconst fields = this.getHostFields();\r\n\r\n\t\tconst result = targetArr.filter(o => !o.__ng?.deleted).map(o => {\r\n\t\t\tconst t = {};\r\n\t\t\tfields.forEach((colnm, i) => {\r\n\t\t\t\tt[colnm] = o.v ? o.v[i] : o[colnm];\r\n\t\t\t});\r\n\t\t\tt.__ng = o.__ng;\r\n\t\t\treturn t;\r\n\t\t});\r\n\r\n\t\treturn isSingle ? result[0] : result;\r\n\t};\r\n}\r\n","import { ngRow, ngData } from \"./ngData.js\";\r\n\r\nexport class ngDataManager {\r\n\t#host;\r\n\r\n\tconstructor(host) {\r\n\t\tthis.#host = host;\r\n\r\n\t\tthis.row = new ngRow(this);\r\n\t\tthis.data = new ngData(this.#host, this);\r\n\r\n\t\tthis.rawRecords = [];\r\n\t\tthis.viewRecords = [];\r\n\t\tthis.delRecords = [];\r\n\t\tthis.pageCnt = 25;\r\n\r\n\t\tthis.viewRecords.reset = () => {\r\n\t\t\tif (this.#host.view?.redraw) this.#host.view.redraw();\r\n\t\t};\r\n\r\n\t\tthis.setDataSource = (ds) => {\r\n\t\t\tif (this.data) this.data.reset();\r\n\r\n\t\t\tthis.rawRecords = [];\r\n\t\t\tthis.viewRecords = [];\r\n\t\t\tthis.delRecords = [];\r\n\r\n\t\t\tthis.data.set(ds || []);\r\n\t\t};\r\n\r\n\t\tthis.getRowState = (nRow) => {\r\n\t\t\tconst rowIdx = parseInt(nRow, 10);\r\n\t\t\tif (rowIdx >= this.data.count()) return;\r\n\t\t\treturn this.data.getValidData()[rowIdx]?.__ng?.rowState;\r\n\t\t};\r\n\r\n\t\tthis.getRowPosition = () => this.row.at;\r\n\t\tthis.setRowPosition = (nRow) => { this.row.at = nRow; };\r\n\r\n\t\tthis.scrollTo_V1 = (nRow) => {\r\n\t\t\tif (nRow < 0) nRow = 0;\r\n\t\t\tif (nRow >= this.rawRecords.length) nRow = this.rawRecords.length - 1;\r\n\r\n\t\t\tthis.viewRecords.rawIndex = nRow;\r\n\t\t\tif (this.viewRecords.reset) this.viewRecords.reset();\r\n\r\n\t\t\treturn (nRow <= 0 || nRow >= this.rawRecords.length - 1) ? false : true;\r\n\t\t};\r\n\r\n\t\tthis.getColumn = (rowidx, colnm) => this.data.get(rowidx, colnm);\r\n\r\n\t\tthis.setColumn = (rowidx, colnm, v) => {\r\n\t\t\trowidx = parseInt(rowidx, 10);\r\n\t\t\tthis.data.setValue(rowidx, colnm, v);\r\n\t\t};\r\n\r\n\t\t// 초기 빈 데이터 바인딩\r\n\t\tthis.setDataSource([]);\r\n\t}\r\n}","import { trace } from \"@nopeer\";\n\nexport class fields {\n\t#host;\n\t#fields = []; // 🎯 이제 { name: string, type: string } 객체들의 배열로 관리합니다.\n\n\tconstructor(host) {\n\t\tthis.#host = host;\n\t\tthis.#init();\n\t};\n\n\t// 🎯 기존에 필드 이름만 쓰던 곳들과의 호환을 위해 이름 배열만 리턴하는 메서드 유지\n\tget() {\n\t\treturn this.#fields.map(f => f.name);\n\t};\n\n\t// 🎯 내부 객체 통째로 얻기\n\tgetFields() {\n\t\treturn this.#fields;\n\t}\n\n\t// 🎯 특정 필드의 데이터 타입 조회\n\tgetType(fieldName) {\n\t\tconst found = this.#fields.find(f => f.name === fieldName);\n\t\treturn found ? found.type : 'string';\n\t}\n\n\tadd = (arr, type = 'string') => {\n\t\tarr.forEach(fName => {\n\t\t\tif (!this.#fields.some(f => f.name === fName)) {\n\t\t\t\tthis.#fields.push({ name: fName, type: type });\n\t\t\t}\n\t\t});\n\t\tthis.#adjust();\n\t};\n\n\tindexOf(v) {\n\t\treturn this.#fields.findIndex(f => f.name === v);\n\t};\n\n\tincludes(v) {\n\t\treturn this.#fields.some(f => f.name === v);\n\t};\n\n\t#adjust = () => {\n\t\t// 🎯 이름 기준으로 중복 제거 (Map을 활용하여 마지막에 들어온 타입 유지)\n\t\tconst map = new Map();\n\t\tthis.#fields.forEach(f => {\n\t\t\tmap.set(f.name, f.type);\n\t\t});\n\n\t\tthis.#fields = Array.from(map, ([name, type]) => ({ name, type }));\n\n\t\t// 🎯 빈 문자열이나 __ng 필터링\n\t\tthis.#fields = this.#fields.filter(f => f.name !== \"\" && f.name !== \"__ng\");\n\n\t\t// 🎯 긴 이름순 정렬\n\t\tthis.#fields.sort((a, b) => { return (a.name.length < b.name.length) ? 1 : -1; });\n\t};\n\n\t#init = () => {\n\t\tthis.#fields = [];\n\n\t\ttrace.log(this.#host.querySelectorAll(\"table\"));\n\n\t\tconst rawTables = Array.from(this.#host.querySelectorAll(\"table\"));\n\n\t\tif (!rawTables || rawTables.length === 0) return;\n\n\t\tfor (const tbl of rawTables) {\n\t\t\ttrace.log(tbl);\n\n\t\t\t// 1. [data-bind] 속성 탐색 및 타입 수집\n\t\t\ttbl.querySelectorAll('[data-bind]').forEach((el) => {\n\t\t\t\tconst fieldName = el.dataset.bind;\n\t\t\t\tconst fieldType = el.getAttribute(\"data-type\") || 'string';\n\n\t\t\t\tif (fieldName) {\n\t\t\t\t\tthis.#fields.push({ name: fieldName, type: fieldType });\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// 2. 표현식 속성들 탐색 (순수 자바스크립트로 변환)\n\t\t\tconst exprAttrs = [\n\t\t\t\t\"data-expr\", \"background-color\", \"color\", \"tooltip\",\n\t\t\t\t\"visible\", \"readonly\", \"enable-button\", \"enable-check\",\n\t\t\t\t\"class-expr\", \"icon-color\", \"icon-src\"\n\t\t\t];\n\n\t\t\texprAttrs.forEach(attr => {\n\t\t\t\t// 💡 jQuery의 $([attr], tbl).each(...)를 순수 querySelectorAll로 대체\n\t\t\t\ttbl.querySelectorAll(`[${attr}]`).forEach((el) => {\n\t\t\t\t\tlet expr = el.getAttribute(attr);\n\t\t\t\t\tif (!expr) return;\n\n\t\t\t\t\tif (expr.indexOf(\"data.\") < 0) {\n\t\t\t\t\t\tconst lastIndex = expr.search(/[(]/g);\n\n\t\t\t\t\t\tif (lastIndex > 0) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\texpr = String(window[expr.substring(0, lastIndex).trim()]);\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\texpr = \"\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\texpr.split(\"data.\").forEach(v => {\n\t\t\t\t\t\tif (v.trim() != \"\") {\n\t\t\t\t\t\t\tconst lastIndex = v.search(/[^_A-Za-z0-9]/g);\n\t\t\t\t\t\t\tlet targetField = '';\n\n\t\t\t\t\t\t\tif (lastIndex >= 0) {\n\t\t\t\t\t\t\t\ttargetField = v.substring(0, lastIndex);\n\t\t\t\t\t\t\t} else if (expr.startsWith(\"data.\")) {\n\t\t\t\t\t\t\t\ttargetField = v.replace(\"data.\", \"\");\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (targetField) {\n\t\t\t\t\t\t\t\tthis.#fields.push({ name: targetField, type: 'string' });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tthis.#adjust();\n\t};\n};","export class NineTableSheets extends HTMLElement {\n constructor() {\n super();\n }\n\n connectedCallback() {\n this.#init();\n }\n\n #init = () => {\n\n };\n\n}\n\nif (!customElements.get('nine-table-sheets')) {\n customElements.define('nine-table-sheets', NineTableSheets);\n}","export class NineTableSheetsFooter extends HTMLElement {\n #host;\n\n constructor() {\n super();\n }\n\n connectedCallback() {\n this.#init();\n }\n\n refresh = () => {\n this.querySelector(\"#row-count\").innerHTML = this.#host.data.count().toLocaleString();\n };\n\n #init = () => {\n this.#host = this.getRootNode().host;\n\n this.#render();\n\n this.querySelector('.nine-tab-bar')?.addEventListener('click', (e) => {\n const isMultiSelect = e.ctrlKey || e.metaKey || e.shiftKey;\n const tabItem = e.target.closest('nt-sheets-tab-item');\n\n if (!tabItem) return;\n\n const index = parseInt(tabItem.dataset.index, 10);\n this.#switchSheet(index, isMultiSelect);\n });\n\n setTimeout(() => {\n this.#switchSheet(0, false);\n })\n };\n\n #switchSheet = (index, isMultiSelect = false) => {\n\n const updateSplitters = () => {\n const sheets = Array.from(this.#host.shadowRoot.querySelectorAll('nine-table-sheet'));\n const splitters = Array.from(this.#host.shadowRoot.querySelectorAll('nine-splitter'));\n\n // 1. 모든 스플리터 일단 숨김 처리\n splitters.forEach(s => s.style.setProperty('display', 'none'));\n\n // 2. 현재 active 상태인 시트들을 인덱스 오름차순으로 정렬\n const activeSheets = sheets\n .map((sheet, idx) => ({ sheet, idx }))\n .filter(({ sheet }) => sheet.classList.contains('active'));\n\n if (activeSheets.length < 2) return;\n\n // 3. 인접한 활성화 시트 쌍 사이에 정확히 하나의 스플리터만 노출\n for (let i = 0; i < activeSheets.length - 1; i++) {\n const currentIdx = activeSheets[i].idx;\n\n const targetSplitter = this.#host.shadowRoot.querySelector(`nine-splitter[data-split-index=\"${currentIdx}\"]`);\n if (targetSplitter) {\n targetSplitter.style.setProperty('display', '');\n }\n }\n };\n\n const tabBar = this.querySelector('.nine-tab-bar');\n const body = this.#host.shadowRoot.querySelector('nine-table-sheets-body');\n const tabItems = tabBar.querySelectorAll('nt-sheets-tab-item');\n const sheetElements = body.querySelectorAll('nine-table-sheet');\n\n if (!tabItems[index]) return;\n\n if (!isMultiSelect) {\n tabItems.forEach((tab, idx) => {\n tab.setActive(idx === index);\n });\n\n sheetElements.forEach((sheet, idx) => {\n const isActive = idx === index;\n sheet.classList.toggle('active', isActive);\n sheet.style.flex = isActive ? '1 1 100%' : '';\n });\n } else {\n const clickedTab = tabItems[index];\n const activeTabs = tabBar.querySelectorAll('nt-sheets-tab-item.active');\n\n if (clickedTab.classList.contains('active') && activeTabs.length <= 1) {\n return;\n }\n\n clickedTab.classList.toggle('active');\n const targetSheet = body.querySelector(`nine-table-sheet[data-index=\"${index}\"]`);\n if (targetSheet) {\n targetSheet.classList.toggle('active');\n if (!targetSheet.classList.contains('active')) {\n targetSheet.style.flex = '';\n }\n }\n }\n\n const activeSheets = body.querySelectorAll('nine-table-sheet.active');\n\n activeSheets?.forEach(sheet => {\n sheet.style.flex = (activeSheets.length > 1) ? '1 1 0%' : '1 1 100%';\n\n if (typeof sheet.refreshLayout === 'function') {\n sheet.refreshLayout();\n } else {\n sheet.invalidate?.();\n }\n });\n\n updateSplitters();\n };\n\n #render() {\n const rawElements = Array.from(this.#host.children);\n const rawTables = rawElements.filter(el => (el.tagName.toUpperCase() === 'TABLE'));\n\n const tabsHtml = rawTables.map((table, idx) => {\n const className = idx === 0 ? 'active' : '';\n const tabName = table.getAttribute('caption') || `Sheet ${idx + 1}`;\n\n return `<nt-sheets-tab-item class=\"${className}\" data-index=\"${idx}\">${tabName}</nt-sheets-tab-item>`;\n }).join('');\n\n this.innerHTML = `\n <div class=\"nine-tab-bar\">${tabsHtml}</div>\n <div class=\"sheets-counter\">Total : <span id=\"row-count\">0</span></div>\n `;\n };\n}\n\nexport class SheetTabItem extends HTMLElement {\n constructor() {\n super();\n }\n\n connectedCallback() {\n\n }\n\n setActive(isActive) {\n this.classList.toggle('active', isActive);\n }\n}\n\nif (!customElements.get('nt-sheets-tab-item')) {\n customElements.define('nt-sheets-tab-item', SheetTabItem);\n}\n\nif (!customElements.get('nine-table-sheets-footer')) {\n customElements.define('nine-table-sheets-footer', NineTableSheetsFooter);\n}","import { trace } from \"@nopeer\";\n\nexport class Toolbar extends HTMLElement {\n #host;\n #customContainer;\n\n connectedCallback() {\n this.#host = this.getRootNode().host;\n this.#render();\n this.#bindEvents();\n }\n\n #render() {\n this.innerHTML = `\n <div class=\"ng-toolbar-left\">\n <button type=\"button\" class=\"ng-toolbar-menu-btn\" title=\"Menu\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#374151\" stroke-width=\"2\">\n <line x1=\"3\" y1=\"12\" x2=\"21\" y2=\"12\"></line>\n <line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"></line>\n <line x1=\"3\" y1=\"18\" x2=\"21\" y2=\"18\"></line>\n </svg>\n </button>\n <span class=\"ng-toolbar-title\"></span>\n </div>\n\n <div class=\"ng-toolbar-custom\" id=\"custom-container\"></div>\n `;\n\n this.#customContainer = this.querySelector('#custom-container');\n this.#syncStateFromHost();\n }\n\n #syncStateFromHost() {\n const isSimple = this.#host.getAttribute('theme') === 'simple' || this.#host.classList.contains('simple');\n const showToolbar = this.#host.getAttribute('show-toolbar') !== 'false';\n const showMenu = this.#host.getAttribute('show-menu') !== 'false';\n const caption = this.#host.getAttribute('caption') || '';\n\n if (isSimple || !showToolbar) {\n this.setAttribute('hidden', '');\n } else {\n this.removeAttribute('hidden');\n }\n\n this.setAttribute('show-menu', showMenu ? 'true' : 'false');\n this.updateCaption(caption);\n }\n\n #bindEvents() {\n const titleEl = this.querySelector('.ng-toolbar-title');\n if (titleEl) {\n titleEl.addEventListener('dblclick', () => {\n const link = '<font color=\"green\">https://www.ninegrid.net</font>';\n const currentCaption = this.#host.getAttribute('caption') || '';\n titleEl.innerHTML = titleEl.innerHTML === link ? currentCaption : link;\n });\n }\n\n const menuBtn = this.querySelector('.ng-toolbar-menu-btn');\n if (menuBtn) {\n menuBtn.addEventListener('click', () => {\n this.#host.dispatchEvent(new CustomEvent('toolbar-menu-click', {\n bubbles: true,\n composed: true,\n detail: { targetTable: this.#host }\n }));\n });\n }\n }\n\n addCustomElement(element) {\n if (this.#customContainer) {\n this.#customContainer.append(element);\n }\n }\n\n updateCaption(text) {\n const titleEl = this.querySelector('.ng-toolbar-title');\n if (titleEl) titleEl.textContent = text;\n }\n}\n\nif (!customElements.get('nine-table-toolbar')) {\n customElements.define('nine-table-toolbar', Toolbar);\n}","// ui/nine-table-hscrollbar.js\nimport { trace } from \"@nopeer\";\n\nexport class NineTableHScrollBar extends HTMLElement {\n #owner;\n #dragging = false;\n #elements;\n #interval1;\n #interval2;\n #resizeObserver;\n\n constructor() {\n super();\n }\n\n connectedCallback() {\n this.#owner = this.closest(\"nine-table-sheet\") || this.getRootNode().host;\n if (!this.#owner) return;\n\n this.innerHTML = `\n <button class='scroll-left' disabled><div class='scroll-icon'></div></button>\n <div class='scroll-track'><div class='scroll-thumb'></div></div>\n <button class='scroll-right' disabled><div class='scroll-icon'></div></button>\n `;\n\n const initWhenReady = () => {\n const body = this.#owner.querySelector(\".ng-sheet-body .ng-container-body\");\n if (!body) {\n setTimeout(initWhenReady, 10);\n return;\n }\n\n this.#elements = {\n container : body,\n track : this.querySelector(\".scroll-track\"),\n thumb : this.querySelector(\".scroll-thumb\"),\n left : this.querySelector(\".scroll-left\"),\n right : this.querySelector(\".scroll-right\"),\n };\n\n this.#init();\n this.#observeResize();\n this.refresh();\n };\n\n initWhenReady();\n }\n\n disconnectedCallback() {\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n }\n }\n\n #observeResize = () => {\n if (!this.#owner) return;\n const body = this.#owner.querySelector(\".ng-sheet-body .ng-container-body\");\n if (!body) return;\n\n this.#resizeObserver = new ResizeObserver(() => {\n this.refresh();\n });\n this.#resizeObserver.observe(body);\n };\n\n refresh = () => {\n\n if (!this.#owner || !this.#elements || this.#dragging) return;\n\n const body = this.#elements.container;\n const table = body.querySelector(\"table\");\n if (!table) return;\n\n const track = this.#elements.track;\n const thumb = this.#elements.thumb;\n\n const bodyWidth = body.clientWidth;\n const tableWidth = table.scrollWidth;\n\n //trace.log(bodyWidth, tableWidth, bodyWidth);\n\n // 🎯 [순수 클래스 연동] 인라인 스타일 조작 없이 오직 클래스 토글만 수행\n const needsHScroll = (bodyWidth !== 0 && tableWidth > bodyWidth);\n this.#owner.classList.toggle('hscroll-visible', needsHScroll);\n\n if (!needsHScroll) {\n return;\n }\n\n const trackWidth = track.clientWidth;\n if (trackWidth <= 0) return;\n\n const thumbWidth = Math.max(Math.min(trackWidth * (bodyWidth / tableWidth), trackWidth), 20);\n thumb.style.width = `${thumbWidth}px`;\n\n const currentLeft = body.scrollLeft;\n const maxScrollLeft = tableWidth - bodyWidth;\n\n let l = 0;\n if (maxScrollLeft > 0) {\n l = parseInt((currentLeft / maxScrollLeft) * (trackWidth - thumbWidth), 10);\n }\n if (l < 0) l = 0;\n\n const maxThumbLeft = trackWidth - thumbWidth;\n if (l > maxThumbLeft) l = maxThumbLeft;\n\n thumb.style.left = `${l}px`;\n\n this.#elements.left.disabled = (l === 0);\n this.#elements.right.disabled = (l >= maxThumbLeft - 1);\n };\n\n #thumbMoveTo = (x) => {\n if (!this.#elements) return false;\n\n const body = this.#elements.container;\n const table = body.querySelector(\"table\");\n if (!table) return false;\n\n const trackBound = this.#elements.track.getBoundingClientRect();\n const thumbWidth = this.#elements.thumb.clientWidth;\n\n let targetX = x;\n if (targetX < 0) targetX = 0;\n const maxThumbLeft = trackBound.width - thumbWidth;\n if (targetX > maxThumbLeft) targetX = maxThumbLeft;\n targetX = parseInt(targetX, 10);\n\n this.#elements.thumb.style.left = `${targetX}px`;\n\n this.#elements.left.disabled = (targetX === 0);\n this.#elements.right.disabled = (targetX >= maxThumbLeft - 1);\n\n const bodyWidth = body.clientWidth;\n const tableWidth = table.scrollWidth;\n const maxScrollLeft = tableWidth - bodyWidth;\n\n if (maxThumbLeft > 0 && maxScrollLeft > 0) {\n const newScrollLeft = (targetX / maxThumbLeft) * maxScrollLeft;\n body.scrollLeft = newScrollLeft;\n }\n\n return (targetX > 0 && targetX < maxThumbLeft - 1);\n };\n\n #init = () => {\n const delayScroll = (pos) => {\n clearInterval(this.#interval1);\n clearInterval(this.#interval2);\n\n const thumbLeft = parseInt(this.#elements.thumb.style.left || 0, 10);\n this.#thumbMoveTo(thumbLeft + pos);\n\n this.#interval1 = setInterval(() => {\n clearInterval(this.#interval1);\n\n this.#interval2 = setInterval(() => {\n const currentThumbLeft = parseInt(this.#elements.thumb.style.left || 0, 10);\n if (!this.#thumbMoveTo(currentThumbLeft + pos)) {\n clearInterval(this.#interval2);\n }\n }, 50);\n }, 500);\n };\n\n const clearTimer = () => {\n clearInterval(this.#interval1);\n clearInterval(this.#interval2);\n };\n\n ['mouseup', 'mouseleave', 'touchend'].forEach(evt => {\n this.#elements.left.addEventListener(evt, clearTimer);\n this.#elements.right.addEventListener(evt, clearTimer);\n this.#elements.track.addEventListener(evt, clearTimer);\n });\n\n this.#elements.left.addEventListener(\"mousedown\", e => { if (e.button !== 0) return; delayScroll(-20); });\n this.#elements.right.addEventListener(\"mousedown\", e => { if (e.button !== 0) return; delayScroll(20); });\n this.#elements.left.addEventListener(\"touchstart\", () => delayScroll(-20));\n this.#elements.right.addEventListener(\"touchstart\", () => delayScroll(20));\n\n this.#elements.track.addEventListener(\"mousedown\", e => {\n if (e.button !== 0) return;\n e.preventDefault();\n const trackRect = this.#elements.track.getBoundingClientRect();\n const thumbWidth = this.#elements.thumb.clientWidth;\n this.#thumbMoveTo(e.clientX - trackRect.left - (thumbWidth / 2));\n });\n\n this.#elements.thumb.addEventListener(\"mousedown\", e => {\n if (e.button !== 0) return;\n e.stopPropagation();\n e.preventDefault();\n this.#dragging = true;\n this.shiftX = e.clientX - this.#elements.thumb.getBoundingClientRect().left;\n\n const onMouseMove = (moveEvent) => {\n if (!this.#dragging) return;\n const trackRect = this.#elements.track.getBoundingClientRect();\n this.#thumbMoveTo(moveEvent.clientX - trackRect.left - this.shiftX);\n };\n\n const onMouseUp = () => {\n this.#dragging = false;\n clearTimer();\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n this.refresh();\n };\n\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n });\n };\n}\n\nif (!customElements.get('nine-table-hscrollbar')) {\n customElements.define(\"nine-table-hscrollbar\", NineTableHScrollBar);\n}","// ui/nine-table-vscrollbar.js\nimport { trace } from \"@nopeer\";\n\nexport class NineTableVScrollBar extends HTMLElement {\n #host;\n #sheet;\n #dragging = false;\n #elements;\n #startY = 0;\n #startScrollTop = 0;\n #startThumbTop = 0;\n\n constructor() {\n super();\n }\n\n connectedCallback() {\n this.#host = this.getRootNode().host;\n this.#sheet = this.closest(\"nine-table-sheet\");\n\n this.innerHTML = `\n <button class='scroll-top' disabled><div class='scroll-icon'></div></button>\n <div class='scroll-track'><div class='scroll-thumb'></div></div>\n <button class='scroll-bottom' disabled><div class='scroll-icon'></div></button>\n `;\n\n const initWhenReady = () => {\n const body = this.#sheet.querySelector(\".ng-sheet-body\");\n if (!body) {\n setTimeout(initWhenReady, 10);\n return;\n }\n\n this.#elements = {\n container: body,\n track: this.querySelector(\".scroll-track\"),\n thumb: this.querySelector(\".scroll-thumb\"),\n top: this.querySelector(\".scroll-top\"),\n bottom: this.querySelector(\".scroll-bottom\"),\n };\n\n this.#init();\n this.refresh();\n };\n\n initWhenReady();\n }\n\n #getScaleInfo = () => {\n const viewRecords = this.#sheet.view.getArray();\n const totalCount = viewRecords ? viewRecords.length : 0;\n\n // 🎯 [핵심] 그룹핑이든 일반이든 스크롤홀더(scrollHolder)가 가진 실제 가상 총 높이를 최우선으로 반영\n const scrollHolder = this.#sheet.elements?.scrollHolder;\n let rawContentHeight = scrollHolder ? parseFloat(scrollHolder.style.height) || 0 : 0;\n\n if (!rawContentHeight || rawContentHeight <= 0) {\n const isGrouped = this.#sheet.sourceTable?.querySelector(\"tbody tr[grouping='true']\") ? true : false;\n if (isGrouped && this.#sheet.rowManager) {\n // RowManager가 관리하는 누적 높이 활용 또는 fallback\n rawContentHeight = (body.scrollHeight > body.clientHeight) ? body.scrollHeight : (totalCount * 30);\n } else {\n const rowHeight = this.#sheet.getRowHeight() || 1;\n rawContentHeight = totalCount * rowHeight;\n }\n }\n\n const MAX_BROWSER_HEIGHT = 15000000;\n const useScaling = rawContentHeight > MAX_BROWSER_HEIGHT;\n\n let scaleFactor = 1;\n let contentHeight = rawContentHeight;\n\n if (useScaling) {\n scaleFactor = MAX_BROWSER_HEIGHT / rawContentHeight;\n contentHeight = MAX_BROWSER_HEIGHT;\n }\n\n return { rawContentHeight, contentHeight, scaleFactor, useScaling, totalCount };\n };\n\n #getViewHeight = () => {\n const body = this.#elements.container;\n if (!body) return 0;\n\n const thead = this.#sheet.elements?.body?.thead?.offsetHeight || 0;\n const tfoot = this.#sheet.elements?.body?.tfoot?.offsetHeight || 0;\n const tbodyHead = this.#sheet.elements?.body?.tbody?.head?.offsetHeight || 0;\n const fixedHeight = thead + tfoot + tbodyHead;\n\n return body.clientHeight - fixedHeight;\n };\n\n refresh = () => {\n //trace.log(\"=================\", \"vscrollbar.refresh\");\n // 💡 드래그 중에는 refresh에 의한 썸 위치 덮어쓰기 차단\n if (this.#dragging) return;\n\n if (!this.#sheet || !this.#sheet.elements || !this.#elements) return;\n\n const body = this.#elements.container;\n const track = this.#elements.track;\n const thumb = this.#elements.thumb;\n\n\n\n //const bodyHeight = this.#getViewHeight();\n const { contentHeight } = this.#getScaleInfo();\n\n\n\n const fixedHeight = (this.#sheet.querySelector('thead')?.offsetHeight || 0) +\n (this.#sheet.querySelector('tfoot')?.offsetHeight || 0) +\n (this.#sheet.querySelector('tbody.head')?.offsetHeight || 0);\n\n const bodyHeight = (this.#sheet.querySelector('.ng-sheet-body').offsetHeight || 0);\n const viewHeight = bodyHeight - fixedHeight;\n\n const viewRecords = this.#sheet.view.getArray();\n const totalCount = viewRecords.length;\n\n const rawContentHeight = this.#sheet.getRowHeight() * totalCount;\n\n const needsVScroll = (rawContentHeight > viewHeight);\n\n // 1. 전체 실제 데이터의 높이 계산\n //const rawTotalVirtualHeight = Math.max(totalCount * rowHeight + (rowHeight*2) + fixedHeight - viewHeight, 0);\n //trace.log(viewHeight, fixedHeight);\n\n //trace.log(rawContentHeight, bodyHeight);\n //trace.log(\"**************************************\", needsVScroll);\n\n this.#sheet.classList.toggle('vscroll-visible', needsVScroll);\n\n if (!needsVScroll) {\n return;\n }\n\n const trackHeight = track.clientHeight;\n if (trackHeight <= 0) return;\n\n //trace.log(body, body.scrollTop, bodyHeight, viewHeight, contentHeight);\n\n //trace.log(bodyHeight, rawContentHeight, contentHeight);\n\n const thumbHeight = Math.max(Math.min(trackHeight * (bodyHeight / rawContentHeight), trackHeight), 20);\n thumb.style.height = `${thumbHeight}px`;\n\n const currentScrollTop = body.scrollTop;\n //const maxScrollTop = Math.max(contentHeight - bodyHeight, 1);\n const maxScrollTop = Math.max(contentHeight - this.#sheet.rowManager.getRowHeight(), 1);\n\n let thumbTop = 0;\n if (maxScrollTop > 0) {\n thumbTop = (currentScrollTop / maxScrollTop) * (trackHeight - thumbHeight);\n }\n\n const maxThumbTop = trackHeight - thumbHeight;\n if (thumbTop < 0) thumbTop = 0;\n if (thumbTop > maxThumbTop) thumbTop = maxThumbTop;\n\n thumb.style.top = `${thumbTop}px`;\n\n /**\n // 🎯 [디버깅 로그] 스크롤바가 리프레시될 때 현재 상태 로깅\n trace.log(\"🔍 [VScroll Refresh]\", {\n isGrouped: this.#sheet.sourceTable?.querySelector(\"tbody tr[grouping='true']\") ? true : false,\n totalCount,\n bodyScrollTop: currentScrollTop,\n maxScrollTop,\n thumbTop,\n maxThumbTop\n }); */\n\n this.#elements.top.disabled = (currentScrollTop <= 0);\n this.#elements.bottom.disabled = (currentScrollTop >= maxScrollTop - 1);\n };\n\n #init = () => {\n trace.log(\"nine-table-vscrollbar.#init\");\n\n const body = this.#elements.container;\n\n this.#elements.thumb.addEventListener(\"mousedown\", (e) => {\n if (e.button !== 0) return;\n e.stopPropagation();\n e.preventDefault();\n this.#dragging = true;\n\n this.#startY = e.clientY;\n this.#startThumbTop = parseFloat(this.#elements.thumb.style.top) || 0;\n const trackRect = this.#elements.track.getBoundingClientRect();\n const trackHeight = trackRect.height;\n const thumbHeight = this.#elements.thumb.clientHeight;\n const maxThumbTop = trackHeight - thumbHeight;\n\n const onMouseMove = (moveEvent) => {\n if (!this.#dragging) return;\n if (maxThumbTop <= 0) return;\n\n //this.#elements.container.scrollTop = 0;\n\n const deltaY = moveEvent.clientY - this.#startY;\n let targetThumbTop = this.#startThumbTop + deltaY;\n\n if (targetThumbTop < 0) targetThumbTop = 0;\n if (targetThumbTop > maxThumbTop) targetThumbTop = maxThumbTop;\n\n // 썸 위치 즉시 고정\n this.#elements.thumb.style.top = `${targetThumbTop}px`;\n\n const ratio = targetThumbTop / maxThumbTop;\n\n const rowHeight =this.#sheet.getRowHeight();\n const viewHeight = (this.#sheet.querySelector('.ng-sheet-body').offsetHeight || 0) -\n (this.#sheet.elements.body.thead?.offsetHeight || 0) -\n (this.#sheet.elements.body.tfoot?.offsetHeight || 0) -\n (this.#sheet.elements.body.tbody.head.offsetHeight || 0);\n\n const visibleRowCount = Math.floor(viewHeight / rowHeight);\n\n const { totalCount } = this.#getScaleInfo();\n //const targetRow = Math.max(0, Math.min(Math.floor(ratio * (totalCount - 1)), totalCount - 1));\n const targetRow = Math.floor(ratio * (totalCount - visibleRowCount + 1));\n // 1000010 - 6\n this.#sheet.rowManager.scrollToDataRow(targetRow);\n\n const { rawContentHeight, contentHeight } = this.#getScaleInfo();\n const currentScrollTop = this.#elements.container.scrollTop;\n const maxScrollTop = Math.max(contentHeight - this.#sheet.rowManager.getRowHeight(), 0);\n\n //trace.log(\"*****************\", visibleRowCount, ratio, totalCount, targetRow);\n\n this.#elements.top.disabled = (currentScrollTop <= 0);\n this.#elements.bottom.disabled = (currentScrollTop >= maxScrollTop - 1);\n };\n\n const onMouseUp = () => {\n this.#dragging = false;\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n //this.refresh();\n };\n\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n });\n\n this.#elements.track.addEventListener(\"mousedown\", (e) => {\n if (e.button !== 0 || e.target === this.#elements.thumb) return;\n const trackRect = this.#elements.track.getBoundingClientRect();\n const thumbHeight = this.#elements.thumb.clientHeight;\n const trackHeight = this.#elements.track.clientHeight;\n const maxThumbTop = trackHeight - thumbHeight;\n\n if (maxThumbTop > 0) {\n const clickY = e.clientY - trackRect.top - (thumbHeight / 2);\n const ratio = Math.max(0, Math.min(1, clickY / maxThumbTop));\n\n const { totalCount } = this.#getScaleInfo();\n const targetRow = Math.max(0, Math.min(Math.floor(ratio * (totalCount - 1)), totalCount - 1));\n\n trace.log(\"🎯 [VScroll Track Click]\", { ratio, clickY, totalCount, targetRow });\n\n if (targetRow >= 0 && this.#sheet.rowManager && typeof this.#sheet.rowManager.scrollToDataRow === 'function') {\n this.#sheet.rowManager.scrollToDataRow(targetRow, 'top');\n }\n }\n this.refresh();\n });\n\n /**\n this.#elements.top.addEventListener(\"click\", () => {\n const currentTopRow = Math.floor(body.scrollTop / this.#sheet.getRowHeight());\n const targetRow = Math.max(0, currentTopRow - 1);\n if (this.#sheet.rowManager && typeof this.#sheet.rowManager.scrollToDataRow === 'function') {\n this.#sheet.rowManager.scrollToDataRow(targetRow, 'top');\n }\n });\n */\n /**\n this.#elements.bottom.addEventListener(\"click\", (e) => {\n\n const $firstTr = this.#sheet.querySelector(\"tbody.body tr\");\n const targetRow = parseInt($firstTr.dataset.row, 10) + 1;\n\n this.#sheet.rowManager.scrollToDataRow(targetRow + 1, null, () => {\n this.refresh();\n });\n }); */\n\n // 🎯 아래쪽 화살표 꾹 누를 때 연속 스크롤 처리\n // 🎯 상하 화살표 꾹 누를 때 연속 스크롤 공통 처리 함수\n let scrollInterval = null;\n\n const startContinuousScroll = (direction) => {\n if (scrollInterval) return;\n\n const scrollStep = () => {\n const $firstTr = this.#sheet.querySelector(\"tbody.body tr\");\n\n if (!$firstTr || $firstTr.dataset.row === undefined) {\n return;\n }\n\n trace.log(this.#sheet.isLastRow());\n if (direction === 'down' && this.#sheet.isLastRow()) {\n return;\n }\n\n const currentRow = parseInt($firstTr.dataset.row, 10);\n const targetRow = direction === 'down' ? currentRow+1 : Math.max(0, currentRow-1);\n\n this.#sheet.rowManager.scrollToDataRow(targetRow, null, () => {\n this.refresh();\n });\n };\n\n scrollStep();\n scrollInterval = setInterval(scrollStep, 200); // 100ms 간격 반복\n };\n\n const stopContinuousScroll = () => {\n if (scrollInterval) {\n clearInterval(scrollInterval);\n scrollInterval = null;\n }\n };\n\n // 1. 위쪽(top) 버튼 이벤트 바인딩\n this.#elements.top.addEventListener(\"mousedown\", (e) => {\n if (e.button !== 0) return;\n startContinuousScroll('up');\n });\n\n // 2. 아래쪽(bottom) 버튼 이벤트 바인딩\n this.#elements.bottom.addEventListener(\"mousedown\", (e) => {\n if (e.button !== 0) return;\n startContinuousScroll('down');\n });\n\n // 마우스가 떼어지거나 버튼 영역을 벗어났을 때 공통 정지\n document.addEventListener(\"mouseup\", stopContinuousScroll);\n this.#elements.top.addEventListener(\"mouseleave\", stopContinuousScroll);\n this.#elements.bottom.addEventListener(\"mouseleave\", stopContinuousScroll);\n };\n}\n\nif (!customElements.get('nine-table-vscrollbar')) {\n customElements.define(\"nine-table-vscrollbar\", NineTableVScrollBar);\n}","import { trace } from \"@nopeer\";\r\n\r\n// 💡 배열 인덱스 상수 정의\r\nexport const GROUP_IDX = {\r\n\tID: 0,\r\n\tDEPTH: 1,\r\n\tNAME: 2,\r\n\tCHILDREN: 3,\r\n};\r\n\r\nexport class GroupingManager {\r\n\t#sheet;\r\n\t#host;\r\n\t#groupColumns = [];\r\n\t#groupMap = new Map(); // 그룹별 자식 ID 매핑 관리용\r\n\t#isApplying = false;\r\n\r\n\tconstructor(sheet) {\r\n\t\tthis.#sheet = sheet;\r\n\t\tthis.#host = this.#sheet.getRootNode().host;\r\n\t}\r\n\r\n\tget columns() {\r\n\t\treturn this.#groupColumns;\r\n\t}\r\n\r\n\tget groupMap() {\r\n\t\treturn this.#groupMap;\r\n\t}\r\n\r\n\tinitialize = () => {\r\n\t\tlet groupColumns = [];\r\n\t\tconst sourceTable = this.#sheet.sourceTable;\r\n\t\tif (sourceTable) {\r\n\t\t\tsourceTable.querySelectorAll('tbody tr[grouping=\"true\"]').forEach(($tr) => {\r\n\t\t\t\tconst $cell =$tr.querySelector(`[cell-type=\"tree\"]`);\r\n\t\t\t\tif ($cell &&$cell.dataset.bind) {\r\n\t\t\t\t\tgroupColumns.push($cell.dataset.bind);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.#groupColumns = groupColumns;\r\n\t};\r\n\r\n\tapply() {\r\n\r\n\t\ttrace.log(\"==================\", \"Grouping.Apply\");\r\n\r\n\t\tif (this.#isApplying) return;\r\n\t\tthis.#isApplying = true;\r\n\r\n\t\tlet groupColumns = [];\r\n\t\tconst sourceTable = this.#sheet.sourceTable;\r\n\t\tif (sourceTable) {\r\n\t\t\tsourceTable.querySelectorAll('tbody tr[grouping=\"true\"]').forEach(($tr) => {\r\n\t\t\t\tconst $cell =$tr.querySelector(`[cell-type=\"tree\"]`);\r\n\t\t\t\tif ($cell &&$cell.dataset.bind) {\r\n\t\t\t\t\tgroupColumns.push($cell.dataset.bind);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.#groupColumns = groupColumns;\r\n\r\n\t\t// 💡 데이터 캐시와 렌더링 아이템은 이제 SheetView 단일 파이프라인에서 관리하므로\r\n\t\t// 그룹핑 설정이 바뀌면 SheetView.refresh()를 호출해 전체 흐름을 일괄 재계산합니다.\r\n\t\tthis.#isApplying = false;\r\n\t\tthis.#sheet.scrollToY(0);\r\n\t\tthis.#sheet.view.refresh(); // 🎯 SheetView에서 필터/정렬/그룹핑 일괄 처리\r\n\t}\r\n\r\n\tclear() {\r\n\t\tthis.#groupColumns = [];\r\n\t\tthis.#groupMap.clear();\r\n\t\tthis.#isApplying = false;\r\n\t\tthis.#sheet.scrollToY(0);\r\n\t\tthis.#sheet.view.refresh();\r\n\t}\r\n\r\n\t// SheetView가 그룹핑 연산 후 groupMap을 공유할 수 있도록 설정 메서드 제공\r\n\tsetGroupMap(map) {\r\n\t\tthis.#groupMap = map;\r\n\t}\r\n\r\n\tgetChildrenRowIds(groupId) {\r\n\t\treturn this.#groupMap.get(groupId) || [];\r\n\t}\r\n\r\n\tgetChildrenRecords(groupId) {\r\n\t\tconst rowIds = this.getChildrenRowIds(groupId);\r\n\t\tconst dataManager = this.#host.data;\r\n\t\treturn rowIds.map(rowid => dataManager.getArray(rowid)).filter(Boolean);\r\n\t}\r\n}\r\n\r\nexport class Grouping {\r\n\r\n\tstatic apply(rawRecords, groupColumns = [], fields = []) {\r\n\t\tif (!groupColumns || groupColumns.length === 0) {\r\n\t\t\treturn { headers: [], renderItems: [], groupMap: new Map() };\r\n\t\t}\r\n\r\n\t\tconst validRaw = rawRecords.filter(o => !o.__ng?.deleted);\r\n\t\tconst groupMap = new Map();\r\n\r\n\t\tconst nestedTree = Grouping.#buildNestedMap(validRaw, groupColumns, fields);\r\n\t\tconst flatResult = [];\r\n\t\tconst renderItems = [];\r\n\r\n\t\tGrouping.#flattenTree(nestedTree, 0, groupColumns, flatResult, renderItems, groupMap, \"\");\r\n\r\n\t\treturn { headers: flatResult, renderItems, groupMap };\r\n\t}\r\n\r\n\tstatic #flattenTree(mapOrArray, depth, groupColumns, resultArr, renderItems, groupMap, parentId) {\r\n\t\tlet counter = 0;\r\n\t\tconst isLastLevel = (depth === groupColumns.length - 1); // 💡 연산자 수정 반영\r\n\r\n\t\tfor (let [groupKey, subMapOrRecords] of mapOrArray.entries()) {\r\n\t\t\tconst groupId = parentId ? `${parentId}_${counter++}` : `g_${counter++}`;\r\n\r\n\t\t\tconst rowIds = Grouping.#collectLeafRowIds(subMapOrRecords);\r\n\t\t\tgroupMap.set(groupId, rowIds);\r\n\r\n\t\t\tconst groupRecord = [];\r\n\t\t\tgroupRecord[GROUP_IDX.ID] = groupId;\r\n\t\t\tgroupRecord[GROUP_IDX.DEPTH] = depth;\r\n\t\t\tgroupRecord[GROUP_IDX.NAME] = groupKey;\r\n\t\t\tgroupRecord[GROUP_IDX.CHILDREN] = rowIds;\r\n\r\n\t\t\tgroupRecord.__isGroupHeader = true;\r\n\t\t\tgroupRecord.__groupId = groupId;\r\n\r\n\t\t\tresultArr.push(groupRecord);\r\n\r\n\t\t\trenderItems.push({\r\n\t\t\t\ttype: 'group',\r\n\t\t\t\trecord: groupRecord,\r\n\t\t\t\tgroupId: groupId\r\n\t\t\t});\r\n\r\n\t\t\tif (!isLastLevel && subMapOrRecords instanceof Map) {\r\n\t\t\t\tGrouping.#flattenTree(subMapOrRecords, depth + 1, groupColumns, resultArr, renderItems, groupMap, groupId);\r\n\t\t\t} else {\r\n\t\t\t\tconst leafRecords = Grouping.#collectLeafRecords(subMapOrRecords);\r\n\t\t\t\tleafRecords.forEach(record => {\r\n\t\t\t\t\trecord.__isGroupHeader = false;\r\n\t\t\t\t\trecord.__groupId = groupId;\r\n\t\t\t\t\tresultArr.push(record);\r\n\r\n\t\t\t\t\trenderItems.push({\r\n\t\t\t\t\t\ttype: 'data',\r\n\t\t\t\t\t\trecord: record,\r\n\t\t\t\t\t\tgroupId: groupId\r\n\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tstatic #buildNestedMap(records, groupColumns, fields) {\r\n\t\tconst colIndex = fields.indexOf(groupColumns[0]);\r\n\t\tconst remainingCols = groupColumns.slice(1);\r\n\t\tconst map = new Map();\r\n\r\n\t\trecords.forEach(record => {\r\n\t\t\tconst key = colIndex >= 0 ? record.v[colIndex] : '(Unknown)';\r\n\t\t\tif (!map.has(key)) map.set(key, []);\r\n\t\t\tmap.get(key).push(record);\r\n\t\t});\r\n\r\n\t\tif (remainingCols.length > 0) {\r\n\t\t\tconst result = new Map();\r\n\t\t\tfor (let [key, subRecords] of map.entries()) {\r\n\t\t\t\tresult.set(key, Grouping.#buildNestedMap(subRecords, remainingCols, fields));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\treturn map;\r\n\t}\r\n\r\n\tstatic #collectLeafRowIds(subMapOrRecords) {\r\n\t\tlet rowIds = [];\r\n\t\tif (subMapOrRecords instanceof Map) {\r\n\t\t\tfor (let subVal of subMapOrRecords.values()) {\r\n\t\t\t\trowIds = rowIds.concat(Grouping.#collectLeafRowIds(subVal));\r\n\t\t\t}\r\n\t\t} else if (Array.isArray(subMapOrRecords)) {\r\n\t\t\trowIds = rowIds.concat(subMapOrRecords.map(r => r.__ng?.rowid ?? r.m?._?.[0]));\r\n\t\t}\r\n\t\treturn rowIds;\r\n\t}\r\n\r\n\tstatic #collectLeafRecords(subMapOrRecords) {\r\n\t\tlet records = [];\r\n\t\tif (subMapOrRecords instanceof Map) {\r\n\t\t\tfor (let subVal of subMapOrRecords.values()) {\r\n\t\t\t\trecords = records.concat(Grouping.#collectLeafRecords(subVal));\r\n\t\t\t}\r\n\t\t} else if (Array.isArray(subMapOrRecords)) {\r\n\t\t\trecords = records.concat(subMapOrRecords);\r\n\t\t}\r\n\t\treturn records;\r\n\t}\r\n}","import { trace } from \"@nopeer\";\nimport { NINE_TABLE } from \"@/core/constants.js\";\nimport { GROUP_IDX } from \"@/data/Grouping.js\";\n\nexport class RowManager {\n #BUFFER_ROW_COUNT = 3;\n\n #host;\n #sheet;\n #element;\n\n #containerTemplates = new Map();\n\n #templateRowHeights = []; // 💡 [추가] 템플릿 행별 개별 높이 보관 ([그룹1, 그룹2, 데이터])\n #cachedTemplateHeight = null;\n\n #resizeObserver = null;\n #sheetHeight = 0;\n #cachedRowCount;\n\n #isProgrammaticScroll = false;\n #isGrouped = false;\n\n constructor(sheet) {\n this.#host = sheet.getRootNode().host;\n this.#sheet = sheet;\n\n this.#initResizeObserver();\n }\n\n // ==========================================\n // 🎯 Public APIs & Getters\n // ==========================================\n\n getRowHeight() {\n return this.#templateRowHeights.reduce((sum, h) => sum + h, 0);//this.#cachedTemplateHeight;\n }\n\n\n refresh = (force = false) => {\n //trace.log(\"rowManager.refresh\", { force });\n\n //this.#isGrouped = this.#sheet.sourceTable.querySelector(\"tbody tr[group='true']\") ? true : false;\n\n if (!this.#sheet.classList.contains('active')) return;\n\n const bodyViewport = this.#sheet.querySelector('.ng-sheet-body');\n if (!bodyViewport) return;\n\n const wasInvalidHeight = !this.#cachedTemplateHeight || this.#cachedTemplateHeight <= 0;\n\n if (wasInvalidHeight) {\n this.#measureAndCacheHeight();\n if (this.#cachedTemplateHeight && this.#cachedTemplateHeight > 0) {\n this.#renderAllContainers();\n }\n }\n\n\n //this.#updateFooterSpacing();\n\n this.#handleScroll(bodyViewport.scrollTop, force);\n\n this.#sheet.querySelector('nine-table-vscrollbar')?.refresh();\n };\n\n #handleScroll = (scrollTop, force = false) => {\n\n if (this.#isGrouped) {\n this.#handleGroupedScroll(scrollTop, force);\n return;\n }\n\n const rowHeight = this.#cachedTemplateHeight;\n if (!rowHeight || rowHeight <= 0) return;\n\n const viewRecords = this.#sheet.view.getArray();\n const totalCount = viewRecords.length;\n\n if (totalCount === 0) {\n this.#sheet.elements.scrollHolder.style.height = '0px';\n return;\n }\n\n const templateLength = this.#sheet.templateLength;\n\n const fixedHeight = (this.#sheet.elements.body.thead?.offsetHeight || 0) +\n (this.#sheet.elements.body.tfoot?.offsetHeight || 0) +\n this.#sheet.elements.body.tbody.head.offsetHeight;\n\n const viewHeight = this.#sheet.querySelector('.ng-sheet-body').offsetHeight || 0;\n // 1. 전체 실제 데이터의 높이 계산\n //const rawTotalVirtualHeight = Math.max(totalCount * rowHeight + (rowHeight*2) + fixedHeight - viewHeight, 0);\n const rawTotalVirtualHeight = Math.max(totalCount * rowHeight - (viewHeight - fixedHeight - rowHeight), 0);\n\n\n // 🎯 [핵심] 브라우저 DOM 최대 높이 제한 대응 (약 1,500만 픽셀 상한선)\n const MAX_BROWSER_HEIGHT = 15000000;\n const useScaling = rawTotalVirtualHeight > MAX_BROWSER_HEIGHT;\n\n let scaleFactor = 1;\n let totalVirtualHeight = rawTotalVirtualHeight;\n\n if (useScaling) {\n scaleFactor = MAX_BROWSER_HEIGHT / rawTotalVirtualHeight;\n totalVirtualHeight = MAX_BROWSER_HEIGHT;\n }\n //trace.log(totalCount, rowHeight, rawTotalVirtualHeight, MAX_BROWSER_HEIGHT);\n // 스크롤홀더에는 브라우저가 소화할 수 있는 최대 높이만 부여\n this.#sheet.elements.scrollHolder.style.height = `${totalVirtualHeight}px`;\n\n //trace.log(\"*************\",this.#sheet.querySelector('.ng-sheet-body').clientHeight, this.#sheet.querySelector('.ng-sheet-body').offsetHeight, viewHeight, fixedHeight, rawTotalVirtualHeight, totalVirtualHeight);\n\n //trace.log(totalVirtualHeight);\n // 🎯 스크롤바 위치(scrollTop)를 실제 데이터 좌표계로 역환산\n const actualScrollTop = useScaling ? (scrollTop / scaleFactor) : scrollTop;\n\n const maxStartIndex = Math.max(0, totalCount - 1);\n const clampedScrollTop = Math.min(actualScrollTop, rawTotalVirtualHeight);\n\n // 실제 데이터 좌표 기준으로 시작 인덱스 산출 (원하시는 -1 보정 유지)\n //const startIndex = Math.max(0, Math.min(Math.floor(clampedScrollTop / rowHeight) - 1, maxStartIndex));\n\n //const calculatedIndexFloat = clampedScrollTop / rowHeight;\n //const startIndex = Math.max(0, Math.min(Math.floor(calculatedIndexFloat) - 1, maxStartIndex));\n const startIndex = Math.max(0, Math.min(Math.floor(clampedScrollTop / rowHeight), maxStartIndex));\n\n /**\n trace.log(\"🔍 [#handleScroll DEBUG]\", {\n scrollTop,\n actualScrollTop,\n clampedScrollTop,\n rowHeight,\n //calculatedIndexFloat,\n startIndex,\n firstTrDatasetRow: this.#element.firstTr?.dataset?.row\n }); */\n\n // 🎯 화면 렌더링 오프셋도 '실제 데이터 좌표(clampedScrollTop)' 기준의 모듈러 연산 적용\n const renderOffsetTop = clampedScrollTop % rowHeight;\n this.#sheet.elements.left.tbody.body.style.top =\n this.#sheet.elements.body.tbody.body.style.top =\n this.#sheet.elements.right.tbody.body.style.top = `-${renderOffsetTop}px`;\n\n const firstTr = this.#element.firstTr;\n const currentStartIndex = firstTr && firstTr.dataset.row !== undefined ? parseInt(firstTr.dataset.row, 10) : -1;\n\n if (!force && currentStartIndex === startIndex) {\n //trace.log(`[Perf ${getTimestamp()}] ⏭️ 인덱스 동일로 스킵! 총 소요: ${(performance.now() - startTime).toFixed(2)}ms`);\n return;\n }\n\n //trace.log(`${getTimestamp()}`);\n\n\n // [범인 구간 추적]\n [\n this.#sheet.elements.left.tbody.body,\n this.#sheet.elements.body.tbody.body,\n this.#sheet.elements.right.tbody.body\n ].forEach(($tbody, tbodyIdx) => {\n if (!$tbody) return;\n\n const rows = $tbody.querySelectorAll('tbody.body tr');\n\n //trace.log(`${getTimestamp()}`);\n\n rows.forEach(($tr, index) => {\n const dataIndex = startIndex + Math.floor(index / templateLength);\n\n if (dataIndex >= totalCount) {\n $tr.style.display = 'none';\n $tr.dataset.matrixRow = null;\n $tr.dataset.row = null;\n $tr.dataset.index = null;\n return;\n }\n\n // trace.log(`${getTimestamp()}`);\n const record = viewRecords[dataIndex];//this.#sheet.view.getArray(dataIndex);\n //trace.log(`${getTimestamp()}`);\n\n if (!record) {\n $tr.style.display = 'none';\n return;\n }\n\n const rowid = record.m._[NINE_TABLE.META.INDEX.ROWID];\n\n $tr.style.display = '';\n\n // 💡 만약 개별 바인딩 안에서 느린지 확인하려면 여기서 측정 가능\n this.#bindRowData($tr, record, rowid, dataIndex);\n });\n });\n\n // 셀렉션 갱신\n this.#sheet.selection.refresh();\n };\n\n\n #handleGroupedScroll = (scrollTop, force = false) => {\n\n trace.log(\"handleGroupdScroll() start\")\n\n const allRenderItems = this.#sheet.view.getArray() || [];\n const totalVirtualCount = allRenderItems.length;\n\n if (totalVirtualCount === 0) {\n this.#sheet.elements.scrollHolder.style.height = '0px';\n return;\n }\n\n //trace.log(allRenderItems);\n\n const bodyContent = this.#sheet.querySelector('.ng-sheet-body .ng-sheet-body-content');\n const templateLength = this.#sheet.templateLength || 1;\n\n const getItemHeight = (item) => {\n if (item.type === 'group') {\n const depth = item.record[GROUP_IDX.DEPTH] || 0;\n // 💡 해당 뎁스 그룹 행의 높이가 정확히 잡히는지 확인 (없으면 첫 번째 템플릿 높이)\n const groupHeight = this.#templateRowHeights[depth] || this.#cachedTemplateHeight / templateLength;\n return groupHeight;\n } else {\n // 💡 데이터 행은 전체 템플릿 높이에서 그룹 TR들을 제외한 순수 데이터 TR들의 높이 합산이어야 합니다.\n // 만약 templateLength가 1이고 일반 행이라면 아래와 같이 처리\n let dataRowsHeight = 0;\n // templateRowHeights 전체 중에서 그룹이 아닌 데이터 행들의 높이만 합산하거나,\n // 단일 데이터 템플릿 높이를 정확히 반환해야 합니다.\n const templateLength = this.#sheet.templateLength || 1;\n\n // 간단하게 전체 캐시된 템플릿 높이에서 그룹 높이들을 뺀 나머지를 데이터 높이로 산정\n let groupHeightsTotal = 0;\n for(let i = 0; i < templateLength - 1; i++) {\n groupHeightsTotal += this.#templateRowHeights[i] || 0;\n }\n dataRowsHeight = this.#cachedTemplateHeight - groupHeightsTotal;\n\n return dataRowsHeight > 0 ? dataRowsHeight : this.#cachedTemplateHeight;\n }\n };\n\n\n let totalVirtualHeight = 0;\n const itemHeights = new Array(totalVirtualCount);\n for (let i = 0; i < totalVirtualCount; i++) {\n const h = getItemHeight(allRenderItems[i]);\n itemHeights[i] = h;\n totalVirtualHeight += h;\n }\n\n this.#sheet.elements.scrollHolder.style.height = `${totalVirtualHeight}px`;\n\n trace.log(\"*************\", totalVirtualHeight);\n\n const viewportClientHeight = this.#sheet.clientHeight;\n\n let accumulatedHeight = 0;\n let startIndex = 0;\n\n for (let i = 0; i < totalVirtualCount; i++) {\n const h = itemHeights[i];\n if (accumulatedHeight + h > scrollTop) {\n startIndex = i;\n break;\n }\n accumulatedHeight += h;\n startIndex = i;\n }\n\n //trace.log(startIndex);\n\n const offsetY = scrollTop - accumulatedHeight;\n if (bodyContent) {\n bodyContent.querySelectorAll(\"tbody\").forEach(($tbody) => {\n $tbody.style.top = `-${Math.max(0, offsetY)}px`;\n });\n }\n\n const firstTr = this.#element.firstTr;\n const currentStartIndex = firstTr && firstTr.dataset.virtualIndex !== undefined\n ? parseInt(firstTr.dataset.virtualIndex, 10)\n : -1;\n\n if (!force && currentStartIndex === startIndex) {\n return;\n }\n\n const visibleRowsCount = Math.ceil(viewportClientHeight / (this.#cachedTemplateHeight / templateLength));\n const dynamicBuffer = (this.#sheet.grouping.columns?.length || 1) * 15;\n const targetStart = startIndex;\n const targetEnd = Math.min(totalVirtualCount, startIndex + visibleRowsCount + dynamicBuffer);\n\n\n\n\n const renderedItems = allRenderItems.slice(targetStart, targetEnd);\n\n //trace.log(\"handleGroupdScroll() 22\", renderedItems);\n\n ['.ng-container-body', '.ng-container-left', '.ng-container-right'].forEach(selector => {\n const container = this.#sheet.querySelector(`.ng-sheet-body ${selector}`);\n if (!container) return;\n\n const trs = Array.from(container.querySelectorAll('tbody.body tr'));\n\n for (let i = 0; i < trs.length; i += templateLength) {\n const itemIndex = Math.floor(i / templateLength);\n const item = renderedItems[itemIndex];\n const chunkTrs = trs.slice(i, i + templateLength);\n\n if (!item || itemIndex >= renderedItems.length) {\n chunkTrs.forEach(tr => {\n tr.style.display = 'none';\n tr.dataset.matrixRow = null;\n tr.dataset.row = null;\n tr.dataset.index = null;\n });\n continue;\n }\n\n const dataIndex = startIndex + itemIndex;\n\n chunkTrs.forEach((tr, subIdx) => {\n const virtualIndex = startIndex + itemIndex;\n tr.dataset.virtualIndex = virtualIndex;\n tr.dataset.row = (item.type === 'data') ? dataIndex : '';\n\n const isTrGroup = tr.getAttribute('grouping') === 'true';\n\n if (item.type === 'group') {\n if (isTrGroup) {\n const depth = item.record[GROUP_IDX.DEPTH];\n if (subIdx === depth) {\n tr.style.display = '';\n this.#bindGroupRowData(tr, allRenderItems, item.record, virtualIndex);\n } else {\n tr.style.display = 'none';\n tr.dataset.matrixRow = null;\n tr.dataset.row = null;\n tr.dataset.index = null;\n }\n } else {\n tr.style.display = 'none';\n tr.dataset.matrixRow = null;\n tr.dataset.row = null;\n tr.dataset.index = null;\n }\n } else {\n if (isTrGroup) {\n tr.style.display = 'none';\n tr.dataset.matrixRow = null;\n tr.dataset.row = null;\n tr.dataset.index = null;\n } else {\n tr.style.display = '';\n\n //trace.log(item.record)\n const rowid = item.record.m?.rowid ?? 0;\n this.#bindRowData(tr, item.record, rowid, virtualIndex);\n }\n }\n });\n }\n });\n\n this.#sheet.selection.refresh();\n\n trace.log(\"handleGroupdScroll() end\")\n };\n\n #bindGroupRowData = ($tr, allRenderItems, groupRecord, virtualIndex) => {\n const templateLength = this.#sheet.templateLength || 1;\n const subRowIndex = parseInt($tr.dataset.subrow, 10) || 0;\n const matrixRow = (virtualIndex * templateLength) + subRowIndex;\n\n const indices = groupRecord[GROUP_IDX.CHILDREN]; // 인덱스 배열이 들어있는 위치 (정확한 인덱스는 구조에 맞게 조절)\n const allRecords = this.#host.data.getArray();\n const childrenRecords = indices ? indices.map(idx => allRecords[idx]).filter(Boolean) : [];\n\n // 필요하다면 groupRecord나 tr에 자식 레코드들을 캐싱해 둘 수도 있습니다.\n //groupRecord.childrenRecords = childrenRecords;\n\n //trace.log(allRecords, childrenRecords);\n\n\n $tr.dataset.virtualIndex = virtualIndex;\n $tr.dataset.row = '';\n $tr.dataset.matrixRow = matrixRow;\n $tr.data = childrenRecords;//groupRecord;\n $tr.dataset.groupId = groupRecord[GROUP_IDX.ID];\n\n //trace.log(tr, groupRecord)\n\n Array.from($tr.cells).forEach(($cell) => {\n\n $cell.dataset.row = virtualIndex;\n\n const customComp = Array.from($cell.children).find($el =>\n $el.tagName.toLowerCase().startsWith('cell-') || typeof $el.refresh === 'function'\n );\n\n //trace.log(customComp)\n\n if (customComp !== undefined && typeof customComp.refresh === 'function') {\n customComp?.refresh();\n }\n });\n };\n\n #bindRowData = ($tr, record, rowid, dataIndex) => {\n const templateLength = this.#sheet.templateLength || 1;\n const subRowIndex = parseInt($tr.dataset.subrow, 10) || 0;\n const matrixRow = (dataIndex * templateLength) + subRowIndex;\n\n $tr.dataset.index = dataIndex;\n $tr.dataset.row = rowid;\n $tr.dataset.matrixRow = matrixRow;\n $tr.data = record;\n\n Array.from($tr.cells).forEach(($cell) => {\n $cell.dataset.index = dataIndex;\n $cell.dataset.row = rowid;\n\n const customComp = Array.from($cell.children).find($el =>\n $el.tagName.toLowerCase().startsWith('cell-') && typeof $el.refresh === 'function'\n );\n\n customComp?.refresh();\n });\n };\n\n initialize = () => {\n //trace.log(\"rowManager.initialize\");\n\n this.#isGrouped = this.#sheet.sourceTable.querySelector(\"tbody tr[grouping='true']\") ? true : false;\n\n this.#cachedTemplateHeight = null;\n this.#containerTemplates.clear();\n\n this.#element = {\n scrollTables: this.#sheet.querySelectorAll('.ng-sheet-body table'),\n firstTr: this.#sheet.querySelector('.ng-sheet-body .ng-container-body tbody.body tr'),\n };\n\n // 컨테이너 템플릿 수집 부분도 tbody.body 기준으로 변경\n ['.ng-container-body', '.ng-container-left', '.ng-container-right'].forEach(selector => {\n const container = this.#sheet.querySelector(`.ng-sheet-body ${selector}`);\n if (!container) return;\n\n const tableEl = container.querySelector('table');\n if (!tableEl) return;\n\n const tbody = tableEl.querySelector('tbody.body'); // 👈 .bindable-tbody 대신 tbody.body\n if (!tbody) return;\n\n const trs = Array.from(tbody.querySelectorAll('tr'));\n const templateTrs = trs.map(tr => tr.cloneNode(true));\n this.#containerTemplates.set(selector, templateTrs);\n });\n\n const bodyViewport = this.#sheet.querySelector('.ng-sheet-body');\n\n if (bodyViewport) {\n this.#sheetHeight = bodyViewport.clientHeight;\n\n this.#measureAndCacheHeight();\n this.#renderAllContainers();\n this.#handleScroll(bodyViewport.scrollTop, true);\n\n bodyViewport.addEventListener('scroll', (e) => {\n\n if (this.#isProgrammaticScroll) return;\n\n const rowHeight = this.#cachedTemplateHeight || 0;\n const totalCount = this.#sheet.view.getArray()?.length || 0;\n const rawTotalVirtualHeight = totalCount * rowHeight;\n\n if (rawTotalVirtualHeight <= bodyViewport.clientHeight) {\n trace.log(rawTotalVirtualHeight, bodyViewport.clientHeight)\n return;\n }\n\n this.#handleScroll(bodyViewport.scrollTop);\n\n this.#sheet.querySelector('nine-table-vscrollbar').refresh();\n //this.#sheet.querySelector('nine-table-hscrollbar').refresh();\n }, { passive: true });\n }\n };\n\n scrollToDataRow(dataRow, align = 'top', onRendered) {\n //trace.log(\"🔍 [scrollToDataRow ENTER]\", { dataRow, isGrouped: this.#isGrouped });\n\n const bodyViewport = this.#sheet.querySelector('.ng-sheet-body');\n\n const viewRecords = this.#sheet.view.getArray();\n const totalCount = viewRecords?.length || 0;\n\n const targetRow = Math.max(0, Math.min(dataRow, totalCount - 1));\n let targetScrollTop = 0;\n\n // 🎯 [핵심] 그룹핑 모드일 때는 실제 scrollHeight(또는 렌더링된 총 높이)를 기준으로 비율 계산\n if (this.#isGrouped) {\n const maxScrollTop = Math.max(bodyViewport.scrollHeight - bodyViewport.clientHeight, 1);\n // targetRow가 전체 totalCount에서 차지하는 비율(ratio)만큼 실제 스크롤 최대 높이에 곱해줌\n const ratio = targetRow / Math.max(totalCount - 1, 1);\n targetScrollTop = ratio * maxScrollTop;\n } else {\n /**\n const rowHeight = this.#cachedTemplateHeight;\n\n let rawTargetScrollTop = targetRow * rowHeight;\n\n const fixedHeight = (this.#sheet.elements.body.thead?.offsetHeight || 0) +\n (this.#sheet.elements.body.tfoot?.offsetHeight || 0) +\n this.#sheet.elements.body.tbody.head.offsetHeight;\n\n const viewHeight = this.#sheet.querySelector('.ng-sheet-body').offsetHeight || 0;\n // 1. 전체 실제 데이터의 높이 계산\n const rawTotalVirtualHeight = Math.max(totalCount * rowHeight + (rowHeight*2) + fixedHeight - viewHeight, 0);\n\n //const rawTotalVirtualHeight = 0;\n\n trace.log(\"****************\", rawTotalVirtualHeight);\n\n //const rawTotalVirtualHeight = totalCount * rowHeight;\n const MAX_BROWSER_HEIGHT = 15000000;\n const useScaling = rawTotalVirtualHeight > MAX_BROWSER_HEIGHT;\n\n let scaleFactor = 1;\n if (useScaling) {\n scaleFactor = MAX_BROWSER_HEIGHT / rawTotalVirtualHeight;\n }\n\n targetScrollTop = rawTargetScrollTop * scaleFactor;\n */\n const rowHeight = this.#cachedTemplateHeight;\n const rawTargetScrollTop = targetRow * rowHeight;\n\n const fixedHeight = (this.#sheet.elements.body.thead?.offsetHeight || 0) +\n (this.#sheet.elements.body.tfoot?.offsetHeight || 0) +\n this.#sheet.elements.body.tbody.head.offsetHeight;\n\n const viewHeight = bodyViewport.offsetHeight || 0;\n\n // #handleScroll에서 사용하는 rawTotalVirtualHeight 공식과 정확히 일치시켜야 함\n const rawTotalVirtualHeight = Math.max(totalCount * rowHeight + fixedHeight - viewHeight, 0);\n\n const MAX_BROWSER_HEIGHT = 15000000;\n const useScaling = rawTotalVirtualHeight > MAX_BROWSER_HEIGHT;\n\n let scaleFactor = 1;\n if (useScaling) {\n scaleFactor = MAX_BROWSER_HEIGHT / rawTotalVirtualHeight;\n }\n\n targetScrollTop = rawTargetScrollTop * scaleFactor;\n }\n\n //trace.log(\"🔍 [scrollToDataRow CALC FIXED]\", { targetRow, totalCount, targetScrollTop });\n\n trace.log(targetScrollTop);\n\n this.#isProgrammaticScroll = true;\n bodyViewport.scrollTop = targetScrollTop;\n this.#handleScroll(targetScrollTop);\n //trace.log(targetScrollTop);\n\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n this.#isProgrammaticScroll = false;\n if (typeof onRendered === 'function') onRendered();\n });\n });\n }\n\n\n\n destroy = () => {\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = null;\n }\n };\n\n #measureAndCacheHeight = () => {\n if (!this.#sheet.classList.contains('active')) return;\n\n if (!this.#sheet.sourceTable) return;\n\n const trTemplates = this.#sheet.sourceTable?.querySelectorAll('tbody.body tr');\n //trace.log(\"[DEBUG #measureAndCacheHeight] bodyTemplates count:\", trTemplates?.length);\n //if (!trTemplates || trTemplates.length === 0) return;\n\n const $tbody = this.#sheet.querySelector('.ng-sheet-body .ng-container-body tbody.body');\n //if (!tbody) return -1;\n\n $tbody.querySelectorAll('tr').forEach(tr => tr.remove());\n\n const fragment = document.createDocumentFragment();\n trTemplates.forEach($tr => fragment.appendChild($tr.cloneNode(true)));\n $tbody.appendChild(fragment);\n\n //let totalHeight = 0;\n const renderedTrs = $tbody.querySelectorAll('tr');\n\n this.#templateRowHeights = [];\n renderedTrs.forEach($tr => {\n //const h = $tr.offsetHeight;\n //trace.log(`[DEBUG #measureAndCacheHeight] tr[${idx}] height:`, h);\n //totalHeight += h;\n\n if ($tr?.offsetHeight === 2) {\n trace.log(\"================================\");\n trace.log(this.#sheet);\n trace.log($tr);\n trace.log($tr.cloneNode(true));\n\n const computedStyle = window.getComputedStyle($tr);\n //const rectHeight = parseFloat(computedStyle.height) || parseFloat(computedStyle.minHeight) || 0\n\n trace.log(\"================================\", computedStyle, computedStyle.height, computedStyle.minHeight);\n }\n\n this.#templateRowHeights.push(Math.max($tr.offsetHeight, 24));\n });\n\n renderedTrs.forEach(tr => tr.remove());\n\n this.#cachedTemplateHeight = this.#templateRowHeights.reduce((sum, h) => sum + h, 0);\n\n this.#updateRowCount();\n };\n\n #updateRowCount = () => {\n trace.log(\"[DEBUG #updateRowCount] sheetHeight:\", this.#sheetHeight, \"cachedTemplateHeight:\", this.#cachedTemplateHeight);\n if (this.#sheetHeight > 0 && this.#cachedTemplateHeight > 0) {\n const visibleRows = Math.ceil(this.#sheetHeight / this.#cachedTemplateHeight);\n\n // 💡 [유연한 개선] 그룹화가 켜져 있다면 그룹 컬럼 깊이(다단 레벨)에 따라 버퍼를 동적으로 확장\n let dynamicBuffer = this.#BUFFER_ROW_COUNT;\n if (this.#isGrouped && this.#sheet.grouping) {\n const groupDepth = this.#sheet.grouping.columns?.length || 1;\n // 그룹 단계가 깊을수록 헤더 행이 많이 차지하므로 여유분을 비례해서 늘림 (예: 기본 버퍼 + (뎁스당 추가 여유))\n dynamicBuffer += (groupDepth * 15);\n }\n\n this.#cachedRowCount = visibleRows + dynamicBuffer;\n trace.log(\"[DEBUG #updateRowCount] calculated cachedRowCount:\", this.#host, this.#cachedRowCount);\n }\n };\n\n #renderAllContainers = () => {\n trace.log(\"rowManager.#renderAllContainers\");\n\n ['.ng-container-body', '.ng-container-left', '.ng-container-right'].forEach(selector => {\n const container = this.#sheet.querySelector(`.ng-sheet-body ${selector}`);\n if (container && container.querySelector('tbody')) {\n this.#renderRows(container); // selector 인자 제거!\n }\n });\n\n this.#syncRowHeights();\n };\n\n #renderRows = (container) => {\n let targetFixedType = null;\n if (container.classList.contains('ng-container-left')) targetFixedType = 'left';\n else if (container.classList.contains('ng-container-right')) targetFixedType = 'right';\n\n // 🎯 [수정] 원본 테이블에서 tbody.body에 해당하는 tr들만 복제\n const templateTrs = Array.from(this.#sheet.sourceTable.querySelectorAll('tbody.body tr')).map(tr => {\n const clonedTr = tr.cloneNode(true);\n\n if (targetFixedType === 'left') {\n clonedTr.querySelectorAll('th,td').forEach($cell => {\n if ($cell.getAttribute('fixed') !== 'left') $cell.remove();\n });\n } else if (targetFixedType === 'right') {\n clonedTr.querySelectorAll('th,td').forEach($cell => {\n if ($cell.getAttribute('fixed') !== 'right') $cell.remove();\n });\n } else {\n clonedTr.querySelectorAll('[fixed=left], [fixed=right]').forEach($cell => {\n $cell.remove();\n });\n }\n\n return clonedTr;\n });\n\n if (templateTrs.length === 0) return;\n\n // 🎯 [수정] targetTbody도 일반 tbody가 아니라 tbody.body를 정확히 타겟팅\n const targetTbody = container.querySelector('tbody.body');\n if (!targetTbody) return;\n\n targetTbody.querySelectorAll(\"tr\").forEach(tr => tr.remove());\n\n const fragment = document.createDocumentFragment();\n for (let i = 0; i < this.#cachedRowCount; i++) {\n templateTrs.forEach(tmpl => fragment.appendChild(tmpl.cloneNode(true)));\n }\n\n\n targetTbody.appendChild(fragment);\n\n if (container.classList.contains('ng-container-body')) {\n this.#element.firstTr = targetTbody.querySelector('tr');\n }\n };\n\n\n\n #syncRowHeights = () => {\n const leftTable = this.#sheet.querySelector('.ng-sheet-body .ng-container-left table');\n const bodyTable = this.#sheet.querySelector('.ng-sheet-body .ng-container-body table');\n const rightTable = this.#sheet.querySelector('.ng-sheet-body .ng-container-right table');\n\n if (bodyTable) {\n const leftRows = leftTable ? Array.from(leftTable.querySelectorAll('tbody tr')) : [];\n const bodyRows = Array.from(bodyTable.querySelectorAll('tbody tr'));\n const rightRows = rightTable ? Array.from(rightTable.querySelectorAll('tbody tr')) : [];\n\n const maxRows = Math.max(leftRows.length, bodyRows.length, rightRows.length);\n\n for (let i = 0; i < maxRows; i++) {\n const heights = [\n leftRows[i]?.getBoundingClientRect().height || 0,\n bodyRows[i]?.getBoundingClientRect().height || 0,\n rightRows[i]?.getBoundingClientRect().height || 0\n ];\n const maxHeight = Math.max(...heights);\n\n if (maxHeight > 0) {\n if (leftRows[i]) leftRows[i].style.height = `${maxHeight}px`;\n if (bodyRows[i]) bodyRows[i].style.height = `${maxHeight}px`;\n if (rightRows[i]) rightRows[i].style.height = `${maxHeight}px`;\n }\n }\n }\n };\n\n #initResizeObserver = () => {\n\n if (!this.#sheet || !(this.#sheet instanceof HTMLElement)) return;\n\n this.#resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n\n const sheetEl = entry.target;\n if (!sheetEl.classList.contains('active')) continue;\n\n const height = entry.contentRect.height;\n const width = entry.contentRect.width;\n\n if (width > 0 && this.#sheet.isAutoFitCol) {\n this.#sheet.autoFit(true);\n }\n\n if (height > 0 && this.#sheetHeight !== height) {\n this.#sheetHeight = height;\n this.#updateRowCount();\n\n if (this.#cachedTemplateHeight !== null) {\n this.#renderAllContainers();\n this.refresh();\n }\n }\n }\n });\n\n this.#resizeObserver.observe(this.#sheet);\n };\n}","import { trace } from \"@nopeer\";\n\nexport const COLLAPSED_WIDTH = 16;\n\nexport class TableCompiler {\n\n static compile($srcTable) {\n\n const $table = $srcTable.cloneNode(true);\n\n // 1. 헤더 컴파일\n TableCompiler.resetColIndex($table, $table.querySelectorAll('thead tr'));\n TableCompiler.resetColIndex($table, $table.querySelectorAll('tbody.body tr[grouping=\"true\"]'));\n TableCompiler.resetColIndex($table, $table.querySelectorAll('tbody.body tr:not([grouping=\"true\"])'));\n TableCompiler.resetColIndex($table, $table.querySelectorAll('tfoot tr'));\n\n // 4. colgroup과 인덱스/fixed 속성 동기화\n TableCompiler.#syncColAttributes($table);\n\n /**\n setTimeout(() => {\n console.log(\"DEBUG------------------+++++++\", $table);\n\n const templateHeights = TableCompiler.#measureTemplateHeights($table);\n $table.__templateRowHeights = templateHeights;\n $table.__cachedTemplateHeight = templateHeights.reduce((sum, h) => sum + h, 0);\n\n console.log(\"DEBUG------------------\", $table.__templateRowHeights, $table.__cachedTemplateHeight);\n }); */\n\n return $table;\n }\n\n static recompile($table) {\n\n /** 너비조정은 필요없을듯 */\n /**\n const cols = Array.from($table.querySelectorAll('colgroup col'));\n cols.forEach((col, idx) => {\n //trace.log(col.cloneNode(true));\n\n col.setAttribute('data-col', idx);\n\n let w = col.getAttribute('width');\n if (!w || isNaN(parseFloat(w))) {\n w = parseFloat(col.style.width);\n }\n if (w && !isNaN(parseFloat(w))) {\n const numericWidth = Math.round(parseFloat(w));\n //trace.log(w, numericWidth);\n\n col.setAttribute('width', numericWidth);\n col.style.width = `${numericWidth}px`;\n }\n }); */\n\n TableCompiler.resetColIndex($table, $table.querySelectorAll('thead tr'));\n TableCompiler.resetColIndex($table, $table.querySelectorAll('tbody.body tr[grouping=\"true\"]'));\n TableCompiler.resetColIndex($table, $table.querySelectorAll('tbody.body tr:not([grouping=\"true\"])'));\n TableCompiler.resetColIndex($table, $table.querySelectorAll('tfoot tr'));\n\n TableCompiler.#syncColAttributes($table);\n\n\n\n return $table;\n }\n\n static #measureTemplateHeights($table) {\n const trTemplates = $table.querySelectorAll('tbody tr');\n if (!trTemplates || trTemplates.length === 0) return [24]; // 방어 코드\n\n // 1. 화면에 영향을 주지 않는 숨겨진 측정용 임시 컨테이너 생성\n const measureBox = document.createElement('div');\n measureBox.style.cssText = 'position: absolute; visibility: hidden; pointer-events: none; top: -9999px; left: -9999px; width: 1000px;';\n\n const tempTable = document.createElement('table');\n const tempTbody = document.createElement('tbody');\n tempTbody.className = 'body';\n\n trTemplates.forEach($tr => {\n trace.log(\"DEBUG\", $tr);\n tempTbody.appendChild($tr.cloneNode(true));\n });\n tempTable.appendChild(tempTbody);\n measureBox.appendChild(tempTable);\n document.body.appendChild(measureBox);\n\n // 2. 브라우저 레이아웃 엔진을 통해 실제 렌더링 높이 측정\n const heights = [];\n tempTbody.querySelectorAll('tr').forEach($tr => {\n const h = $tr.getBoundingClientRect().height || $tr.offsetHeight;\n heights.push(h > 0 ? h : 24); // 0일 경우 최소 높이 24 보장\n });\n\n // 3. 측정 완료 후 즉시 DOM에서 제거 (메모리 누수 방지)\n document.body.removeChild(measureBox);\n\n return heights;\n }\n\n static #syncColAttributes($table) {\n\n $table.querySelectorAll('colgroup col').forEach(($col, i) => {\n $col.setAttribute('data-col', i);\n const fixed = $col.getAttribute('fixed');\n\n $table.querySelectorAll(`[data-col=\"${i}\"]`).forEach($el => {\n fixed ? $el.setAttribute('fixed', fixed) : $el.removeAttribute('fixed');\n });\n });\n }\n\n static resetColIndex($table, trs) {\n\n const cols = $table.querySelectorAll('colgroup col');\n const grid = Array.from({ length: trs.length }, () => Array(cols.length).fill(null));\n\n trs.forEach(($tr, index) => {\n\n $tr.dataset.subrow = index;\n\n let colIndex = 0;\n\n $tr.querySelectorAll('th, td').forEach($cell => {\n\n while (colIndex < cols.length && grid[index][colIndex] !== null) {\n colIndex++;\n }\n\n $cell.dataset.col = colIndex;\n\n const rowSpan = $cell.rowSpan || 1;\n const colSpan = $cell.colSpan || 1;\n\n for (let r = 0; r < rowSpan; r++) {\n for (let c = 0; c < colSpan; c++) {\n if (index + r < trs.length && colIndex + c < cols.length) {\n grid[index + r][colIndex + c] = $cell;\n }\n }\n }\n\n colIndex += colSpan;\n });\n });\n }\n\n\n}","import { trace } from \"@nopeer\";\r\n\r\nexport class CellSelection {\r\n\t#sheet;\r\n\t#range = { startRow: -1, startCol: -1, endRow: -1, endCol: -1 };\r\n\r\n\tconstructor(sheet) {\r\n\t\tthis.#sheet = sheet;\r\n\t\tthis.#initEvents();\r\n\r\n\t\t/**\r\n\t\t// 🎯 [신규 구조 대응] .ng-sheet-body 및 내부 컨테이너 스크롤 감지\r\n\t\tconst bodyViewport = this.#sheet.querySelector('.ng-sheet-body');\r\n\t\tif (bodyViewport) {\r\n\t\t\tbodyViewport.addEventListener('scroll', () => {\r\n\t\t\t\tif (this.#range.startRow >= 0 && this.#range.startCol >= 0) {\r\n\t\t\t\t\tthis.render();\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t} */\r\n\r\n\t\t/**\r\n\t\tconst containers = this.#sheet.querySelectorAll(\r\n\t\t\t'.ng-sheet-body-content .ng-container-left, .ng-sheet-body-content .ng-container-body, .ng-sheet-body-content .ng-container-right'\r\n\t\t);\r\n\r\n\t\tcontainers.forEach(container => {\r\n\t\t\tcontainer.addEventListener('scroll', () => {\r\n\t\t\t\tif (this.#range.startRow >= 0 && this.#range.startCol >= 0) {\r\n\t\t\t\t\tthis.render();\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}); */\r\n\r\n\t\ttrace.log(\"🎯 [CellSelection] Initialized (New Structure Compatible)\");\r\n\t}\r\n\r\n\t#getMatrixRow(tr) {\r\n\t\tif (!tr) return { dataRow: -1, subRowIndex: -1, matrixRow: -1 };\r\n\r\n\t\tconst dataRow = parseInt(tr.dataset.index, 10);\r\n\t\tif (isNaN(dataRow)) return { dataRow: -1, subRowIndex: -1, matrixRow: -1 };\r\n\r\n\t\tconst tbody = tr.closest('tbody');\r\n\t\tconst trs = Array.from(tbody.querySelectorAll('tr'));\r\n\r\n\t\tconst sameGroupTrs = trs.filter(t => parseInt(t.dataset.index, 10) === dataRow);\r\n\t\tconst subRowIndex = sameGroupTrs.indexOf(tr);\r\n\t\tconst templateLength = sameGroupTrs.length > 0 ? sameGroupTrs.length : 1;\r\n\r\n\t\tconst matrixRow = (dataRow * templateLength) + (subRowIndex >= 0 ? subRowIndex : (tr.sectionRowIndex % templateLength));\r\n\r\n\t\treturn { dataRow, subRowIndex, matrixRow };\r\n\t}\r\n\r\n\tsetFocus(matrixRow, col) {\r\n\t\t// 1. 기존 포커스 클래스 제거\r\n\t\tthis.#sheet.querySelectorAll(`tr.selected-start`).forEach($tr => {\r\n\t\t\t$tr.classList.remove(\"selected-start\");\r\n\t\t\t$tr.querySelectorAll(`td.selected-start`).forEach($td => {\r\n\t\t\t\t$td.classList.remove(\"selected-start\");\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// 🎯 [신규 구조 대응] data-matrix-row 탐색 경로 수정 (.ng-sheet-body-content 기준)\r\n\t\tconst $td = this.#sheet.querySelector(`.ng-sheet-body-content tr[data-matrix-row=\"${matrixRow}\"] td[data-col=\"${col}\"]`);\r\n\t\tif (!$td) return;\r\n\r\n\t\t$td.classList.add(\"selected-start\");\r\n\t\t$td.closest('tr')?.classList.add(\"selected-start\");\r\n\t}\r\n\r\n\tsetRange(startRow, startCol, endRow, endCol) {\r\n\t\tlet r1 = Math.min(startRow, endRow);\r\n\t\tlet r2 = Math.max(startRow, endRow);\r\n\t\tlet c1 = Math.min(startCol, endCol);\r\n\t\tlet c2 = Math.max(startCol, endCol);\r\n\r\n\t\t// 🎯 [신규 구조 대응] 컨테이너 셀렉터 경로 수정\r\n\t\tconst containers = this.#sheet.querySelectorAll('.ng-container-left, .ng-container-body, .ng-container-right');\r\n\r\n\t\tlet expanded = true;\r\n\t\tlet loopCount = 0;\r\n\r\n\t\twhile (expanded && loopCount < 5) {\r\n\t\t\texpanded = false;\r\n\t\t\tloopCount++;\r\n\r\n\r\n\r\n\t\t\tcontainers.forEach(container => {\r\n\r\n\t\t\t\tconst visibleTrs = Array.from(container.querySelectorAll('tbody tr')).filter(tr => {\r\n\t\t\t\t\treturn tr.style.display !== 'none'; // 혹은 tr.offsetHeight > 0 체크\r\n\t\t\t\t});\r\n\r\n\t\t\t\tvisibleTrs.forEach(tr => {\r\n\t\t\t\t\tconst { matrixRow } = this.#getMatrixRow(tr);\r\n\t\t\t\t\tif (matrixRow < 0) return;\r\n\r\n\t\t\t\t\ttr.querySelectorAll('td, th').forEach(cell => {\r\n\t\t\t\t\t\tconst col = parseInt(cell.dataset.col, 10);\r\n\t\t\t\t\t\tif (isNaN(col)) return;\r\n\r\n\t\t\t\t\t\tconst rowSpan = parseInt(cell.rowSpan || 1, 10);\r\n\t\t\t\t\t\tconst colSpan = parseInt(cell.colSpan || 1, 10);\r\n\r\n\t\t\t\t\t\tconst cellEndRow = matrixRow + rowSpan - 1;\r\n\t\t\t\t\t\tconst cellEndCol = col + colSpan - 1;\r\n\r\n\t\t\t\t\t\tconst isIntersecting = cellEndRow >= r1 && matrixRow <= r2 && cellEndCol >= c1 && col <= c2;\r\n\r\n\t\t\t\t\t\tif (isIntersecting) {\r\n\t\t\t\t\t\t\tconst nsR = Math.min(r1, matrixRow);\r\n\t\t\t\t\t\t\tconst neR = Math.max(r2, cellEndRow);\r\n\t\t\t\t\t\t\tconst nsC = Math.min(c1, col);\r\n\t\t\t\t\t\t\tconst neC = Math.max(c2, cellEndCol);\r\n\r\n\t\t\t\t\t\t\tif (nsR !== r1 || neR !== r2 || nsC !== c1 || neC !== c2) {\r\n\t\t\t\t\t\t\t\tr1 = nsR; r2 = neR; c1 = nsC; c2 = neC;\r\n\t\t\t\t\t\t\t\texpanded = true;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.#range = { startRow: r1, startCol: c1, endRow: r2, endCol: c2 };\r\n\t\tthis.render();\r\n\t}\r\n\r\n\trefresh = () => {\r\n\t\tthis.render();\r\n\t}\r\n\r\n\trender = () => {\r\n\t\tconst { startRow, startCol, endRow, endCol } = this.#range;\r\n\r\n\t\t// 🎯 [신규 구조 대응] 컨테이너 셀렉터 경로 수정\r\n\t\tconst containers = this.#sheet.querySelectorAll(\r\n\t\t\t'.ng-container-left, .ng-container-body, .ng-container-right'\r\n\t\t);\r\n\r\n\t\t/**\r\n\t\tconst selectedStartTr = this.#sheet.querySelector('tr.selected-start');\r\n\t\tconst selectedStartCell = this.#sheet.querySelector('th.selected-start,td.selected-start');\r\n\r\n\t\tconst selectedStartMatrixRow = parseInt(selectedStartTr?.dataset.matrixRow, 10);\r\n\t\tconst selectedStartIndex = parseInt(selectedStartCell?.dataset.index, 10);\r\n\t\tconst selectedStartCol = parseInt(selectedStartCell?.dataset.col, 10);\r\n\t\t*/\r\n\r\n\t\t// 1. 기존 선택 클래스 초기화\r\n\t\tcontainers.forEach(container => {\r\n\t\t\tcontainer.querySelectorAll('.selected, .selected-top, .selected-bottom, .selected-left, .selected-right, .selected-start').forEach(el => {\r\n\t\t\t\tel.classList.remove('selected', 'selected-top', 'selected-bottom', 'selected-left', 'selected-right', 'selected-start');\r\n\t\t\t});\r\n\r\n\t\t\tcontainer.querySelectorAll('tr.selected-start').forEach(tr => {\r\n\t\t\t\ttr.classList.remove('selected-start');\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tif (startRow < 0 || startCol < 0) return;\r\n\r\n\t\t// 2. 범위 렌더링\r\n\t\tcontainers.forEach((container) => {\r\n\t\t\tconst visibleTrs = Array.from(container.querySelectorAll('tbody tr')).filter(tr => {\r\n\t\t\t\treturn tr.style.display !== 'none'; // 혹은 tr.offsetHeight > 0 체크\r\n\t\t\t});\r\n\r\n\t\t\tvisibleTrs.forEach(tr => {\r\n\t\t\t\tconst { matrixRow } = this.#getMatrixRow(tr);\r\n\t\t\t\tif (matrixRow < 0) return;\r\n\r\n\t\t\t\ttr.querySelectorAll('td, th').forEach(cell => {\r\n\t\t\t\t\tconst col = parseInt(cell.dataset.col, 10);\r\n\t\t\t\t\tif (isNaN(col)) return;\r\n\r\n\t\t\t\t\tconst rowSpan = parseInt(cell.rowSpan || 1, 10);\r\n\t\t\t\t\tconst colSpan = parseInt(cell.colSpan || 1, 10);\r\n\r\n\t\t\t\t\tconst cellEndRow = matrixRow + rowSpan - 1;\r\n\t\t\t\t\tconst cellEndCol = col + colSpan - 1;\r\n\r\n\t\t\t\t\tconst isSelected = cellEndRow >= startRow && matrixRow <= endRow && cellEndCol >= startCol && col <= endCol;\r\n\t\t\t\t\tif (!isSelected) return;\r\n\r\n\t\t\t\t\tcell.classList.add('selected');\r\n\r\n\t\t\t\t\tif (matrixRow <= startRow) cell.classList.add('selected-top');\r\n\t\t\t\t\tif (cellEndRow >= endRow) cell.classList.add('selected-bottom');\r\n\t\t\t\t\tif (col <= startCol) cell.classList.add('selected-left');\r\n\t\t\t\t\tif (cellEndCol >= endCol) cell.classList.add('selected-right');\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t/**\r\n\t\ttrace.log(selectedStartMatrixRow, selectedStartCol);\r\n\t\t// 3. 포커스 셀 복구\r\n\t\tconst $focusTd = this.#sheet.querySelector(`.ng-sheet-body-content tr[data-matrix-row=\"${selectedStartMatrixRow}\"] td[data-col=\"${selectedStartCol}\"]`);\r\n\t\tif ($focusTd) {\r\n\t\t\t$focusTd.classList.add(\"selected-start\");\r\n\t\t}\r\n\r\n\t\tthis.#sheet.querySelectorAll(`.ng-sheet-body-content tr[data-matrix-row=\"${selectedStartMatrixRow}\"]`).forEach($tr => {\r\n\t\t\t$tr.classList.add(\"selected-start\");\r\n\t\t}); */\r\n\t}\r\n\r\n\t#initEvents() {\r\n\t\tconst mainZone = this.#sheet.querySelector('.ng-sheet-body');\r\n\t\tif (!mainZone) {\r\n\t\t\ttrace.log(\"❌ [CellSelection] .ng-sheet-body not found!\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tmainZone.addEventListener('mousedown', (e) => {\r\n\t\t\tif (e.button !== 0) return;\r\n\r\n\t\t\tconst cell = e.target.closest('td, th');\r\n\t\t\tif (!cell) return;\r\n\t\t\tif (cell.dataset.row === undefined || cell.dataset.col === undefined) return;\r\n\r\n\t\t\tthis.#sheet.style.userSelect = 'none';\r\n\t\t\tthis.#sheet.style.webkitUserSelect = 'none';\r\n\r\n\t\t\tconst tr = cell.closest('tr');\r\n\t\t\tconst { matrixRow: startRow } = this.#getMatrixRow(tr);\r\n\t\t\tconst startCol = parseInt(cell.dataset.col, 10);\r\n\r\n\t\t\tif (startRow < 0) {\r\n\t\t\t\tthis.#sheet.style.userSelect = '';\r\n\t\t\t\tthis.#sheet.style.webkitUserSelect = '';\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis.setFocus(startRow, startCol);\r\n\t\t\tthis.setRange(startRow, startCol, startRow, startCol);\r\n\r\n\t\t\tlet lastMatrixRow = startRow;\r\n\t\t\tlet lastCol = startCol;\r\n\r\n\t\t\tconst onMouseMove = (moveEvent) => {\r\n\t\t\t\tconst targetEl = document.elementFromPoint(moveEvent.clientX, moveEvent.clientY);\r\n\t\t\t\tlet targetCell = targetEl?.closest('td, th');\r\n\r\n\t\t\t\tif (!targetCell || !this.#sheet.contains(targetCell)) {\r\n\t\t\t\t\tconst allCells = this.#sheet.querySelectorAll('.ng-sheet-body-content tbody tr td, .ng-sheet-body-content tbody tr:not(.nodata) th');\r\n\t\t\t\t\tfor (const c of allCells) {\r\n\t\t\t\t\t\tconst rect = c.getBoundingClientRect();\r\n\t\t\t\t\t\tif (\r\n\t\t\t\t\t\t\tmoveEvent.clientX >= rect.left &&\r\n\t\t\t\t\t\t\tmoveEvent.clientX <= rect.right &&\r\n\t\t\t\t\t\t\tmoveEvent.clientY >= rect.top &&\r\n\t\t\t\t\t\t\tmoveEvent.clientY <= rect.bottom\r\n\t\t\t\t\t\t) {\r\n\t\t\t\t\t\t\ttargetCell = c;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!targetCell) return;\r\n\t\t\t\tif (targetCell.dataset.row === undefined || targetCell.dataset.col === undefined) return;\r\n\r\n\t\t\t\tconst targetTr = targetCell.closest('tr');\r\n\t\t\t\tconst { matrixRow: endRow } = this.#getMatrixRow(targetTr);\r\n\t\t\t\tconst endCol = parseInt(targetCell.dataset.col, 10);\r\n\r\n\t\t\t\tif (endRow < 0) return;\r\n\t\t\t\tif (lastMatrixRow === endRow && lastCol === endCol) return;\r\n\r\n\t\t\t\tlastMatrixRow = endRow;\r\n\t\t\t\tlastCol = endCol;\r\n\r\n\t\t\t\tthis.setRange(startRow, startCol, endRow, endCol);\r\n\t\t\t};\r\n\r\n\t\t\tconst onMouseUp = () => {\r\n\t\t\t\tthis.#sheet.style.userSelect = '';\r\n\t\t\t\tthis.#sheet.style.webkitUserSelect = '';\r\n\r\n\t\t\t\tdocument.removeEventListener('mousemove', onMouseMove);\r\n\t\t\t\tdocument.removeEventListener('mouseup', onMouseUp);\r\n\t\t\t};\r\n\r\n\t\t\tdocument.addEventListener('mousemove', onMouseMove);\r\n\t\t\tdocument.addEventListener('mouseup', onMouseUp);\r\n\t\t});\r\n\t}\r\n}","import { trace } from \"@nopeer\";\r\n\r\nexport class CellNavigation {\r\n\t#sheet;\r\n\t#host;\r\n\r\n\t#currentCell = null;\r\n\t#currentTr = null;\r\n\r\n\tconstructor(sheet) {\r\n\t\tthis.#sheet = sheet;\r\n\t\tthis.#host = sheet.getRootNode().host;\r\n\r\n\t\tthis.#initEvents();\r\n\t\ttrace.log(\"🎯 [CellNavigation] Initialized (Diagnostic Logging Restored)\");\r\n\t}\r\n\r\n\tget currentCell() {\r\n\t\treturn this.#currentCell;\r\n\t}\r\n\r\n\tset currentCell(cell) {\r\n\t\tif (!cell) return;\r\n\r\n\t\tthis.#currentCell = cell;\r\n\t\tcell.focus({ preventScroll: true });\r\n\r\n\t\tthis.#currentTr = cell.closest(\"tr\");\r\n\t\tconst matrixRow = parseInt(this.#currentTr.dataset.matrixRow, 10);//this.#getMatrixRowFromTr(this.#currentTr);\r\n\r\n\t\t//trace.log(`📌 [setCurCell] Active set -> dataRow: ${cell.dataset.index}, subrow: ${cell.closest('tr')?.dataset.subrow}, matrixRow: ${matrixRow}, col: ${cell.dataset.col}`);\r\n\t\tthis.#sheet.selection.setFocus(matrixRow, this.#currentCell.dataset.col);\r\n\t}\r\n\r\n\r\n\t#moveCellH = (e, cell) => {\r\n\r\n\t\tif (!cell) return;\r\n\r\n\t\tswitch (e.code) {\r\n\t\t\tcase \"Tab\":\r\n\t\t\t\tif (e.shiftKey) {\r\n\t\t\t\t\tif (!this.#isCellLeftVisible(cell)) {\r\n\t\t\t\t\t\tcell.scrollIntoView({ inline: 'nearest', block: 'nearest' });\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (!this.#isCellRightVisible(cell)) {\r\n\t\t\t\t\t\tcell.scrollIntoView({ inline: 'nearest', block: 'nearest' });\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowRight\":\r\n\t\t\t\tif (!this.#isCellRightVisible(cell)) {\r\n\t\t\t\t\tcell.scrollIntoView({ inline: 'nearest', block: 'nearest' });\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowLeft\":\r\n\t\t\t\tif (!this.#isCellLeftVisible(cell)) {\r\n\t\t\t\t\tcell.scrollIntoView({ inline: 'nearest', block: 'nearest' });\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tthis.currentCell = cell;\r\n\t\tthis.#sheet.selection.setRange(this.#currentTr.dataset.matrixRow, cell.dataset.col, this.#currentTr.dataset.matrixRow, cell.dataset.col);\r\n\t};\r\n\r\n\t#moveCellV = (e, cell) => {\r\n\t\tif (cell) {\r\n\t\t\tlet isVisible = false;\r\n\t\t\tswitch (e.code) {\r\n\t\t\t\tcase \"Enter\":\r\n\t\t\t\t\tif (e.shiftKey) {\r\n\t\t\t\t\t\tif (this.#isCellBelowVisible(cell)) {\r\n\t\t\t\t\t\t\tisVisible = true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tif (this.#isCellBelowVisible(cell)) {\r\n\t\t\t\t\t\t\tisVisible = true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"ArrowDown\":\r\n\t\t\t\t\tif (this.#isCellBelowVisible(cell)) {\r\n\t\t\t\t\t\tisVisible = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"ArrowUp\":\r\n\t\t\t\t\tif (this.#isCellAboveVisible(cell)) {\r\n\t\t\t\t\t\tisVisible = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tif (isVisible) {\r\n\t\t\t\tthis.currentCell = cell;\r\n\t\t\t\tthis.#sheet.selection.setRange(this.#currentTr.dataset.matrixRow, cell.dataset.col, this.#currentTr.dataset.matrixRow, cell.dataset.col);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst dataIndex = parseInt(this.#currentTr.dataset.index, 10);\r\n\t\tlet scrollTopIndex = -1;\r\n\t\tswitch (e.code) {\r\n\t\t\tcase \"Enter\":\r\n\t\t\t\tif (e.shiftKey) {\r\n\t\t\t\t\tconst visibleRowCount = this.#getVisibleRowCount();\r\n\t\t\t\t\tscrollTopIndex = Math.max(dataIndex - visibleRowCount + 0, 0);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tscrollTopIndex = Math.min(dataIndex, this.#sheet.view.count());\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowDown\":\r\n\t\t\t\tscrollTopIndex = Math.min(dataIndex, this.#sheet.view.count());\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowUp\":\r\n\t\t\t\tconst visibleRowCount = this.#getVisibleRowCount();\r\n\t\t\t\tscrollTopIndex = Math.max(dataIndex - visibleRowCount + 0, 0);\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tif (scrollTopIndex < 0) return;\r\n\r\n\t\tlet matrixRow = parseInt(this.#currentTr.dataset.matrixRow, 10);\r\n\t\tconst col = parseInt(this.#currentCell.dataset.col, 10);\r\n\t\tconst rowSpan = parseInt(this.#currentCell.rowSpan, 10) || 1;\r\n\r\n\t\tswitch (e.code) {\r\n\t\t\tcase \"ArrowDown\":\r\n\t\t\t\tmatrixRow += rowSpan;\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowUp\":\r\n\t\t\t\tmatrixRow --;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tthis.#sheet.rowManager.scrollToDataRow(scrollTopIndex, null, () => {\r\n\t\t\tconst currentCell = this.#findCell(matrixRow, col);\r\n\r\n\t\t\tif (currentCell) {\r\n\t\t\t\tthis.currentCell = currentCell;\r\n\t\t\t\tthis.#sheet.selection.setRange(this.#currentTr.dataset.matrixRow, currentCell.dataset.col, this.#currentTr.dataset.matrixRow, currentCell.dataset.col);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tmoveCell = (e) => {\r\n\r\n\t\tif (e.target.tagName === \"INPUT\") {\r\n\t\t\tif ([\"text\"].includes(e.target.type)) {\r\n\t\t\t\tif ([\"ArrowLeft\",\"ArrowRight\",\"Home\",\"End\"].includes(e.code)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif ([\"date\",\"datetime-local\",\"time\",\"week\",\"month\"].includes(e.target.type)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!this.#currentCell || !this.#currentTr) {\r\n\t\t\ttrace.log(\"⚠️ [moveCell] currentCell or currentTr is missing!\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet nextCell;\r\n\t\tswitch (e.code) {\r\n\t\t\tcase \"Tab\":\r\n\t\t\t\tnextCell = e.shiftKey ? this.#getPreviousCell() : this.#getNextCell();\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowRight\":\r\n\t\t\t\tnextCell = this.#getNextCell();\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowLeft\":\r\n\t\t\t\tnextCell = this.#getPreviousCell();\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"Enter\":\r\n\t\t\t\tnextCell = e.shiftKey ? this.#getUpCell() : this.#getDownCell();\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowDown\":\r\n\t\t\t\tnextCell = this.#getDownCell();\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ArrowUp\":\r\n\t\t\t\tnextCell = this.#getUpCell();\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\te.preventDefault();\r\n\r\n\t\tif ([\"ArrowLeft\",\"ArrowRight\",\"Tab\"].includes(e.code)) {\r\n\t\t\tthis.#moveCellH(e, nextCell);\r\n\t\t}\r\n\t\telse if ([\"Enter\",\"ArrowUp\",\"ArrowDown\"].includes(e.code)) {\r\n\t\t\tthis.#moveCellV(e, nextCell);\r\n\t\t}\r\n\t}\r\n\r\n\t#getNextCell = () => {\r\n\t\tconst col = parseInt(this.#currentCell.dataset.col, 10);\r\n\t\tconst colSpan = parseInt(this.#currentCell.colSpan, 10) || 1;\r\n\t\tconst dataIndex = parseInt(this.#currentTr.dataset.index, 10);\r\n\t\tconst matrixRow = parseInt(this.#currentTr.dataset.matrixRow, 10);\r\n\r\n\t\tconst nextCol = col + colSpan;\r\n\r\n\t\tlet nextCell = this.#sheet.querySelector(`tbody tr[data-matrix-row=\"${matrixRow}\"] td[data-col=\"${nextCol}\"]`);\r\n\t\tif (!nextCell) {\r\n\t\t\tnextCell = this.#sheet.querySelector(`tbody tr[data-index=\"${dataIndex}\"] td[data-col=\"${nextCol}\"]`);\r\n\t\t}\r\n\r\n\t\treturn nextCell;\r\n\t}\r\n\r\n\t#getPreviousCell = () => {\r\n\r\n\t\tconst col = parseInt(this.#currentCell.dataset.col, 10);\r\n\t\tconst dataIndex = parseInt(this.#currentTr.dataset.index, 10);\r\n\t\tconst matrixRow = parseInt(this.#currentTr.dataset.matrixRow, 10);\r\n\r\n\t\tlet nextCell;\r\n\t\tfor (let i = col - 1; i >= 0; i--) {\r\n\t\t\tnextCell = this.#sheet.querySelector(`tbody tr[data-matrix-row=\"${matrixRow}\"] td[data-col=\"${i}\"]`);\r\n\t\t\tif (!nextCell) {\r\n\t\t\t\tnextCell = this.#sheet.querySelector(`tbody tr[data-index=\"${dataIndex}\"] td[data-col=\"${i}\"]`);\r\n\t\t\t}\r\n\r\n\t\t\tif (nextCell) break;\r\n\t\t}\r\n\r\n\t\treturn nextCell;\r\n\t}\r\n\r\n\r\n\r\n\t#findCell = (matrixRow, col) => {\r\n\r\n\t\tconst $tr = this.#sheet.querySelector(`tbody tr[data-matrix-row=\"${matrixRow}\"]`);\r\n\t\tif (!$tr) return;\r\n\r\n\t\tconst dataIndex = parseInt($tr.dataset.index, 10);\r\n\r\n\t\tlet targetCell = this.#sheet.querySelector(`tbody tr[data-matrix-row=\"${matrixRow}\"] td[data-col=\"${col}\"]`);\r\n\t\tif (!targetCell) {\r\n\t\t\tthis.#sheet.querySelectorAll(`tbody tr[data-matrix-row=\"${matrixRow}\"] td`).forEach($cell => {\r\n\t\t\t\tconst cellCol = parseInt($cell.dataset.col, 10);\r\n\t\t\t\tconst colSpan = parseInt($cell.colSpan, 10) || 1;\r\n\r\n\t\t\t\tif (col >= cellCol && col < cellCol + colSpan) {\r\n\t\t\t\t\ttargetCell = $cell;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tif (!targetCell) {\r\n\t\t\t\ttargetCell = this.#sheet.querySelector(`tbody tr[data-index=\"${dataIndex}\"] td[data-col=\"${col}\"]`);\r\n\r\n\t\t\t\tif (!targetCell) {\r\n\t\t\t\t\tthis.#sheet.querySelectorAll(`tbody tr[data-index=\"${dataIndex}\"] td`).forEach($cell => {\r\n\t\t\t\t\t\tconst cellCol = parseInt($cell.dataset.col, 10);\r\n\t\t\t\t\t\tconst colSpan = parseInt($cell.colSpan, 10) || 1;\r\n\r\n\t\t\t\t\t\tif (col >= cellCol && col < cellCol + colSpan) {\r\n\t\t\t\t\t\t\ttargetCell = $cell;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn targetCell;\r\n\t}\r\n\r\n\t#getUpCell = () => {\r\n\t\tconst col = parseInt(this.#currentCell.dataset.col, 10);\r\n\t\tconst matrixRow = parseInt(this.#currentTr.dataset.matrixRow, 10);\r\n\r\n\t\treturn this.#findCell(matrixRow - 1, col);\r\n\t}\r\n\r\n\t#getDownCell = () => {\r\n\t\tconst col = parseInt(this.#currentCell.dataset.col, 10);\r\n\t\tconst matrixRow = parseInt(this.#currentTr.dataset.matrixRow, 10);\r\n\t\tconst rowSpan = parseInt(this.#currentCell.rowSpan, 10) || 1;\r\n\r\n\t\treturn this.#findCell(matrixRow + rowSpan, col);\r\n\t}\r\n\r\n\t// 1. 위쪽 잘림 체크 (기준: bodyViewport)\r\n\t#isCellAboveVisible = (cell) => {\r\n\t\tconst bodyViewport = this.#sheet.querySelector('.ng-sheet-body');\r\n\t\tif (!bodyViewport || !cell) return true;\r\n\r\n\t\tconst cellRect = cell.getBoundingClientRect();\r\n\t\tconst viewportRect = bodyViewport.getBoundingClientRect();\r\n\t\tconst theadHeight = bodyViewport.querySelector('thead')?.offsetHeight || 0;\r\n\r\n\t\t// 셀의 상단이 헤더 아래쪽보다 위에 있으면 잘린(안 보이는) 상태\r\n\t\treturn cellRect.top >= (viewportRect.top + theadHeight);\r\n\t}\r\n\r\n\t// 2. 아래쪽 잘림 체크 (기준: bodyViewport)\r\n\t#isCellBelowVisible = (cell) => {\r\n\t\tconst bodyViewport = this.#sheet.querySelector('.ng-sheet-body');\r\n\t\tif (!bodyViewport || !cell) return true;\r\n\r\n\t\tconst cellRect = cell.getBoundingClientRect();\r\n\t\tconst viewportRect = bodyViewport.getBoundingClientRect();\r\n\r\n\t\t// 셀의 하단이 뷰포트 하단보다 아래에 있으면 잘린 상태\r\n\t\treturn cellRect.bottom <= viewportRect.bottom;\r\n\t}\r\n\r\n\t// 3. 왼쪽 잘림 체크 (기준: bodyViewport2)\r\n\t#isCellLeftVisible = (cell) => {\r\n\t\tconst bodyViewport2 = this.#sheet.querySelector('.ng-container-body'); // 또는 좌우 스크롤을 담당하는 뷰포트\r\n\t\tif (!bodyViewport2 || !cell) return true;\r\n\r\n\t\tconst cellRect = cell.getBoundingClientRect();\r\n\t\tconst viewportRect = bodyViewport2.getBoundingClientRect();\r\n\r\n\t\t// 셀의 좌측이 뷰포트 좌측보다 왼쪽에 있으면 잘린 상태\r\n\t\treturn cellRect.left >= viewportRect.left;\r\n\t}\r\n\r\n\t// 4. 오른쪽 잘림 체크 (기준: bodyViewport2)\r\n\t#isCellRightVisible = (cell) => {\r\n\t\tconst bodyViewport2 = this.#sheet.querySelector('.ng-container-body');\r\n\t\tif (!bodyViewport2 || !cell) return true;\r\n\r\n\t\tconst cellRect = cell.getBoundingClientRect();\r\n\t\tconst viewportRect = bodyViewport2.getBoundingClientRect();\r\n\r\n\t\t// 셀의 우측이 뷰포트 우측보다 오른쪽에 있으면 잘린 상태\r\n\t\treturn cellRect.right <= viewportRect.right;\r\n\t}\r\n\r\n\t// 💡 필요하다면 이 4개를 조합해서 전체 가시성을 판단하는 통합 함수도 쉽게 구성할 수 있습니다.\r\n\t#isCellVisible = (cell) => {\r\n\t\treturn this.#isCellAboveVisible(cell) &&\r\n\t\t\tthis.#isCellBelowVisible(cell) &&\r\n\t\t\tthis.#isCellLeftVisible(cell) &&\r\n\t\t\tthis.#isCellRightVisible(cell);\r\n\t}\r\n\r\n\t#getVisibleRowCount = () => {\r\n\t\tconst bodyViewport = this.#sheet.querySelector('.ng-sheet-body');\r\n\t\tconst viewportHeight = bodyViewport.clientHeight - (bodyViewport.querySelector('thead')?.offsetHeight || 0);\r\n\t\tconst rowHeight = this.#sheet.rowManager.getRowHeight();\r\n\r\n\t\t// 뷰포트 높이에 들어오는 행 개수 계산 (소수점 버림)\r\n\t\treturn Math.max(1, Math.floor(viewportHeight / rowHeight));\r\n\t}\r\n\r\n\t#initEvents() {\r\n\t\tthis.#sheet.addEventListener('mousedown', (e) => {\r\n\t\t\tif (e.button !== 0) return;\r\n\t\t\tconst cell = e.target.closest('td, th');\r\n\t\t\tif (!cell) return;\r\n\t\t\tif (cell.dataset.index === undefined || cell.dataset.col === undefined) return;\r\n\t\t\tthis.currentCell = cell;\r\n\t\t});\r\n\r\n\t\tthis.#sheet.addEventListener('keydown', (e) => {\r\n\t\t\tif ([\"Enter\", \"Tab\", \"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\"].includes(e.code)) {\r\n\t\t\t\tthis.moveCell(e);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}","// ui/col/ColResizer.js\nimport { trace } from \"@nopeer\";\nimport { COLLAPSED_WIDTH } from \"@/layout/core/TableCompiler.js\";\n\nconst RESIZE_OFFSET = 2; // 🎯 리사이즈 감지 영역 오프셋을 상단으로 추출\n\nexport class ColResizer {\n #sheet;\n #host;\n #panel;\n #tooltip;\n\n #targetColIndex = null;\n #nextColIndex = null;\n #targetContainerType = null;\n #targetCell = null;\n #startX = 0;\n #startColWidth = 0;\n #nextColStartWidth = 0;\n #startCellWidth = 0;\n #startLeft = 0;\n\n constructor(sheet) {\n this.#sheet = sheet;\n this.#host = sheet.getRootNode().host;\n this.#panel = this.#sheet.querySelector('nine-table-col-resizer-panel');\n\n this.#tooltip = this.#panel.querySelector('.resizer-overlay');\n this.bindEvents();\n }\n\n destroy() {\n this.#sheet.removeEventListener('pointermove', this.#onPointerMove);\n this.#sheet.removeEventListener('pointerdown', this.#onPointerDown);\n this.#sheet.removeEventListener('dblclick', this.#onDblClick);\n }\n\n refreshLayout(containerType = 'body') {\n const containers = Array.from(this.#sheet.querySelectorAll(`.ng-container-${containerType}`));\n if (containers.length === 0) return;\n\n const isFixedContainer = containerType === 'left' || containerType === 'right';\n const isAutoFit = !isFixedContainer && (\n this.#sheet.isAutoFitCol ||\n containers[0].querySelector('table')?.getAttribute('auto-fit-col') === 'true'\n );\n\n if (!isAutoFit) {\n\n const firstColgroup = containers[0].querySelector('table colgroup');\n if (!firstColgroup) return;\n\n let totalWidth = 0;\n const colWidths = {};\n\n Array.from(firstColgroup.querySelectorAll('col')).forEach(col => {\n const colIdx = col.getAttribute('data-col');\n const w = parseInt(col.getAttribute('width'), 10);\n if (!isNaN(w)) {\n colWidths[colIdx] = w;\n totalWidth += w;\n }\n });\n\n containers.forEach(container => {\n const tables = container.querySelectorAll('table');\n\n trace.log(\"====================\", containers, containerType);\n\n if (containerType === 'body') {\n tables.forEach(tbl => {\n tbl.style.width = `${totalWidth}px`;\n //tbl.style.minWidth = `${totalWidth}px`;\n });\n } else {\n container.style.flex = `0 0 ${totalWidth}px`;\n container.style.width = `${totalWidth}px`;\n container.style.minWidth = `${totalWidth}px`;\n container.style.maxWidth = `${totalWidth}px`;\n\n tables.forEach(tbl => {\n tbl.style.width = `${totalWidth}px`;\n tbl.style.minWidth = `${totalWidth}px`;\n tbl.style.maxWidth = `${totalWidth}px`;\n\n Object.entries(colWidths).forEach(([colIdx, w]) => {\n tbl.querySelectorAll(`th[data-col=\"${colIdx}\"], td[data-col=\"${colIdx}\"]`).forEach(cell => {\n cell.style.width = `${w}px`;\n cell.style.minWidth = `${w}px`;\n cell.style.maxWidth = `${w}px`;\n });\n });\n });\n }\n });\n } else {\n containers.forEach(container => {\n const tables = container.querySelectorAll('table');\n tables.forEach(tbl => {\n //tbl.style.width = '100%';\n //tbl.style.minWidth = '100%';\n //tbl.style.maxWidth = '';\n });\n });\n }\n\n this.#sheet.querySelector('nine-table-hscrollbar')?.refresh();\n }\n\n setColumnWidth(globalColIndex, width, containerType = null) {\n\n trace.log(\"setColumnWidth\");\n\n\n let targetCols = [];\n\n //if (containerType) {\n // targetCols = Array.from(this.#sheet.querySelectorAll(`.ng-container-${containerType} table colgroup col[data-col=\"${globalColIndex}\"]`));\n //} else {\n // targetCols = Array.from(this.#sheet.querySelectorAll(`table colgroup col[data-col=\"${globalColIndex}\"]`));\n //}\n targetCols = Array.from(this.#sheet.querySelectorAll(`table colgroup col[data-col=\"${globalColIndex}\"]`));\n\n if (targetCols.length === 0) return;\n\n const firstContainer = targetCols[0].closest('.ng-container-left, .ng-container-body, .ng-container-right');\n const resolvedContainerType = containerType || (\n firstContainer?.classList.contains('ng-container-left') ? 'left' :\n firstContainer?.classList.contains('ng-container-right') ? 'right' : 'body'\n );\n\n targetCols.forEach(col => {\n col.setAttribute('width', width);\n col.style.width = `${width}px`;\n\n trace.log(col, width);\n });\n\n const sourceCol = this.#sheet.sourceTable?.querySelector(`colgroup col[data-col=\"${globalColIndex}\"]`);\n if (sourceCol) {\n sourceCol.setAttribute('width', width);\n sourceCol.style.width = `${width}px`;\n }\n\n\n\n this.refreshLayout(resolvedContainerType);\n\n // 🎯 [핵심] autoFit을 여기서 또 호출하면 루프가 돌거나 레이아웃 계산이 꼬입니다.\n // 바디 영역 리사이즈 시에는 body만 refreshLayout 해주면 됩니다!\n if (resolvedContainerType === 'left' || resolvedContainerType === 'right') {\n this.refreshLayout('body');\n }\n\n this.#sheet.rowManager?.refresh();\n }\n\n #checkIsAutoFit(targetCell) {\n if (this.#sheet.isAutoFitCol) return true;\n const table = targetCell?.closest('table');\n if (table && table.getAttribute('auto-fit-col') === 'true') return true;\n return false;\n }\n\n bindEvents() {\n this.#sheet.addEventListener('pointermove', this.#onPointerMove);\n //this.#sheet.addEventListener('pointerdown', this.#onPointerDown);\n //this.#sheet.addEventListener('dblclick', this.#onDblClick);\n\n this.#sheet.addDebounseEventListener('dblclick', this.#onDblClick, 'pointerdown', this.#onPointerDown);\n }\n\n #getContainerType(cell) {\n const container = cell.closest('.ng-container-left, .ng-container-body, .ng-container-right');\n if (!container) return null;\n if (container.classList.contains('ng-container-left')) return 'left';\n if (container.classList.contains('ng-container-right')) return 'right';\n return 'body';\n }\n\n #onPointerMove = (e) => {\n\n\n const headerPart = e.target.closest('thead');\n if (!headerPart) return;\n\n const cell = e.target.closest('th, td');\n\n headerPart.querySelectorAll('.resizable-edge').forEach(el => {\n if (el !== cell) el.classList.remove('resizable-edge');\n });\n\n if (!cell || cell.dataset.col === undefined) return;\n if (cell.getAttribute('collapsed') === 'true') return;\n\n const rect = cell.getBoundingClientRect();\n const offsetX = e.clientX - rect.left;\n const isLeftEdge = offsetX <= RESIZE_OFFSET;\n const isRightEdge = (rect.width - offsetX) <= RESIZE_OFFSET;\n\n if (isLeftEdge) {\n const prevCell = cell.previousElementSibling;\n if (!prevCell || prevCell.getAttribute('collapsed') === 'true') {\n cell.classList.remove('resizable-edge');\n return;\n }\n }\n\n if (isLeftEdge || isRightEdge) {\n cell.classList.add('resizable-edge');\n } else {\n cell.classList.remove('resizable-edge');\n }\n };\n\n #onPointerDown = (e) => {\n\n trace.log(\"onPointerDown\");\n\n const headerPart = e.actualTarget.closest('thead');\n if (!headerPart) return;\n\n const cell = e.actualTarget.closest('th, td');\n trace.log(cell, e.actualTarget);\n\n if (!cell || !cell.classList.contains('resizable-edge')) return;\n\n\n\n e.preventDefault();\n const rect = cell.getBoundingClientRect();\n const offsetX = e.clientX - rect.left;\n\n let targetCell = cell;\n\n if (offsetX <= RESIZE_OFFSET) {\n const prevCell = cell.previousElementSibling;\n if (prevCell && prevCell.dataset.col !== undefined && prevCell.getAttribute('collapsed') !== 'true') {\n targetCell = prevCell;\n } else if (!cell.previousElementSibling) {\n return;\n }\n }\n\n this.#targetCell = targetCell;\n this.#targetContainerType = this.#getContainerType(targetCell);\n\n const container = this.#sheet.querySelector(`.ng-container-${this.#targetContainerType}`);\n if (!container) return;\n\n const baseColIndex = parseInt(targetCell.dataset.col, 10);\n const colSpan = targetCell.colSpan || 1;\n this.#targetColIndex = baseColIndex + colSpan - 1;\n\n const isAutoFit = this.#checkIsAutoFit(targetCell);\n if (isAutoFit) {\n this.#nextColIndex = this.#targetColIndex + 1;\n const nextColEl = container.querySelector(`col[data-col=\"${this.#nextColIndex}\"]`);\n if (nextColEl) {\n this.#nextColStartWidth = parseInt(nextColEl.getAttribute('width'), 10) || 100;\n } else {\n this.#nextColIndex = null;\n }\n } else {\n this.#nextColIndex = null;\n }\n\n const targetRect = targetCell.getBoundingClientRect();\n const sheetRect = this.#sheet.getBoundingClientRect();\n\n this.#startCellWidth = targetRect.width;\n this.#startLeft = targetRect.left - sheetRect.left;\n\n const targetColEl = container.querySelector(`col[data-col=\"${this.#targetColIndex}\"]`);\n const attrW = targetColEl?.getAttribute('width');\n this.#startColWidth = (attrW && !isNaN(parseInt(attrW, 10))) ? parseInt(attrW, 10) : targetRect.width / colSpan;\n\n this.#startX = e.clientX;\n\n if (this.#panel) {\n this.#panel.classList.add('active');\n this.#updatePositions(e.clientX);\n }\n\n window.addEventListener('pointermove', this.#onDragMove);\n window.addEventListener('pointerup', this.#onDragEnd, { once: true });\n };\n\n #updatePositions(clientX) {\n let diff = clientX - this.#startX;\n const isAutoFit = this.#checkIsAutoFit(this.#targetCell);\n\n if (isAutoFit && this.#nextColIndex !== null) {\n const maxDiff = this.#nextColStartWidth - COLLAPSED_WIDTH;\n const minDiff = -(this.#startColWidth - COLLAPSED_WIDTH);\n diff = Math.max(minDiff, Math.min(diff, maxDiff));\n }\n\n const currentColWidth = Math.max(COLLAPSED_WIDTH, this.#startColWidth + diff);\n\n const targetRect = this.#targetCell.getBoundingClientRect();\n let realCellWidth = clientX - targetRect.left;\n\n if (isAutoFit && this.#nextColIndex !== null) {\n const maxCellWidth = this.#startCellWidth + (this.#nextColStartWidth - COLLAPSED_WIDTH);\n realCellWidth = Math.min(realCellWidth, maxCellWidth);\n }\n\n const currentCellWidth = Math.max(COLLAPSED_WIDTH, realCellWidth);\n\n if (this.#panel) {\n this.#panel.style.setProperty('--col-resizer-tooltip-left', `${this.#startLeft}px`);\n this.#panel.style.setProperty('--col-resizer-tooltip-width', `${currentCellWidth}px`);\n }\n\n const sizeBadge = this.#tooltip?.querySelector('.size-badge');\n if (sizeBadge) {\n sizeBadge.textContent = `${Math.round(currentColWidth)}px`;\n }\n }\n\n #onDragMove = (e) => {\n trace.log(e);\n this.#updatePositions(e.clientX);\n };\n\n #onDragEnd = (e) => {\n window.removeEventListener('pointermove', this.#onDragMove);\n\n const diff = e.clientX - this.#startX;\n const isAutoFit = this.#checkIsAutoFit(this.#targetCell);\n let finalWidth = 0;\n\n if (isAutoFit && this.#nextColIndex !== null) {\n let newColWidth = Math.max(COLLAPSED_WIDTH, this.#startColWidth + diff);\n let newNextWidth = this.#startColWidth + this.#nextColStartWidth - newColWidth;\n\n if (newNextWidth < COLLAPSED_WIDTH) {\n newNextWidth = COLLAPSED_WIDTH;\n newColWidth = this.#startColWidth + this.#nextColStartWidth - COLLAPSED_WIDTH;\n }\n\n this.setColumnWidth(this.#targetColIndex, newColWidth, this.#targetContainerType);\n this.setColumnWidth(this.#nextColIndex, newNextWidth, this.#targetContainerType);\n finalWidth = newColWidth;\n } else {\n const newColWidth = Math.max(COLLAPSED_WIDTH, this.#startColWidth + diff);\n if (this.#targetColIndex !== null && this.#targetContainerType) {\n this.setColumnWidth(this.#targetColIndex, newColWidth, this.#targetContainerType);\n finalWidth = newColWidth;\n }\n }\n\n if (this.#targetCell) {\n const targetCell = this.#targetCell;\n if (targetCell.getAttribute('collapsed') !== 'true' && finalWidth > 20) {\n targetCell.dataset.expandWidth = String(finalWidth);\n }\n }\n\n if (this.#panel) {\n this.#tooltip?.classList.add('fade-out');\n setTimeout(() => {\n this.#panel.classList.remove('active');\n this.#tooltip?.classList.remove('fade-out');\n }, 150);\n }\n\n this.#targetColIndex = null;\n this.#nextColIndex = null;\n this.#targetContainerType = null;\n this.#targetCell = null;\n };\n\n #onDblClick = (e) => {\n\n const targetEl = e.target;\n let cell = targetEl.closest('th, td');\n if (!cell || !cell.classList.contains('resizable-edge')) return;\n\n const rect = cell.getBoundingClientRect();\n const offsetX = e.clientX - rect.left;\n\n if (offsetX <= RESIZE_OFFSET) {\n cell = cell.previousElementSibling;\n }\n\n const baseColIndex = parseInt(cell.dataset.col, 10);\n const tbodyCell = this.#sheet.querySelector(`tbody.body [data-col=\"${baseColIndex}\"]`);\n if (!tbodyCell || !tbodyCell.dataset.bind || tbodyCell.classList.contains(\"CELL-RADIO\")) return;\n\n let extraPadding = 0;\n Array.from(tbodyCell.firstElementChild.children).forEach(($el) => {\n switch ($el.tagName) {\n case 'SPAN': extraPadding += 8; break;\n case 'DIV': extraPadding += 8; break;\n case 'BUTTON': extraPadding += 32; break;\n case 'SELECT': extraPadding += 32; break;\n case 'INPUT':\n switch (($el.type || 'text').toLowerCase()) {\n // 1. 체크박스 / 라디오 (비교적 좁은 영역)\n case 'checkbox':\n case 'radio':\n extraPadding += 12;\n break;\n\n // 2. 버튼 계열 input\n case 'button':\n case 'submit':\n case 'reset':\n case 'image':\n extraPadding += 16;\n break;\n\n // 3. 특수 위젯 (컬러, 파일, 슬라이더)\n case 'color':\n case 'file':\n case 'range':\n extraPadding += 24;\n break;\n\n // 4. 화면에 안 보이는 hidden 필드\n case 'hidden':\n extraPadding += 0;\n break;\n\n // 5. 텍스트 및 숫자, 날짜 등 일반 입력 필드 (기본값)\n case 'text':\n case 'search':\n case 'tel':\n case 'url':\n case 'email':\n case 'password':\n case 'number':\n case 'date':\n case 'time':\n case 'datetime-local':\n case 'month':\n case 'week':\n default:\n extraPadding += 16;\n break;\n }\n break;\n }\n });\n\n trace.log(extraPadding);\n\n\n const fieldIdx = this.#host.fields.get().indexOf(tbodyCell.dataset.bind);\n\n const computedStyle = window.getComputedStyle(tbodyCell);\n const font = computedStyle.font || '12px sans-serif';\n\n // 헤더 텍스트 길이 측정\n const headerText = cell.innerText || \"\";\n const headerSize = nine.measureTextSize(headerText, font);\n let maxTextWidth = (headerSize.width || 0) + 16;\n\n this.#host.execute(() => {\n\n this.#sheet.view.getArray().forEach((record, idx) => {\n const val = String(tbodyCell.dataset.expr ? this.#host.exprEngine.evaluate(tbodyCell.dataset.expr, record, idx) : record.v[fieldIdx] ?? \"\").trim();\n const size = nine.measureTextSize(val, font);\n if (size.width && size.width > maxTextWidth) {\n maxTextWidth = size.width;\n }\n });\n\n // 글자 수 당 대략적인 픽셀 계산 (기본 패딩 여백 포함, 최소 32px ~ 최대 400px 제한)\n const calculatedWidth = Math.max(32, Math.min(400, Math.ceil(maxTextWidth) + extraPadding));\n\n // 자동 계산된 너비 적용\n this.setColumnWidth(tbodyCell.dataset.col, calculatedWidth, this.#getContainerType(cell));\n })\n };\n}\n\n\nexport class ColResizerPanel extends HTMLElement {\n #target;\n\n constructor() {\n super();\n }\n\n connectedCallback() {\n\n this.#renderer();\n }\n\n #renderer = () => {\n this.innerHTML = `\n <div class=\"resizer-overlay\">\n <span class=\"size-badge\">0px</span>\n </div>\n `;\n };\n}\n\nif (!customElements.get('nine-table-col-resizer-panel')) {\n customElements.define(\"nine-table-col-resizer-panel\", ColResizerPanel);\n}\n","// ui/col/ColMover.js\nimport { trace } from \"@nopeer\";\nimport { TableCompiler } from \"@/layout/core/TableCompiler.js\";\n\nexport class ColMover {\n #sheet;\n #grip;\n #indi;\n\n #isDragging = false;\n #sourceCell = null;\n #sourceColIndex = null;\n #targetColIndex = null;\n #shiftX = 0;\n #timer = null;\n\n constructor(sheet) {\n this.#sheet = sheet;\n this.#grip = this.#sheet.querySelector('.ng-col-mover-grip');\n this.#indi = this.#sheet.querySelector('.ng-col-mover-indi');\n this.bindEvents();\n }\n\n bindEvents() {\n this.#sheet.addEventListener('pointerdown', this.#onPointerDown);\n }\n\n #checkIsMovable() {\n const host = this.#sheet.getRootNode()?.host;\n return this.#sheet.getAttribute('col-movable') === 'true' || host?.getAttribute('col-movable') === 'true';\n }\n\n #getDeepElementFromPoint(x, y) {\n const root = this.#sheet.getRootNode();\n let el = root.elementFromPoint ? root.elementFromPoint(x, y) : document.elementFromPoint(x, y);\n\n while (el && el.shadowRoot && el.shadowRoot.elementFromPoint) {\n const nested = el.shadowRoot.elementFromPoint(x, y);\n if (!nested || nested === el) break;\n el = nested;\n }\n\n return el;\n }\n\n #getColGroupRange(cell) {\n if (!cell || cell.dataset.col === undefined) return null;\n\n const startCol = parseInt(cell.dataset.col, 10);\n const colSpan = cell.colSpan || 1;\n const endCol = startCol + colSpan - 1;\n const rowIndex = cell.closest('tr')?.sectionRowIndex ?? 0;\n\n const table = cell.closest('table');\n if (!table) return { startCol, colSpan, endCol, rowIndex, isGroup: false, parentGroupRange: null, isValidGroup: true };\n\n const headerCells = table.querySelectorAll('thead th, thead td');\n let hasStrictChildren = false;\n let isValidGroup = true;\n let parentGroupRange = null;\n\n for (const subCell of headerCells) {\n if (subCell === cell || subCell.dataset.col === undefined) continue;\n\n const subStart = parseInt(subCell.dataset.col, 10);\n const subSpan = subCell.colSpan || 1;\n const subEnd = subStart + subSpan - 1;\n const subRowIndex = subCell.closest('tr')?.sectionRowIndex ?? 0;\n\n if (subRowIndex < rowIndex && subStart <= startCol && subEnd >= endCol && subSpan > colSpan) {\n if (!parentGroupRange) {\n parentGroupRange = { startCol: subStart, endCol: subEnd };\n } else {\n parentGroupRange.startCol = Math.max(parentGroupRange.startCol, subStart);\n parentGroupRange.endCol = Math.min(parentGroupRange.endCol, subEnd);\n }\n }\n\n const isOverlap = !(subEnd < startCol || subStart > endCol);\n if (isOverlap) {\n const isFullyContained = (subStart >= startCol && subEnd <= endCol);\n\n if (isFullyContained) {\n if (subSpan < colSpan) {\n hasStrictChildren = true;\n }\n } else if (subStart < startCol || subEnd > endCol) {\n if (!(subStart <= startCol && subEnd >= endCol)) {\n isValidGroup = false;\n }\n }\n }\n }\n\n const isRealGroup = hasStrictChildren && isValidGroup;\n\n return {\n startCol,\n colSpan: isRealGroup ? colSpan : 1,\n endCol: isRealGroup ? endCol : startCol,\n rowIndex,\n isGroup: isRealGroup,\n parentGroupRange,\n isValidGroup\n };\n }\n\n #createGroupHeaderPreview(cell) {\n const groupRange = this.#getColGroupRange(cell);\n if (!groupRange) return null;\n\n const { startCol, endCol, isGroup } = groupRange;\n\n // 핵심: 테이블이 여러 개인 구조이므로 cell이 속한 바로 그 테이블을 직접 가져옵니다.\n const origTable = cell.closest('table');\n if (!origTable) return null;\n\n let minLeft = Infinity, maxRight = -Infinity, minTop = Infinity, maxBottom = -Infinity;\n const targetCells = [];\n\n origTable.querySelectorAll('thead th, thead td').forEach(c => {\n if (c.dataset.col === undefined) return;\n const cCol = parseInt(c.dataset.col, 10);\n const cSpan = c.colSpan || 1;\n const cEnd = cCol + cSpan - 1;\n\n const isTarget = isGroup\n ? (cCol >= startCol && cEnd <= endCol)\n : (c === cell);\n\n if (isTarget) {\n const rect = c.getBoundingClientRect();\n minLeft = Math.min(minLeft, rect.left);\n maxRight = Math.max(maxRight, rect.right);\n minTop = Math.min(minTop, rect.top);\n maxBottom = Math.max(maxBottom, rect.bottom);\n\n const computedStyle = window.getComputedStyle(c);\n targetCells.push({ el: c, rect, style: computedStyle });\n }\n });\n\n if (targetCells.length === 0) return null;\n\n const groupWidth = maxRight - minLeft;\n const groupHeight = maxBottom - minTop;\n\n const headerContent = document.createElement('div');\n headerContent.className = 'grip-header-content';\n headerContent.style.position = 'relative';\n headerContent.style.width = `${groupWidth}px`;\n headerContent.style.height = `${groupHeight}px`;\n\n targetCells.forEach(({ el, rect, style }) => {\n const clonedCell = el.cloneNode(true);\n\n clonedCell.style.position = 'absolute';\n clonedCell.style.left = `${rect.left - minLeft}px`;\n clonedCell.style.top = `${rect.top - minTop}px`;\n\n clonedCell.style.width = `${rect.width}px`;\n clonedCell.style.minWidth = `${rect.width}px`;\n clonedCell.style.maxWidth = 'none';\n\n clonedCell.style.height = `${rect.height}px`;\n clonedCell.style.boxSizing = 'border-box';\n clonedCell.style.margin = '0';\n\n clonedCell.style.backgroundColor = style.backgroundColor !== 'transparent' && style.backgroundColor !== 'rgba(0, 0, 0, 0)'\n ? style.backgroundColor\n : '#f9fafb';\n clonedCell.style.color = style.color;\n clonedCell.style.font = style.font;\n clonedCell.style.fontWeight = style.fontWeight;\n clonedCell.style.fontSize = style.fontSize;\n clonedCell.style.textAlign = style.textAlign;\n clonedCell.style.padding = style.padding;\n clonedCell.style.border = style.border;\n clonedCell.style.borderRight = style.borderRight;\n clonedCell.style.borderBottom = style.borderBottom;\n clonedCell.style.display = 'flex';\n clonedCell.style.alignItems = 'center';\n clonedCell.style.justifyContent = style.textAlign === 'center' ? 'center' : (style.textAlign === 'right' ? 'flex-end' : 'flex-start');\n\n headerContent.appendChild(clonedCell);\n });\n\n return {\n element: headerContent,\n bounds: {\n left: minLeft,\n right: maxRight,\n top: minTop,\n bottom: maxBottom,\n width: groupWidth,\n height: groupHeight\n }\n };\n }\n\n #onPointerDown = (e) => {\n if (!this.#checkIsMovable()) return;\n\n const headerPart = e.target.closest('.ng-sheet-header');\n if (!headerPart) return;\n\n const cell = e.target.closest('th, td');\n if (!cell || cell.classList.contains('resizable-edge') || ['INPUT', 'BUTTON'].includes(e.target.tagName)) return;\n if (cell.dataset.col === undefined) return;\n\n e.preventDefault();\n\n const startX = e.clientX;\n const startY = e.clientY;\n\n const cancelTimer = () => {\n if (this.#timer) {\n clearTimeout(this.#timer);\n this.#timer = null;\n }\n window.removeEventListener('pointermove', onPointerMovePending);\n window.removeEventListener('pointerup', cancelTimer);\n window.removeEventListener('pointercancel', cancelTimer);\n };\n\n const onPointerMovePending = (moveEvent) => {\n const dist = Math.hypot(moveEvent.clientX - startX, moveEvent.clientY - startY);\n if (dist > 5) {\n cancelTimer();\n }\n };\n\n this.#timer = setTimeout(() => {\n cancelTimer();\n this.#startDrag(e, cell);\n }, 500);\n\n window.addEventListener('pointermove', onPointerMovePending);\n window.addEventListener('pointerup', cancelTimer, { once: true });\n window.addEventListener('pointercancel', cancelTimer, { once: true });\n };\n\n #startDrag(e, cell) {\n if (this.#isDragging) return;\n\n const preview = this.#createGroupHeaderPreview(cell);\n if (!preview) return;\n\n this.#isDragging = true;\n this.#sourceCell = cell;\n this.#sourceColIndex = parseInt(cell.dataset.col, 10);\n\n const sheetRect = this.#sheet.getBoundingClientRect();\n const { bounds, element } = preview;\n\n this.#shiftX = e.clientX - bounds.left;\n\n if (this.#grip) {\n this.#grip.replaceChildren(element);\n\n const relativeTop = bounds.top - sheetRect.top;\n const fullHeight = sheetRect.height - relativeTop;\n\n this.#grip.style.width = `${bounds.width}px`;\n this.#grip.style.height = `${fullHeight}px`;\n this.#grip.style.top = `${relativeTop}px`;\n this.#grip.style.display = 'block';\n\n this.#updateGripPosition(e.clientX);\n }\n\n document.body.style.cursor = 'move';\n\n window.addEventListener('pointermove', this.#onPointerMove);\n window.addEventListener('pointerup', this.#onPointerUp, { once: true });\n }\n\n #onPointerMove = (e) => {\n if (!this.#isDragging) return;\n\n this.#updateGripPosition(e.clientX);\n\n if (this.#grip) this.#grip.style.pointerEvents = 'none';\n if (this.#indi) this.#indi.style.pointerEvents = 'none';\n\n const targetElement = this.#getDeepElementFromPoint(e.clientX, e.clientY);\n const targetCell = targetElement?.closest('.ng-sheet-header th, .ng-sheet-header td');\n\n if (targetCell && targetCell.dataset.col !== undefined) {\n const targetColIndex = parseInt(targetCell.dataset.col, 10);\n const sheetRect = this.#sheet.getBoundingClientRect();\n const table = targetCell.closest('table');\n\n let colMinLeft = Infinity;\n let colMaxRight = -Infinity;\n\n if (table) {\n table.querySelectorAll('thead th, thead td').forEach(c => {\n if (c.dataset.col === undefined) return;\n const cCol = parseInt(c.dataset.col, 10);\n const cSpan = c.colSpan || 1;\n const cEnd = cCol + cSpan - 1;\n\n if (cCol <= targetColIndex && cEnd >= targetColIndex) {\n const cRect = c.getBoundingClientRect();\n colMinLeft = Math.min(colMinLeft, cRect.left);\n colMaxRight = Math.max(colMaxRight, cRect.right);\n }\n });\n }\n\n if (colMinLeft === Infinity) {\n const rect = targetCell.getBoundingClientRect();\n colMinLeft = rect.left;\n colMaxRight = rect.right;\n }\n\n const midX = colMinLeft + ((colMaxRight - colMinLeft) / 2);\n let calculatedTargetCol = 0;\n let indicatorLeft = 0;\n\n if (e.clientX < midX) {\n calculatedTargetCol = targetColIndex;\n indicatorLeft = colMinLeft - sheetRect.left;\n } else {\n const colSpan = targetCell.colSpan || 1;\n calculatedTargetCol = targetColIndex + colSpan;\n indicatorLeft = colMaxRight - sheetRect.left;\n }\n\n const sourceGroup = this.#getColGroupRange(this.#sourceCell);\n const movingSpan = sourceGroup.colSpan;\n\n const sourceRowStart = sourceGroup.rowIndex;\n const sourceRowSpan = this.#sourceCell.rowSpan || 1;\n const sourceRowEnd = sourceRowStart + sourceRowSpan - 1;\n\n const targetRowStart = targetCell.closest('tr')?.sectionRowIndex ?? 0;\n const targetRowSpan = targetCell.rowSpan || 1;\n const targetRowEnd = targetRowStart + targetRowSpan - 1;\n\n const isRowSpanCompatible = !(sourceRowEnd < targetRowStart || sourceRowStart > targetRowEnd);\n\n let isOutOfBoundsOfParent = false;\n if (sourceGroup.parentGroupRange) {\n const { startCol: pStart, endCol: pEnd } = sourceGroup.parentGroupRange;\n if (calculatedTargetCol < pStart || (calculatedTargetCol + movingSpan - 1) > pEnd) {\n isOutOfBoundsOfParent = true;\n }\n }\n\n let isDroppingInsideOtherGroup = false;\n if (table) {\n const spannedCells = table.querySelectorAll('thead th[colspan], thead td[colspan]');\n\n for (const sCell of spannedCells) {\n if (sCell === this.#sourceCell) continue;\n\n const sRowStart = sCell.closest('tr')?.sectionRowIndex ?? 0;\n const sRowSpan = sCell.rowSpan || 1;\n const sRowEnd = sRowStart + sRowSpan - 1;\n\n const isVerticalOverlap = !(sourceRowEnd < sRowStart || sourceRowStart > sRowEnd);\n if (!isVerticalOverlap) continue;\n\n const sStart = parseInt(sCell.dataset.col, 10);\n const sSpan = sCell.colSpan || 1;\n const sEnd = sStart + sSpan - 1;\n\n if (calculatedTargetCol > sStart && calculatedTargetCol < sEnd + 1) {\n isDroppingInsideOtherGroup = true;\n break;\n }\n\n const moveEndCol = calculatedTargetCol + movingSpan - 1;\n const isCrossIntersecting = (\n (calculatedTargetCol > sStart && calculatedTargetCol <= sEnd && moveEndCol > sEnd) ||\n (calculatedTargetCol < sStart && moveEndCol >= sStart && moveEndCol < sEnd)\n );\n\n if (isCrossIntersecting) {\n isDroppingInsideOtherGroup = true;\n break;\n }\n }\n }\n\n const isSelfGroup = (\n calculatedTargetCol >= sourceGroup.startCol &&\n calculatedTargetCol <= sourceGroup.endCol + 1\n );\n\n const isInvalidMove = !isRowSpanCompatible || isSelfGroup || isOutOfBoundsOfParent || isDroppingInsideOtherGroup || !sourceGroup.isValidGroup;\n\n if (isInvalidMove) {\n this.#targetColIndex = null;\n if (this.#indi) this.#indi.style.display = 'none';\n if (this.#grip) this.#grip.classList.add('invalid');\n } else {\n this.#targetColIndex = calculatedTargetCol;\n if (this.#grip) this.#grip.classList.remove('invalid');\n\n if (this.#indi) {\n const headerPart = targetCell.closest('.ng-sheet-header');\n const headerRect = headerPart.getBoundingClientRect();\n const relativeTop = headerRect.top - sheetRect.top;\n const fullHeight = sheetRect.height - relativeTop;\n\n this.#indi.style.top = `${relativeTop}px`;\n this.#indi.style.height = `${fullHeight}px`;\n this.#indi.style.left = `${indicatorLeft - 1}px`;\n this.#indi.style.display = 'block';\n }\n }\n } else {\n if (this.#indi) this.#indi.style.display = 'none';\n if (this.#grip) this.#grip.classList.add('invalid');\n this.#targetColIndex = null;\n }\n };\n\n #updateGripPosition(clientX) {\n if (!this.#grip) return;\n const sheetRect = this.#sheet.getBoundingClientRect();\n const left = clientX - sheetRect.left - this.#shiftX;\n this.#grip.style.left = `${left}px`;\n }\n\n #onPointerUp = (e) => {\n if (!this.#isDragging) return;\n\n window.removeEventListener('pointermove', this.#onPointerMove);\n document.body.style.cursor = '';\n\n if (this.#grip) {\n this.#grip.style.display = 'none';\n this.#grip.replaceChildren();\n }\n if (this.#indi) this.#indi.style.display = 'none';\n\n if (\n this.#targetColIndex !== null &&\n this.#sourceColIndex !== null &&\n this.#targetColIndex !== this.#sourceColIndex &&\n this.#targetColIndex !== this.#sourceColIndex + 1\n ) {\n this.moveColumn(this.#sourceColIndex, this.#targetColIndex);\n }\n\n this.#isDragging = false;\n this.#sourceCell = null;\n this.#sourceColIndex = null;\n this.#targetColIndex = null;\n };\n\n moveColumn(fromColIndex, toColIndex) {\n\n trace.log(this.#sheet.sourceTable.cloneNode(true));\n\n const colgroup = this.#sheet.sourceTable.querySelector('colgroup');\n const targetCol = colgroup.querySelector(`col[data-col=\"${toColIndex}\"]`);\n\n const sourceGroup = this.#getColGroupRange(this.#sourceCell);\n if (!sourceGroup || !sourceGroup.isValidGroup) return;\n\n const spanCount = sourceGroup.colSpan;\n const isInRange = (idx) => idx >= fromColIndex && idx < fromColIndex + spanCount;\n\n // 1. colgroup 내 <col> 이동 및 fixed 설정\n const targetViewportCol = this.#sheet.querySelector(`.ng-sheet-body-content col[data-col=\"${toColIndex}\"]`);\n const fixedType = targetViewportCol?.closest('.ng-container-left') ? 'left' : targetViewportCol?.closest('.ng-container-right') ? 'right' : null;\n\n colgroup.querySelectorAll('col').forEach(col => {\n if (isInRange(parseInt(col.getAttribute('data-col'), 10))) {\n fixedType ? col.setAttribute('fixed', fixedType) : col.removeAttribute('fixed');\n colgroup.insertBefore(col, targetCol);\n }\n });\n\n // 2. 테이블 행(tr) 내부의 셀(th, td) 순서 동기화\n ['thead', 'tbody', 'tfoot'].forEach(group => {\n this.#sheet.sourceTable.querySelectorAll(`${group} tr`).forEach(tr => {\n const cells = Array.from(tr.children);\n const targetRowCell = cells.find(c => parseInt(c.dataset.col, 10) >= toColIndex);\n\n cells.forEach(cell => {\n if (isInRange(parseInt(cell.dataset.col, 10))) {\n tr.insertBefore(cell, targetRowCell || null);\n }\n });\n });\n });\n\n this.#sheet.recompileAndRefresh();\n }\n\n destroy() {\n this.#sheet.removeEventListener('pointerdown', this.#onPointerDown);\n }\n}","// ui/col/ColFixManager.js\nimport { trace } from \"@nopeer\";\nimport { TableCompiler } from \"@/layout/core/TableCompiler.js\";\n\nexport class ColFixManager {\n #sheet;\n\n constructor(sheet) {\n this.#sheet = sheet;\n }\n\n /**\n * 🎯 현재 클릭된 셀의 고정 구역('left', 'right', 'none') 탐색\n */\n getFixState(targetCell, table) {\n if (!targetCell || !table) return 'none';\n\n // 🎯 [보정] 3분할 레이어 구조 내부의 컨테이너를 안전하게 탐색\n const container = targetCell.closest('.ng-container-left, .ng-container-right, .ng-container-body');\n if (container?.classList.contains('ng-container-left')) return 'left';\n if (container?.classList.contains('ng-container-right')) return 'right';\n\n const baseCol = parseInt(targetCell.dataset.col, 10);\n if (!isNaN(baseCol)) {\n const colEl = table.querySelector(`colgroup col[data-col=\"${baseCol}\"]`);\n const fixedAttr = colEl?.getAttribute('fixed');\n if (fixedAttr) return fixedAttr;\n }\n\n return 'none';\n }\n\n /**\n * 🎯 상하 멀티 헤더 경계선 일치 여부 검사 (Fix Column 가부 판별)\n */\n canFixColumn(targetCell, table) {\n if (!targetCell || targetCell.tagName !== 'TH' || !table) return false;\n\n const baseCol = parseInt(targetCell.dataset.col, 10);\n const colSpan = targetCell.colSpan || 1;\n if (isNaN(baseCol)) return false;\n\n const targetBoundaryCol = baseCol + colSpan - 1;\n const theadTrs = Array.from(table.querySelectorAll('thead tr'));\n\n if (theadTrs.length <= 1) return true;\n\n for (const tr of theadTrs) {\n const cells = Array.from(tr.querySelectorAll('th, td'));\n let cellBoundaryFound = false;\n\n for (const cell of cells) {\n const cCol = parseInt(cell.dataset.col, 10);\n const cSpan = cell.colSpan || 1;\n const cEndCol = cCol + cSpan - 1;\n\n // 목표 경계선이 특정 셀의 중간을 관통하는 경우 (Fix 불가능)\n if (cCol <= targetBoundaryCol && targetBoundaryCol < cEndCol) {\n return false;\n }\n\n if (cEndCol === targetBoundaryCol) {\n cellBoundaryFound = true;\n break;\n }\n }\n\n if (!cellBoundaryFound) return false;\n }\n\n return true;\n }\n\n /**\n * 🎯 [인스턴스 메서드] 배치 범위 고정 및 해제 처리\n * - 원본(`sourceTable`)의 구조(fixed 속성)를 직접 조작하므로 decompile은 절대 호출하지 않음!\n */\n executeFixToggle(action, targetCell, fixType = 'left') {\n if (!this.#sheet || !targetCell) return;\n\n const sourceTable = this.#sheet.sourceTable;\n if (!sourceTable) return;\n\n const baseCol = parseInt(targetCell.dataset.col, 10);\n const colSpan = targetCell.colSpan || 1;\n const targetColIndex = baseCol + colSpan - 1;\n\n if (isNaN(targetColIndex)) return;\n\n const colgroup = sourceTable.querySelector('colgroup');\n if (!colgroup) return;\n\n const cols = Array.from(colgroup.querySelectorAll('col'));\n\n if (action === 'fix-column') {\n // 🎯 Batch Fix: 0번부터 targetColIndex까지의 모든 <col>과 셀에 fixed 속성 일괄 부여\n cols.forEach(col => {\n const idx = parseInt(col.getAttribute('data-col'), 10);\n if (idx <= targetColIndex) {\n col.setAttribute('fixed', fixType);\n }\n });\n\n ['thead', 'tbody', 'tfoot'].forEach(group => {\n sourceTable.querySelectorAll(`${group} tr`).forEach(tr => {\n Array.from(tr.children).forEach(cell => {\n const cIdx = parseInt(cell.dataset.col, 10);\n if (!isNaN(cIdx) && cIdx <= targetColIndex) {\n cell.setAttribute('fixed', fixType);\n }\n });\n });\n });\n\n } else if (action === 'unfix-column') {\n let minBaseCol = baseCol;\n let maxEndCol = baseCol + colSpan - 1;\n\n ['thead', 'tbody', 'tfoot'].forEach(group => {\n sourceTable.querySelectorAll(`${group} tr`).forEach((tr, rIdx) => {\n Array.from(tr.children).forEach(cell => {\n const cCol = parseInt(cell.dataset.col, 10);\n const cSpan = cell.colSpan || 1;\n const cEnd = cCol + cSpan - 1;\n const rSpan = cell.rowSpan || 1;\n const trIndex = tr.sectionRowIndex ?? rIdx;\n\n // 현재 클릭된 셀의 수직 범위와 겹치는 머지 셀이 있는지 검사\n const isVerticalOverlap = !(trIndex + rSpan - 1 < cell.closest('tr').sectionRowIndex || trIndex > (cell.closest('tr').sectionRowIndex + rSpan - 1));\n\n // 만약 기존에 고정(fixed)되어 있으면서 현재 클릭한 타겟 라인과 걸쳐있는 머지 셀이라면 범위를 확장합니다.\n const isHorizontalOverlap = !(cEnd < baseCol || cCol > targetColIndex);\n\n if (isHorizontalOverlap) {\n minBaseCol = Math.min(minBaseCol, cCol);\n maxEndCol = Math.max(maxEndCol, cEnd);\n }\n });\n });\n });\n\n // 🎯 2단계: 계산된 실제 머지 블록의 시작점(minBaseCol) 이상인 모든 <col> 속성 해제\n cols.forEach(col => {\n const idx = parseInt(col.getAttribute('data-col'), 10);\n if (idx >= minBaseCol) {\n col.removeAttribute('fixed');\n }\n });\n\n // 🎯 3단계: left 구역의 고정 연속성(체인) 검증\n let isBroken = false;\n cols.forEach(col => {\n if (isBroken) {\n col.removeAttribute('fixed');\n } else if (!col.getAttribute('fixed')) {\n isBroken = true;\n }\n });\n\n // 🎯 4단계: <col>들의 최종 fixed 상태를 기준으로 모든 thead, tbody, tfoot 셀(th, td)의 fixed 속성 완벽 동기화\n ['thead', 'tbody', 'tfoot'].forEach(group => {\n sourceTable.querySelectorAll(`${group} tr`).forEach(tr => {\n Array.from(tr.children).forEach(cell => {\n const cIdx = parseInt(cell.dataset.col, 10);\n if (isNaN(cIdx)) return;\n\n const correspondingCol = cols.find(c => parseInt(c.getAttribute('data-col'), 10) === cIdx);\n const isColFixed = correspondingCol?.getAttribute('fixed');\n\n if (isColFixed) {\n cell.setAttribute('fixed', isColFixed);\n } else {\n cell.removeAttribute('fixed');\n }\n });\n });\n });\n }\n\n trace.log(this.#sheet.sourceTable);\n\n // 🎯 recompileAndRefresh 단 1회 호출로 원본 정렬 및 뷰포트 재생성 완결\n this.#sheet.recompileAndRefresh?.();\n }\n}","import { NINE_TABLE } from '@/core/constants.js';\r\nimport { trace } from \"@nopeer\";\r\n\r\n/**\r\n * 🎯 [필터 패널 커스텀 엘리먼트 Light DOM 버전]\r\n */\r\nexport class NineTableFilterPanel extends HTMLElement {\r\n\t#sheet;\r\n\t#host;\r\n\t#nineTable;\r\n\t#view;\r\n\t#button;\r\n\tcurrentCol = null;\r\n\r\n\tconnectedCallback() {\r\n\t\tthis.#init();\r\n\t\tdocument.addEventListener(\"mousedown\", this.#closeHandler);\r\n\t}\r\n\r\n\t#init = () => {\r\n\t\t//setTimeout(() => {\r\n\t\t\tthis.#renderer();\r\n\r\n\t\t\tthis.#sheet = this.closest(\"nine-table-sheet\");\r\n\t\t\tthis.#host = this.getRootNode().host;\r\n\r\n\t\t\tthis.#nineTable = this.querySelector(\"nine-table-simple\");\r\n\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\tthis.#view = this.#nineTable.shadowRoot.querySelector(\"nine-table-sheet\");\r\n\t\t\t})\r\n\r\n\r\n\t\t\tthis.querySelector(\".search-box\").addEventListener(\"focusin\", (e) => {\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t});\r\n\t\t\tthis.querySelector(\".search-box\").addEventListener(\"input\", this.#onInput);\r\n\t\t\tthis.querySelector(\"#chkSelectAll\").addEventListener(\"change\", this.#onSelectAll);\r\n\t\t\tthis.querySelector(\"#btnOk\").addEventListener(\"click\", this.#onOk);\r\n\t\t//});\r\n\t}\r\n\r\n\t#renderer = () => {\r\n\t\tthis.innerHTML = `\r\n <input type=\"text\" class=\"search-box\" placeholder=\"Search...\">\r\n \r\n <nine-table-simple class=\"filter-list\" theme=\"simple\">\r\n <table auto-fit-col=\"true\">\r\n <colgroup>\r\n <col width=\"32\" fixed=\"left\" />\r\n <col width=\"180\" />\r\n <col width=\"0\" fixed=\"right\"/>\r\n </colgroup>\r\n <tbody>\r\n <tr>\r\n <td cell-type=\"checkbox\" data-bind=\"CHK\"></td>\r\n <td data-bind=\"DATA2\" html=\"true\"></td>\r\n <td data-bind=\"DATA\"></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </nine-table-simple>\r\n\r\n <div class=\"footer-section\">\r\n <div class=\"footer-btns\">\r\n <label><input type=\"checkbox\" id=\"chkSelectAll\" checked> Select All</label>\r\n <div class=\"btn-group\">\r\n <button id=\"btnOk\">Apply</button>\r\n </div>\r\n </div>\r\n </div>\r\n `;\r\n\t}\r\n\r\n\topen(filterBtn) {\r\n\t\tthis.#button = filterBtn;\r\n\r\n\t\tconst cell = filterBtn.closest(\"th, td\");\r\n\t\tthis.currentCol = cell?.dataset.col;\r\n\r\n\t\tconst cellRect = cell.getBoundingClientRect();\r\n\t\tconst sheetRect = this.#sheet.getBoundingClientRect();\r\n\r\n\t\tconst panelWidth = this.offsetWidth || 240;\r\n\t\tlet left = (cellRect.right - sheetRect.left) - panelWidth;\r\n\t\tlet top = cellRect.bottom - sheetRect.top;\r\n\r\n\t\tif (left < 0) {\r\n\t\t\tleft = Math.max(0, cellRect.left - sheetRect.left);\r\n\t\t}\r\n\r\n\t\tthis.style.left = `${left}px`;\r\n\t\tthis.style.top = `${top}px`;\r\n\r\n\t\tconst searchBox = this.querySelector(\".search-box\");\r\n\t\tsearchBox.value = \"\";\r\n\r\n\r\n\t\tthis.classList.add(\"active\");\r\n\t\tthis.classList.add(\"loading\");\r\n\r\n\t\tsetTimeout(() => {\r\n\t\t\ttry {\r\n\t\t\t\tthis.#loadVirtualFilterItems();\r\n\t\t\t\tthis.#view.rowManager.scrollToDataRow(0);\r\n\t\t\t\tsearchBox.focus();\r\n\t\t\t} finally {\r\n\t\t\t\tthis.classList.remove(\"loading\");\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t#closeHandler = (e) => {\r\n\t\tconst path = e.composedPath ? e.composedPath() : [];\r\n\t\tif (path.includes(this) || (this.#button && path.includes(this.#button))) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.close();\r\n\t};\r\n\r\n\tclose() {\r\n\t\tthis.currentCol = null;\r\n\t\tthis.classList.remove(\"active\");\r\n\t\tthis.#button = null;\r\n\t}\r\n\r\n\t#loadVirtualFilterItems() {\r\n\t\tconst filteredRecords = this.#host.data.getArray();\r\n\t\tconst targetCols = this.#button?.columns || []; // [{ bind, expr }] 형태 배열\r\n\t\tconst fields = this.#host.fields.get() || [];\r\n\t\tconst activeFilters = this.#sheet.filtering?.filters || {};\r\n\t\tconst exprEngine = this.#host.exprEngine;\r\n\r\n\t\tconst ds = targetCols.flatMap((colInfo) => {\r\n\t\t\tconst bindKey = colInfo.bind;\r\n\t\t\tconst exprKey = colInfo.expr;\r\n\r\n\t\t\tconst filterKey = bindKey || exprKey; // 실제 필터 파라미터 키로 사용\r\n\t\t\tconst fieldIdx = bindKey ? fields.indexOf(bindKey) : -1;\r\n\t\t\tconst activeSelectedVals = activeFilters[filterKey] || [];\r\n\r\n\t\t\t// 1. Map을 이용한 O(N) 고속 유니크 추출 (DATA는 bind/원시값, DATA2는 expr 연산 결과)\r\n\t\t\tconst uniqueMap = new Map();\r\n\t\t\tfor (let i = 0; i < filteredRecords.length; i++) {\r\n\t\t\t\tconst record = filteredRecords[i];\r\n\t\t\t\tif (!record) continue;\r\n\r\n\t\t\t\t// DATA 기준이 될 원시 값 (bind가 있으면 필드 인덱스에서, 없으면 expr 결과)\r\n\t\t\t\tlet rawVal = undefined;\r\n\t\t\t\tif (fieldIdx >= 0 && record.v) {\r\n\t\t\t\t\trawVal = record.v[fieldIdx];\r\n\t\t\t\t} else if (bindKey && bindKey.includes(\"data.\")) {\r\n\t\t\t\t\trawVal = exprEngine ? exprEngine.evaluate(bindKey, record, i) : undefined;\r\n\t\t\t\t} else if (exprKey && exprEngine) {\r\n\t\t\t\t\trawVal = exprEngine.evaluate(exprKey, record, i);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// DATA2에 출력될 화면 표시 값 (expr 수식 연산 결과, 없으면 rawVal)\r\n\t\t\t\tlet displayVal = rawVal;\r\n\t\t\t\tif (exprKey && exprEngine) {\r\n\t\t\t\t\tdisplayVal = exprEngine.evaluate(exprKey, record, i);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (displayVal !== undefined && displayVal !== null && !uniqueMap.has(displayVal)) {\r\n\t\t\t\t\tuniqueMap.set(displayVal, {\r\n\t\t\t\t\t\tv: rawVal, // 💡 필터링 비교 기준 (DATA)\r\n\t\t\t\t\t\tv2: displayVal // 💡 화면 출력 기준 (DATA2)\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst uniqueList = [...uniqueMap.values()];\r\n\r\n\t\t\t// 2. 출력값(v2) 기준 정렬\r\n\t\t\t// 2. 출력값(v2) 기준 정렬 (숫자와 문자열 분기 처리)\r\n\t\t\tuniqueList.sort((a, b) => {\r\n\t\t\t\tconst valA = a.v2;\r\n\t\t\t\tconst valB = b.v2;\r\n\r\n\t\t\t\t// 빈 값이나 null 처리를 위한 안전 장치\r\n\t\t\t\tif (valA === valB) return 0;\r\n\t\t\t\tif (valA === undefined || valA === null || valA === '') return 1;\r\n\t\t\t\tif (valB === undefined || valB === null || valB === '') return -1;\r\n\r\n\t\t\t\tconst numA = Number(valA);\r\n\t\t\t\tconst numB = Number(valB);\r\n\r\n\t\t\t\t// 둘 다 유효한 숫자일 경우 숫자 크기 비교\r\n\t\t\t\tconst isNumA = !isNaN(numA);\r\n\t\t\t\tconst isNumB = !isNaN(numB);\r\n\r\n\t\t\t\tif (isNumA && isNumB) {\r\n\t\t\t\t\treturn numA - numB;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// 그 외의 경우는 문자열(localeCompare) 비교\r\n\t\t\t\treturn String(valA).localeCompare(String(valB));\r\n\t\t\t});\r\n\t\t\tactiveSelectedVals.sort((a, b) => { return a > b ? 1 : -1; });\r\n\r\n\t\t\treturn uniqueList.map(o => ({\r\n\t\t\t\tLVL: 2,\r\n\t\t\t\tDATA: o.v, // 필터링 비교용 값\r\n\t\t\t\tDATA2: (o.v2 === \"\" || o.v2 === null || o.v2 === undefined) ? '<span class=\"empty-value\">(empty)</span>' : o.v2, // 화면 출력용 값\r\n\t\t\t\tCOLNM: filterKey,\r\n\t\t\t\tCHK: activeSelectedVals.length === 0 || activeSelectedVals.nineBinarySearch(o.v) >= 0 ? \"Y\" : \"N\"\r\n\t\t\t}));\r\n\t\t});\r\n\r\n\t\tthis.#nineTable.data.set(ds);\r\n\r\n\t\tconst selectAllChk = this.querySelector(\"#chkSelectAll\");\r\n\t\tif (selectAllChk) {\r\n\t\t\tselectAllChk.checked = ds.length > 0 && ds.every(item => item.CHK === \"Y\");\r\n\t\t}\r\n\t}\r\n\r\n\t#onOk = () => {\r\n\t\tthis.#host.loading = true;\r\n\r\n\t\tconst filterRecords = this.#view.view.getArray();\r\n\t\tconst fields = this.#nineTable.data.getHostFields();\r\n\r\n\t\tconst checkedRecords = filterRecords.filter(record => {\r\n\t\t\tconst chk = record.v[fields.indexOf(\"CHK\")];\r\n\t\t\treturn (chk === \"Y\" || chk === true);\r\n\t\t});\r\n\r\n\t\tconst filterParams = { ...(this.#sheet.filtering?.filters || {}) };\r\n\r\n\t\tthis.#button.columns.forEach(colInfo => {\r\n\t\t\tconst filterKey = colInfo.expr || colInfo.bind;\r\n\t\t\tconst fieldIdx = colInfo.expr ? fields.indexOf(\"DATA2\") : fields.indexOf(\"DATA\");\r\n\t\t\tconst selectedVals = checkedRecords.map(r => r.v[fieldIdx]);\r\n\r\n\t\t\tif (selectedVals.length > 0) {\r\n\t\t\t\tfilterParams[filterKey] = selectedVals;\r\n\t\t\t} else {\r\n\t\t\t\tdelete filterParams[filterKey];\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tconst totalCount = this.#nineTable.data.count();\r\n\r\n\t\tsetTimeout(() => {\r\n\t\t\ttry {\r\n\t\t\t\tif (totalCount === checkedRecords.length) {\r\n\t\t\t\t\tthis.#button.columns.forEach(colInfo => {\r\n\t\t\t\t\t\tconst filterKey = colInfo.expr || colInfo.bind;\r\n\t\t\t\t\t\tif (filterKey) this.#sheet.filtering.clear(filterKey);\r\n\t\t\t\t\t});\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.#sheet.filtering.set(filterParams);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.#sheet.querySelectorAll(\"nine-table-filter-button\").forEach(btn => {\r\n\t\t\t\t\tbtn.updateFilteredState();\r\n\t\t\t\t});\r\n\r\n\t\t\t\tthis.#sheet.invalidate();\r\n\t\t\t\tthis.close();\r\n\t\t\t} finally {\r\n\t\t\t\tthis.#host.loading = false;\r\n\t\t\t}\r\n\t\t});\r\n\t};\r\n\r\n\t#onInput = (e) => {\r\n\r\n\t\tconst query = e.target.value.toLowerCase().trim();\r\n\r\n\t\tif (!query) {\r\n\t\t\tthis.#view.filtering.clear();\r\n\t\t} else {\r\n\t\t\tconst rawRecords = this.#nineTable.data.getArray();\r\n\t\t\tconst fields = this.#nineTable.data.getHostFields();\r\n\t\t\tconst data2Idx = fields.indexOf(\"DATA2\");\r\n\r\n\t\t\tconst matchedValues = [];\r\n\t\t\trawRecords.forEach(record => {\r\n\t\t\t\tconst val = data2Idx >= 0 && record.v ? record.v[data2Idx] : \"\";\r\n\t\t\t\tconst textVal = String(val).replace(/<[^>]*>?/gm, '').toLowerCase();\r\n\r\n\t\t\t\t// 💡 expr 연산 결과가 담긴 DATA2 텍스트와 검색어 비교\r\n\t\t\t\tif (textVal.includes(query)) {\r\n\t\t\t\t\tmatchedValues.push(val);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\ttrace.log(matchedValues);\r\n\r\n\t\t\tthis.#view.filtering.set({\r\n\t\t\t\tDATA2: [...new Set(matchedValues)]\r\n\t\t\t});\r\n\t\t}\r\n\t};\r\n\r\n\t#onSelectAll = (e) => {\r\n\t\tconst isChecked = e.target.checked;\r\n\t\tconst rawRecords = this.#nineTable?.data?.getArray() || [];\r\n\t\tconst fields = this.#nineTable.data.getHostFields();\r\n\t\tconst chkIdx = fields.indexOf(\"CHK\");\r\n\r\n\t\tif (chkIdx >= 0) {\r\n\t\t\trawRecords.forEach(record => {\r\n\t\t\t\trecord.v[chkIdx] = isChecked ? \"Y\" : \"N\";\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.#nineTable.refresh();\r\n\t};\r\n\r\n\t#onCancel = () => {\r\n\t\tthis.close();\r\n\t};\r\n}\r\n\r\nexport class NineTableFilterButton extends HTMLElement {\r\n\t#sheet;\r\n\t#columns = null;\r\n\r\n\tconnectedCallback() {\r\n\t\tthis.#sheet = this.closest(\"nine-table-sheet\") || this.getRootNode().host;\r\n\t\tthis.removeEventListener(\"click\", this.#onClick);\r\n\t\tthis.addEventListener(\"click\", this.#onClick);\r\n\t}\r\n\r\n\tget columns() {\r\n\t\tif (this.#columns) return this.#columns;\r\n\r\n\t\tconst cell = this.closest(\"th, td\");\r\n\t\tconst colIndex = cell?.dataset.col;\r\n\t\tconst sourceTable = this.#sheet.sourceTable;\r\n\r\n\t\tconst cols = [];\r\n\t\tconst seen = new Set();\r\n\r\n\t\tif (sourceTable && colIndex !== undefined) {\r\n\t\t\tsourceTable.querySelectorAll(`tbody [data-col=\"${colIndex}\"]`).forEach($td => {\r\n\t\t\t\tconst bindKey = $td.dataset.bind;\r\n\t\t\t\tconst exprKey = $td.dataset.expr;\r\n\r\n\t\t\t\tif (bindKey || exprKey) {\r\n\t\t\t\t\tconst uniqueKey = `${bindKey || ''}_${exprKey || ''}`;\r\n\t\t\t\t\tif (!seen.has(uniqueKey)) {\r\n\t\t\t\t\t\tseen.add(uniqueKey);\r\n\t\t\t\t\t\tcols.push({\r\n\t\t\t\t\t\t\tbind: bindKey,\r\n\t\t\t\t\t\t\texpr: exprKey,\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.#columns = cols;\r\n\t\treturn this.#columns;\r\n\t}\r\n\r\n\tupdateFilteredState = () => {\r\n\t\tconst activeFilters = this.#sheet.filtering?.filters || {};\r\n\t\tconst isFiltered = this.columns.some(colInfo => {\r\n\t\t\tconst key = colInfo.expr || colInfo.bind;\r\n\t\t\treturn key && activeFilters[key] && activeFilters[key].length > 0;\r\n\t\t});\r\n\t\tthis.classList.toggle('filtered', isFiltered);\r\n\t};\r\n\r\n\t#onClick = (e) => {\r\n\t\ttrace.log(e);\r\n\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tconst panel = this.#sheet.querySelector(\"nine-table-filter-panel\");\r\n\t\tconst cell = this.closest(\"th, td\");\r\n\t\tconst col = cell.dataset.col;\r\n\r\n\t\t//trace.log(panel, cell, col, panel.currentCol, panel.classList.contains('active'));\r\n\r\n\t\tif (panel && panel.currentCol === col && panel.classList.contains('active')) {\r\n\t\t\tpanel.close();\r\n\t\t} else if (panel) {\r\n\t\t\tpanel.open(this);\r\n\t\t}\r\n\t};\r\n}\r\n\r\nexport class Filtering {\r\n\t#sheet;\r\n\t#host;\r\n\t#isFiltering = false;\r\n\t#filterPanel = null;\r\n\t#filters = {};\r\n\r\n\tconstructor(sheet) {\r\n\t\tthis.#sheet = sheet;\r\n\t\tthis.#host = this.#sheet.getRootNode().host;\r\n\t\tthis.#init();\r\n\t}\r\n\r\n\tget filters() {\r\n\t\treturn this.#filters;\r\n\t};\r\n\r\n\t#init = () => {\r\n\t\tthis.#initFilterPanel();\r\n\t}\r\n\r\n\t#initFilterPanel = () => {\r\n\t\tif (this.#host.tagName.toLowerCase() === \"nine-table-simple\") {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet panel = this.#sheet.querySelector(\"nine-table-filter-panel\");\r\n\t\tif (!panel) {\r\n\t\t\tpanel = document.createElement(\"nine-table-filter-panel\");\r\n\t\t\tthis.#sheet.appendChild(panel);\r\n\t\t}\r\n\t\tthis.#filterPanel = panel;\r\n\t}\r\n\r\n\tisFiltering() {\r\n\t\treturn this.#isFiltering;\r\n\t}\r\n\r\n\tclear = (colnm) => {\r\n\t\tif (colnm) {\r\n\t\t\tdelete this.#filters[colnm];\r\n\t\t} else {\r\n\t\t\tthis.#filters = {};\r\n\t\t}\r\n\r\n\t\tthis.#isFiltering = Object.keys(this.#filters).length > 0;\r\n\t\tthis.#applyFiltering();\r\n\r\n\t\tthis.#sheet.querySelectorAll(\"nine-table-filter-button\").forEach(btn => {\r\n\t\t\tbtn.updateFilteredState();\r\n\t\t});\r\n\r\n\t\ttrace.log(`🔄 [NineTableFiltering] Filter cleared for ${colnm || 'all'}`);\r\n\t}\r\n\r\n\tset = (oFilter) => {\r\n\r\n\t\ttrace.log(oFilter);\r\n\r\n\t\tlet jsonFilter = Array.isArray(oFilter)\r\n\t\t\t? Object.fromEntries(Object.keys(oFilter[0]).map(k => [k, [...new Set(oFilter.map(item => item[k]))]]))\r\n\t\t\t: oFilter;\r\n\r\n\t\tthis.#filters = jsonFilter;\r\n\t\tthis.#isFiltering = Object.keys(jsonFilter).length > 0;\r\n\t\tthis.#sheet.toggleAttribute(\"filtering\", this.#isFiltering);\r\n\r\n\t\tthis.#applyFiltering();\r\n\t}\r\n\r\n\t#applyFiltering() {\r\n\t\tconst hostData = this.#host.data;\r\n\t\tconst rawRecords = hostData.getArray();\r\n\t\tconst fields = this.#host.data.getHostFields();\r\n\t\tconst sheetIndex = this.#sheet.index;\r\n\t\tconst exprEngine = this.#host.exprEngine;\r\n\r\n\t\tconst hasFilters = Object.keys(this.#filters).length > 0;\r\n\r\n\t\tif (!hasFilters) {\r\n\t\t\trawRecords.forEach(record => {\r\n\t\t\t\tif (record?.m?._?.[NINE_TABLE.META.INDEX.FILTER]) {\r\n\t\t\t\t\trecord.m._[NINE_TABLE.META.INDEX.FILTER][sheetIndex] = true;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tthis.#sheet.invalidate();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 💡 필터 규칙 빌드 (targetKey가 bind인지 expr 수식인지 판별)\r\n\t\tconst filterRules = Object.entries(this.#filters).map(([targetKey, allowedValues]) => {\r\n\t\t\tconst isExpr = targetKey.includes(\"data.\") || targetKey.includes(\"host.\") || targetKey.includes(\"rowItem.v\");\r\n\t\t\treturn {\r\n\t\t\t\ttargetKey,\r\n\t\t\t\tisExpr,\r\n\t\t\t\tfieldIdx: !isExpr ? fields.indexOf(targetKey) : -1,\r\n\t\t\t\tallowedSet: new Set(allowedValues)\r\n\t\t\t};\r\n\t\t});\r\n\r\n\t\trawRecords.forEach((record, recordIdx) => {\r\n\t\t\tif (!record) return;\r\n\r\n\t\t\tif (!record.m._[NINE_TABLE.META.INDEX.FILTER]) {\r\n\t\t\t\trecord.m._[NINE_TABLE.META.INDEX.FILTER] = [];\r\n\t\t\t}\r\n\r\n\t\t\tlet isPass = true;\r\n\r\n\t\t\tfor (let i = 0; i < filterRules.length; i++) {\r\n\t\t\t\tconst { targetKey, isExpr, fieldIdx, allowedSet } = filterRules[i];\r\n\t\t\t\tlet val = undefined;\r\n\r\n\t\t\t\tif (isExpr && exprEngine) {\r\n\t\t\t\t\tval = exprEngine.evaluate(targetKey, record, recordIdx);\r\n\t\t\t\t} else if (fieldIdx >= 0 && record.v) {\r\n\t\t\t\t\tval = record.v[fieldIdx];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!allowedSet.has(val)) {\r\n\t\t\t\t\tisPass = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\trecord.m._[NINE_TABLE.META.INDEX.FILTER][sheetIndex] = isPass;\r\n\t\t});\r\n\r\n\t\tthis.#sheet.invalidate();\r\n\t}\r\n}\r\n\r\nif (!customElements.get('nine-table-filter-panel')) {\r\n\tcustomElements.define(\"nine-table-filter-panel\", NineTableFilterPanel);\r\n}\r\n\r\nif (!customElements.get('nine-table-filter-button')) {\r\n\tcustomElements.define(\"nine-table-filter-button\", NineTableFilterButton);\r\n}","// ui/data/Sorting.js (또는 정렬 관련 소스)\r\nimport { trace } from \"@nopeer\";\r\nimport { TableCompiler } from \"@/layout/core/TableCompiler.js\";\r\n\r\nexport class Sorting {\r\n\t#sheet;\r\n\t#host;\r\n\r\n\t#columns = [];\r\n\r\n\tconstructor(sheet) {\r\n\t\tthis.#sheet = sheet;\r\n\t\tthis.#host = sheet.getRootNode().host;\r\n\r\n\t\tsetTimeout(() => {\r\n\t\t\tthis.#initEvents();\r\n\t\t}, 300);\r\n\t}\r\n\r\n\t#initEvents() {\r\n\r\n\t\tthis.#sheet.querySelectorAll(\"thead\").forEach($el => {\r\n\r\n\t\t\t$el.addEventListener('dblclick', (e) => {\r\n\r\n\t\t\t\tconst cell = e.target.closest('th, td');\r\n\t\t\t\tif (!cell || cell.classList.contains('resizable-edge')) return;\r\n\r\n\t\t\t\tif ([\"INPUT\",\"CELL-CHECKBOX\"].includes(e.target.tagName)) return;\r\n\r\n\t\t\t\t// 🎯 [수정] 줄바꿈으로 깨져있던 마이너스 연산자를 한 줄로 정상 복구\r\n\t\t\t\tif (e.offsetX <= 2 || e.offsetX >= cell.offsetWidth - 2) return;\r\n\r\n\t\t\t\tconst host = this.#sheet.getRootNode().host;\r\n\r\n\t\t\t\thost.loading = true;\r\n\t\t\t\tsetTimeout(() => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tthis.#handleSort(e, cell);\r\n\t\t\t\t\t} finally {\r\n\t\t\t\t\t\t// 🎯 3. 작업이 끝나면 무조건 로딩바 끄기\r\n\t\t\t\t\t\thost.loading = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}); // 또는 requestAnimationF\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\ttrace.log(\"🎯 [NineTableSorting] Initialized\");\r\n\t}\r\n\r\n\t#handleSort(e, cell) {\r\n\t\tconst colIndex = cell.dataset.col;\r\n\t\tconst tr = cell.closest('tr');\r\n\t\tconst subRowIndex = tr ? tr.dataset.subrow || String(tr.sectionRowIndex) : '0';\r\n\r\n\t\tif (colIndex === undefined) return;\r\n\r\n\t\tconst sourceTable = this.#sheet.sourceTable;\r\n\t\tif (!sourceTable) return;\r\n\r\n\t\tlet colName = null;\r\n\t\tlet exprVal = null; // 💡 expr 속성 수집용 변수\r\n\r\n\t\t// 1. 🎯 데이터 바인딩 키(colName) 및 expr 탐지\r\n\t\tsourceTable.querySelectorAll(`tbody [data-col=\"${colIndex}\"]`).forEach($td => {\r\n\t\t\tif ($td.dataset.bind) {\r\n\t\t\t\tcolName = $td.dataset.bind;\r\n\t\t\t}\r\n\t\t\t// 💡 셀에 선언된 expr 식 추출\r\n\t\t\tif ($td.dataset.expr) {\r\n\t\t\t\texprVal = $td.dataset.expr;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (!colName && !exprVal) return;\r\n\r\n\t\tconst isAsc = cell.classList.contains('asc');\r\n\t\tconst isDesc = cell.classList.contains('desc');\r\n\r\n\t\tif (!e.ctrlKey && !e.shiftKey) {\r\n\t\t\tthis.#columns = [];\r\n\t\t}\r\n\r\n\t\tconst existingColIndex = this.#columns.findIndex(\r\n\t\t\tm => (m.colIndex === colIndex && m.subRowIndex === subRowIndex) || m.colName === colName\r\n\t\t);\r\n\r\n\t\t// 정렬 규칙 추가 시 expr 속성(`expr`) 함께 저장\r\n\t\tconst ruleData = {\r\n\t\t\tcolIndex,\r\n\t\t\tsubRowIndex,\r\n\t\t\tcolname: colName || exprVal,\r\n\t\t\tcolName: colName || exprVal,\r\n\t\t\texpr: exprVal, // 💡 expr 규칙 보관\r\n\t\t\tasc: true,\r\n\t\t\t\"expr-func\": exprVal ? (record, idx) => this.#host.exprEngine(exprVal, record, idx) : null\r\n\t\t};\r\n\r\n\t\tif (!isAsc && !isDesc) {\r\n\t\t\tif (existingColIndex >= 0) {\r\n\t\t\t\tthis.#columns[existingColIndex].asc = true;\r\n\t\t\t} else {\r\n\t\t\t\tthis.#columns.push({ ...ruleData, asc: true });\r\n\t\t\t}\r\n\t\t} else if (isAsc) {\r\n\t\t\tif (existingColIndex >= 0) {\r\n\t\t\t\tthis.#columns[existingColIndex].asc = false;\r\n\t\t\t} else {\r\n\t\t\t\tthis.#columns.push({ ...ruleData, asc: false });\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis.#columns = this.#columns.filter(\r\n\t\t\t\tm => !((m.colIndex === colIndex && m.subRowIndex === subRowIndex) || m.colName === colName)\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tthis.#applySorting();\r\n\t}\r\n\r\n\t#applySorting() {\r\n\t\tif (!this.#sheet.view) {\r\n\t\t\tconsole.warn(\"⚠️ [NineTableSorting] Sheet view (SheetView) is not initialized.\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.#sheet.view.setSorting(this.#columns);\r\n\t\tthis.#syncHeaderUI();\r\n\t\tthis.#sheet.invalidate();\r\n\t\t//this.#sheet.rowManager?.refresh(true);\r\n\r\n\t\ttrace.log(\"🔄 [NineTableSorting] Sorting applied via RowManager.refresh(true)\");\r\n\t}\r\n\r\n\t#syncHeaderUI() {\r\n\t\t// 기존 UI 클래스 초기화\r\n\t\tthis.#sheet.querySelectorAll('thead th, thead td').forEach(el => {\r\n\t\t\tel.classList.remove('asc', 'desc');\r\n\t\t});\r\n\r\n\t\tif (this.#columns.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 🎯 [핵심] tr[data-subrow] + [data-col] 조합으로 정밀 타겟팅\r\n\t\tthis.#columns.forEach(colRule => {\r\n\t\t\tconst { colIndex, subRowIndex, asc } = colRule;\r\n\r\n\t\t\tif (colIndex !== undefined) {\r\n\t\t\t\tlet selector = `thead [data-col=\"${colIndex}\"]`;\r\n\t\t\t\tif (subRowIndex !== undefined) {\r\n\t\t\t\t\tselector = `thead tr[data-subrow=\"${subRowIndex}\"] [data-col=\"${colIndex}\"]`;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst targetHeaderCells = this.#sheet.querySelectorAll(selector);\r\n\t\t\t\ttargetHeaderCells.forEach(cell => {\r\n\t\t\t\t\tcell.classList.add(asc ? 'asc' : 'desc');\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t//TableCompiler.decompile(this.#sheet);\r\n\t}\r\n\r\n\trestore() {\r\n\t\tthis.#columns = [];\r\n\t\tif (this.#sheet.view) {\r\n\t\t\tthis.#sheet.view.resetSorting();\r\n\t\t}\r\n\r\n\t\tthis.#syncHeaderUI();\r\n\t\tthis.#sheet.rowManager?.refresh(true);\r\n\t}\r\n}","import { trace } from \"@nopeer\";\r\nimport { NINE_TABLE } from \"@/core/constants.js\";\r\nimport {Grouping} from \"@/data/Grouping.js\";\r\n\r\nexport class SheetView {\r\n\t#sheet;\r\n\t#host;\r\n\t#sortingColumns = []; // 정렬 규칙 [{ colname, asc, expr-func }]\r\n\t#filterRules = []; // 필터 규칙\r\n\t#viewIndexes = []; // 필터링 및 소팅이 반영된 유효 데이터 인덱스 버퍼\r\n\r\n\t#cachedVisibleRecords = null; // 💡 [추가] 캐싱된 유효 레코드 배열\r\n\r\n\tconstructor(sheet) {\r\n\t\tthis.#sheet = sheet;\r\n\t\tthis.#host = sheet.getRootNode().host;\r\n\r\n\t\tthis.refresh();\r\n\t}\r\n\r\n\t/**\r\n\t * 🎯 [시트 뷰 전용 배열 조회] - 캐시 적용으로 성능 대폭 개선\r\n\t */\r\n\tgetArray = (at, colnm) => {\r\n\t\t// 💡 캐시가 없거나 비어있을 때만 가져옴 (보통 refresh에서 갱신됨)\r\n\t\tif (!this.#cachedVisibleRecords) {\r\n\t\t\tconst records = this.#host.data.getArray();\r\n\t\t\tthis.#cachedVisibleRecords = this.#viewIndexes.map(idx => records[idx]);\r\n\t\t}\r\n\r\n\t\tconst visibleRecords = this.#cachedVisibleRecords;\r\n\r\n\t\tif (at === undefined || at === null) {\r\n\t\t\treturn visibleRecords;\r\n\t\t}\r\n\r\n\t\tif (at < 0 || at >= visibleRecords.length) return null;\r\n\r\n\t\tconst targetRecord = visibleRecords[at];\r\n\t\tif (colnm != null) {\r\n\t\t\tconst fields = this.#host.data.getHostFields();\r\n\t\t\tconst idx = fields.indexOf(colnm);\r\n\t\t\treturn (idx >= 0 && targetRecord.v) ? targetRecord.v[idx] : null;\r\n\t\t}\r\n\r\n\t\treturn targetRecord;\r\n\t};\r\n\r\n\tcount = () => {\r\n\t\t// 💡 캐시가 없거나 비어있을 때만 가져옴 (보통 refresh에서 갱신됨)\r\n\t\tif (!this.#cachedVisibleRecords) {\r\n\t\t\tconst records = this.#host.data.getArray();\r\n\t\t\tthis.#cachedVisibleRecords = this.#viewIndexes.map(idx => records[idx]);\r\n\t\t}\r\n\r\n\t\treturn this.#cachedVisibleRecords.length;\r\n\t}\r\n\r\n\tget = (at, colnm) => {\r\n\t\tconst visibleRecords = this.getArray();\r\n\t\tconst fields = this.#host.data.getHostFields?.() || [];\r\n\r\n\t\tif (at === undefined || at === null) {\r\n\t\t\treturn visibleRecords.map(record => this.#convSingle(record, fields));\r\n\t\t}\r\n\r\n\t\tif (at < 0 || at >= visibleRecords.length) return null;\r\n\r\n\t\tconst targetRecord = visibleRecords[at];\r\n\t\tif (!targetRecord) return null;\r\n\r\n\t\tif (colnm != null) {\r\n\t\t\tconst idx = fields.indexOf(colnm);\r\n\t\t\treturn (idx >= 0 && targetRecord.v) ? targetRecord.v[idx] : null;\r\n\t\t}\r\n\r\n\t\treturn this.#convSingle(targetRecord, fields);\r\n\t};\r\n\r\n\t#convSingle = (o, fields) => {\r\n\t\tif (!o) return null;\r\n\t\tconst t = {};\r\n\t\tfields.forEach((colnm, i) => {\r\n\t\t\tt[colnm] = o.v ? o.v[i] : o[colnm];\r\n\t\t});\r\n\t\tif (o.m) t.m = o.m;\r\n\t\tif (o._) t._ = o._;\r\n\t\treturn t;\r\n\t};\r\n\r\n\t/**\r\n\t * 🎯 유효 데이터 또는 정렬/필터 변경 시에만 실행되는 뷰 버퍼 재계산\r\n\t */\r\n\t\t// SheetView.refresh() 내부 예시\r\n\trefresh = () => {\r\n\r\n\t\tthis.#cachedVisibleRecords = null;\r\n\r\n\t\t// 1. 필터 적용\r\n\t\tconst rawRecords = this.#host.data.getArray();\r\n\t\tlet indices = [];\r\n\t\trawRecords.forEach((record, i) => {\r\n\t\t\tif (!record) return;\r\n\t\t\tconst filterSlot = record.m?._?.[NINE_TABLE.META.INDEX.FILTER];\r\n\t\t\tif (filterSlot && filterSlot[this.#sheet.index] === false) return;\r\n\t\t\tindices.push(i);\r\n\t\t});\r\n\r\n\t\t// 2. 정렬 적용\r\n\t\tif (this.#sortingColumns.length > 0) {\r\n\t\t\tindices = this.#applySorting(indices, rawRecords);\r\n\t\t}\r\n\r\n\t\tthis.#viewIndexes = indices;\r\n\t\tconst validRecords = indices.map(idx => rawRecords[idx]);\r\n\r\n\t\t//trace.log(this.#sheet.sourceTable);\r\n\t\t//const isGrouped = this.#sheet.sourceTable?.querySelector(\"tbody tr[grouping='true']\") ? true : false;\r\n\t\t//trace.log(\"#######\", isGrouped, this.#sheet.grouping?.columns);\r\n\t\tconst groupColumns = this.#sheet.grouping?.columns || [];\r\n\t\tif (groupColumns.length > 0) {\r\n\t\t\t//this.#sheet.grouping.apply();\r\n\t\t\tconst groupResult = Grouping.apply(validRecords, groupColumns, this.#host.data.getHostFields());\r\n\t\t\t//const groupResult = Grouping.apply(validRecords);\r\n\t\t\tthis.#cachedVisibleRecords = groupResult.renderItems; // 최종 렌더링 아이템\r\n\r\n\t\t\t//trace.log(\"2.============================\", groupColumns, this.#cachedVisibleRecords);\r\n\r\n\t\t\tthis.#sheet.grouping.setGroupMap(groupResult.groupMap); // 자식 매핑 공유\r\n\t\t} else {\r\n\t\t\tthis.#cachedVisibleRecords = validRecords;\r\n\t\t}\r\n\r\n\r\n\r\n\t}\r\n\r\n\tsetSorting = (columns) => {\r\n\t\tthis.#sortingColumns = columns || [];\r\n\t\tthis.refresh();\r\n\t};\r\n\r\n\tgetSorting = () => {\r\n\t\treturn this.#sortingColumns;\r\n\t};\r\n\r\n\tresetSorting = () => {\r\n\t\tthis.#sortingColumns = [];\r\n\t\tthis.refresh();\r\n\t};\r\n\r\n\r\n\t#applySorting = (indices, validRecords) => {\r\n\t\ttrace.log(new Date());\r\n\r\n\t\tconst fields = typeof this.#host.data.getHostFields === 'function' ? this.#host.data.getHostFields() : [];\r\n\r\n\t\tconst rulesWithIdx = this.#sortingColumns.map(rule => ({\r\n\t\t\t...rule,\r\n\t\t\tcolIndex: fields.indexOf(rule.colname || rule.colName)\r\n\t\t}));\r\n\r\n\t\treturn indices.sort((idxA, idxB) => {\r\n\t\t\tconst a = validRecords[idxA];\r\n\t\t\tconst b = validRecords[idxB];\r\n\r\n\t\t\tfor (const rule of rulesWithIdx) {\r\n\t\t\t\tconst isAsc = rule.asc;\r\n\t\t\t\tconst expr = rule.expr; // 💡 등록된 expr 수식\r\n\t\t\t\tlet valA, valB;\r\n\r\n\t\t\t\t// 💡 1. expr 수식이 존재하면 ExprEngine으로 연산된 결과값을 가져옴\r\n\t\t\t\tif (expr) {\r\n\t\t\t\t\tvalA = this.#host.exprEngine.evaluate(expr, a, idxA);\r\n\t\t\t\t\tvalB = this.#host.exprEngine.evaluate(expr, b, idxB);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 2. 일반 바인딩 필드인 경우 원시 배열에서 추출\r\n\t\t\t\t\tif (rule.colIndex >= 0 && a.v && b.v) {\r\n\t\t\t\t\t\tvalA = a.v[rule.colIndex];\r\n\t\t\t\t\t\tvalB = b.v[rule.colIndex];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst isEmptyA = (valA === null || valA === undefined || valA === '');\r\n\t\t\t\tconst isEmptyB = (valB === null || valB === undefined || valB === '');\r\n\r\n\t\t\t\tif (isEmptyA && isEmptyB) continue;\r\n\t\t\t\tif (isEmptyA) return 1;\r\n\t\t\t\tif (isEmptyB) return -1;\r\n\r\n\t\t\t\tif (valA !== valB) {\r\n\t\t\t\t\tlet diff = 0;\r\n\r\n\t\t\t\t\tif (typeof valA === 'number' && typeof valB === 'number') {\r\n\t\t\t\t\t\tdiff = valA - valB;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tconst strA = String(valA);\r\n\t\t\t\t\t\tconst strB = String(valB);\r\n\t\t\t\t\t\tdiff = strA > strB ? 1 : (strA < strB ? -1 : 0);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (diff !== 0) {\r\n\t\t\t\t\t\treturn isAsc ? diff : -diff;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn idxA - idxB;\r\n\t\t});\r\n\r\n\t\ttrace.log(new Date());\r\n\t};\r\n}","import { trace } from \"@nopeer\";\nimport { TableCompiler } from \"@/layout/core/TableCompiler.js\";\n\nexport const COLLAPSED_WIDTH = 16;\n\nexport class PreCompiler {\n\n static initializeTable(host, tbl) {\n\n // 1. 기본 구조 보장 (colgroup, thead)\n PreCompiler.#ensureColgroup(tbl);\n PreCompiler.#ensureThead(tbl);\n PreCompiler.#ensureSectionTbodys(tbl);\n\n PreCompiler.#ensureRowIndicator(tbl);\n\n PreCompiler.#normalizeColAttributes(tbl);\n\n TableCompiler.resetColIndex(tbl, tbl.querySelectorAll('thead tr'));\n TableCompiler.resetColIndex(tbl, tbl.querySelectorAll('tbody.body tr[grouping=\"true\"]'));\n TableCompiler.resetColIndex(tbl, tbl.querySelectorAll('tbody.body tr:not([grouping=\"true\"])'));\n TableCompiler.resetColIndex(tbl, tbl.querySelectorAll('tfoot tr'));\n\n PreCompiler.#createColIndicator(tbl);\n\n // 2. 속성 정규화 (collapsed=\"true\" -> collapsible=\"true\" 보정)\n PreCompiler.#normalizeCollapsibleAttributes(tbl);\n\n // 3. 셀 커스텀 엘리먼트 생성\n PreCompiler.#generateCell(host, tbl);\n\n // 5. 초기 접힘/펼치기(expand) 버튼 및 너비 세팅\n PreCompiler.#initColExpanders(tbl);\n\n // 6. 필터 버튼 생성\n PreCompiler.#initFilterButtons(host, tbl);\n\n PreCompiler.#applyInitialCellWidths(tbl);\n //tbl.classList.add('nine-table-element');\n\n //trace.log(\"**************\", tbl.cloneNode(true));\n return tbl;\n }\n\n static #createColIndicator(tbl) {\n const thead = tbl.querySelector('thead');\n if (!thead || thead.querySelector('.col-indicator-rowgroup')) return;\n\n const tdTmpl = `<th data-col=\"@col\" class=\"col-indicator\" scope=\"col\"></th>`;\n\n // 맨 위에 인덱스용 row(tr) 삽입\n const tr = thead.insertRow(0);\n tr.setAttribute('role', 'row');\n tr.classList.add('col-indicator-rowgroup');\n tr.classList.add('collapse');\n\n const firstRow = tbl.querySelector('tbody tr');\n if (!firstRow) return;\n\n let cnt = 0;\n firstRow.querySelectorAll('th, td').forEach(td => {\n if (!td.classList.contains('dummy')) {\n const colSpan = td.colSpan || 1;\n for (let i = 0; i < colSpan; i++) {\n const html = tdTmpl.replace('@col', cnt).replace('@text', PreCompiler.#numToExcelCol(cnt++));\n tr.insertAdjacentHTML('beforeend', html);\n }\n }\n });\n\n // 🎯 colgroup의 모든 스타일 및 속성 동기화\n const cols = Array.from(tbl.querySelectorAll('colgroup col'));\n tr.querySelectorAll('.col-indicator').forEach((el, i) => {\n const background = cols[i].getAttribute('background');\n if (background) {\n el.style.background = background;\n }\n });\n }\n\n // 엑셀 스타일 알파벳 변환 유틸 (A, B, C ... Z, AA, AB ...)\n static #numToExcelCol(num) {\n let text = '';\n for (let n = num; n >= 0; n = Math.floor(n / 26) - 1) {\n text = String.fromCharCode(65 + (n % 26)) + text;\n }\n return text;\n }\n\n static #ensureSectionTbodys(tbl) {\n let tbody = tbl.querySelector('tbody:not(.head):not(.foot)');\n\n if (!tbody) return;\n\n tbody.classList.add('body');\n\n // 🎯 이미 존재하지 않을 때만 생성\n if (!tbl.querySelector('tbody.head')) {\n const headTbody = document.createElement('tbody');\n headTbody.classList.add('head');\n tbody.before(headTbody);\n }\n\n if (!tbl.querySelector('tbody.foot')) {\n const footTbody = document.createElement('tbody');\n footTbody.classList.add('foot');\n tbody.after(footTbody);\n }\n }\n\n static #ensureColgroup(tbl) {\n let colgroup = tbl.querySelector('colgroup');\n if (!colgroup) {\n colgroup = document.createElement('colgroup');\n tbl.prepend(colgroup);\n }\n\n // 🎯 <col> 엘리먼트 자체가 없다면 행 기준으로 생성\n if (colgroup.querySelectorAll('col').length === 0) {\n const firstRow = tbl.querySelector('tbody tr');\n let colCount = 1;\n if (firstRow) {\n colCount = Array.from(firstRow.querySelectorAll('th, td')).reduce((sum, cell) => {\n return sum + (parseInt(cell.getAttribute('colspan') || cell.colSpan, 10) || 1);\n }, 0);\n }\n colCount = Math.max(colCount, 1);\n\n for (let i = 0; i < colCount; i++) {\n const col = document.createElement('col');\n colgroup.appendChild(col);\n }\n }\n\n // 🎯 col 속성 및 너비 정리는 별도 함수로 분리\n //PreCompiler.#normalizeColAttributes(tbl);\n }\n\n // 🎯 <col>들의 data-col, width, style.width 속성 정리를 전담하는 메서드\n static #normalizeColAttributes(tbl) {\n const cols = Array.from(tbl.querySelectorAll('colgroup col'));\n if (cols.length === 0) return;\n\n const containerWidth = tbl.clientWidth || 0;\n const defaultWidth = Math.max(Math.floor(containerWidth / cols.length), 100);\n\n cols.forEach((col, i) => {\n // 1. data-col 인덱스 보장\n if (!col.hasAttribute('data-col')) {\n col.setAttribute('data-col', i);\n }\n\n // 2. width 속성 및 style.width 정규화\n const width = col.getAttribute('width') || parseInt(col.style.width, 10) || defaultWidth;\n col.setAttribute('width', width);\n\n const widthVal = String(width).includes('px') ? width : `${width}px`;\n col.style.width = widthVal;\n });\n }\n\n static #ensureThead(tbl) {\n if (tbl.querySelector('thead')) return;\n\n const thead = document.createElement('thead');\n const colgroup = tbl.querySelector('colgroup');\n\n if (colgroup) {\n colgroup.after(thead);\n } else {\n tbl.prepend(thead);\n }\n }\n\n static #normalizeCollapsibleAttributes(tbl) {\n const headers = tbl.querySelectorAll('thead th, thead td');\n headers.forEach(cell => {\n const isCollapsed = cell.getAttribute('collapsed') === 'true';\n if (isCollapsed && cell.getAttribute('collapsible') !== 'true') {\n cell.setAttribute('collapsible', 'true');\n }\n });\n }\n\n static #generateCell(host, $tbl) {\n\n const targetAttributes = ['data-bind', 'data-expr', 'type'];\n let autoIdCounter = 0;\n\n $tbl.querySelectorAll('tbody th, tbody td').forEach($cell => {\n const cellType = $cell.getAttribute('cell-type') || \"renderer\";\n const tagName = `cell-${cellType}`;\n\n const $datalist = $cell.querySelector(\"datalist\");\n\n if ($datalist) {\n let l = [];\n $datalist.querySelectorAll('option').forEach($option => {\n l.push({\n k: $option.getAttribute(\"k\"),\n v: $option.getAttribute(\"v\"),\n value: $option.getAttribute(\"value\"),\n });\n });\n\n // 🎯 1. 절대 겹치지 않는 유니크한 가상 함수 이름 생성\n const uniqueFuncName = `__ds_${Date.now()}_${++autoIdCounter}`;\n\n // 🎯 2. 호스트(NineTable)에 해당 데이터를 반환하는 클로저 함수 등록\n if (host) {\n host[uniqueFuncName] = () => l;\n }\n\n // 🎯 3. 셀에 data-source 자동 장착 (정규식/세터 스캔기가 알아서 캐치함)\n $cell.setAttribute(\"data-source\", `host.${uniqueFuncName}()`);\n\n // 🎯 4. 사용이 끝난 정적 datalist 엘리먼트는 DOM에서 제거\n $datalist.remove();\n }\n\n const expr = $cell.dataset.expr;\n if (expr) {\n $cell.setAttribute('data-expr', host.exprEngine.precompile(expr));\n }\n\n // 💡 2. 기타 속성들 중 표현식이 포함된 경우 프리컴파일\n Array.from($cell.attributes).forEach(attr => {\n if (['data-bind', 'data-expr', 'cell-type', 'validator'].includes(attr.name)) return;\n if (attr.value.includes(\"data.\") || attr.value.includes(\"host.\")) {\n $cell.setAttribute(attr.name, host.exprEngine.precompile(attr.value));\n }\n });\n\n const innerAttrs = targetAttributes\n .filter(attr => $cell.hasAttribute(attr))\n .map(attr => `${attr}=\"${$cell.getAttribute(attr)}\"`);\n\n $cell.innerHTML = `<${tagName} ${innerAttrs.join(' ')}></${tagName}>`;\n $cell.setAttribute('tabindex', '0');\n });\n\n $tbl.querySelectorAll('thead th, thead td, tfoot th, tfoot td').forEach($cell => {\n const cellType = $cell.getAttribute('cell-type');\n if (cellType) {\n const originalContent = $cell.innerHTML;\n const tagName = `cell-${cellType}`;\n const innerAttrs = targetAttributes\n .filter(attr => $cell.hasAttribute(attr))\n .map(attr => `${attr}=\"${$cell.getAttribute(attr)}\"`);\n\n $cell.innerHTML = `<${tagName} ${innerAttrs.join(' ')} content=\"${originalContent}\"></${tagName}>`;\n }\n });\n }\n\n static #initFilterButtons(host, tbl) {\n const hostFilter = host.getAttribute('filtering') === 'true';\n const tableFilter = tbl.getAttribute('filtering') === 'true';\n\n // 🎯 인덱스 행을 제외한 실제 헤더 셀들만 타겟팅\n tbl.querySelectorAll('thead tr:not(.col-indicator-rowgroup) th, thead tr:not(.col-indicator-rowgroup) td').forEach(cell => {\n const finalFiltering = cell.getAttribute('filtering') === 'true' || tableFilter || hostFilter;\n\n cell.setAttribute('filtering', finalFiltering ? 'true' : 'false');\n\n if (finalFiltering) {\n cell.appendChild(document.createElement('nine-table-filter-button'));\n }\n });\n }\n\n static #initColExpanders(tbl) {\n /** 작동하나? */\n tbl.querySelectorAll('thead th, thead td').forEach(cell => {\n const isCollapsible = cell.getAttribute('collapsible') === 'true' || cell.getAttribute('expandable') === 'true';\n if (!isCollapsible) return;\n\n const colIndex = parseInt(cell.dataset.col, 10);\n const colSpan = cell.colSpan || 1;\n const col = tbl.querySelector(`colgroup col[data-col=\"${colIndex}\"]`);\n\n const currentWidth = col ? (parseInt(col.getAttribute('width'), 10) || 100) : 100;\n\n if (!cell.dataset.expandWidth || parseInt(cell.dataset.expandWidth, 10) <= COLLAPSED_WIDTH) {\n cell.dataset.expandWidth = String(currentWidth > COLLAPSED_WIDTH ? currentWidth : 100);\n }\n\n let expandBtn = cell.querySelector('nine-table-col-expand');\n if (!expandBtn) {\n expandBtn = document.createElement('nine-table-col-expand');\n cell.insertBefore(expandBtn, cell.firstChild);\n }\n\n const isCollapsed = cell.getAttribute('collapsed') === 'true';\n\n if (isCollapsed) {\n expandBtn.classList.add('collapsed');\n expandBtn.classList.remove('expand');\n expandBtn.setAttribute('collapsed', 'true');\n cell.style.color = 'transparent';\n\n const targetWidth = Math.max(10, Math.floor(COLLAPSED_WIDTH / colSpan));\n if (!isNaN(colIndex)) {\n for (let i = 0; i < colSpan; i++) {\n const targetCol = tbl.querySelector(`colgroup col[data-col=\"${colIndex + i}\"]`);\n if (targetCol) {\n targetCol.setAttribute('width', targetWidth);\n targetCol.style.width = `${targetWidth}px`;\n }\n }\n }\n } else {\n expandBtn.classList.remove('collapsed');\n expandBtn.classList.add('expand');\n expandBtn.setAttribute('collapsed', 'false');\n cell.style.color = '';\n }\n });\n }\n\n static #ensureRowIndicator(tbl, host) {\n // 1. colgroup에 인디케이터용 <col> 추가\n const w = tbl.getAttribute(\"row-indicator\") === 'true' ? 48 : 0;\n\n const colgroup = tbl.querySelector('colgroup');\n\n //if (colgroup && !colgroup.querySelector('col.row-indicator-col')) {\n const col = document.createElement('col');\n //col.className = 'row-indicator-col';\n col.setAttribute('fixed', 'left');\n col.setAttribute('width', w);\n col.style.width = `${w}px`;\n colgroup.prepend(col);\n //}\n\n // 2. thead, tbody, tfoot 각 섹션별로 첫 번째 tr에 인디케이터 생성 및 rowSpan 부여\n //const sections = tbl.querySelectorAll('thead, tbody, tfoot');\n\n tbl.querySelectorAll('thead, tbody, tfoot').forEach(section => {\n const rows = Array.from(section.querySelectorAll('tr'));\n if (rows.length === 0) return;\n\n const firstTr = rows[0];\n\n const indicatorCell = document.createElement('th');\n indicatorCell.className = 'row-indicator';\n indicatorCell.setAttribute('cell-type', 'row-indicator');\n //indicatorCell.setAttribute('filtering', 'false');\n\n // 💡 섹션 내 행이 여러 개면(멀티 라인 템플릿 등) 전체를 아우르도록 rowSpan 설정\n if (rows.length > 1) {\n indicatorCell.rowSpan = rows.length;\n }\n\n firstTr.insertBefore(indicatorCell, firstTr.firstElementChild);\n });\n }\n\n static #applyInitialCellWidths(tbl) {\n // 🎯 컬럼 기준이 아닌 셀(th, td) 기준으로 순회하여 colspan 반영\n tbl.querySelectorAll('th[data-col], td[data-col]').forEach(cell => {\n\n const startColIdx = parseInt(cell.getAttribute('data-col'), 10);\n if (isNaN(startColIdx)) return;\n\n // 셀의 실제 colspan 값 추출 (기본값 1)\n const colSpan = parseInt(cell.getAttribute('colspan') || cell.colSpan, 10) || 1;\n let totalWidth = 0;\n\n // colspan 만큼 다음 컬럼들의 너비를 누적 합산\n for (let i = 0; i < colSpan; i++) {\n const targetIdx = startColIdx + i;\n const col = tbl.querySelector(`colgroup col[data-col=\"${targetIdx}\"]`);\n if (col) {\n totalWidth += parseInt(col.getAttribute('width'), 10) || 100;\n }\n }\n\n if (totalWidth > 0) {\n const widthVal = `${totalWidth}px`;\n cell.style.width = widthVal;\n cell.style.minWidth = widthVal;\n cell.style.maxWidth = widthVal;\n }\n });\n }\n}","// NineTableSheet.js (필터 버튼 레이아웃 및 패딩 스타일 완벽 통합본)\n\nimport { trace } from \"@nopeer\";\nimport './nine-table-hscrollbar.js';\nimport './nine-table-vscrollbar.js';\nimport { RowManager } from './core/RowManager.js';\nimport { TableCompiler } from \"./core/TableCompiler.js\";\nimport { CellSelection } from \"@/cell-manager/CellSelection.js\";\nimport { CellNavigation } from \"@/cell-manager/CellNavigation.js\";\n\nimport { ColResizer } from \"@/col/ColResizer.js\";\nimport { ColMover } from \"@/col/ColMover.js\";\nimport { ColFixManager } from \"@/col/ColFixManager.js\";\n\nimport { Filtering } from \"@/data/Filtering.js\";\nimport {Grouping, GroupingManager} from \"@/data/Grouping.js\";\nimport { Sorting } from \"@/data/Sorting.js\";\nimport { SheetView } from \"@/data/SheetView.js\";\n\nimport { PreCompiler } from \"@/layout/core/PreCompiler.js\";\n\nexport class NineTableSheet extends HTMLElement {\n #index;\n #host;\n #rowManager;\n #cellSelection;\n #cellNavigation;\n #colResizer;\n #colMover;\n #colFix;\n #sorting;\n #filtering;\n #grouping;\n\n #view;\n\n #source = {\n table: null,\n };\n\n #elements;\n\n static SCROLLBAR_SIZE = 16;\n\n constructor() {\n super();\n\n this.#host = this.getRootNode().host;\n this.#rowManager = new RowManager(this);\n }\n\n connectedCallback() {\n this.#init();\n }\n\n get index() { return this.#index; }\n get colResizer() { return this.#colResizer; }\n get filtering() { return this.#filtering; }\n get grouping() { return this.#grouping; }\n get colMover() { return this.#colMover; }\n get colFix() { return this.#colFix; }\n get rowManager() { return this.#rowManager; }\n get selection() { return this.#cellSelection; }\n get navigation() { return this.#cellNavigation; }\n get templateLength() { return this.#source.tbody.tr.length || 0; }\n\n get elements() { return this.#elements; }\n\n get isAutoFitCol() {\n const attrTrue = this.getAttribute('auto-fit-col') === 'true' || this.#host?.getAttribute('auto-fit-col') === 'true';\n const sourceTableTrue = this.#source.table?.getAttribute('auto-fit-col') === 'true';\n return attrTrue || sourceTableTrue;\n }\n\n get sourceTable() {\n return this.#source.table;\n }\n\n get source() {\n return this.#source;\n }\n\n get #isSimple() {\n return this.#host.hasAttribute('simple') || this.#host.getAttribute('theme') === 'simple';\n }\n\n recompileAndRefresh() {\n if (!this.#source.table) return;\n\n TableCompiler.recompile(this.#source.table);\n\n ['left', 'right', 'body'].forEach(type => {\n ['header', 'body', 'footer'].forEach(section => {\n const container = this.querySelector(`.ng-sheet-${section} .ng-container-${type}`);\n if (!container) return;\n container.querySelectorAll('table').forEach(tbl => tbl.remove());\n });\n });\n\n this.#renderSplitContainers();\n\n this.#updateContainerWidths();\n\n this.#rowManager.initialize();\n\n if (this.isAutoFitCol) {\n this.autoFit(true);\n } else {\n this.querySelector('nine-table-hscrollbar')?.refresh();\n }\n\n requestAnimationFrame(() => {\n this.#updateContainerWidths();\n this.#rowManager?.refresh();\n });\n }\n\n refreshLayout() {\n\n requestAnimationFrame(() => {\n trace.log(\"*************************\", this.classList, this.#source.table);\n\n if (!this.classList.contains('active') || !this.#source.table) return;\n\n this.#updateContainerWidths();\n\n if (this.isAutoFitCol) {\n this.autoFit(true);\n } else {\n this.querySelector('nine-table-hscrollbar')?.refresh();\n }\n\n this.#adjustOverlay();\n\n this.#colResizer?.refreshLayout();\n\n this.#rowManager?.refresh();\n });\n }\n\n #adjustOverlay = () => {\n // 3분할된 영역 중 중앙(body) 또는 좌측 영역의 thead를 타겟팅하여 높이 측정\n const $thead = this.querySelector('.ng-container-body thead');\n const $overlay = this.querySelector('.nodata-overlay');\n $overlay.style.top = `${$thead.offsetHeight}px`;\n\n trace.log(\"***************************************\", $thead);\n trace.log($thead.offsetHeight);\n }\n\n get view() {\n if (!this.#view && this.#host?.data) {\n this.#view = new SheetView(this);\n }\n return this.#view;\n }\n\n invalidate = () => {\n\n this.view.refresh();\n\n this.#rowManager.refresh(true);\n\n if (this.isAutoFitCol) {\n this.autoFit(true);\n }\n };\n\n autoFit = (enable = true) => {\n requestAnimationFrame(() => {\n this.#autoFit?.(enable);\n });\n };\n\n #autoFit = (enable = true) => {\n trace.log(\"***************** autoFit\", this);\n\n const container = this.querySelector('.ng-sheet-body .ng-container-body');\n if (!container) return;\n\n //const tables = container.querySelectorAll('table');\n const firstColgroup = this.querySelector('.ng-container-body table colgroup');\n if (!firstColgroup) return;\n\n if (enable) {\n this.setAttribute('auto-fit-col', 'true');\n const containerWidth = container.clientWidth;\n if (containerWidth <= 0) return;\n\n let totalOriginalWidth = 0;\n const colList = [];\n\n // 1단계: 접힌 컬럼(16px 고정)과 일반 컬럼을 분리해서 수집\n firstColgroup.querySelectorAll('col').forEach(col => {\n const globalColIndex = col.getAttribute('data-col');\n const headerCell = this.querySelector(`thead th[data-col=\"${globalColIndex}\"]`);\n const isCollapsed = headerCell?.getAttribute('collapsed') === 'true';\n\n if (isCollapsed) {\n colList.unshift({ globalColIndex, width: 16, isCollapsed: true });\n trace.log(`[AutoFit Col] Index ${globalColIndex}: COLLAPSED (forced 16px)`);\n } else {\n const w = parseInt(col.getAttribute('width'), 10) || 100;\n colList.push({ globalColIndex, width: w, isCollapsed: false });\n totalOriginalWidth += w;\n trace.log(`[AutoFit Col] Index ${globalColIndex}: NORMAL (original width: ${w}px)`);\n }\n });\n\n trace.log(`[AutoFit] Total Original Width of Normal Cols: ${totalOriginalWidth}px`);\n\n // 접힌 컬럼들이 차지하는 총 너비 계산\n const collapsedTotalWidth = colList\n .filter(c => c.isCollapsed)\n .reduce((sum, c) => sum + c.width, 0);\n\n // 남은 컨테이너 너비를 펼쳐진 컬럼들에게만 배분 (오류 수정)\n const availableWidth = Math.max(0, containerWidth - collapsedTotalWidth);\n trace.log(`[AutoFit] Collapsed Total Width: ${collapsedTotalWidth}px | Available Width for Normal Cols: ${availableWidth}px`);\n\n if (totalOriginalWidth > 0 && colList.length > 0) {\n let allocatedTotal = 0;\n\n const calculatedCols = colList.map(item => {\n if (item.isCollapsed) {\n return { globalColIndex: item.globalColIndex, remainder: 0, width: 16 };\n }\n\n // 연산자 오류 수정 (* 와 - 추가)\n const exactWidth = (item.width * availableWidth) / totalOriginalWidth;\n const baseWidth = Math.max(30, Math.floor(exactWidth));\n allocatedTotal += baseWidth;\n return {\n globalColIndex: item.globalColIndex,\n remainder: exactWidth - Math.floor(exactWidth),\n width: baseWidth\n };\n });\n\n // 잔여 픽셀 보정 (오류 수정)\n let remainderPixels = availableWidth - allocatedTotal;\n trace.log(`[AutoFit] Initial Allocated Total: ${allocatedTotal}px | Remainder Pixels to distribute: ${remainderPixels}`);\n\n const uncollapsedCols = calculatedCols.filter(c => !colList.find(item => item.globalColIndex === c.globalColIndex)?.isCollapsed);\n\n if (remainderPixels > 0 && uncollapsedCols.length > 0) {\n uncollapsedCols.sort((a, b) => b.remainder - a.remainder);\n for (let i = 0; i < remainderPixels; i++) {\n uncollapsedCols[i % uncollapsedCols.length].width += 1;\n }\n } else if (remainderPixels < 0 && uncollapsedCols.length > 0) {\n uncollapsedCols.sort((a, b) => a.remainder - b.remainder);\n for (let i = 0; i < Math.abs(remainderPixels); i++) {\n const target = uncollapsedCols[i % uncollapsedCols.length];\n if (target.width > 30) target.width -= 1;\n }\n }\n\n const finalSumWidth = calculatedCols.reduce((sum, c) => sum + c.width, 0);\n trace.log(`[AutoFit Verification] Target Container Width: ${containerWidth}px | Sum of All Calculated Cols: ${finalSumWidth}px`);\n\n if (containerWidth !== finalSumWidth) {\n trace.log(`⚠️ [AutoFit Mismatch Warning!] 오차 발생: ${containerWidth - finalSumWidth}px 차이가 납니다.`);\n } else {\n trace.log(`✅ [AutoFit Success] 완벽하게 일치합니다!`);\n }\n\n // 최종 적용\n calculatedCols.forEach(({ globalColIndex, width }) => {\n trace.log(`[AutoFit Apply] Col Index ${globalColIndex} -> ${width}px`);\n this.#colResizer?.setColumnWidth(globalColIndex, width, 'body');\n });\n }\n } else {\n this.removeAttribute('auto-fit-col');\n }\n\n this.querySelector('nine-table-hscrollbar')?.refresh();\n }\n\n generate = ($table, index) => {\n\n $table.style.display = 'none';\n\n this.#index = index;\n\n PreCompiler.initializeTable(this.#host, $table);\n\n $table.style.display = '';\n\n this.#source = {\n table: TableCompiler.compile($table),\n tbody: {\n tr: $table.querySelectorAll(\"tbody tr\"),\n }\n };\n\n\n //trace.log(\"---------\", this, this.sourceTable.cloneNode(true));\n this.#renderSplitContainers();\n //trace.log(\"---------\", this, this.sourceTable.cloneNode(true));\n\n this.#updateContainerWidths();\n //trace.log(\"---------\", this, this.sourceTable.cloneNode(true));\n\n this.#syncHeaderAndFooterHeights();\n //trace.log(\"---------\", this, this.sourceTable.cloneNode(true));\n //\n this.#initRowHoverEvent();\n\n ['left', 'body', 'right'].forEach(type => {\n const prefix = `.ng-container-${type}`;\n this.#elements[type] = {\n thead: this.querySelector(`${prefix} thead`),\n tbody: {\n head: this.querySelector(`${prefix} tbody.head`),\n body: this.querySelector(`${prefix} tbody.body`),\n foot: this.querySelector(`${prefix} tbody.foot`),\n },\n tfoot: this.querySelector(`${prefix} tfoot`),\n };\n });\n\n //trace.log(\"---------\", this, this.sourceTable.cloneNode(true));\n //trace.log(\"********1\", this.#source.table)\n\n this.#rowManager.initialize();\n\n if (this.isAutoFitCol) {\n this.autoFit(true);\n } else {\n this.querySelector('nine-table-hscrollbar').refresh();\n }\n\n //this.#grouping = new GroupingManager(this);\n this.#grouping.initialize();\n\n this.loaded = true;\n };\n\n\n #updateContainerWidths = () => {\n const isAutoFit = this.isAutoFitCol;\n\n ['left', 'right', 'body'].forEach(type => {\n const containers = this.querySelectorAll(`.ng-container-${type}`);\n if (containers.length === 0) return;\n\n const firstTable = containers[0].querySelector('table');\n if (!firstTable) return;\n\n let width = 0;\n firstTable.querySelectorAll('col').forEach(col => {\n const w = parseInt(col.getAttribute('width'), 10);\n if (!isNaN(w)) width += w;\n });\n\n containers.forEach(container => {\n const tables = container.querySelectorAll('table');\n if (type === 'body') {\n container.style.flex = `1`;\n tables.forEach(tbl => {\n //tbl.style.width = isAutoFit ? `100%` : `${width}px`;\n //tbl.style.minWidth = isAutoFit ? `100%` : `${width}px`;\n });\n } else {\n container.style.flex = `0 0 ${width}px`;\n container.style.width = `${width}px`;\n container.style.minWidth = `${width}px`;\n container.style.maxWidth = `${width}px`;\n tables.forEach(tbl => {\n //tbl.style.width = `${width}px`;\n //tbl.style.minWidth = `${width}px`;\n });\n }\n });\n });\n };\n\n #renderSplitContainers = () => {\n const colTypes = [\n { selector: '.ng-container-left', type: 'left' },\n { selector: '.ng-container-body', type: null },\n { selector: '.ng-container-right', type: 'right' }\n ];\n\n colTypes.forEach(({ selector, type }) => {\n this.querySelector(`.ng-sheet-body ${selector}`).appendChild(this.#createSplitTable(type));\n });\n };\n\n #createSplitTable = (targetFixedType) => {\n\n const $tbl = this.#source.table.cloneNode(true);\n\n if (targetFixedType === 'left') {\n $tbl.querySelectorAll(\"col, th, td\").forEach($el => {\n if ($el.getAttribute(\"fixed\") !== \"left\") $el.remove();\n });\n } else if (targetFixedType === 'right') {\n $tbl.querySelectorAll(\"col, th, td\").forEach($el => {\n if ($el.getAttribute(\"fixed\") !== \"right\") $el.remove();\n });\n } else {\n $tbl.querySelectorAll(\"[fixed=left], [fixed=right]\").forEach($el => {\n $el.remove();\n });\n }\n\n return $tbl;\n };\n\n getRowHeight = () => {\n return this.#rowManager.getRowHeight();\n };\n\n /**\n * this.#elements = {\n * mainBody: this.querySelector('.ng-sheet-body .ng-container-body'),\n * hscrollbar: this.querySelector('nine-table-hscrollbar'),\n * vscrollbar: this.querySelector('nine-table-vscrollbar'),\n * content: this.querySelector('.ng-sheet-body .ng-sheet-body-content'),\n * scrollHolder: this.querySelector('.ng-sheet-body .ng-virtual-height-holder'),\n * }\n * @returns {*}\n */\n\n getViewHeight = () => {\n\n const viewHeight = this.#elements.content.offsetHeight || 0;\n\n const fixedHeight = (this.#elements.body.thead?.offsetHeight || 0) +\n (this.#elements.body.tfoot?.offsetHeight || 0) +\n (this.#elements.body.tbody.head.offsetHeight || 0);\n\n return viewHeight - fixedHeight;\n };\n\n isLastRow = () => {\n\n // 1. 시트(뷰포트) 엘리먼트와 마지막 tr 찾기\n const sheet = this.querySelector('.ng-sheet-body');\n const tbody = this.querySelector(\".ng-container-body tbody.body\");\n\n const offsetHeight = (this.#elements.body.tfoot?.offsetHeight || 0);\n\n const sheetBottom = sheet.getBoundingClientRect().bottom;\n const tbodyBottom = tbody.getBoundingClientRect().bottom;\n\n trace.log(sheetBottom, tbodyBottom, offsetHeight);\n\n // 💡 tbody의 하단이 sheet의 하단보다 위에 있는지(안 보이는지/덜 채워졌는지) 확인\n return (sheetBottom - offsetHeight) >= tbodyBottom;\n };\n\n scrollToX = (scrollLeft) => {\n const bodyContainer = this.querySelector('.ng-sheet-body .ng-container-body');\n if (bodyContainer) bodyContainer.scrollLeft = scrollLeft;\n };\n\n scrollToY = (scrollTop) => {\n const bodyViewport = this.querySelector('.ng-sheet-body');\n if (bodyViewport) bodyViewport.scrollTop = scrollTop;\n };\n\n #init = () => {\n\n this.#render();\n\n this.#cellSelection = new CellSelection(this);\n this.#cellNavigation = new CellNavigation(this);\n this.#colResizer = new ColResizer(this);\n this.#colMover = new ColMover(this);\n this.#colFix = new ColFixManager(this);\n\n this.#view = new SheetView(this);\n this.#filtering = new Filtering(this);\n this.#grouping = new GroupingManager(this);\n\n if (!this.#isSimple) {\n this.#sorting = new Sorting(this);\n }\n\n this.#elements.mainBody.addEventListener('scroll', () => {\n this.querySelector(\"nine-table-hscrollbar\").refresh();\n });\n };\n\n\n\n #render = () => {\n\n this.innerHTML = `\n <div class=\"ng-sheet-body\">\n <div class=\"ng-sheet-body-content\">\n <div class=\"ng-container-left\"></div>\n <div class=\"ng-container-body\"></div>\n <div class=\"ng-container-right\"></div>\n </div>\n <div class=\"ng-virtual-height-holder\"></div>\n </div>\n\n <div class=\"nodata-overlay\">Data Not Found</div>\n\n <!-- [Grid Row 1, Col 2] 세로 스크롤바 -->\n <nine-table-vscrollbar></nine-table-vscrollbar>\n\n <!-- [Grid Row 2, Col 1] 가로 스크롤바 -->\n <nine-table-hscrollbar></nine-table-hscrollbar>\n\n <!-- [Grid Row 2, Col 2] 우하단 엣지 -->\n <div class=\"scroll-edge\"></div>\n \n <!-- 리사이저 및 드래그 패널들 -->\n <nine-table-col-resizer-panel></nine-table-col-resizer-panel>\n <!--\n <div class=\"ng-col-resizer-panel\">\n <div class=\"resizer-overlay\">\n <span class=\"size-badge\">0px</span>\n </div>\n </div> ->\n \n <div class=\"ng-col-mover-grip\"></div>\n <div class=\"ng-col-mover-indi\"></div>\n `;\n\n //let fixedHeight = this.#sheet.querySelector('.ng-container-body thead').offsetHeight + this.#sheet.querySelector('.ng-container-body tfoot').offsetHeight;\n\n this.#elements = {\n mainBody: this.querySelector('.ng-sheet-body .ng-container-body'),\n hscrollbar: this.querySelector('nine-table-hscrollbar'),\n vscrollbar: this.querySelector('nine-table-vscrollbar'),\n content: this.querySelector('.ng-sheet-body .ng-sheet-body-content'),\n scrollHolder: this.querySelector('.ng-sheet-body .ng-virtual-height-holder'),\n }\n trace.log(\"444*****************\");\n };\n\n #syncHeaderAndFooterHeights = () => {\n trace.log(\"**********************\", \"#syncHeaderAndFooterHeights\");\n\n //requestAnimationFrame(() => {\n // requestAnimationFrame(() => {\n const leftTable = this.querySelector('.ng-container-left table');\n const bodyTable = this.querySelector('.ng-container-body table');\n const rightTable = this.querySelector('.ng-container-right table');\n\n // 1. 헤더(thead) 행 높이 싱크 (인덱스 행 제외)\n const leftHeaderRows = Array.from(leftTable.querySelectorAll('thead tr:not(.col-indicator-rowgroup)'));\n const bodyHeaderRows = Array.from(bodyTable.querySelectorAll('thead tr:not(.col-indicator-rowgroup)'));\n const rightHeaderRows = Array.from(rightTable.querySelectorAll('thead tr:not(.col-indicator-rowgroup)'));\n\n this.#applyMaxHeights(leftHeaderRows, bodyHeaderRows, rightHeaderRows);\n\n // 2. 푸터(tfoot) 행 높이 싱크\n const leftFooterRows = Array.from(leftTable.querySelectorAll('tfoot tr'));\n const bodyFooterRows = Array.from(bodyTable.querySelectorAll('tfoot tr'));\n const rightFooterRows = Array.from(rightTable.querySelectorAll('tfoot tr'));\n\n this.#applyMaxHeights(leftFooterRows, bodyFooterRows, rightFooterRows);\n // });\n //});\n };\n\n// 공통 최대 높이 적용 헬퍼 메서드\n #applyMaxHeights = (leftRows, bodyRows, rightRows) => {\n /** 바닐라에서 setTimeout 없으면 높이계산이 가끔 안됨 */\n setTimeout(() => {\n const maxRows = Math.max(leftRows.length, bodyRows.length, rightRows.length);\n\n trace.log(this.#host);\n for (let i = 0; i < maxRows; i++) {\n trace.log(maxRows);\n\n const heights = [\n leftRows[i]?.getBoundingClientRect().height || 0,\n bodyRows[i]?.getBoundingClientRect().height || 0,\n rightRows[i]?.getBoundingClientRect().height || 0\n ];\n const maxHeight = Math.max(...heights);\n\n trace.log(heights, maxHeight);\n\n if (maxHeight > 0) {\n if (leftRows[i]) leftRows[i].style.height = `${maxHeight}px`;\n if (bodyRows[i]) bodyRows[i].style.height = `${maxHeight}px`;\n if (rightRows[i]) rightRows[i].style.height = `${maxHeight}px`;\n }\n }\n });\n };\n\n #initRowHoverEvent = () => {\n const bodyViewport = this.querySelector('.ng-sheet-body');\n if (!bodyViewport) return;\n\n let activeRowIndex = null;\n\n // 마우스 진입 (모든 컨테이너 탐색)\n bodyViewport.addEventListener('mouseover', (e) => {\n const tr = e.target.closest('tr');\n if (!tr || !tr.dataset.row && tr.dataset.row !== '0') return;\n\n const rowIndex = tr.dataset.row;\n if (activeRowIndex === rowIndex) return;\n activeRowIndex = rowIndex;\n\n // 좌측, 본문, 우측 컨테이너에서 동일한 data-row를 가진 tr들을 모두 찾아 .hover 부여\n bodyViewport.querySelectorAll(`tr[data-row=\"${rowIndex}\"]`).forEach($tr => {\n $tr.classList.add('hover');\n });\n });\n\n // 마우스 이탈\n bodyViewport.addEventListener('mouseout', (e) => {\n const tr = e.target.closest('tr');\n if (!tr) return;\n\n // 현재 영역을 완전히 벗어났을 때만 전체 hover 제거\n const relatedTarget = e.relatedTarget;\n if (tr.contains(relatedTarget)) return;\n\n bodyViewport.querySelectorAll('tr.hover').forEach($tr => {\n $tr.classList.remove('hover');\n });\n activeRowIndex = null;\n });\n }\n\n disconnectedCallback() {\n this.#colResizer?.destroy();\n this.#colMover?.destroy();\n this.innerHTML = '';\n }\n}\n\nif (!customElements.get('nine-table-sheet')) {\n customElements.define('nine-table-sheet', NineTableSheet);\n}","import { trace } from \"@nopeer\";\nimport '@/layout/nine-table-sheets.js';\nimport '@/layout/nine-table-sheets-footer.js';\nimport '@/layout/nine-table-toolbar.js';\nimport { NineTableSheet } from \"@/layout/nine-table-sheet.js\";\n\nexport class LayoutManager {\n #host;\n\n constructor(owner) {\n this.#host = owner;\n this.#init();\n }\n\n #init = () => {\n this.#render();\n\n new ResizeObserver((entries) => {\n for (let entry of entries) {\n const isAutoHeight = this.#host.getAttribute('auto-height') === 'true';\n if (isAutoHeight) {\n this.#applyAutoHeight();\n }\n }\n }).observe(this.#host);\n }\n\n set loading(val) {\n if (!!val) {\n this.#host.classList.add(\"loading\");\n } else {\n this.#host.classList.remove(\"loading\");\n }\n }\n\n #applyAutoHeight = () => {\n const activeSheets = Array.from(this.#host.shadowRoot.querySelectorAll('nine-table-sheet.active'));\n if (activeSheets.length === 0) return;\n\n const maxDisplayRows = parseInt(this.#host.getAttribute('max-display-row'), 10) || 10;\n const maxRowHeight = Math.max(...activeSheets.map(sheet => sheet.getRowHeight()));\n\n const toolbarEl = this.#host.shadowRoot.querySelector('nine-table-toolbar');\n const footerEl = this.#host.shadowRoot.querySelector('nine-table-sheets-footer');\n\n const toolbarHeight = toolbarEl ? toolbarEl.getBoundingClientRect().height : 0;\n const footerHeight = footerEl ? footerEl.getBoundingClientRect().height : 0;\n const extraPadding = NineTableSheet.SCROLLBAR_SIZE;\n\n const calculatedHeight = (maxDisplayRows * maxRowHeight) + toolbarHeight + footerHeight + extraPadding;\n\n this.#host.style.height = `${calculatedHeight}px`;\n };\n\n #render = () => {\n\n const rawElements = Array.from(this.#host.children);\n const rawTables = rawElements.filter(el => (el.tagName.toUpperCase() === 'TABLE') );\n const isAutoHeight = this.#host.getAttribute('auto-height') === 'true';\n const sheetCount = rawTables.length;\n\n const sheetsHtml = rawTables.map((tbl, idx) => {\n const className = idx === 0 ? 'active' : '';\n const sheetId = tbl.id || `sheet${idx + 1}`;\n\n const sheetTag = `<nine-table-sheet class=\"${className}\" data-index=\"${idx}\" data-sheet-id=\"${sheetId}\" id=\"${sheetId}\"></nine-table-sheet>`;\n const splitterTag = idx < sheetCount - 1 ? `<nine-splitter class=\"h\" data-split-index=\"${idx}\"></nine-splitter>` : '';\n return sheetTag + splitterTag;\n }).join('');\n\n // 1. 공통 파일명 배열 정의\n\n\n const cssFiles = [\n 'layout', 'nine-table-sheet', 'nine-table-vscrollbar', 'nine-table-hscrollbar', 'table', 'col-resize', 'sorting', 'fitering', 'col-expand',\n 'host', 'cell-combo', 'cell-selection'\n ];\n\n trace.log(\"Welcome nine-table\", __APP_VERSION__);\n\n const cssImports = [\n `@import \"https://cdn.jsdelivr.net/npm/@ninebone/table@${__APP_VERSION__}/dist/css/nine-table.css\";`,\n ];\n\n if (nine[\"nine-table\"] && nine[\"nine-table\"].cssFile) {\n cssImports.push(`@import \"${nine[\"nine-table\"].cssFile}\";`);\n }\n\n this.#host.shadowRoot.innerHTML = `\n <style>\n ${cssImports.join('\\n')}\n </style>\n \n <nine-table-toolbar></nine-table-toolbar>\n\n <nine-table-body>\n <nine-table-summary></nine-table-summary>\n <div class=\"ng-loading-bar\"></div>\n <nine-table-sheets>\n <nine-table-sheets-body>\n ${sheetsHtml}\n </nine-table-sheets-body>\n <nine-table-sheets-footer></nine-table-sheets-footer>\n </nine-table-sheets>\n <nine-table-analysis></nine-table-analysis>\n </nine-table-body>\n <nine-table-footer></nine-table-footer>\n `;\n\n /**\n * <div class=\"nine-tab-bar\">${tabsHtml}</div>\n * <div class=\"sheets-counter\">Total : <span id=\"row-count\">0</span></div>\n */\n this.#host.shadowRoot.querySelectorAll('nine-table-sheet').forEach(($el, idx) => {\n\n if (rawTables[idx]) {\n setTimeout(() => {\n $el.generate(rawTables[idx], idx);\n if (isAutoHeight) {\n this.#applyAutoHeight();\n }\n });\n }\n });\n };\n}","import { trace } from \"@nopeer\";\n\nexport class ExprEngine {\n #host;\n #fields;\n #exprCache = new Map(); // 💡 통합된 단일 캐시로 모든 컴파일된 함수 관리\n\n constructor(host) {\n this.#host = host;\n this.#fields = host.fields.get();\n }\n\n /**\n * 🎯 표현식 내의 data.fieldName을 원시 배열 인덱스 접근(rowItem.v[idx])으로 변환\n */\n rewriteExpr(expr) {\n\n if (!expr || !this.#fields.length) return expr;\n\n return expr.replace(/data\\.([a-zA-Z_$][\\w$]*)/g, (match, fieldName) => {\n const idx = this.#fields.indexOf(fieldName);\n return idx >= 0 ? `rowItem.v[${idx}]` : match;\n });\n }\n\n /**\n * 🎯 셀 또는 컬럼 정의에 선언된 expr 프리컴파일\n */\n precompile(expr) {\n if (!expr) return expr;\n return this.rewriteExpr(expr);\n }\n\n /**\n * 🎯 표현식 평가 및 실행 (통합 캐싱)\n */\n evaluate(expr, rowItem, row = 0) {\n\n if (expr === undefined || expr === null) return \"\";\n\n try {\n const trimmedExpr = String(expr).trim();\n const compiledExpr = this.rewriteExpr(trimmedExpr);\n\n // 💡 함수 호출, 데이터 참조, 연산식이 포함된 경우 통합 평가 및 캐싱\n if (compiledExpr.includes(\"data.\") || compiledExpr.includes(\"rowItem.v\") || compiledExpr.includes(\"host.\") || compiledExpr.includes(\"(\")) {\n let evalFn = this.#exprCache.get(compiledExpr);\n\n if (!evalFn) {\n evalFn = new Function('rowItem', 'row', 'host', `\n const data = rowItem;\n\n if (!data && !host) return \"\";\n return ${compiledExpr};\n `);\n\n this.#exprCache.set(compiledExpr, evalFn);\n }\n\n return evalFn(rowItem, row, this.#host);\n }\n\n return compiledExpr;\n } catch (e) {\n //console.trace(\"ExprEngine evaluation error:\", e);\n return expr;\n }\n }\n}","import { trace } from \"@nopeer\";\nimport { ngDataManager } from '@/data/ngDataManager.js';\nimport { fields } from \"@/data/Fields.js\";\nimport { LayoutManager } from '@/layout/core/LayoutManager.js';\nimport { ExprEngine } from \"@/core/ExprEngine.js\";\nimport { NINE_TABLE } from \"@/core/constants.js\";\n\nexport default class NineTable extends HTMLElement {\n #shadowRoot;\n #dataManager;\n #layoutManager;\n #templateCnt = 0; // 🎯 로딩 상태 플래그\n\n constructor() {\n super();\n\n this.#shadowRoot = this.attachShadow({ mode: 'open' });\n this.#dataManager = new ngDataManager(this);\n }\n\n connectedCallback() {\n setTimeout(() => {\n this.#templateCnt = this.querySelectorAll(\"table\")?.length;\n\n this.fields = new fields(this);\n this.exprEngine = new ExprEngine(this);\n\n this.#bindDynamicSetters();\n\n this.#layoutManager = new LayoutManager(this);\n\n this.#dispatchLoad();\n //this.dispatchEvent(new CustomEvent('load', { bubbles: true, detail: { target: this } }));\n });\n }\n\n disconnectedCallback() {\n trace.log('NineTable disconnected.');\n }\n\n #dispatchLoad = () => {\n // 🎯 2. 변수명 오타 수정 (#sheetCnt -> #templateCnt)\n //trace.log(\"*********************** template count:\", this.#templateCnt);\n\n let checkCount = 0;\n const maxChecks = 50; // 최대 5초 대기 (100ms * 50)\n\n const checkTimer = setInterval(() => {\n checkCount++;\n\n const sheets = this.shadow.querySelectorAll('nine-table-sheet');\n //trace.log(\"Current mounted sheets:\", sheets.length);\n\n if (checkCount >= maxChecks) {\n clearInterval(checkTimer);\n }\n\n if (sheets.length >= this.#templateCnt) {\n let loadSheetCnt = 0;\n sheets.forEach($sheet => {\n if ($sheet.loaded) loadSheetCnt++;\n });\n\n //trace.log('Checking sheet loaded status:', loadSheetCnt, '/', this.#templateCnt);\n\n if (loadSheetCnt >= this.#templateCnt) {\n clearInterval(checkTimer);\n this.loaded = true;\n this.dispatchEvent(new CustomEvent(NINE_TABLE.EVENT.LOAD, { bubbles: true, detail: { target: this } }));\n }\n }\n }, 100);\n }\n\n\n // 🎯 공통 데이터 & API 접근자\n get shadow() { return this.#shadowRoot; }\n get dataManager() { return this.#dataManager; }\n get data() { return this.#dataManager.data; }\n get row() { return this.#dataManager.row; }\n\n setData(records) {\n this.#dataManager.data.set(records);\n this.refresh();\n }\n\n refresh() {\n this.activeSheet?.invalidate();\n }\n\n // 🎯 섀도우 돔 내부에서 로딩바 요소를 안전하게 캐싱\n\n\n set loading(val) {\n if (this.#layoutManager) this.#layoutManager.loading = val;\n }\n\n /**\n * 랜더링 이후에 생기는 data-source 처리기능\n */\n rerenderer() {\n\n this.activeSheet?.querySelectorAll(\"tbody.body th,tbody.body td\").forEach(($cell) => {\n const customComp = Array.from($cell.children).find($el => {\n return $el.tagName.toLowerCase().startsWith('cell-') && typeof $el.rerenderer === 'function'\n });\n\n customComp?.rerenderer();\n })\n }\n\n // 시트 제어 API\n sheet = (idOrIndex) => {\n if (idOrIndex === null || idOrIndex < 0) return this.activeSheet;\n const sheets = Array.from(this.shadow.querySelectorAll('nine-table-sheet'));\n\n if (typeof idOrIndex === 'number') return sheets[idOrIndex] || null;\n if (typeof idOrIndex === 'string') {\n return this.shadow.querySelector(`nine-table-sheet#${idOrIndex}, nine-table-sheet[data-sheet-id=\"${idOrIndex}\"]`) || null;\n }\n return sheets[0] || null;\n }\n\n get sheets() {\n return Array.from(this.shadow.querySelectorAll('nine-table-sheet'));\n }\n\n get activeSheet() {\n return this.shadow.querySelector('nine-table-sheet.active') || null;\n }\n\n #bindDynamicSetters() {\n const extractedMethodNames = new Set();\n\n this.querySelectorAll('[data-source]').forEach(el => {\n const dataSource = el.getAttribute('data-source');\n if (!dataSource) return;\n\n // 💡 [수정] 뒤에 여멀림 괄호 '('가 오는 형태만 매칭하여 'DEPART' 같은 파라미터는 배제!\n const matches = dataSource.matchAll(/(?:host\\.)?([a-zA-Z0-9_$]+)\\s*\\(/g);\n for (const match of matches) {\n const name = match[1];\n if (name && name !== 'host') {\n extractedMethodNames.add(name);\n }\n }\n });\n\n // 추출된 메서드 이름별로 NineTable 인스턴스에 동적 세터 생성\n extractedMethodNames.forEach(methodName => {\n let internalValue = null;\n\n Object.defineProperty(this, methodName, {\n set: (newValue) => {\n internalValue = newValue;\n\n // 값이 대입되는 순간 그리드 자동 갱신\n //this.refresh();\n this.rerenderer();\n },\n get: () => internalValue,\n configurable: true,\n enumerable: true\n });\n });\n }\n\n execute = (fn) => {\n setTimeout(() => {\n this.loading = true;\n setTimeout(() => {\n try {\n fn.call(this);\n } finally {\n this.loading = false;\n }\n });\n });\n }\n}\n\nif (!customElements.get('nine-table')) {\n customElements.define('nine-table', NineTable);\n}\n\nif (!customElements.get('nine-table-simple')) {\n customElements.define('nine-table-simple', class extends NineTable {\n connectedCallback() {\n // simple 태그로 생성되면 자동으로 mode=\"simple\" 속성 부여\n this.setAttribute('theme', 'simple');\n\n super.connectedCallback();\n }\n });\n}","export class BasicCellElement extends HTMLElement {\r\n\r\n\tstatic _styleCache = new Map();\r\n\tstatic _customStyleCache = new Map(); // 👈 커스텀 스타일용 캐시 추가\r\n\r\n\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tapplyBaseStyle() {\r\n\t\tconst className = this.constructor.name;\r\n\r\n\t\treturn;\r\n\t\t// 1. 기본 스타일 시트 처리 (캐싱 O)\r\n\t\tif (!ngElement._styleCache.has(className)) {\r\n\t\t\tconst baseSheet = new CSSStyleSheet();\r\n\t\t\tngElement._styleCache.set(className, baseSheet);\r\n\r\n\t\t\tconst baseUrl = `https://cdn.jsdelivr.net/npm/@ninebone/grid@${__APP_VERSION__}/dist/css/${className}.css`;\r\n\t\t\tfetch(baseUrl)\r\n\t\t\t\t.then(res => res.text())\r\n\t\t\t\t.then(cssText => baseSheet.replaceSync(cssText))\r\n\t\t\t\t.catch(err => console.error(`Base CSS Load Error:`, err));\r\n\t\t}\r\n\r\n\t\tconst sheets = [ngElement._styleCache.get(className)];\r\n\r\n\t\t// 2. 커스텀 스타일 시트 처리 (자바스크립트 단 캐싱 O)\r\n\t\tif (nine.cssPath) {\r\n\t\t\tif (!ngElement._customStyleCache.has(className)) {\r\n\t\t\t\tconst customSheet = new CSSStyleSheet();\r\n\t\t\t\tngElement._customStyleCache.set(className, customSheet);\r\n\r\n\t\t\t\t// 💡 오타 수정 및 캐시 파라미터 제거\r\n\t\t\t\tconst customUrl = `${nine.cssPath}/ninegrid/${className}.css`;\r\n\r\n\t\t\t\tfetch(customUrl)\r\n\t\t\t\t\t.then(res => res.text())\r\n\t\t\t\t\t.then(cssText => customSheet.replaceSync(cssText))\r\n\t\t\t\t\t.catch(err => console.error(`Custom CSS Load Error:`, err));\r\n\t\t\t}\r\n\r\n\t\t\t// 캐시된 커스텀 시트가 있으면 기본 시트 배열 뒤에 추가\r\n\t\t\tsheets.push(ngElement._customStyleCache.get(className));\r\n\t\t}\r\n\r\n\t\t// 한 번에 섀도우 돔에 적용\r\n\t\tthis.shadowRoot.adoptedStyleSheets = sheets;\r\n\t}\r\n\r\n\tconnectedCallback() {\r\n\t\t// ngElement 레벨에서는 비워두셔도 됩니다.\r\n\t}\r\n}","import { trace } from \"@nopeer\";\r\nimport { BasicCellElement } from './BasicCellElement.js';\r\n\r\nconst exprCache = new Map();\r\nconst hostFuncCache = new Map();\r\n\r\nexport class CellElement extends BasicCellElement {\r\n\t#host;\r\n\t#sheet;\r\n\t#tr;\r\n\t#cell;\r\n\r\n\t#attr;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tget host() { return this.#host; }\r\n\tget sheet() { return this.#sheet; }\r\n\tget cell() { return this.#cell; }\r\n\tget tr() { return this.#tr; }\r\n\tget attr() { return this.#attr; }\r\n\r\n\tconnectedCallback() {\r\n\t\tsuper.connectedCallback();\r\n\r\n\t\tthis.#host = this.getRootNode().host;\r\n\r\n\t\tthis.#cell = this.closest(\"th,td\");\r\n\t\tthis.#tr = this.#cell.closest(\"tr\");\r\n\t\tthis.#sheet = this.#tr.closest(\"nine-table-sheet\");\r\n\r\n\t\tthis.#cell.classList.add(this.tagName);\r\n\r\n\t\tthis.#attr = {};\r\n\t\tfor (let i = 0; i < this.#cell.attributes.length; i++) {\r\n\t\t\tconst name = this.#cell.attributes[i].name;\r\n\t\t\tif (![\"text-align\",\"class\",\"cell-type\",\"data-bind\",\"data-expr\",\"data-col\",\"tabindex\"].includes(name)) {\r\n\t\t\t\tthis.#attr[name] = this.#cell.attributes[i].value;\r\n\t\t\t\t//this.setAttribute(name, this.#cell.attributes[i].value);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!this.#cell) return;\r\n\r\n\r\n\t\tconst root = this.shadowRoot || this;\r\n\r\n\t\t// 🎯 버튼 이벤트 연결\r\n\t\troot.querySelectorAll(\"button, ng-expand-button\").forEach(button => {\r\n\t\t\tbutton.addEventListener(\"click\", () => {\r\n\t\t\t\tlet fn = this.getAttribute(\"onbuttonclick\") || this.getAttribute(\"onButtonClick\") || this.#cell?.getAttribute(\"onbuttonclick\") || this.#cell?.getAttribute(\"onButtonClick\");\r\n\r\n\t\t\t\tconst rowData = this.data; // Proxy Lazy 접근\r\n\t\t\t\tconst curRow = parseInt(this.#cell.dataset.row, 10);\r\n\r\n\t\t\t\tif (fn && this.#host) {\r\n\t\t\t\t\tfn = fn.replace(\"()\", \"\");\r\n\t\t\t\t\tconst match = fn.match(/^(\\w+)\\s*\\(/);\r\n\t\t\t\t\tconst methodName = match?.[1] || fn;\r\n\r\n\t\t\t\t\tif (typeof this.#host[methodName] === 'function') {\r\n\t\t\t\t\t\tthis.#host[methodName].call(this.#host, rowData, curRow, this.#cell);\r\n\t\t\t\t\t} else if (typeof this.#host.exprFunction === 'function') {\r\n\t\t\t\t\t\tthis.#host.exprFunction(fn).call(this, rowData, curRow);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t/**\r\n\t\t\t\tthis.#host?.dispatchEvent(new CustomEvent(ninegrid.EVENT.BUTTON_CLICK, {\r\n\t\t\t\t\tdetail: { target: this.#cell, data: rowData, currow: curRow },\r\n\t\t\t\t\tbubbles: true,\r\n\t\t\t\t\tcomposed: true\r\n\t\t\t\t})); */\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// 🎯 링크 이벤트 연결\r\n\t\tconst renderer = root.querySelector(\".renderer\");\r\n\t\tif (renderer && this.getAttribute(\"link\") === \"true\") {\r\n\t\t\trenderer.classList.add(\"link\");\r\n\r\n\t\t\trenderer.addEventListener(\"click\", () => {\r\n\t\t\t\tlet fn = this.getAttribute(\"onlinkclick\") || this.getAttribute(\"onLinkClick\");\r\n\r\n\t\t\t\tconst rowData = this.data;\r\n\t\t\t\tconst curRow = parseInt(this.#cell.dataset.row, 10);\r\n\r\n\t\t\t\tif (fn && this.#host) {\r\n\t\t\t\t\tfn = fn.replace(\"()\", \"\");\r\n\t\t\t\t\tconst match = fn.match(/^(\\w+)\\s*\\(/);\r\n\t\t\t\t\tconst methodName = match?.[1] || fn;\r\n\r\n\t\t\t\t\tif (typeof this.#host[methodName] === 'function') {\r\n\t\t\t\t\t\tthis.#host[methodName].call(this.#host, rowData, curRow, this.#cell);\r\n\t\t\t\t\t} else if (typeof this.#host.exprFunction === 'function') {\r\n\t\t\t\t\t\tthis.#host.exprFunction(fn).call(this, rowData, curRow);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.#host?.dispatchEvent(new CustomEvent(ninegrid.EVENT.LINK_CLICK, {\r\n\t\t\t\t\tdetail: { target: this.#cell, data: rowData, currow: curRow },\r\n\t\t\t\t\tbubbles: true,\r\n\t\t\t\t\tcomposed: true\r\n\t\t\t\t}));\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 🎯 [Proxy 최적화] 속성 읽기 시에도 fields.indexOf() 사용\r\n\t */\r\n\tget data() {\r\n\t\tconst rawRecord = this.#tr?.data;\r\n\t\tif (!rawRecord) return null;\r\n\t\tif (!rawRecord.v) return rawRecord;\r\n\r\n\t\tconst host = this.#host;\r\n\r\n\t\treturn new Proxy(rawRecord, {\r\n\t\t\tget(target, prop) {\r\n\t\t\t\tif (prop === '__ng') return target.__ng;\r\n\t\t\t\tif (prop === 'v') return target.v;\r\n\r\n\t\t\t\t// 💡 host.fields.indexOf(prop) 사용\r\n\t\t\t\tconst idx = host?.fields?.indexOf?.(prop) ?? -1;\r\n\t\t\t\treturn idx >= 0 ? target.v[idx] : target[prop];\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * 🎯 [핵심] 변환 없이 원시 v 배열에서 direct 인덱스 검색 (GC zero)\r\n\t */\r\n\tget value() {\r\n\t\tif (!this.#cell || !this.#tr?.data) return \"\";\r\n\r\n\t\tconst bindKey = this.#cell.dataset?.bind;\r\n\t\tif (!bindKey) return \"\";\r\n\r\n\t\tconst rawRecord = this.#tr.data;\r\n\r\n\t\t// 1. 원시 데이터 배열({ v: [...] }) 구조인 경우\r\n\t\tif (rawRecord.v && Array.isArray(rawRecord.v)) {\r\n\t\t\t// 💡 fields.indexOf(bindKey)로 바로 찾기!\r\n\t\t\tconst colIdx = this.#host.fields.get().indexOf(bindKey) ?? -1;\r\n\t\t\treturn colIdx >= 0 ? (rawRecord.v[colIdx] ?? \"\") : \"\";\r\n\t\t}\r\n\r\n\t\t// 2. 일반 JSON 객체인 경우 (하위 호환)\r\n\t\treturn rawRecord[bindKey] ?? \"\";\r\n\t}\r\n\r\n\tset value(v) {\r\n\t\tif (!this.#cell || !this.#host?.data) return;\r\n\r\n\t\tconst row = parseInt(this.#cell.dataset.row, 10);\r\n\t\tconst bindKey = this.#cell.dataset.bind;\r\n\t\tif (isNaN(row) || !bindKey) return;\r\n\r\n\t\tconst updateRowState = this.getAttribute('update-row-state') !== \"false\";\r\n\t\tthis.#host.data.setValue(row, bindKey, v, updateRowState);\r\n\t}\r\n\r\n\tget row() {\r\n\t\treturn parseInt(this.#cell?.dataset?.row, 10);\r\n\t}\r\n\tget index() {\r\n\t\treturn parseInt(this.#cell?.dataset?.index, 10);\r\n\t}\r\n\r\n\tisValid() {\r\n\t\treturn this.#cell.classList.contains(\"invalid\") ? false : true;\r\n\t}\r\n\r\n\tisInvalid() {\r\n\t\treturn !this.isValid();\r\n\t}\r\n\r\n\tgetDisplayText = (defaultValue = \"\") => {\r\n\r\n\t\tif (!this.#cell || !this.#cell.closest(\"tbody\")) return defaultValue;\r\n\r\n\t\tconst rawRecord = this.#tr.data;\r\n\r\n\t\tif (!rawRecord) return defaultValue;\r\n\r\n\t\tconst expr = this.#cell.dataset.expr;\r\n\t\tconst bindKey = this.#cell.dataset.bind;\r\n\t\tconst row = parseInt(this.#cell.dataset.row, 10);\r\n\r\n\t\tif (expr) {\r\n\t\t\ttry {\r\n\t\t\t\tif (this.#tr.getAttribute(\"grouping\") === \"true\") {\r\n\t\t\t\t\t// 💡 상수가 정의되어 있다면 GROUP_IDX.ID 로 고유 ID 추출 (아니면 배열 인덱스 직접 참조)\r\n\t\t\t\t\t// 배열 구조체인 경우: rawRecord[0]이 groupId임\r\n\t\t\t\t\t//const groupId = Array.isArray(rawRecord) ? rawRecord[0] : (rawRecord.__ng?.id || rawRecord.m?.id);\r\n\r\n\t\t\t\t\t// 💡 매니저를 통해 해당 그룹의 자식 레코드 목록을 O(1)로 획득\r\n\t\t\t\t\t//const childRecords = this.#sheet.grouping.getChildrenRecords(\"g_0\");\r\n\t\t\t\t\t//trace.log(\"--========\", childRecords);\r\n\t\t\t\t\t// 그룹 전용 표현식 계산 메서드 호출\r\n\t\t\t\t\t//return \"\";//this.getGroupExprValue(expr, childRecords, row, this.#cell);\r\n\r\n\t\t\t\t\t//trace.log(this, this.#cell.dataset.bind);\r\n\t\t\t\t\t//return \"x\";//this.data.length;\r\n\t\t\t\t\treturn this.getGroupExprValue(expr, this.#tr.data, row, this.#cell);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn this.#host.exprEngine.evaluate(expr, this.#tr.data, row);\r\n\r\n\t\t\t\t\t//return this.getExprValue(expr, this.#tr.data, row, this.#cell);\r\n\t\t\t\t}\r\n\t\t\t} catch (e) {\r\n\t\t\t\tconsole.trace(e);\r\n\t\t\t\t//console.error(\"Expr evaluation error:\", expr, e);\r\n\t\t\t\treturn defaultValue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (bindKey) {\r\n\t\t\tconst val = this.value; // 직통 읽기\r\n\t\t\treturn val !== null && val !== undefined ? val : defaultValue;\r\n\t\t}\r\n\r\n\t\treturn defaultValue;\r\n\t};\r\n\r\n\r\n\r\n\trefresh() {\r\n\r\n\t\tif (!this.#cell || !this.#tr) return;\r\n\r\n\t\tconst val = this.value; // 원시 배열 직통 조회\r\n\r\n\t\tthis.#cell.classList.remove(\"invalid\");\r\n\r\n\t\t[\"color\",\"background\",\"background-color\",\"visible\",\"enable\",\"validator\"].forEach(v => {\r\n\r\n\t\t\tconst expr = this.#attr[v];\r\n\t\t\tif (expr) {\r\n\t\t\t\tconst result = this.#host.exprEngine.evaluate(expr, this.#tr.data, parseInt(this.#cell.dataset.row, 10));\r\n\r\n\t\t\t\tif (v === \"validator\") {\r\n\t\t\t\t\tif (!result) {\r\n\t\t\t\t\t\tthis.#cell.classList.add(\"invalid\");\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (v === \"visible\") {\r\n\t\t\t\t\tthis.style[\"display\"] = result ? \"\" : \"none\";\r\n\t\t\t\t} else if (v === \"enable\") {\r\n\t\t\t\t\tthis.querySelectorAll(\"input, button, textarea, select\").forEach($el => {\r\n\t\t\t\t\t\t$el.disabled = !result;\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\tif (!!result) {\r\n\t\t\t\t\t\tthis.#cell.removeAttribute(\"disabled\");\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.#cell.setAttribute(\"disabled\", \"true\");\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.#cell.style[v] = result;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn val;\r\n\t}\r\n\r\n\tgetExprValue(expr, data, row) {\r\n\t\tif (!this.#host || !this.#host.exprEngine || expr === undefined || expr === null || expr === \"\") return expr;\r\n\r\n\t\treturn this.#host.exprEngine.evaluate(expr, data, row);\r\n\t}\r\n\r\n\t/**\r\n\t * 🎯 [신규] 그룹 행의 자식 데이터 목록(childRecords)을 기반으로 합계/평균/개수 등을 처리하는 메서드\r\n\t */\r\n\tgetGroupExprValue = (expr, groupRecord, row, cell) => {\r\n\t\tif (!expr) return \"\";\r\n\r\n\t\ttry {\r\n\t\t\trow = parseInt(row, 10);\r\n\t\t\tconst cleanExpr = expr.replace(\"()\", \"\").trim();\r\n\r\n\t\t\t// 1. 호스트(컴포넌트)에 정의된 그룹 전용 커스텀 메서드가 있는 경우 우선 위임\r\n\t\t\tif (this.#host && typeof this.#host[cleanExpr] === 'function') {\r\n\t\t\t\treturn this.#host[cleanExpr].call(this, groupRecord, row, cell);\r\n\t\t\t}\r\n\r\n\t\t\t// 2. 기본 내장 집계 함수 파싱 처리 (예: sum(price), count(), avg(score) 등)\r\n\t\t\tconst match = cleanExpr.match(/^(\\w+)\\s*\\(\\s*([\\w\\-]*)\\s*\\)/);\r\n\t\t\tif (match) {\r\n\t\t\t\t// 💡 groupRecord에서 자식 레코드 목록 안전하게 추출 (indices 배열 -> 실제 레코드 매핑)\r\n\t\t\t\tconst indices = groupRecord[GROUP_IDX.CHILDREN];\r\n\t\t\t\tconst allRecords = this.#host?.data?.getArray ? this.#host.data.getArray() : [];\r\n\t\t\t\tconst childRecords = indices ? indices.map(idx => allRecords[idx]).filter(Boolean) : [];\r\n\r\n\t\t\t\tconst [, funcName, field] = match;\r\n\t\t\t\tconst host = this.#host;\r\n\r\n\t\t\t\tswitch (funcName.toLowerCase()) {\r\n\t\t\t\t\tcase 'count':\r\n\t\t\t\t\t\treturn childRecords.length;\r\n\r\n\t\t\t\t\tcase 'sum': {\r\n\t\t\t\t\t\tconst colIdx = host?.fields?.indexOf?.(field) ?? -1;\r\n\t\t\t\t\t\treturn childRecords.reduce((acc, record) => {\r\n\t\t\t\t\t\t\tconst val = colIdx >= 0 ? record.v?.[colIdx] : record[field];\r\n\t\t\t\t\t\t\treturn acc + (Number(val) || 0);\r\n\t\t\t\t\t\t}, 0);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcase 'avg': {\r\n\t\t\t\t\t\tif (childRecords.length === 0) return 0;\r\n\t\t\t\t\t\tconst colIdx = host?.fields?.indexOf?.(field) ?? -1;\r\n\t\t\t\t\t\tconst sum = childRecords.reduce((acc, record) => {\r\n\t\t\t\t\t\t\tconst val = colIdx >= 0 ? record.v?.[colIdx] : record[field];\r\n\t\t\t\t\t\t\treturn acc + (Number(val) || 0);\r\n\t\t\t\t\t\t}, 0);\r\n\t\t\t\t\t\treturn sum / childRecords.length;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// 3. 호스트의 exprFunction 활용\r\n\t\t\tif (this.#host && typeof this.#host.exprFunction === 'function') {\r\n\t\t\t\treturn this.#host.exprFunction(expr).call(this, groupRecord, row, this.#host.data);\r\n\t\t\t}\r\n\r\n\t\t\t// 4. 💡 캐싱을 적용한 그룹 동적 표현식 평가 (예: \"childRecords.reduce(...)\")\r\n\t\t\t// groupRecord 자체나 내부 자식들을 활용하는 표현식 문자열 처리\r\n\t\t\t// 4. 💡 캐싱을 적용한 그룹 동적 표현식 평가 (안전성 강화 버전)\r\n\t\t\tif (expr.includes(\"data.\") || expr.includes(\"childRecords\") || expr.includes(\"groupRecord\")) {\r\n\t\t\t\tlet evalFn = exprCache.get(\"grp_\" + expr);\r\n\t\t\t\tif (!evalFn) {\r\n\t\t\t\t\tevalFn = new Function('groupRecord', 'row', 'cell', 'host', `\r\n const indices = groupRecord[3]; // GROUP_IDX.CHILDREN = 3\r\n const allRecords = host?.data?.getArray ? host.data.getArray() : [];\r\n \r\n let childRecords = [];\r\n if (Array.isArray(indices)) {\r\n // indices가 숫자 인덱스 배열인지, rowid 문자열 배열인지 판별하여 안전하게 추출\r\n childRecords = indices.map(idx => {\r\n if (typeof idx === 'number') {\r\n return allRecords[idx];\r\n } else {\r\n // rowid 등 문자열 식별자인 경우 전체 배열에서 찾거나 dataManager 활용\r\n return allRecords.find(r => r?.__ng?.rowid === idx || r?.m?._?.[0] === idx);\r\n }\r\n }).filter(Boolean);\r\n }\r\n \r\n // 만약 위에서 못 찾았는데 host.grouping을 쓸 수 있다면 매니저 위임 시도\r\n if (childRecords.length === 0 && host?.grouping?.getChildrenRecords && groupRecord[0]) {\r\n childRecords = host.grouping.getChildrenRecords(groupRecord[0]);\r\n }\r\n\r\n const data = childRecords; // data.length 등을 쓸 수 있도록 호환\r\n return ${expr};\r\n `);\r\n\t\t\t\t\texprCache.set(\"grp_\" + expr, evalFn);\r\n\t\t\t\t}\r\n\t\t\t\treturn evalFn(groupRecord, row, cell, this.#host);\r\n\t\t\t}\r\n\r\n\t\t\treturn expr;\r\n\t\t} catch (e) {\r\n\t\t\tconsole.error(\"Group expr evaluation error:\", expr, e);\r\n\t\t\treturn expr;\r\n\t\t}\r\n\t};\r\n}\r\n\r\nexport class EditableCellElement extends CellElement {\r\n\r\n\tget host() { return super.host; }\r\n\tget sheet() { return super.sheet; }\r\n\tget cell() { return super.cell; }\r\n\tget tr() { return super.tr; }\r\n\tget attr() { return super.attr; }\r\n\r\n\tgetExprValue(expr, data, row, cell) {\r\n\t\treturn super.getExprValue(expr, data, row, cell);\r\n\t}\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tconnectedCallback() {\r\n\t\tsuper.connectedCallback();\r\n\r\n\r\n\r\n\t\t/**\r\n\t\tthis.querySelectorAll(\"input, textarea\").forEach($el => {\r\n\t\t\t$el.addEventListener(\"change\", (event) => {\r\n\t\t\t\tif (!this.closest(\"tbody\")) return;\r\n\r\n\t\t\t\tconst target = event.target;\r\n\t\t\t\tconst inputType = target.getAttribute('type');\r\n\r\n\t\t\t\tif (inputType === \"checkbox\") {\r\n\t\t\t\t\tconst trueVal = super.attr[\"true-value\"] || \"Y\";\r\n\t\t\t\t\tconst falseVal = super.attr[\"false-value\"] || \"N\";\r\n\t\t\t\t\tthis.value = target.checked ? trueVal : falseVal;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlet v = target.value;\r\n\t\t\t\t\tconst maxbyte = super.attr[\"maxbyte\"];\r\n\r\n\t\t\t\t\ttrace.log(maxbyte);\r\n\r\n\t\t\t\t\tif (maxbyte) {\r\n\t\t\t\t\t\tconst byteLen = nine.getByteLength(v);\r\n\t\t\t\t\t\tif (byteLen >= parseInt(maxbyte, 10)) {\r\n\t\t\t\t\t\t\tv = nine.cut(v, parseInt(maxbyte, 10));\r\n\t\t\t\t\t\t\ttarget.value = v;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tthis.value = this.getAttribute(\"type\") === \"number\" ? (isNaN(v) ? \"\" : Number(v)) : v;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsuper.sheet.invalidate();\r\n\t\t\t});\r\n\t\t}); */\r\n\t}\r\n\r\n\trefresh() {\r\n\t\treturn super.refresh();\r\n\t}\r\n\r\n\tgetExprValue = (expr, data, row, cell) => {\r\n\t\treturn super.getExprValue(expr, data, row, cell);\r\n\t}\r\n\r\n\tisValid = () => {\r\n\t\treturn super.isValid();\r\n\t}\r\n\r\n\tisInvalid = () => {\r\n\t\treturn super.isInvalid();\r\n\t}\r\n}","import { trace } from \"@nopeer\";\nimport { EditableCellElement } from \"./core/CellElement.js\";\n\nclass CellInputText extends EditableCellElement\n{\n\t#target;\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\t\n\tconnectedCallback() {\n\n\t\tsuper.connectedCallback();\n\n\t\tthis.#renderer();\n\n\t\tthis.#target = this.querySelector(\"input\");\n\n\t\tthis.#initEvent();\n\t};\n\n\trefresh = () => {\n\t\tconst v = super.refresh();\n\t\tthis.#target.value = v;\n\t};\n\n\t#initEvent = () => {\n\t\tthis.#target.addEventListener(\"input\", e => {\n\t\t\tif (this.#maxbyte) {\n\t\t\t\tconst maxByteNum = Number(this.#maxbyte);\n\t\t\t\tconst currentBytes = nine.getByteLength(e.target.value);\n\n\t\t\t\tif (currentBytes > maxByteNum) {\n\t\t\t\t\te.target.value = nine.cut(e.target.value, maxByteNum);\n\t\t\t\t\tthis.value = e.target.value;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.#target.addEventListener(\"change\", (event) => {\n\t\t\tthis.value = event.target.value;\n\t\t\tthis.sheet.rowManager.refresh(true);\n\t\t});\n\t};\n\n\t#renderer = () => {\n\n\t\tthis.innerHTML = `\n\t\t\t<input type=\"text\" ondragstart=\"return false;\">\n\t\t`;\n\t};\n\n\tget #maxbyte() {\n\t\treturn this.cell.getAttribute(\"maxbyte\") || this.cell.getAttribute(\"max-byte\");\n\t}\n}\n\nif (!customElements.get('cell-input')) {\n\tcustomElements.define(\"cell-input\", CellInputText);\n}\n","import { trace } from \"@nopeer\";\nimport { EditableCellElement } from \"./core/CellElement.js\";\n\nclass CellInputNumber extends EditableCellElement\n{\n\t#target;\n\n\tconstructor () {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\n\t\tsuper.connectedCallback();\n\n\t\tthis.#renderer();\n\n\t\tthis.#target = this.querySelector(\"input\");\n\n\t\tthis.#initEvent();\n\n\n\t};\n\n\t#renderer = () => {\n\t\tthis.innerHTML = `\n <input type=\"text\" ondragstart=\"return false;\">\n `;\n\t};\n\n\t#initEvent = () => {\n\t\tthis.#target.addEventListener(\"keydown\", this.#onKeyDown);\n\n\t\tthis.#target.addEventListener(\"input\", (event) => {\n\t\t\tthis.value = event.target.value;\n\t\t\tthis.sheet.rowManager.refresh(true);\n\t\t});\n\n\t\tthis.#target.addEventListener(\"change\", (event) => {\n\t\t\tthis.value = event.target.value;\n\t\t\tthis.sheet.rowManager.refresh(true);\n\t\t});\n\t};\n\n\trefresh = () => {\n\t\tconst v = super.refresh();\n\n\t\tthis.#target.value = v;//v !== undefined && v !== null ? v : \"\";\n\n\t\tif (this.isValid()) {\n\t\t\tthis.#validate();\n\t\t}\n\t};\n\n\t#validate = () => {\n\n\t\tconst v = this.#target.value;\n\n\t\tif (v !== \"\" && v !== null && v !== undefined) {\n\t\t\tconst num = Number(v);\n\n\t\t\tif (isNaN(num) || (this.#max && num > Number(this.#max)) || (this.#min && num < Number(this.#min))) {\n\t\t\t\tthis.cell.classList.add(\"invalid\");\n\t\t\t}\n\t\t\telse if (this.#scale) {\n\t\t\t\tconst str = String(v);\n\t\t\t\tconst idx = str.indexOf('.');\n\t\t\t\tif (idx >= 0 && str.substring(idx + 1).length > Number(this.#scale)) {\n\t\t\t\t\tthis.cell.classList.add(\"invalid\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t#onKeyDown = e => {\n\n\t\tif ([\"Escape\", \"Enter\", \"Tab\", \"Home\", \"End\", \"ArrowLeft\", \"ArrowRight\", \"PageUp\", \"PageDown\", \"Backspace\", \"Delete\"].includes(e.code)) return;\n\n\t\tconst target = e.target;\n\t\tconst value = target.value;\n\t\tconst selectionStart = target.selectionStart;\n\t\tconst key = e.key;\n\n\t\tif (key === \"-\") {\n\t\t\tif (value.includes(\"-\") || selectionStart !== 0) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (key === \".\") {\n\t\t\tconst scale = Number(this.#scale);\n\n\t\t\tif (isNaN(scale) || scale <= 0 || value.includes(\".\")) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tlet validKey = [];\n\t\tif (this.#scale && Number(this.#scale) > 0) validKey.push(\".\");\n\t\tif (this.#min || Number(this.#min) > 0) validKey.push(\"-\");\n\n\t\t// 숫자 키패드 및 상단 숫자 키 허용 + 소수점/마이너스 허용\n\t\tconst isNumKey = (e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 96 && e.keyCode <= 105);\n\n\t\tif (!isNumKey && !validKey.includes(e.key)) {\n\t\t\te.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\t// 소수점 자리수(scale) 제한 체크\n\t\tif (this.#scale && isNumKey && e.target.selectionStart == e.target.selectionEnd) {\n\t\t\tconst s = e.target.value;\n\t\t\tconst idx = s.indexOf(\".\");\n\t\t\tif (idx >= 0 && e.target.selectionStart > idx) {\n\t\t\t\tconst decimalPart = s.substr(idx + 1);\n\t\t\t\tif (decimalPart.length >= Number(this.#scale)) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.#maxbyte && nine.getByteLength(e.target.value) >= Number(this.#maxbyte) && e.target.selectionStart == e.target.selectionEnd) {\n\t\t\te.preventDefault();\n\t\t}\n\t}\n\n\tget #min() {\n\t\treturn this.cell.getAttribute(\"min\") || \"\";\n\t}\n\n\tget #max() {\n\t\treturn this.cell.getAttribute(\"max\") || \"\";\n\t}\n\n\tget #scale() {\n\t\treturn this.cell.getAttribute(\"scale\") || \"\";\n\t}\n\n\tget #maxbyte() {\n\t\treturn this.cell.getAttribute(\"maxbyte\") || this.cell.getAttribute(\"max-byte\");\n\t}\n}\n\nif (!customElements.get('cell-input-number')) {\n\tcustomElements.define(\"cell-input-number\", CellInputNumber);\n}","import { trace } from \"@nopeer\";\nimport { EditableCellElement } from \"./core/CellElement.js\";\n\nclass CellInputColor extends EditableCellElement\n{\n\t#target;\n\t#btn;\n\t#dataSource;\n\n\tconstructor () {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\n\t\tsuper.connectedCallback();\n\n\t\tthis.#renderer();\n\n\t\tthis.#target = this.querySelector(\"input[type=color]\");\n\t\tthis.#btn = this.querySelector(\"button\");\n\n\t\t//this.#rendererColor();\n\n\t\tthis.#initEvent();\n\t};\n\n\t#initEvent = () => {\n\t\tthis.#btn.addEventListener(\"click\", () => {\n\t\t\tthis.#target.click();\n\t\t});\n\n\t\t// 색상 변경 즉시 반영\n\t\tthis.#target.addEventListener(\"input\", (event) => {\n\t\t\tconst val = event.target.value;\n\t\t\tthis.value = val;\n\t\t\tthis.#validate(val);\n\n\t\t\tthis.sheet.rowManager.refresh(true);\n\t\t});\n\n\t\tthis.#target.addEventListener(\"change\", (event) => {\n\t\t\tconst val = event.target.value;\n\t\t\tthis.value = val;\n\t\t\tthis.#validate(val);\n\n\t\t\tthis.sheet.rowManager.refresh(true);\n\t\t});\n\t}\n\n\t#renderer = () => {\n\t\tthis.innerHTML = `\n <input type=\"color\" ondragstart=\"return false;\">\n <button tabindex=\"-1\" type=\"button\"></button>\n `;\n\t};\n\n\trerenderer = () => {\n\t\t//this.#rendererColor();\n\t\tthis.refresh();\n\t};\n\n\t#rendererColor = () => {\n\n\t\tif (!this.tr.data) {\n\t\t\t//return;\n\t\t\t//trace.log(this.tr.cloneNode(true))\n\t\t}\n\n\t\tconst dataSource = this.cell.getAttribute(\"data-source\");\n\t\tif (!dataSource) return;\n\n\t\tthis.#dataSource = super.getExprValue(dataSource, this.tr.data, this.tr.dataset.row);\n\n\t\t//trace.log(dataSource, this.#dataSource, this.tr.data);\n\n\t\tthis.querySelector(\"datalist\")?.remove();\n\n\t\tif (this.#dataSource && Array.isArray(this.#dataSource)) {\n\t\t\t// 2. 고유 ID 생성 (datalist와 input을 연결하기 위함)\n\t\t\tconst datalistId = `color-list-${Math.random().toString(36).substr(2, 9)}`;\n\n\t\t\t// 3. <datalist> 생성\n\t\t\tconst datalist = document.createElement('datalist');\n\t\t\tdatalist.id = datalistId;\n\n\t\t\tconst fragment = document.createDocumentFragment();\n\n\t\t\tthis.#dataSource.forEach(v => {\n\t\t\t\tif (v.value) {\n\t\t\t\t\tconst option = document.createElement('option');\n\t\t\t\t\toption.value = v.value;\n\t\t\t\t\tfragment.appendChild(option);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tdatalist.appendChild(fragment);\n\t\t\tthis.appendChild(datalist);\n\n\t\t\t// 4. <input type=\"color\">에 list 속성 부여하여 datalist 연결\n\t\t\tthis.#target.setAttribute(\"list\", datalistId);\n\t\t}\n\t};\n\n\trefresh = () => {\n\t\tif (!this.tr.data) return;\n\n\t\tconst v = super.refresh();\n\n\t\t/** datasource(datalist) refresh */\n\t\tthis.#rendererColor();\n\n\t\tthis.#target.value = v !== undefined && v !== null && v !== \"\" ? v : \"#ffffff\";\n\n\t\tif (this.isValid()) {\n\t\t\tthis.#validate();\n\t\t}\n\t};\n\n\t#validate = () => {\n\n\t\tconst v = this.#target.value;\n\n\t\tif (v !== \"\" && v !== null && v !== undefined) {\n\t\t\tif (!this.#isValidColor(v)) {\n\t\t\t\tthis.cell.classList.add(\"invalid\");\n\t\t\t}\n\t\t\telse if (this.#dataSource && Array.isArray(this.#dataSource) && this.#dataSource.length > 0) {\n\t\t\t\tconst exists = this.#dataSource.some(item => {\n\t\t\t\t\tconst itemCode = item.value !== undefined ? item.value : (item.code !== undefined ? item.code : '');\n\t\t\t\t\t// 대소문자 구분 없이 비교하기 위해 toLowerCase 처리\n\t\t\t\t\treturn itemCode.toLowerCase() === v.toLowerCase();\n\t\t\t\t});\n\n\t\t\t\tif (!exists) {\n\t\t\t\t\tthis.cell.classList.add(\"invalid\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t#isValidColor = (v) => {\n\t\tif (typeof v !== \"string\" || v.length != 7 || !v.startsWith(\"#\")) return false;\n\n\t\tvar r = parseInt(v.substr(1, 2), 16);\n\t\tvar g = parseInt(v.substr(3, 2), 16);\n\t\tvar b = parseInt(v.substr(5, 2), 16);\n\n\t\tif (isNaN(r) || isNaN(g) || isNaN(b)) return false;\n\t\tif (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) return false;\n\n\t\treturn true;\n\t}\n}\n\nif (!customElements.get('cell-input-color')) {\n\tcustomElements.define(\"cell-input-color\", CellInputColor);\n}","import { trace } from \"@nopeer\";\nimport { EditableCellElement } from \"./core/CellElement.js\";\n\nclass CellInputDate extends EditableCellElement\n{\n\t#target;\n\t#type;\n\n\tconstructor () {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback();\n\n\t\tthis.#renderer();\n\n\t\tthis.#target = this.querySelector(\"input\");\n\n\t\t// 값 변경 시 즉시 반영 및 검증\n\t\tthis.#target.addEventListener(\"input\", (event) => {\n\t\t\tconst val = event.target.value;\n\t\t\tthis.value = val;\n\t\t\tthis.#target.classList.toggle(\"has-value\", !!val); // 💡 실시간 반영\n\t\t\tthis.#validate(val);\n\n\t\t\tsuper.sheet.rowManager.refresh(true);\n\t\t});\n\n\t\tthis.#target.addEventListener(\"change\", (event) => {\n\t\t\tconst val = event.target.value;\n\t\t\tthis.value = val;\n\t\t\tthis.#validate(val);\n\n\t\t\tsuper.sheet.rowManager.refresh(true);\n\t\t});\n\t};\n\n\t#renderer = () => {\n\n\t\tthis.#type = this.cell.getAttribute(\"date-type\") || \"date\";\n\t\tif (![\"date\",\"datetime-local\",\"time\",\"week\",\"month\"].includes(this.#type)) {\n\t\t\tthrow `invalid type : ${this.#type}`;\n\t\t}\n\n\t\tlet attr = [];\n\t\tfor (let i = 0; i < this.cell.attributes.length; i++) {\n\t\t\tif ([\"value\", \"max\", \"min\", \"step\"].includes(this.cell.attributes[i].name)) {\n\t\t\t\tattr.push(`${this.cell.attributes[i].name}=\"${this.cell.attributes[i].value}\"`);\n\t\t\t}\n\t\t}\n\n\t\tthis.innerHTML = `\n <input\n type=\"${this.#type}\"\n data-placeholder=\"${this.cell.getAttribute('placeholder') || 'Select'}\"\n ${attr.join(\" \")}\n required\n />\n `;\n\t};\n\n\trefresh = () => {\n\n\t\tconst v = super.refresh();\n\n\t\tlet formattedVal = v;\n\t\tif (formattedVal) {\n\n\t\t\tswitch (this.#type) {\n\t\t\t\tcase \"date\":\n\t\t\t\t\tformattedVal = formattedVal.substr(0, 10);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"datetime-local\":\n\t\t\t\t\tformattedVal = formattedVal.substr(0, 16);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"time\":\n\t\t\t\t\tvar d = new Date(v);\n\t\t\t\t\tif (d != \"Invalid Date\" && !isNaN(d)) {\n\t\t\t\t\t\tformattedVal = (\"00\" + d.getHours()).slice(-2) + \":\" + (\"00\" + d.getMinutes()).slice(-2);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"month\":\n\t\t\t\t\tvar d = new Date(v);\n\t\t\t\t\tif (d != \"Invalid Date\" && !isNaN(d)) {\n\t\t\t\t\t\tformattedVal = (\"0000\" + d.getFullYear()).slice(-4) + \"-\" + (\"00\" + (d.getMonth() + 1)).slice(-2);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t//trace.log(this.#type, formattedVal);\n\n\t\tthis.#target.value = formattedVal || \"\";\n\t\tthis.#target.classList.toggle(\"has-value\", !!formattedVal); // 💡 값이 있으면 클래스 추가\n\n\t\tif (this.isValid()) {\n\t\t\tthis.#validate(formattedVal);\n\t\t}\n\t};\n\n\t#validate = (val) => {\n\n\t\tif (val !== \"\" && val !== null && val !== undefined) {\n\t\t\tlet isValid = this.#isValidDate(val);\n\n\t\t\t// 💡 형식 검증을 통과했더라도 min/max 범위를 벗어났다면 invalid 처리\n\t\t\tif (isValid) {\n\t\t\t\tif (this.#min && val < this.#min) isValid = false;\n\t\t\t\tif (this.#max && val > this.#max) isValid = false;\n\t\t\t}\n\n\t\t\tif (!isValid) {\n\t\t\t\tsuper.cell.classList.add(\"invalid\");\n\t\t\t}\n\t\t}\n\t};\n\n\t#isValidDate = (v) => {\n\n\t\tif (typeof v !== \"string\") return false;\n\n\t\tlet isValid = true;\n\n\t\tswitch (this.#type) {\n\t\t\tcase \"date\":\n\t\t\tcase \"datetime-local\":\n\t\t\t\tconst year = Number(v.substr(0, 4));\n\t\t\t\tconst month = Number(v.substr(5, 2));\n\t\t\t\tconst day = Number(v.substr(8, 2));\n\n\t\t\t\tif (isNaN(year) || isNaN(month) || isNaN(day)) {\n\t\t\t\t\tisValid = false;\n\t\t\t\t} else if (month < 1 || month > 12 || day < 1 || day > 31) {\n\t\t\t\t\tisValid = false;\n\t\t\t\t} else if ([4, 6, 9, 11].includes(month) && day == 31) {\n\t\t\t\t\tisValid = false;\n\t\t\t\t} else if (month == 2) {\n\t\t\t\t\tlet isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));\n\t\t\t\t\tif (day > 29 || (day == 29 && !isleap)) {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (isValid) {\n\t\t\tswitch (this.#type) {\n\t\t\t\tcase \"datetime-local\":\n\t\t\t\t\tvar t = v.substr(10, 1);\n\t\t\t\t\tvar hour = Number(v.substr(11, 2));\n\t\t\t\t\tvar min = Number(v.substr(14, 2));\n\n\t\t\t\t\tif (t != \"T\") {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t} else if (isNaN(hour) || isNaN(min)) {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t} else if (hour < 0 || hour > 23 || min < 0 || min > 59) {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"month\":\n\t\t\t\t\tvar year = Number(v.substr(0, 4));\n\t\t\t\t\tvar month = Number(v.substr(5, 2));\n\n\t\t\t\t\tif (isNaN(year) || isNaN(month)) {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t} else if (month < 1 || month > 12) {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"week\":\n\t\t\t\t\tvar year = Number(v.substr(0, 4));\n\t\t\t\t\tvar w = v.substr(5, 1);\n\t\t\t\t\tvar week = Number(v.substr(6, 2));\n\n\t\t\t\t\tif (w != \"W\") {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t} else if (isNaN(year) || isNaN(week)) {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t} else if (week <= 0 || week > 53) {\n\t\t\t\t\t\tisValid = false;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn isValid;\n\t}\n\n\tget #min() {\n\t\treturn this.cell.getAttribute(\"min\");\n\t}\n\n\tget #max() {\n\t\treturn this.cell.getAttribute(\"max\");\n\t}\n\n\tget #step() {\n\t\treturn this.cell.getAttribute(\"step\");\n\t}\n}\n\nif (!customElements.get('cell-input-date')) {\n\tcustomElements.define(\"cell-input-date\", CellInputDate);\n}","import { EditableCellElement } from \"./core/CellElement.js\";\nimport {trace} from \"@nopeer\";\n\nclass CellCheckbox extends EditableCellElement {\n #target;\n #label;\n\n constructor() {\n super();\n }\n\n connectedCallback() {\n super.connectedCallback();\n\n this.#renderer();\n\n this.#target = this.querySelector(\"input\");\n this.#label = this.querySelector(\"span\");\n\n this.#initEvent();\n }\n\n\n\n get dataSource() {\n return [\n { value: this.trueValue, text: this.#trueText },\n { value: this.falseValue, text: this.#falseText }\n ];\n }\n\n #initEvent = () => {\n if (this.closest(\"thead\")) {\n this.#target.addEventListener(\"change\", (e) => {\n super.sheet.querySelector(`tbody.body [data-col=\"${super.cell.dataset.col}\"] cell-checkbox`)?.selectAll(e.target.checked);\n });\n }\n\n this.#target.addEventListener(\"change\", (event) => {\n if (!this.closest(\"tbody\")) return;\n\n //const newVal = this.value === this.trueValue ? this.falseValue : this.trueValue;\n if (this.#isRadio) {\n this.selectAll(false);\n this.value = this.trueValue;\n }\n else {\n this.value = event.target.checked ? this.trueValue : this.falseValue;\n }\n\n this.sheet.rowManager.refresh(true);\n });\n };\n\n #renderer = () => {\n\n const trueValue = this.trueValue;//this.cell.getAttribute(\"true-value\") || false;\n //const selectedBorderColor = this.getAttribute(\"selected-border-color\") || \"dimgray\";\n\n const originalContent = this.cell.getAttribute(\"content\") || \"\";\n const childHtml = this.#isRadio ? `<input type=\"radio\" value=\"${trueValue}\" />` : `<label><input type=\"checkbox\" /><span>${originalContent}</span></label>`;\n\n // 🎯 div.ng-wrap 없이 cell-checkbox(Host) 자체를 플렉스 컨테이너로 활용하여 중앙정렬 보장\n this.innerHTML = `\n ${childHtml}\n `;\n }\n\n refresh = () => {\n const val = super.refresh(); // CellElement의 원시값 직통 조회 활용\n\n this.#target.checked = (val === this.trueValue);\n\n if (this.isValid()) {\n this.#validate(val);\n }\n\n const displayText = (val === this.trueValue) ? this.#trueText : ((val === this.falseValue) ? this.#falseText : val);\n\n if (this.#label) {\n this.#label.textContent = displayText;\n }\n };\n\n #validate = (val) => {\n\n this.cell.classList.remove(\"invalid\");\n\n if (val !== \"\" && val !== null && val !== undefined) {\n if (val !== this.trueValue && val !== this.falseValue) {\n this.cell.classList.add(\"invalid\");\n }\n }\n };\n\n selectAll = (v) => {\n if (this.closest(\"thead\")) return; // 헤더 자신은 제외\n\n const data = this.host.data.getArray();\n const colIndex = this.host.fields.indexOf(this.cell.dataset.bind);\n\n if (colIndex < 0) return;\n\n for (let i = 0; i < data.length; i++) {\n if (this.#enable && super.getExprValue(this.#enable, data[i], i, this.cell) === false) continue;\n if (this.#readonly && super.getExprValue(this.#readonly, data[i], i, this.cell) === true) continue;\n if (this.#visible && super.getExprValue(this.#visible, data[i], i, this.cell) === false) continue;\n\n data[i].v[colIndex] = v ? this.trueValue : this.falseValue;\n }\n\n super.sheet.invalidate();\n };\n\n get trueValue() {\n return this.cell.getAttribute(\"true-value\") || \"Y\";\n }\n get falseValue() {\n return this.cell.getAttribute(\"false-value\")|| \"N\";\n }\n get #trueText() {\n return this.cell.getAttribute(\"true-text\") || \"\";\n }\n get #falseText() {\n return this.cell.getAttribute(\"false-text\") || \"\";\n }\n get #isRadio() {\n return this.cell.getAttribute(\"is-radio\") || false;\n }\n get #enable() {\n return this.cell.getAttribute(\"enable\") || false;\n }\n get #readonly() {\n return this.cell.getAttribute(\"readonly\") || false;\n }\n get #visible() {\n return this.cell.getAttribute(\"visible\") || false;\n }\n}\n\nif (!customElements.get('cell-checkbox')) {\n customElements.define(\"cell-checkbox\", CellCheckbox);\n}","import { trace } from \"@nopeer\";\nimport { EditableCellElement } from \"./core/CellElement.js\";\n\nclass CellRadio extends EditableCellElement {\n\t#target;\n\t#radioList;\n\t#dataSource = [];\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\n\t\tsuper.connectedCallback();\n\n\t\tthis.#renderer();\n\n\t\tthis.#rendererRadio();\n\n\t\tthis.#initEvent();\n\t}\n\n\t#initEvent = () => {\n\n\t\tthis.cell.addEventListener(\"keydown\", e => {\n\n\t\t\tif (this.cell.hasAttribute(\"readonly\") || this.cell.classList.contains(\"readonly\")) return;\n\t\t\tif (this.cell.getAttribute(\"disabled\") === \"true\") return;\n\n\t\t\tif (e.code === \"Space\") {\n\t\t\t\te.preventDefault();\n\n\t\t\t\tlet matchIndex = -1;\n\n\t\t\t\tthis.#radioList.forEach(($el,index) => {\n\t\t\t\t\tif (this.value === $el.getAttribute(\"value\")) {\n\t\t\t\t\t\tmatchIndex = index;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tmatchIndex = (matchIndex === this.#radioList.length - 1) ? 0 : (matchIndex >= 0 ? matchIndex + 1 : 0);\n\t\t\t\tthis.value = this.#radioList[matchIndex].getAttribute(\"value\");\n\n\t\t\t\tthis.sheet.rowManager.refresh(true);\n\t\t\t}\n\t\t});\n\t};\n\n\t#rendererRadio = () => {\ntrace.log(\"rendererRadio\");\n\t\t//if (!this.sheet || !this.cell) return;\n\n\t\tconst dataSource = this.cell.getAttribute(\"data-source\");\n\t\tif (!dataSource) return;\n\n\t\tthis.#dataSource = super.getExprValue(dataSource, this.tr.data, this.tr.dataset.row);\n\n\t\tthis.#target.replaceChildren();\n\n\t\tif (this.#dataSource && Array.isArray(this.#dataSource)) {\n\n\t\t\tconst fragment = document.createDocumentFragment();\n\n\t\t\tthis.#dataSource.forEach(v => {\n\t\t\t\tconst codeVal = v[this.#keyName] !== undefined ? v[this.#keyName] : '';\n\t\t\t\tconst nameVal = v[this.#valueName] !== undefined ? v[this.#valueName] : '';\n\n\t\t\t\t// <label> 생성\n\t\t\t\tconst label = document.createElement('label');\n\n\t\t\t\t// <input type=\"radio\" value=\"...\"> 생성\n\t\t\t\tconst input = document.createElement('input');\n\t\t\t\tinput.type = 'radio';\n\t\t\t\tinput.value = codeVal;\n\n\t\t\t\t// <span>텍스트</span> 생성 (textContent를 써야 XSS 방어 및 안전합니다)\n\t\t\t\tconst span = document.createElement('span');\n\t\t\t\tspan.textContent = nameVal;\n\n\t\t\t\t// 조립\n\t\t\t\tlabel.appendChild(input);\n\t\t\t\tlabel.appendChild(span);\n\t\t\t\tfragment.appendChild(label);\n\t\t\t});\n\n\t\t\tthis.#target.appendChild(fragment);\n\n\t\t\tthis.#radioList = Array.from(this.querySelectorAll(\"input\"));\n\n\t\t\tthis.#radioList.forEach($el => {\n\t\t\t\t$el.addEventListener(\"change\", (e) => {\n\t\t\t\t\tthis.value = e.target.value;\n\t\t\t\t\tthis.sheet.rowManager.refresh(true);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t};\n\n\t#renderer = () => {\n\n\t\tthis.innerHTML = `\n\t\t\t<div></div>\n `;\n\n\t\tthis.#target = this.querySelector(\"div\");\n\t};\n\n\trerenderer = () => {\n\t\tthis.#rendererRadio();\n\t\tthis.refresh();\n\t};\n\n\trefresh = () => {\n\n\t\tconst v = super.refresh();\n\n\t\tthis.#radioList.forEach($el => {\n\t\t\t$el.checked = (v === $el.value);\n\t\t});\n\n\t\tif (this.isValid()) {\n\t\t\tthis.#validate();\n\t\t}\n\t};\n\n\t#validate = () => {\n\t\t//if (!super.cell) return;\n\n\t\tif (this.value === null || this.value === undefined || this.value === \"\" || !Array.isArray(this.#dataSource)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst idx = this.#dataSource.findIndex(m => this.value === m[this.#keyName]);\n\t\tif (idx < 0) {\n\t\t\tthis.cell.classList.add(\"invalid\");\n\t\t}\n\t};\n\n\tget dataSource() {\n\t\treturn this.#dataSource;\n\t}\n\n\tget #keyName() {\n\t\treturn this.cell.getAttribute(\"key-name\") || \"k\";\n\t}\n\n\tget #valueName() {\n\t\treturn this.cell.getAttribute(\"value-name\") || \"v\";\n\t}\n}\n\nif (!customElements.get('cell-radio')) {\n\tcustomElements.define(\"cell-radio\", CellRadio);\n}","import { trace } from \"@nopeer\";\n\nexport class CellComboPanel extends HTMLElement {\n\t#parent;\n\t#keyName;\n\t#valueName;\n\t#isOpen = false;\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\t\tthis.#renderer();\n\t\tthis.#initEvents();\n\t}\n\n\t#initData = (dataSource, keyName, valueName, multi, separator) => {\n\t\tconst grd = this.querySelector(\"nine-table-simple\");\n\t\tif (!grd || !dataSource || dataSource.length === 0) return;\n\n\t\t// 1. 부모(parent)의 items 속성 확인 (예: \"CODE,NAME,DESC\" 형태)\n\t\tconst itemsAttr = this.#parent.getAttribute(\"items\");\n\t\tlet fieldKeys = [];\n\n\t\tif (itemsAttr) {\n\t\t\tfieldKeys = itemsAttr.split(\",\").map(s => s.trim());\n\t\t} else {\n\t\t\tfieldKeys = [valueName].filter(Boolean);\n\t\t}\n\n\t\tconst activeColumnCount = fieldKeys.length;\n\n\t\t// 2. 🎯 [수정] multi 모드 여부에 따라 0번 컬럼(체크박스) 가시성 제어\n\t\t//trace.log(grd.shadowRoot, grd.shadowRoot.querySelectorAll('nine-table-body table'));\n\t\tgrd.shadowRoot.querySelector(\".ng-container-left\").style.display = multi ? '' : 'none';\n\n\t\tgrd.shadowRoot.querySelectorAll('table colgroup col, tbody td').forEach(($el, idx) => {\n\t\t\ttrace.log($el);\n\n\t\t\tconst col = parseInt($el.dataset.col, 10);\n\t\t\tif (col >= 2) {\t// row-indicator, checkbox 제외\n\t\t\t\t$el.style.display = (col - 2 >= activeColumnCount) ? 'none' : '';\n\t\t\t}\n\t\t});\n\n\t\t// 3. 동적 데이터 매핑 (dataSource 원본 객체에서 fieldKeys 순서대로 tmp1 ~ tmpN에 매핑)\n\t\tconst formattedData = dataSource.map(item => {\n\t\t\tconst row = {\n\t\t\t\tCHK: \"N\",\n\t\t\t\tk: keyName && item[keyName] !== undefined ? item[keyName] : (item[0] !== undefined ? item[0] : \"\")\n\t\t\t};\n\n\t\t\tfieldKeys.forEach((key, idx) => {\n\t\t\t\trow[`tmp${idx + 1}`] = item[key] !== undefined ? item[key] : (item[idx] !== undefined ? item[idx] : \"\");\n\t\t\t});\n\t\t\treturn row;\n\t\t});\n\n\t\tgrd.data.set(formattedData);\n\n\t\t// 4. 멀티 모드일 때 기존 선택값 반영\n\t\tif (multi && this.#parent.value) {\n\t\t\tconst selectedKeys = String(this.#parent.value).split(separator || \",\");\n\t\t\tgrd.data.getValidData().forEach(m => {\n\t\t\t\tif (selectedKeys.includes(String(m.v[1]))) {\n\t\t\t\t\tm.v[0] = \"Y\";\n\t\t\t\t}\n\t\t\t});\n\t\t\tgrd.refreshData();\n\t\t}\n\t};\n\n\topen = (parent, dataSource, keyName, valueName, multi, separator) => {\n\t\tthis.#parent = parent;\n\t\tthis.#keyName = keyName;\n\t\tthis.#valueName = valueName;\n\t\tthis.#isOpen = true;\n\n\t\ttrace.log(new Date());\n\n\t\tthis.classList.add(\"active\");\n\n\t\tconst grd = this.querySelector(\"nine-table-simple\");\n\t\tif (!grd || !dataSource) return;\n\n\t\t// 🎯 패널을 열자마자 active를 주어 레이아웃(offsetHeight) 확보 및 초기화 수행\n\n\n\t\t// 검색어 초기화 및 체크박스 기본값 설정\n\t\tthis.querySelector(\".search-input\").value = \"\";\n\t\tthis.querySelector(\"#chkAll\").checked = true;\n\n\t\t// 데이터 개수 및 모드에 따른 클래스 제어\n\t\tif (dataSource.length > 10) {\n\t\t\tthis.classList.add(\"expand\");\n\t\t} else {\n\t\t\tthis.classList.remove(\"expand\");\n\t\t}\n\n\t\tif (multi) {\n\t\t\tthis.classList.add(\"multi\");\n\t\t} else {\n\t\t\tthis.classList.remove(\"multi\");\n\t\t}\n\n\t\t// 데이터 및 멀티컬럼 구조 초기화 실행\n\n\t\t// 🎯 [필터 패널 방식 위치 정렬 적용] 시트(sheet) 기준 상대 좌표계산\n\t\tconst sheet = parent.closest(\"nine-table-sheet\");\n\t\tconst btnEl = parent.querySelector(\".btn1\");\n\t\tif (!btnEl || !sheet) return;\n\n\t\tconst btnRect = btnEl.getBoundingClientRect();\n\t\tconst sheetRect = sheet.getBoundingClientRect();\n\n\t\tlet left = btnRect.left - sheetRect.left;\n\t\tlet top = btnRect.bottom - sheetRect.top + 2;\n\n\t\t// 화면 오른쪽 밖으로 넘칠 경우 보정\n\t\tconst panelWidth = this.offsetWidth || 250;\n\t\tconst panelHeight = this.offsetHeight || 250;\n\t\tif (left + panelWidth > sheetRect.width) {\n\t\t\tleft = Math.max(0, sheetRect.width - panelWidth - 5);\n\t\t}\n\n\t\tif (left < 0) {\n\t\t\tleft = 5;\n\t\t}\n\n\t\tif (top + panelHeight > sheetRect.height) {\n\t\t\tconst upwardTop = (btnRect.top - sheetRect.top) - panelHeight - 2;\n\t\t\tif (upwardTop >= 0) {\n\t\t\t\ttop = upwardTop; // 위쪽 공간이 있으면 위로 팝업\n\t\t\t} else {\n\t\t\t\ttop = Math.max(0, sheetRect.height - panelHeight - 5); // 위아래 다 부족하면 시트 하단에 밀착\n\t\t\t}\n\t\t}\n\n\t\tthis.style.left = `${left}px`;\n\t\tthis.style.top = `${top}px`;\n\n\t\t// 내부 그리드 행 클릭 이벤트 바인딩 (싱글 모드용)\n\t\ttrace.log(new Date());\n\n\t\tsetTimeout(() => {\n\t\t\ttrace.log(new Date());\n\t\t\tthis.#initData(dataSource, keyName, valueName, multi, separator);\n\t\t\ttrace.log(new Date());\n\t\t\tconst viewContainer = grd.shadowRoot.querySelector(\".ng-container-body table tbody.body\");\n\n\t\t\t// 중복 바인딩 방지를 위한 플래그 체크 또는 기존 리스너 관리\n\t\t\tif (!viewContainer.__hasClickEvent) {\n\n\t\t\t\tviewContainer.addEventListener(\"mousedown\", (e) => {\n\t\t\t\t\ttrace.log(\"==========================================\", e.target);\n\n\t\t\t\t\tconst tr = e.target.closest(\"tr\");\n\t\t\t\t\tif (!tr) return;\n\n\t\t\t\t\ttrace.log(\"==========================================\", multi);\n\n\t\t\t\t\tif (!multi) {\n\t\t\t\t\t\tthis.#onClickRow(e);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tviewContainer.__hasClickEvent = true;\n\t\t\t}\n\n\t\t\ttrace.log(new Date());\n\t\t}, 100);\n\t}\n\n\tclose = () => {\n\t\tthis.classList.remove(\"active\");\n\t\tthis.#isOpen = false;\n\t\tif (this.#parent && this.#parent.cell) {\n\t\t\tthis.#parent.cell.focus();\n\t\t}\n\t}\n\n\t#onClickRow = (e) => {\n\n\t\tconst sheet = e.target.closest(\"nine-table-sheet\");\n\t\tconst tr = e.target.closest(\"tr\");\n\n\t\tconst rowIndex = parseInt(tr.dataset.row, 10);\n\t\tconst record = sheet.view.get(rowIndex);\n\n\t\tthis.#parent.value = record.k;\n\n\t\t//this.#parent.sheet.invalidate();\n\t\tthis.#parent.sheet.rowManager.refresh(true);\n\n\t\tthis.close();\n\t}\n\n\t#onOk = () => {\n\t\tconst grd = this.querySelector(\"nine-table-simple\");\n\t\tconst data = grd.data.getValidData();\n\n\t\tconst selectedKeys = [];\n\t\tdata.forEach(o => {\n\t\t\tif (o.v[0] === \"Y\") {\n\t\t\t\tselectedKeys.push(o.v[1]);\n\t\t\t}\n\t\t});\n\n\t\tthis.#parent.value = selectedKeys.join(this.#parent.getAttribute(\"multi-separator\") || \",\");\n\t\t//this.#parent.sheet.invalidate();\n\t\tthis.#parent.sheet.rowManager.refresh(true);\n\n\t\tthis.close();\n\t}\n\n\t#onSelectAll = (e) => {\n\t\tconst grd = this.querySelector(\"nine-table-simple\");\n\t\tconst isChecked = e.target.checked ? \"Y\" : \"N\";\n\t\tgrd.data.getValidData().forEach(m => { m.v[0] = isChecked; });\n\t\tgrd.refreshData();\n\t}\n\n\t#onInput = (e) => {\n\t\tconst keyword = e.target.value.toLowerCase();\n\t\tconst grd = this.querySelector(\"nine-table-simple\");\n\n\t\t// 동적 컬럼(모든 밸류) 대상 검색 대응\n\t\tgrd.data.getValidDataNF().forEach(m => {\n\t\t\tconst match = Object.values(m.v).some(val =>\n\t\t\t\tval !== null && val !== undefined && String(val).toLowerCase().includes(keyword)\n\t\t\t);\n\t\t\tm.__ng.filtered = !match;\n\t\t});\n\n\t\tgrd.data.resetRecords();\n\t\tgrd.dataManager.viewRecords.reset();\n\t}\n\n\tget isOpen() {\n\t\treturn this.#isOpen;\n\t}\n\n\tget targetCell() {\n\t\treturn this.#parent;\n\t}\n\n\t#initEvents = () => {\n\t\tthis.querySelector(\".search-input\").addEventListener(\"input\", this.#onInput);\n\t\tthis.querySelector(\"#btnOk\").addEventListener(\"click\", this.#onOk);\n\t\tthis.querySelector(\"#chkAll\").addEventListener(\"change\", this.#onSelectAll);\n\n\n\n\t\t// 🎯 [개선] open() 할 때마다 붙일 필요 없이, 내부 그리드 영역에 이벤트 위임 처리\n\n\t\t/**\n\t\t// shadowRoot 내부 또는 컴포넌트 전체 영역을 감싸는 리스너 등록\n\t\tthis.querySelector(\"nine-table-simple\").addEventListener(\"click\", (e) => {\n\t\t\ttrace.log(e);\n\n\t\t\tconst tr = e.target.closest(\"tr\");\n\t\t\tif (!tr) return;\n\n\t\t\t// 멀티 모드가 아닐 때만 행 클릭 동작 수행\n\t\t\tconst isMulti = this.classList.contains(\"multi\");\n\t\t\tif (!isMulti) {\n\t\t\t\tthis.#onClickRow(e, false, grd);\n\t\t\t}\n\t\t}); */\n\n\t\t// 패널 외부 클릭 시 닫기\n\t\tdocument.addEventListener(\"mousedown\", (e) => {\n\t\t\tconst path = e.composedPath ? e.composedPath() : [];\n\n\t\t\t// 패널 자신이나 현재 열려 있는 필터 버튼이 경로에 포함되어 있다면 닫지 않음\n\t\t\tif (path.includes(this)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.close();\n\t\t});\n\t}\n\n\t#renderer = () => {\n\t\tthis.innerHTML = `\n <div class=\"head\">\n <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" />\n </div>\n \n <nine-table-simple class=\"combo-list\" theme=\"simple\">\n <table auto-fit-col=\"true\">\n <colgroup>\n <col width=\"30\" fixed=\"left\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"100\" />\n <col width=\"0\" />\n </colgroup>\n <tbody>\n <tr>\n <td cell-type=\"checkbox\" data-bind=\"CHK\"></td>\n <td data-bind=\"tmp1\" />\n <td data-bind=\"tmp2\" />\n <td data-bind=\"tmp3\" />\n <td data-bind=\"tmp4\" />\n <td data-bind=\"tmp5\" />\n <td data-bind=\"tmp6\" />\n <td data-bind=\"tmp7\" />\n <td data-bind=\"tmp8\" />\n <td data-bind=\"tmp9\" />\n <td data-bind=\"tmp10\" />\n <td data-bind=\"k\" />\n </tr>\n </tbody>\n </table>\n </nine-table-simple>\n \n <div class=\"footer\">\n <div>\n <input id=\"chkAll\" type=\"checkbox\" checked>\n <label for=\"chkAll\">Select All</label>\n </div>\n <button id=\"btnOk\">OK</button>\n </div>\n `;\n\t};\n}\n\nif (!customElements.get('cell-combo-panel')) {\n\tcustomElements.define(\"cell-combo-panel\", CellComboPanel);\n}","import { trace } from \"@nopeer\";\nimport { EditableCellElement } from \"./core/CellElement.js\";\nimport \"./cell-combo-panel.js\";\n\nexport class CellCombo extends EditableCellElement {\n\t#targetBtn;\n\t#dataSource = [];\n\t#keyName;\n\t#valueName;\n\t#multi;\n\t#multiSeparator;\n\t#panel;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.applyBaseStyle();\n\t}\n\n\tconnectedCallback() {\n\n\n\t\tthis.#renderer();\n\t\tsuper.connectedCallback();\n\n\t\tthis.#keyName = super.cell.getAttribute(\"key-name\") || \"k\";\n\t\tthis.#valueName = super.cell.getAttribute(\"value-name\") || \"v\";\n\t\tthis.#multi = super.cell.getAttribute('multi') === \"true\";\n\t\tthis.#multiSeparator = super.cell.getAttribute(\"multi-separator\") || \",\";\n\n\t\tthis.#initData();\n\t\tthis.#initEvent();\n\t}\n\n\trerenderer = () => {\n\t\ttrace.log(\"rerenderer\");\n\t\tthis.#initData();\n\t\tthis.refresh();\n\t};\n\n\t#initData = () => {\n\t\tif (!super.sheet || !super.cell) return;\n\n\t\tconst dataSource = super.cell?.getAttribute(\"data-source\");\n\t\tif (!dataSource) return;\n\n\t\t// 🎯 공통 표현식 평가기를 통해 데이터 소스(배열 또는 함수 결과) 획득\n\t\t//this.#host.exprEngine.evaluate(dataSource, data, row);\n\n\t\tthis.#dataSource = super.getExprValue(dataSource, super.tr.data, super.tr.dataset.row);\n\t\t//trace.log(\"*******************************\", this.#dataSource);\n\t}\n\n\t#initEvent = () => {\n\t\t// 엔터 키 입력 시 드롭다운 토글\n\t\t/**\n\t\tthis.addEventListener(\"keydown\", e => {\n\t\t\tif (e.code === \"Enter\") {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.#togglePanel();\n\t\t\t}\n\t\t}); */\n\n\t\t// Light DOM 기준이므로 this 안에서 버튼 탐색\n\t\tthis.querySelectorAll(\"button\").forEach(btn => {\n\t\t\tbtn.addEventListener(\"click\", (e) => {\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.#togglePanel();\n\t\t\t});\n\t\t});\n\t}\n\n\t#togglePanel = () => {\n\t\ttrace.log(new Date());\n\t\tif (!this.#panel) {\n\t\t\t// 🎯 필터링 패널 방식과 동일하게 현재 셀이 속한 sheet(또는 그리드) 탐색\n\t\t\tthis.#panel = super.sheet.querySelector(\"cell-combo-panel\");\n\t\t\tif (!this.#panel) {\n\t\t\t\tthis.#panel = document.createElement(\"cell-combo-panel\");\n\t\t\t\tsuper.sheet.appendChild(this.#panel);\n\t\t\t}\n\t\t}\n\n\t\ttrace.log(new Date());\n\n\t\tif (this.#panel.isOpen && this.#panel.targetCell === this) {\n\t\t\tthis.#panel.close();\n\t\t} else {\n\t\t\tthis.#panel.open(this, this.#dataSource, this.#keyName, this.#valueName, this.#multi, this.#multiSeparator);\n\t\t}\n\n\t\ttrace.log(new Date());\n\t}\n\n\t#renderer = () => {\n\t\tthis.innerHTML = `\n <button class=\"btn1\" type=\"button\" tabindex=\"-1\">Select</button>\n <button class=\"btn2\" type=\"button\" tabindex=\"-1\"></button>\n `;\n\n\t\t// Light DOM 구조이므로 this에서 직접 쿼리\n\t\tthis.#targetBtn = this.querySelector(\".btn1\");\n\t};\n\n\trefresh = () => {\n\t\tconst v = super.refresh();\n\t\tif (!this.#targetBtn) return v;\n\n\t\t// 현재 값에 매칭되는 텍스트(표시명) 계산\n\t\tthis.#targetBtn.textContent = this.#getDisplayText() || \"Select\";\n\t\tthis.#validateInput();\n\n\t\treturn v;\n\t};\n\n\t#getDisplayText = () => {\n\t\tif (!this.value || !Array.isArray(this.#dataSource)) return \"\";\n\n\t\tif (this.#multi) {\n\t\t\tconst keys = String(this.value).split(this.#multiSeparator);\n\t\t\treturn this.#dataSource\n\t\t\t\t.filter(m => keys.includes(String(m[this.#keyName])))\n\t\t\t\t.map(m => m[this.#valueName])\n\t\t\t\t.join(this.#multiSeparator);\n\t\t} else {\n\t\t\tconst found = this.#dataSource.find(m => String(m[this.#keyName]) === String(this.value));\n\t\t\treturn found ? found[this.#valueName] : this.value;\n\t\t}\n\t}\n\n\t#validateInput = () => {\n\t\tif (!super.cell) return;\n\t\tsuper.cell.classList.remove(\"invalid\");\n\n\t\tif (this.value === null || this.value === undefined || this.value === \"\" || !Array.isArray(this.#dataSource)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst list = this.#multi ? String(this.value).split(this.#multiSeparator) : [this.value];\n\t\tfor (const v of list) {\n\t\t\tconst idx = this.#dataSource.findIndex(m => String(v) === String(m[this.#keyName]));\n\t\t\tif (idx < 0) {\n\t\t\t\tsuper.cell.classList.add(\"invalid\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t};\n\n\tget dataSource() {\n\t\treturn this.#dataSource;\n\t}\n}\n\nif (!customElements.get('cell-combo')) {\n\tcustomElements.define(\"cell-combo\", CellCombo);\n}","import { trace } from \"@nopeer\";\nimport { CellElement } from \"./core/CellElement.js\"; // Inherits from CellElement instead of EditableCellElement\n\nclass CellRenderer extends CellElement {\n\t#target;\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback();\n\n\t\t// Debug trace for inspecting component context and parent elements\n\t\t// trace.log(\"******************\", this, this.host, this.sheet, this.tr, this.cell);\n\n\t\tthis.#renderer();\n\n\t\t// Cache the internal text span target element\n\t\tthis.#target = this.querySelector(\"span\");\n\t}\n\n\t/**\n\t * Refreshes the cell display value based on binding and expression evaluations.\n\t */\n\trefresh = () => {\n\n\t\tsuper.refresh();\n\n\t\tif (this.cell.getAttribute(\"html\") === \"true\") {\n\t\t\tthis.#target.innerHTML = this.getDisplayText();\n\t\t} else {\n\t\t\tthis.#target.textContent = this.getDisplayText();\n\t\t}\n\t};\n\n\t/**\n\t * Renders the internal markup and CSS layout rules for the cell renderer.\n\t */\n\t#renderer = () => {\n\t\tthis.innerHTML = `\n <span class=\"wrapper\"></span>\n `;\n\t};\n}\n\n// Register the custom element if not already defined\nif (!customElements.get(\"cell-renderer\")) {\n\tcustomElements.define(\"cell-renderer\", CellRenderer);\n}","import { CellElement } from \"./core/CellElement.js\";\nimport { NINE_TABLE } from \"@/core/constants.js\";\nimport { trace } from \"@nopeer\";\n\nexport class CellButton extends CellElement {\n\t#target;\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\n\t\tthis.#renderer();\n\n\t\t// 부모 클래스의 connectedCallback 호출 (필수)\n\t\tsuper.connectedCallback();\n\n\t\tthis.#target = this.querySelector(\"button\");\n\n\t\tthis.#target.removeEventListener(\"click\", this.#cellButtonClick);\n\t\tthis.#target.addEventListener(\"click\", this.#cellButtonClick);\n\t}\n\n\t#cellButtonClick = e => {\n\t\te.stopPropagation();\n\n\t\tconst rowid = parseInt(this.cell.dataset.row, 10);\n\n\t\tconst customEvent = new CustomEvent(NINE_TABLE.EVENT.CELL_BUTTON_CLICK, {\n\t\t\tbubbles: true,\n\t\t\tcomposed: true,\n\t\t\tdetail: {\n\t\t\t\toriginalEvent: e,\n\t\t\t\tcell: this.cell,\n\t\t\t\trow: rowid,\n\t\t\t\tcol: parseInt(this.cell.dataset.col, 10),\n\t\t\t\tbind: this.dataset.bind,\n\t\t\t\tdata: this.host.data.get(rowid),\n\t\t\t\tvalue: this.value,\n\t\t\t}\n\t\t});\n\n\t\tthis.dispatchEvent(customEvent);\n\t};\n\n\t/**\n\t * 레거시 dataRefresh 패턴 반영 (표현식 동적 평가 및 스타일링)\n\t */\n\trefresh = () => {\n\t\tconst rawValue = super.refresh ? super.refresh() : this.value;\n\t\t//let displayValue = this.getDisplayText(rawValue);\n\t\tthis.#target.innerHTML = this.getDisplayText(rawValue);\n\n\t\t/**\n\t\t// 행 데이터 및 인덱스 확보\n\t\tconst rowIdx = parseInt(super.cell.dataset.row, 10);\n\t\tconst rowData = super.host?.data?.get ? super.host.data.get(rowIdx) : (this.closest(\"tr\")?.data);\n\n\t\tif (rowData && !isNaN(rowIdx)) {\n\t\t\t[\"color\", \"background\", \"border\"].forEach(attrName => {\n\t\t\t\tconst expr = this.getAttribute(attrName);\n\t\t\t\tif (expr && this.#target) {\n\t\t\t\t\tconst evaluatedVal = super.getExprValue ? super.getExprValue(expr, rowData, rowIdx, super.cell) : expr;\n\t\t\t\t\tthis.#target.style[attrName] = evaluatedVal;\n\t\t\t\t}\n\t\t\t});\n\t\t} */\n\t};\n\n\t#renderer = () => {\n\t\t/**\n\t\tconst allowedAttrs = [\"color\", \"background\", \"border\", \"class\", \"style\"];\n\t\tconst attrList = [];\n\n\t\tfor (let i = 0; i < this.attributes.length; i++) {\n\t\t\tconst attr = this.attributes[i];\n\t\t\tif (allowedAttrs.includes(attr.name)) {\n\t\t\t\tattrList.push(`${attr.name}=\"${attr.value}\"`);\n\t\t\t}\n\t\t} */\n\n\t\tconst cell = this.closest(\"th,td\");\n\n\t\tconst buttonText = \"...\";//this.getAttribute(\"text\") || super.attr[\"text\"] || \"\";\n\t\tconst height = (parseInt(cell.offsetHeight, 10) || 32) - 8;\n\n\t\tthis.innerHTML = `\n <button class=\"button\">${buttonText}</button>\n `;\n\t};\n}\n\nif (!customElements.get('cell-button')) {\n\tcustomElements.define(\"cell-button\", CellButton);\n}","import { trace } from \"@nopeer\";\nimport { CellElement } from \"./core/CellElement.js\";\n\nclass CellRowIndicator extends CellElement {\n\t#mainTarget;\n\t#subTarget;\n\t#statusTarget;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.applyBaseStyle();\n\t}\n\n\tconnectedCallback() {\n\t\tthis.#renderer();\n\t\tsuper.connectedCallback?.();\n\n\t\tif (this.cell) {\n\t\t\tthis.cell.removeAttribute(\"tabindex\");\n\t\t\tthis.cell.dataset.bind = \"rowState\";\n\n\t\t\tif (!this.cell.dataset.expr) {\n\t\t\t\tthis.cell.dataset.expr = \"data.__ng._[ninegrid.ROW.ORDER]\";\n\t\t\t}\n\n\t\t\tthis.cell.setAttribute(\"text-align\", \"center\");\n\t\t}\n\n\t\tthis.#mainTarget = this.querySelector(\".ng-row-main\");\n\t\tthis.#subTarget = this.querySelector(\".ng-row-sub\");\n\t\tthis.#statusTarget = this.querySelector(\".ng-row-status\");\n\t}\n\n\t#renderer = () => {\n\t\tthis.innerHTML = `\n\t\t\t<span class=\"ng-row-main\"></span>\n <span class=\"ng-row-sub\"></span>\n <span class=\"ng-row-status\"></span>\n `;\n\t}\n\n\t/**\n\t * 행 번호 및 상태 갱신\n\t */\n\trefresh = () => {\n\t\tif (!this.cell || !this.tr) return;\n\n\t\tconst row = this.row;\n\t\tif (isNaN(row)) return;\n\n\t\tconst rawRecord = this.tr.data;\n\n\t\tif (rawRecord && rawRecord.__ng) {\n\t\t\tconst rowState = rawRecord.__ng.rowState;\n\n\t\t\t/**\n\t\t\t// 1. 행 상태에 따른 클래스 제어 및 우측 상단 상태 표시\n\t\t\tif (rowState === ninegrid.ROW_STATE.INSERT) {\n\t\t\t\tthis.classList.add('added');\n\t\t\t\tthis.classList.remove('updated');\n\t\t\t\tif (this.#statusTarget) this.#statusTarget.textContent = \"➕\";\n\t\t\t} else if (rowState === ninegrid.ROW_STATE.UPDATE) {\n\t\t\t\tthis.classList.add('updated');\n\t\t\t\tthis.classList.remove('added');\n\t\t\t\tif (this.#statusTarget) this.#statusTarget.textContent = \"✏️\";\n\t\t\t} else {\n\t\t\t\tthis.classList.remove('added', 'updated');\n\t\t\t\tif (this.#statusTarget) this.#statusTarget.textContent = \"\";\n\t\t\t} */\n\n\t\t\t/**\n\t\t\t// 2. 필터링 등으로 순번이 밀렸을 때 우측 하단에 원본 번호 표시\n\t\t\tif (rawRecord.__ng.i !== undefined) {\n\t\t\t\tconst currentSeq = row + 1;\n\t\t\t\tconst originalSeq = rawRecord.__ng.i + 1;\n\n\t\t\t\tif (this.#subTarget) {\n\t\t\t\t\tif (currentSeq !== originalSeq) {\n\t\t\t\t\t\tthis.#subTarget.textContent = originalSeq;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#subTarget.textContent = \"\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} */\n\t\t}\n\n\t\tconst displayNum = this.index + 1;\n\n\t\t// 천단위 콤마 포맷팅 (예: 1234567 -> \"1,234,567\")\n\t\tconst formattedNum = displayNum.toLocaleString();\n\n\t\t// 3자리 이상일 경우 마지막 3자리(와 콤마 포함된 덩어리)를 기준으로 앞자리와 분리\n\t\tif (displayNum >= 10000) {\n\t\t\t// 뒤에서 4글자(콤마 + 3자리)를 기준으로 분리합니다. (예: \"1,234\" 와 \"567\")\n\t\t\tconst splitIndex = formattedNum.length - 4;\n\t\t\tconst prefixPart = formattedNum.substring(0, splitIndex + 1); // 천단위 이상 (작은 폰트)\n\t\t\tconst suffixPart = formattedNum.substring(splitIndex + 1); // 마지막 콤마 + 3자리 (기본 폰트)\n\n\t\t\tthis.#mainTarget.innerHTML = `\n <span class=\"ng-row-prefix\">${prefixPart}</span>\n <span class=\"ng-row-suffix\">${suffixPart}</span>\n `;\n\t\t} else {\n\t\t\t// 1000 미만인 경우 콤마만 있거나 일반 숫자로 그대로 표시\n\t\t\tthis.#mainTarget.innerHTML = `${formattedNum}`;\n\t\t}\n\n\t\tconst isSorted = this.sheet.querySelector(\"thead .asc,thead .desc\") ? true : false;\n\t\tconst isFitered = this.sheet.querySelector(\"thead nine-table-filter-button.filtered\") ? true : false;\n\n\t\tthis.#subTarget.innerHTML = row;\n\t\tthis.#subTarget.style.display = (isSorted || isFitered) ? \"\" : \"none\";\n\t};\n}\n\nif (!customElements.get('cell-row-indicator')) {\n\tcustomElements.define(\"cell-row-indicator\", CellRowIndicator);\n}","// ui/col/col-expand.js\nimport { TableCompiler, COLLAPSED_WIDTH } from \"@/layout/core/TableCompiler.js\";\n\nexport class ColExpand extends HTMLElement {\n #sheet;\n #cell;\n\n constructor() {\n super();\n }\n\n connectedCallback() {\n this.#cell = this.closest('th, td');\n this.#sheet = this.closest('nine-table-sheet');\n\n if (this.#cell) {\n this.#cell.style.position = 'relative';\n }\n\n const isCollapsed =\n this.getAttribute('collapsed') === 'true' ||\n this.#cell?.getAttribute('collapsed') === 'true';\n\n if (isCollapsed) {\n requestAnimationFrame(() => {\n this.collapse(true);\n });\n } else {\n this.classList.remove('collapsed');\n this.classList.add('expand');\n }\n\n this.removeEventListener('click', this.#onClick);\n this.addEventListener('click', this.#onClick);\n }\n\n #onClick = (e) => {\n e.preventDefault();\n e.stopPropagation();\n\n if (this.classList.contains('expand')) {\n this.collapse();\n } else {\n this.expand();\n }\n };\n\n /**\n * 🎯 원래 너비(dataset.expandWidth)로 복구\n */\n expand = () => {\n if (!this.#sheet?.colResizer || !this.#cell) return;\n const colIndex = parseInt(this.#cell.dataset.col, 10);\n const colSpan = this.#cell.colSpan || 1;\n\n this.classList.remove('collapsed');\n this.classList.add('expand');\n this.#cell.setAttribute('collapsed', 'false');\n this.#cell.style.color = '';\n\n const targetWidth = parseInt(this.#cell.dataset.expandWidth, 10) || 100;\n\n if (colSpan === 1) {\n this.#sheet.colResizer.setColumnWidth(colIndex, targetWidth);\n } else {\n const singleWidth = Math.max(30, Math.floor(targetWidth / colSpan));\n for (let i = 0; i < colSpan; i++) {\n this.#sheet.colResizer.setColumnWidth(colIndex + i, singleWidth);\n }\n }\n\n requestAnimationFrame(() => {\n if (typeof this.#sheet.refreshLayout === 'function') {\n this.#sheet.refreshLayout();\n }\n });\n };\n\n collapse = (isInitialInit = false) => {\n if (!this.#sheet?.colResizer || !this.#cell) return;\n const colIndex = parseInt(this.#cell.dataset.col, 10);\n const colSpan = this.#cell.colSpan || 1;\n\n if (this.classList.contains('expand')) {\n const col = this.#sheet.querySelector(`colgroup col[data-col=\"${colIndex}\"]`);\n const currentW = col ? parseInt(col.getAttribute('width'), 10) : 0;\n if (currentW > COLLAPSED_WIDTH) {\n this.#cell.dataset.expandWidth = String(currentW * colSpan);\n }\n }\n\n this.classList.remove('expand');\n this.classList.add('collapsed');\n this.#cell.setAttribute('collapsed', 'true');\n this.#cell.style.color = 'transparent';\n\n // 🎯 colSpan이 1이면 16px(COLLAPSED_WIDTH)을 그대로 적용, 2 이상이면 균등 분할\n if (colSpan === 1) {\n this.#sheet.colResizer.setColumnWidth(colIndex, COLLAPSED_WIDTH);\n } else {\n const splitWidth = Math.max(10, Math.floor(COLLAPSED_WIDTH / colSpan));\n for (let i = 0; i < colSpan; i++) {\n this.#sheet.colResizer.setColumnWidth(colIndex + i, splitWidth);\n }\n }\n\n requestAnimationFrame(() => {\n if (typeof this.#sheet.refreshLayout === 'function') {\n this.#sheet.refreshLayout();\n }\n });\n };\n\n disconnectedCallback() {\n this.removeEventListener('click', this.#onClick);\n }\n}\n\nif (!customElements.get('nine-table-col-expand')) {\n customElements.define('nine-table-col-expand', ColExpand);\n}","// ui/menu/nine-table-menu.js (수정본)\n\nimport { trace } from \"@nopeer\";\nimport { ColFixManager } from \"@/col/ColFixManager.js\";\n\nexport class ContextMenu extends HTMLElement {\n #tableHost;\n #panel;\n\n connectedCallback() {\n const root = this.getRootNode();\n this.#tableHost = root instanceof ShadowRoot ? root.host : (this.closest('nine-table') || root.host);\n\n if (!this.#tableHost) {\n this.#tableHost = this.parentElement?.closest('nine-table') || this.assignedSlot?.closest('nine-table');\n }\n\n if (!this.#tableHost) return;\n\n //this.#tableHost.addEventListener('contextmenu', this.#onContextMenu);\n }\n\n #onContextMenu = (e) => {\n const path = e.composedPath ? e.composedPath() : [];\n const targetCell = path.find(el => el.tagName === 'TH' || el.tagName === 'TD');\n\n if (!targetCell) return;\n\n const targetTable = path.find(el => el.tagName === 'TABLE') || targetCell.closest('table');\n\n e.preventDefault();\n e.stopPropagation();\n\n this.openMenu(e.clientX, e.clientY, targetCell, targetTable);\n };\n\n /**\n * 🎯 우클릭이 발생한 대상 시트(NineTableSheet) 구하기\n */\n #getTargetSheet(targetCell) {\n return targetCell?.closest('nine-table-sheet') || this.#tableHost.activeSheet || this.#tableHost;\n }\n\n #getFixManager(targetCell) {\n const sheet = this.#getTargetSheet(targetCell);\n if (!sheet) return null;\n\n if (!sheet.colFix) {\n sheet.colFix = new ColFixManager(sheet);\n }\n return sheet.colFix;\n }\n\n #parseCustomMenuItems(containerElement, activeTable) {\n const items = [];\n const activeTableId = activeTable?.id;\n const allUls = Array.from(containerElement.querySelectorAll(':scope > ul'));\n\n allUls.forEach(rootUl => {\n const targetTableAttr = rootUl.getAttribute('target-table');\n\n if (!targetTableAttr || (activeTableId && targetTableAttr === activeTableId)) {\n const parsedList = this.#traverseUl(rootUl);\n items.push(...parsedList);\n }\n });\n\n return items;\n }\n\n #traverseUl(ulEl) {\n const list = [];\n Array.from(ulEl.children).forEach(child => {\n const tagName = child.tagName.toLowerCase();\n\n if (tagName === 'hr' || child.classList.contains('separator')) {\n list.push({ type: 'separator' });\n return;\n }\n\n if (tagName === 'li') {\n let name = '';\n const spanEl = child.querySelector(':scope > span');\n if (spanEl) {\n name = spanEl.textContent.trim();\n } else {\n name = Array.from(child.childNodes)\n .filter(n => n.nodeType === Node.TEXT_NODE)\n .map(n => n.textContent.trim())\n .join('');\n }\n\n const subUl = child.querySelector(':scope > ul');\n const item = {\n menuId: child.id || name,\n name: name,\n className: child.className || '',\n disabled: child.hasAttribute('disabled') || child.getAttribute('disabled') === 'true',\n isCustom: true\n };\n\n if (subUl) {\n item.items = this.#traverseUl(subUl);\n }\n\n list.push(item);\n }\n });\n return list;\n }\n\n #buildMenuItems(activeTable, isHeaderCell, targetCell) {\n const useDefault = this.getAttribute('use-default-menu') !== 'false';\n let rawItems = [];\n\n const customItems = this.#parseCustomMenuItems(this, activeTable);\n if (customItems.length > 0) {\n rawItems.push(...customItems);\n }\n\n const fixManager = this.#getFixManager(targetCell);\n const currentFixState = fixManager?.getFixState(targetCell, activeTable) ?? 'none';\n const isFixable = isHeaderCell && (fixManager?.canFixColumn(targetCell, activeTable) ?? false);\n\n let fixMenuItem = null;\n if (currentFixState === 'left' || currentFixState === 'right') {\n fixMenuItem = {\n menuId: 'unfix-column',\n name: 'Unfix Column',\n className: 'ng-menu-unfix-col',\n disabled: !isHeaderCell\n };\n } else {\n fixMenuItem = {\n menuId: 'fix-column',\n name: 'Fix Column',\n className: 'ng-menu-fix-col',\n disabled: !isFixable\n };\n }\n\n if (useDefault) {\n rawItems.push(\n { type: 'separator' },\n {\n menuId: 'sort',\n name: 'Sort',\n className: 'ng-menu-sort',\n disabled: !isHeaderCell\n },\n fixMenuItem,\n { type: 'separator' },\n { menuId: 'filtering', name: 'Filtering', className: 'ng-menu-filtering' },\n { menuId: 'maximize', name: 'Maximize', className: 'maximize' },\n {\n menuId: 'export',\n name: 'Export',\n className: 'export',\n items: [\n { menuId: 'export-excel', name: 'Excel', className: 'export-excel' },\n { menuId: 'export-pdf', name: 'PDF', className: 'export-pdf', disabled: true }\n ]\n },\n {\n menuId: 'properties',\n name: 'Options',\n className: 'options',\n items: [\n { menuId: 'show-title-bar', name: 'Title Bar Show/Hide', className: 'show-title-bar' },\n { menuId: 'show-status-bar', name: 'Status Bar Show/Hide', className: 'show-status-bar' },\n { menuId: 'auto-fit-col', name: 'Auto Fit Columns', className: 'auto-fit-col' }\n ]\n }\n );\n }\n\n const cleanedItems = [];\n rawItems.forEach((item) => {\n if (item.type === 'separator') {\n if (cleanedItems.length === 0 || cleanedItems[cleanedItems.length - 1].type === 'separator') {\n return;\n }\n }\n cleanedItems.push(item);\n });\n\n if (cleanedItems.length > 0 && cleanedItems[cleanedItems.length - 1].type === 'separator') {\n cleanedItems.pop();\n }\n\n return cleanedItems;\n }\n\n openMenu(x, y, targetCell, targetTable) {\n const targetParent = this.#tableHost.shadowRoot || this.#tableHost;\n\n if (!this.#panel) {\n this.#panel = document.createElement('nine-table-menu-panel');\n targetParent.appendChild(this.#panel);\n }\n\n const isHeaderCell = !!targetCell.closest('thead');\n const menuItems = this.#buildMenuItems(targetTable, isHeaderCell, targetCell);\n\n this.#panel.render(menuItems, (e) => this.#handleMenuClick(e, targetCell, targetTable));\n\n const targetSheet = this.#getTargetSheet(targetCell);\n this.#syncMenuStates(targetSheet);\n\n // 🎯 targetCell을 3번째 인자로 전달하여 셀 우측선 정렬\n this.#panel.openAt(x, y);\n }\n\n /**\n * 🎯 메뉴 항목 활성화 체크 표시(✓) 동기화\n */\n #syncMenuStates(targetSheet) {\n if (!this.#panel || !targetSheet) return;\n\n // 🎯 클릭된 개별 시트의 filtering 상태 검사\n const isFiltering = targetSheet.filtering?.isFiltering?.() || false;\n this.#panel.toggleItemState('filtering', 'on', isFiltering);\n\n const autoFit = this.#tableHost.getAttribute('auto-fit-col') === 'true';\n this.#panel.toggleItemState('auto-fit-col', 'on', autoFit);\n\n const showTitle = this.#tableHost.getAttribute('show-title-bar') === 'true';\n this.#panel.toggleItemState('show-title-bar', 'on', showTitle);\n }\n\n #handleMenuClick(e, targetCell, targetTable) {\n const menuId = e.menuId;\n\n const customEvent = new CustomEvent('menu-click', {\n detail: { menuId, targetCell, targetTable, originalEvent: e },\n bubbles: true,\n composed: true\n });\n this.dispatchEvent(customEvent);\n\n const baseCol = parseInt(targetCell.dataset.col, 10);\n\n // 🎯 클릭된 셀의 소속 시트 인스턴스 타겟팅\n const targetSheet = this.#getTargetSheet(targetCell);\n\n switch (menuId) {\n case 'fix-column':\n case 'unfix-column':\n const fixManager = this.#getFixManager(targetCell);\n fixManager?.executeFixToggle(menuId, targetCell);\n break;\n\n case 'sort':\n if (!isNaN(baseCol)) {\n targetSheet.sorting?.handleSortFromMenu?.(baseCol, targetCell);\n }\n break;\n\n case 'filtering':\n targetSheet?.filtering?.toggle();\n break;\n\n case 'auto-fit-col':\n this.#tableHost.setAttribute('auto-fit-col', this.#tableHost.getAttribute('auto-fit-col') === 'true' ? 'false' : 'true');\n break;\n\n case 'show-title-bar':\n this.#tableHost.setAttribute('show-title-bar', this.#tableHost.getAttribute('show-title-bar') === 'true' ? 'false' : 'true');\n break;\n }\n\n this.#panel.close();\n }\n\n disconnectedCallback() {\n this.#tableHost?.removeEventListener('contextmenu', this.#onContextMenu);\n }\n}\n\nif (!customElements.get('nine-table-menu')) {\n customElements.define('nine-table-menu', ContextMenu);\n}","// ui/menu/nine-table-menu-panel.js\n\nexport class MenuPanel extends HTMLElement {\n #onCallback;\n #closeHandler = null; // 🎯 이벤트 누수 방지용 리스너 참조\n\n constructor() {\n super();\n }\n\n connectedCallback() {\n // 🎯 [보정 1] 패널 자체의 기본 레이아웃 스타일은 element style로 직접 지정\n this.style.position = 'fixed';\n this.style.display = 'none';\n this.style.zIndex = '99999';\n\n this.innerHTML = `\n <div class=\"menu-wrapper\">\n <ul class=\"menu-container\"></ul>\n </div>\n `;\n }\n\n render(items, callback) {\n this.#onCallback = callback;\n const container = this.querySelector('.menu-container');\n if (!container) return;\n\n container.innerHTML = '';\n\n this.#appendItems(container, items);\n this.#bindClickEvents();\n }\n\n /**\n * 🎯 패널의 우측선과 targetCell의 우측선을 일치시키는 포지셔닝\n */\n openAt(x, y, targetCell = null) {\n this.style.display = 'block';\n\n if (targetCell) {\n const cellRect = targetCell.getBoundingClientRect();\n // 셀의 오른쪽 경계선 좌표\n const cellRightX = cellRect.right;\n\n requestAnimationFrame(() => {\n const wrapper = this.querySelector('.menu-wrapper');\n if (!wrapper) return;\n const panelWidth = wrapper.getBoundingClientRect().width;\n\n // 패널 우측선을 셀 우측선에 맞춤 (Left = cellRight - panelWidth)\n let calculatedLeft = cellRightX - panelWidth;\n\n // 뷰포트 왼쪽 밖으로 벗어나는 예외 처리\n if (calculatedLeft < 0) {\n calculatedLeft = cellRect.left; // 공간이 부족하면 셀 좌측선에 맞춤\n }\n\n // 뷰포트 아래쪽 벗어남 처리\n const panelHeight = wrapper.getBoundingClientRect().height;\n let calculatedTop = y;\n if (y + panelHeight > window.innerHeight) {\n calculatedTop = y - panelHeight;\n }\n\n this.style.left = `${calculatedLeft}px`;\n this.style.top = `${calculatedTop}px`;\n });\n } else {\n // 기본 마우스 클릭 좌표 기반 (Fallback)\n this.style.left = `${x}px`;\n this.style.top = `${y}px`;\n\n requestAnimationFrame(() => {\n const wrapper = this.querySelector('.menu-wrapper');\n if (!wrapper) return;\n const rect = wrapper.getBoundingClientRect();\n\n if (x + rect.width > window.innerWidth) {\n this.style.left = `${x - rect.width}px`;\n }\n if (y + rect.height > window.innerHeight) {\n this.style.top = `${y - rect.height}px`;\n }\n });\n }\n\n // 바깥 클릭 핸들러 등록\n if (this.#closeHandler) {\n window.removeEventListener('pointerdown', this.#closeHandler);\n }\n\n this.#closeHandler = (e) => {\n const path = e.composedPath ? e.composedPath() : [];\n if (!path.includes(this) && !this.contains(e.target)) {\n this.close();\n }\n };\n\n setTimeout(() => {\n window.addEventListener('pointerdown', this.#closeHandler);\n }, 0);\n }\n\n close() {\n this.style.display = 'none';\n if (this.#closeHandler) {\n window.removeEventListener('pointerdown', this.#closeHandler);\n this.#closeHandler = null;\n }\n }\n\n toggleItemState(menuId, className, condition) {\n const li = this.querySelector(`li[menu-id=\"${menuId}\"]`);\n if (li) {\n condition ? li.classList.add(className) : li.classList.remove(className);\n }\n }\n\n #appendItems(parentUl, items) {\n items.forEach(item => {\n if (item.type === 'separator') {\n const sep = document.createElement('li');\n sep.className = 'ng-menu-separator';\n parentUl.appendChild(sep);\n return;\n }\n\n const li = document.createElement('li');\n li.setAttribute('menu-id', item.menuId);\n li.className = `${item.className || ''} ${item.items ? 'submenu' : ''} ${item.disabled ? 'disabled' : ''}`.trim();\n\n const span = document.createElement('span');\n span.textContent = item.name;\n li.appendChild(span);\n\n if (item.items && item.items.length > 0) {\n const subUl = document.createElement('ul');\n subUl.className = 'ng-menu-sublist';\n this.#appendItems(subUl, item.items);\n li.appendChild(subUl);\n }\n\n parentUl.appendChild(li);\n });\n }\n\n #bindClickEvents() {\n this.querySelectorAll('li[menu-id]').forEach(li => {\n li.addEventListener('click', (e) => {\n e.stopPropagation();\n if (li.classList.contains('disabled')) return;\n\n const menuId = li.getAttribute('menu-id');\n this.#onCallback?.({ menuId, target: li });\n this.close();\n });\n });\n }\n\n disconnectedCallback() {\n this.close();\n }\n}\n\nif (!customElements.get('nine-table-menu-panel')) {\n customElements.define('nine-table-menu-panel', MenuPanel);\n}"],"mappings":"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"}
|