ninegrid2 6.1248.0 → 6.1250.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -118768,8 +118768,6 @@ class NineGridContainer extends HTMLElement
118768
118768
  this.querySelectorAll("nx-buttons *").forEach(v => {v.grid = this;});
118769
118769
  $(this.shadowRoot.querySelector("ng-head").shadowRoot.querySelector("ng-custom")).append(this.querySelectorAll("nx-buttons"));
118770
118770
 
118771
-
118772
-
118773
118771
  this.#prepare();
118774
118772
 
118775
118773
  this.createTemplate();
@@ -121840,33 +121838,48 @@ class nxTitle extends HTMLElement {
121840
121838
 
121841
121839
  customElements.define("nx-title", nxTitle);
121842
121840
 
121843
- class nxDiv extends HTMLElement
121844
- {
121841
+ class nxDiv extends HTMLElement {
121845
121842
  originContents;
121846
121843
  #isInitialized = false;
121844
+ #root; // Shadow DOM 사용 여부에 따라 shadowRoot 또는 this를 가리킴
121847
121845
 
121848
- constructor () {
121846
+ constructor() {
121849
121847
  super();
121850
- this.attachShadow({ mode: 'open' });
121848
+ // 1. 'use-shadow' 속성이 "false"가 아니면 기본적으로 Shadow DOM을 사용하도록 설정
121849
+ const useShadow = this.getAttribute("use-shadow") !== "false";
121850
+
121851
+ if (useShadow) {
121852
+ this.attachShadow({ mode: 'open' });
121853
+ this.#root = this.shadowRoot;
121854
+ } else {
121855
+ this.#root = this;
121856
+ }
121851
121857
  }
121852
-
121858
+
121853
121859
  connectedCallback() {
121854
121860
  if (!this.#isInitialized) {
121855
121861
  this.#init();
121856
- this.#isInitialized = true; // 3. 초기화 후 플래그를 true로 변경합니다.
121862
+ this.#isInitialized = true;
121857
121863
  return true;
121858
121864
  }
121859
-
121860
121865
  return false;
121861
121866
  }
121862
121867
 
121868
+ // 공통 쿼리 함수: 현재 root(Shadow 또는 Light DOM)에서 요소를 찾음
121869
+ #getElements() {
121870
+ return ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.#root);
121871
+ }
121872
+
121873
+ // 자식 클래스에서 접근할 수 있도록 getter 제공
121874
+ get root() {
121875
+ return this.#root;
121876
+ }
121877
+
121863
121878
  getData = () => {
121864
121879
  const jsonData = {};
121865
-
121866
- // Shadow DOM 내의 폼 요소만 선택
121867
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
121880
+ this.#getElements().forEach(el => {
121868
121881
  const key = el.name;
121869
- if (!key) return; // name이 없는 요소는 건너뜁니다.
121882
+ if (!key) return;
121870
121883
 
121871
121884
  let value;
121872
121885
  if (el.tagName === "INPUT" && (el.type === "checkbox" || el.type === "radio")) {
@@ -121875,50 +121888,40 @@ class nxDiv extends HTMLElement
121875
121888
  value = el.value;
121876
121889
  }
121877
121890
 
121878
- // 중복 name을 대비한 배열 처리
121879
121891
  if (jsonData[key]) {
121880
- if (!Array.isArray(jsonData[key])) {
121881
- jsonData[key] = [jsonData[key]];
121882
- }
121892
+ if (!Array.isArray(jsonData[key])) jsonData[key] = [jsonData[key]];
121883
121893
  jsonData[key].push(value);
121884
121894
  } else {
121885
121895
  jsonData[key] = value;
121886
121896
  }
121887
121897
  });
121888
-
121889
121898
  return jsonData;
121890
121899
  };
121891
121900
 
121892
121901
  setData = (jsonData) => {
121893
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
121894
- console.log("------", el);
121902
+ this.#getElements().forEach(el => {
121895
121903
  el.removeEventListener("input", this.#changeHandler);
121896
121904
  el.addEventListener("input", this.#changeHandler);
121897
121905
  });
121898
121906
 
121899
- if (!jsonData || typeof jsonData !== 'object') {
121900
- console.error("setData: Invalid data provided. Expected an object.");
121901
- return;
121902
- }
121907
+ if (!jsonData || typeof jsonData !== 'object') return;
121903
121908
 
121904
121909
  let bChanged = false;
121905
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
121910
+ this.#getElements().forEach(el => {
121906
121911
  const key = el.name;
121907
121912
  if (!key || !jsonData.hasOwnProperty(key)) return;
121908
121913
 
121909
121914
  const value = jsonData[key];
121910
-
121911
- // 폼 요소에만 데이터를 설정합니다.
121912
121915
  if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
121913
121916
  if (el.type === "checkbox" || el.type === "radio") {
121914
- if (el.checked !== (el.value === String(value))) bChanged = true;
121915
- el.checked = (el.value === String(value));
121917
+ const isChecked = (String(el.value) === String(value));
121918
+ if (el.checked !== isChecked) bChanged = true;
121919
+ el.checked = isChecked;
121916
121920
  } else {
121917
121921
  if (el.value !== value) bChanged = true;
121918
121922
  el.value = value;
121919
121923
  }
121920
121924
  } else {
121921
- // 폼 요소가 아닌 경우, textContent를 사용합니다.
121922
121925
  if (el.textContent !== value) bChanged = true;
121923
121926
  el.textContent = value;
121924
121927
  }
@@ -121945,22 +121948,22 @@ class nxDiv extends HTMLElement
121945
121948
  }
121946
121949
 
121947
121950
  #init = () => {
121948
-
121949
- //console.log(this);
121950
- //console.log(this.querySelectorAll("input[name], textarea[name], select[name]"));
121951
-
121952
- /**
121953
- * css style 적용
121954
- */
121951
+ // CSS Style 적용
121955
121952
  for (const attr of this.attributes) {
121956
121953
  if (attr.name.startsWith("css-")) {
121957
- // "css-" 접두사를 제거하고 CSS 속성명으로 변환
121958
121954
  this.style.setProperty(attr.name.substring(4), attr.value);
121959
121955
  }
121960
121956
  }
121961
121957
 
121958
+ // 2. HTML 내용 처리
121962
121959
  this.originContents = this.innerHTML.trim();
121963
- this.innerHTML = ""; // 기존 내부 HTML 제거
121960
+
121961
+ // Shadow DOM을 사용할 경우 내용을 안으로 옮김
121962
+ if (this.shadowRoot) {
121963
+ this.shadowRoot.innerHTML = this.originContents;
121964
+ this.innerHTML = ""; // 외부(Light DOM) 내용은 비움
121965
+ }
121966
+ // Shadow DOM을 안 쓰면 그대로 유지 (this.#root가 this이므로 별도 처리 불필요)
121964
121967
  };
121965
121968
  }
121966
121969
 
@@ -122247,27 +122250,36 @@ class nxPanel extends nxDiv {
122247
122250
  customElements.define("nx-panel", nxPanel);
122248
122251
 
122249
122252
  class nxButtons extends nxDiv {
122250
-
122251
122253
  constructor() {
122252
122254
  super();
122253
122255
  }
122254
122256
 
122255
122257
  connectedCallback() {
122256
122258
  if (super.connectedCallback()) this.#init();
122257
- };
122259
+ }
122258
122260
 
122259
122261
  #init = () => {
122260
- const htmlTmpl = document.createElement("template");
122261
- htmlTmpl.innerHTML = `
122262
- <style>
122263
- @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
122264
- ${ninegrid.getCustomPath(this,"nxButtons.css")}
122265
- </style>
122266
-
122267
- ${this.originContents}
122262
+ // 1. 스타일과 내용을 합친 템플릿 생성
122263
+ const styleContent = `
122264
+ <style>
122265
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
122266
+ ${ninegrid.getCustomPath(this, "nxButtons.css")}
122267
+ </style>
122268
122268
  `;
122269
+ console.log("11111");
122270
+ const htmlTmpl = document.createElement("template");
122269
122271
 
122270
- this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
122272
+ // Shadow DOM일 때는 originContents를 옮겨야 하고,
122273
+ // Light DOM일 때는 이미 본문에 있으므로 스타일만 추가하면 됨
122274
+ if (this.shadowRoot) {
122275
+ htmlTmpl.innerHTML = `${styleContent}${this.originContents}`;
122276
+ this.root.appendChild(htmlTmpl.content.cloneNode(true));
122277
+ } else {
122278
+ // Light DOM 모드일 때: 스타일만 상단에 추가
122279
+ const styleDiv = document.createElement("div");
122280
+ styleDiv.innerHTML = styleContent;
122281
+ this.root.prepend(styleDiv);
122282
+ }
122271
122283
  }
122272
122284
  }
122273
122285
 
@@ -118764,8 +118764,6 @@ class NineGridContainer extends HTMLElement
118764
118764
  this.querySelectorAll("nx-buttons *").forEach(v => {v.grid = this;});
118765
118765
  $(this.shadowRoot.querySelector("ng-head").shadowRoot.querySelector("ng-custom")).append(this.querySelectorAll("nx-buttons"));
118766
118766
 
118767
-
118768
-
118769
118767
  this.#prepare();
118770
118768
 
118771
118769
  this.createTemplate();
@@ -121836,33 +121834,48 @@ class nxTitle extends HTMLElement {
121836
121834
 
121837
121835
  customElements.define("nx-title", nxTitle);
121838
121836
 
121839
- class nxDiv extends HTMLElement
121840
- {
121837
+ class nxDiv extends HTMLElement {
121841
121838
  originContents;
121842
121839
  #isInitialized = false;
121840
+ #root; // Shadow DOM 사용 여부에 따라 shadowRoot 또는 this를 가리킴
121843
121841
 
121844
- constructor () {
121842
+ constructor() {
121845
121843
  super();
121846
- this.attachShadow({ mode: 'open' });
121844
+ // 1. 'use-shadow' 속성이 "false"가 아니면 기본적으로 Shadow DOM을 사용하도록 설정
121845
+ const useShadow = this.getAttribute("use-shadow") !== "false";
121846
+
121847
+ if (useShadow) {
121848
+ this.attachShadow({ mode: 'open' });
121849
+ this.#root = this.shadowRoot;
121850
+ } else {
121851
+ this.#root = this;
121852
+ }
121847
121853
  }
121848
-
121854
+
121849
121855
  connectedCallback() {
121850
121856
  if (!this.#isInitialized) {
121851
121857
  this.#init();
121852
- this.#isInitialized = true; // 3. 초기화 후 플래그를 true로 변경합니다.
121858
+ this.#isInitialized = true;
121853
121859
  return true;
121854
121860
  }
121855
-
121856
121861
  return false;
121857
121862
  }
121858
121863
 
121864
+ // 공통 쿼리 함수: 현재 root(Shadow 또는 Light DOM)에서 요소를 찾음
121865
+ #getElements() {
121866
+ return ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.#root);
121867
+ }
121868
+
121869
+ // 자식 클래스에서 접근할 수 있도록 getter 제공
121870
+ get root() {
121871
+ return this.#root;
121872
+ }
121873
+
121859
121874
  getData = () => {
121860
121875
  const jsonData = {};
121861
-
121862
- // Shadow DOM 내의 폼 요소만 선택
121863
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
121876
+ this.#getElements().forEach(el => {
121864
121877
  const key = el.name;
121865
- if (!key) return; // name이 없는 요소는 건너뜁니다.
121878
+ if (!key) return;
121866
121879
 
121867
121880
  let value;
121868
121881
  if (el.tagName === "INPUT" && (el.type === "checkbox" || el.type === "radio")) {
@@ -121871,50 +121884,40 @@ class nxDiv extends HTMLElement
121871
121884
  value = el.value;
121872
121885
  }
121873
121886
 
121874
- // 중복 name을 대비한 배열 처리
121875
121887
  if (jsonData[key]) {
121876
- if (!Array.isArray(jsonData[key])) {
121877
- jsonData[key] = [jsonData[key]];
121878
- }
121888
+ if (!Array.isArray(jsonData[key])) jsonData[key] = [jsonData[key]];
121879
121889
  jsonData[key].push(value);
121880
121890
  } else {
121881
121891
  jsonData[key] = value;
121882
121892
  }
121883
121893
  });
121884
-
121885
121894
  return jsonData;
121886
121895
  };
121887
121896
 
121888
121897
  setData = (jsonData) => {
121889
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
121890
- console.log("------", el);
121898
+ this.#getElements().forEach(el => {
121891
121899
  el.removeEventListener("input", this.#changeHandler);
121892
121900
  el.addEventListener("input", this.#changeHandler);
121893
121901
  });
121894
121902
 
121895
- if (!jsonData || typeof jsonData !== 'object') {
121896
- console.error("setData: Invalid data provided. Expected an object.");
121897
- return;
121898
- }
121903
+ if (!jsonData || typeof jsonData !== 'object') return;
121899
121904
 
121900
121905
  let bChanged = false;
121901
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
121906
+ this.#getElements().forEach(el => {
121902
121907
  const key = el.name;
121903
121908
  if (!key || !jsonData.hasOwnProperty(key)) return;
121904
121909
 
121905
121910
  const value = jsonData[key];
121906
-
121907
- // 폼 요소에만 데이터를 설정합니다.
121908
121911
  if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
121909
121912
  if (el.type === "checkbox" || el.type === "radio") {
121910
- if (el.checked !== (el.value === String(value))) bChanged = true;
121911
- el.checked = (el.value === String(value));
121913
+ const isChecked = (String(el.value) === String(value));
121914
+ if (el.checked !== isChecked) bChanged = true;
121915
+ el.checked = isChecked;
121912
121916
  } else {
121913
121917
  if (el.value !== value) bChanged = true;
121914
121918
  el.value = value;
121915
121919
  }
121916
121920
  } else {
121917
- // 폼 요소가 아닌 경우, textContent를 사용합니다.
121918
121921
  if (el.textContent !== value) bChanged = true;
121919
121922
  el.textContent = value;
121920
121923
  }
@@ -121941,22 +121944,22 @@ class nxDiv extends HTMLElement
121941
121944
  }
121942
121945
 
121943
121946
  #init = () => {
121944
-
121945
- //console.log(this);
121946
- //console.log(this.querySelectorAll("input[name], textarea[name], select[name]"));
121947
-
121948
- /**
121949
- * css style 적용
121950
- */
121947
+ // CSS Style 적용
121951
121948
  for (const attr of this.attributes) {
121952
121949
  if (attr.name.startsWith("css-")) {
121953
- // "css-" 접두사를 제거하고 CSS 속성명으로 변환
121954
121950
  this.style.setProperty(attr.name.substring(4), attr.value);
121955
121951
  }
121956
121952
  }
121957
121953
 
121954
+ // 2. HTML 내용 처리
121958
121955
  this.originContents = this.innerHTML.trim();
121959
- this.innerHTML = ""; // 기존 내부 HTML 제거
121956
+
121957
+ // Shadow DOM을 사용할 경우 내용을 안으로 옮김
121958
+ if (this.shadowRoot) {
121959
+ this.shadowRoot.innerHTML = this.originContents;
121960
+ this.innerHTML = ""; // 외부(Light DOM) 내용은 비움
121961
+ }
121962
+ // Shadow DOM을 안 쓰면 그대로 유지 (this.#root가 this이므로 별도 처리 불필요)
121960
121963
  };
121961
121964
  }
121962
121965
 
@@ -122243,27 +122246,36 @@ class nxPanel extends nxDiv {
122243
122246
  customElements.define("nx-panel", nxPanel);
122244
122247
 
122245
122248
  class nxButtons extends nxDiv {
122246
-
122247
122249
  constructor() {
122248
122250
  super();
122249
122251
  }
122250
122252
 
122251
122253
  connectedCallback() {
122252
122254
  if (super.connectedCallback()) this.#init();
122253
- };
122255
+ }
122254
122256
 
122255
122257
  #init = () => {
122256
- const htmlTmpl = document.createElement("template");
122257
- htmlTmpl.innerHTML = `
122258
- <style>
122259
- @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
122260
- ${ninegrid.getCustomPath(this,"nxButtons.css")}
122261
- </style>
122262
-
122263
- ${this.originContents}
122258
+ // 1. 스타일과 내용을 합친 템플릿 생성
122259
+ const styleContent = `
122260
+ <style>
122261
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
122262
+ ${ninegrid.getCustomPath(this, "nxButtons.css")}
122263
+ </style>
122264
122264
  `;
122265
+ console.log("11111");
122266
+ const htmlTmpl = document.createElement("template");
122265
122267
 
122266
- this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
122268
+ // Shadow DOM일 때는 originContents를 옮겨야 하고,
122269
+ // Light DOM일 때는 이미 본문에 있으므로 스타일만 추가하면 됨
122270
+ if (this.shadowRoot) {
122271
+ htmlTmpl.innerHTML = `${styleContent}${this.originContents}`;
122272
+ this.root.appendChild(htmlTmpl.content.cloneNode(true));
122273
+ } else {
122274
+ // Light DOM 모드일 때: 스타일만 상단에 추가
122275
+ const styleDiv = document.createElement("div");
122276
+ styleDiv.innerHTML = styleContent;
122277
+ this.root.prepend(styleDiv);
122278
+ }
122267
122279
  }
122268
122280
  }
122269
122281
 
@@ -653,8 +653,6 @@ export class NineGridContainer extends HTMLElement
653
653
  this.querySelectorAll("nx-buttons *").forEach(v => {v.grid = this;});
654
654
  $(this.shadowRoot.querySelector("ng-head").shadowRoot.querySelector("ng-custom")).append(this.querySelectorAll("nx-buttons"));
655
655
 
656
-
657
-
658
656
  this.#prepare();
659
657
 
660
658
  this.createTemplate();
package/dist/nx/_nxDiv.js CHANGED
@@ -1,32 +1,47 @@
1
1
  import ninegrid from "../index.js";
2
2
 
3
- export class nxDiv extends HTMLElement
4
- {
3
+ export class nxDiv extends HTMLElement {
5
4
  originContents;
6
5
  #isInitialized = false;
6
+ #root; // Shadow DOM 사용 여부에 따라 shadowRoot 또는 this를 가리킴
7
7
 
8
- constructor () {
8
+ constructor() {
9
9
  super();
10
- this.attachShadow({ mode: 'open' });
10
+ // 1. 'use-shadow' 속성이 "false"가 아니면 기본적으로 Shadow DOM을 사용하도록 설정
11
+ const useShadow = this.getAttribute("use-shadow") !== "false";
12
+
13
+ if (useShadow) {
14
+ this.attachShadow({ mode: 'open' });
15
+ this.#root = this.shadowRoot;
16
+ } else {
17
+ this.#root = this;
18
+ }
11
19
  }
12
-
20
+
13
21
  connectedCallback() {
14
22
  if (!this.#isInitialized) {
15
23
  this.#init();
16
- this.#isInitialized = true; // 3. 초기화 후 플래그를 true로 변경합니다.
24
+ this.#isInitialized = true;
17
25
  return true;
18
26
  }
19
-
20
27
  return false;
21
28
  }
22
29
 
30
+ // 공통 쿼리 함수: 현재 root(Shadow 또는 Light DOM)에서 요소를 찾음
31
+ #getElements() {
32
+ return ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.#root);
33
+ }
34
+
35
+ // 자식 클래스에서 접근할 수 있도록 getter 제공
36
+ get root() {
37
+ return this.#root;
38
+ }
39
+
23
40
  getData = () => {
24
41
  const jsonData = {};
25
-
26
- // Shadow DOM 내의 폼 요소만 선택
27
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
42
+ this.#getElements().forEach(el => {
28
43
  const key = el.name;
29
- if (!key) return; // name이 없는 요소는 건너뜁니다.
44
+ if (!key) return;
30
45
 
31
46
  let value;
32
47
  if (el.tagName === "INPUT" && (el.type === "checkbox" || el.type === "radio")) {
@@ -35,50 +50,40 @@ export class nxDiv extends HTMLElement
35
50
  value = el.value;
36
51
  }
37
52
 
38
- // 중복 name을 대비한 배열 처리
39
53
  if (jsonData[key]) {
40
- if (!Array.isArray(jsonData[key])) {
41
- jsonData[key] = [jsonData[key]];
42
- }
54
+ if (!Array.isArray(jsonData[key])) jsonData[key] = [jsonData[key]];
43
55
  jsonData[key].push(value);
44
56
  } else {
45
57
  jsonData[key] = value;
46
58
  }
47
59
  });
48
-
49
60
  return jsonData;
50
61
  };
51
62
 
52
63
  setData = (jsonData) => {
53
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
54
- console.log("------", el);
64
+ this.#getElements().forEach(el => {
55
65
  el.removeEventListener("input", this.#changeHandler);
56
66
  el.addEventListener("input", this.#changeHandler);
57
67
  });
58
68
 
59
- if (!jsonData || typeof jsonData !== 'object') {
60
- console.error("setData: Invalid data provided. Expected an object.");
61
- return;
62
- }
69
+ if (!jsonData || typeof jsonData !== 'object') return;
63
70
 
64
71
  let bChanged = false;
65
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
72
+ this.#getElements().forEach(el => {
66
73
  const key = el.name;
67
74
  if (!key || !jsonData.hasOwnProperty(key)) return;
68
75
 
69
76
  const value = jsonData[key];
70
-
71
- // 폼 요소에만 데이터를 설정합니다.
72
77
  if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
73
78
  if (el.type === "checkbox" || el.type === "radio") {
74
- if (el.checked !== (el.value === String(value))) bChanged = true;
75
- el.checked = (el.value === String(value));
79
+ const isChecked = (String(el.value) === String(value));
80
+ if (el.checked !== isChecked) bChanged = true;
81
+ el.checked = isChecked;
76
82
  } else {
77
83
  if (el.value !== value) bChanged = true;
78
84
  el.value = value;
79
85
  }
80
86
  } else {
81
- // 폼 요소가 아닌 경우, textContent를 사용합니다.
82
87
  if (el.textContent !== value) bChanged = true;
83
88
  el.textContent = value;
84
89
  }
@@ -105,21 +110,21 @@ export class nxDiv extends HTMLElement
105
110
  }
106
111
 
107
112
  #init = () => {
108
-
109
- //console.log(this);
110
- //console.log(this.querySelectorAll("input[name], textarea[name], select[name]"));
111
-
112
- /**
113
- * css style 적용
114
- */
113
+ // CSS Style 적용
115
114
  for (const attr of this.attributes) {
116
115
  if (attr.name.startsWith("css-")) {
117
- // "css-" 접두사를 제거하고 CSS 속성명으로 변환
118
116
  this.style.setProperty(attr.name.substring(4), attr.value);
119
117
  }
120
118
  }
121
119
 
120
+ // 2. HTML 내용 처리
122
121
  this.originContents = this.innerHTML.trim();
123
- this.innerHTML = ""; // 기존 내부 HTML 제거
122
+
123
+ // Shadow DOM을 사용할 경우 내용을 안으로 옮김
124
+ if (this.shadowRoot) {
125
+ this.shadowRoot.innerHTML = this.originContents;
126
+ this.innerHTML = ""; // 외부(Light DOM) 내용은 비움
127
+ }
128
+ // Shadow DOM을 안 쓰면 그대로 유지 (this.#root가 this이므로 별도 처리 불필요)
124
129
  };
125
130
  }
@@ -0,0 +1,125 @@
1
+ import ninegrid from "../index.js";
2
+
3
+ export class nxDiv extends HTMLElement
4
+ {
5
+ originContents;
6
+ #isInitialized = false;
7
+
8
+ constructor () {
9
+ super();
10
+ this.attachShadow({ mode: 'open' });
11
+ }
12
+
13
+ connectedCallback() {
14
+ if (!this.#isInitialized) {
15
+ this.#init();
16
+ this.#isInitialized = true; // 3. 초기화 후 플래그를 true로 변경합니다.
17
+ return true;
18
+ }
19
+
20
+ return false;
21
+ }
22
+
23
+ getData = () => {
24
+ const jsonData = {};
25
+
26
+ // Shadow DOM 내의 폼 요소만 선택
27
+ ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
28
+ const key = el.name;
29
+ if (!key) return; // name이 없는 요소는 건너뜁니다.
30
+
31
+ let value;
32
+ if (el.tagName === "INPUT" && (el.type === "checkbox" || el.type === "radio")) {
33
+ value = el.checked;
34
+ } else {
35
+ value = el.value;
36
+ }
37
+
38
+ // 중복 name을 대비한 배열 처리
39
+ if (jsonData[key]) {
40
+ if (!Array.isArray(jsonData[key])) {
41
+ jsonData[key] = [jsonData[key]];
42
+ }
43
+ jsonData[key].push(value);
44
+ } else {
45
+ jsonData[key] = value;
46
+ }
47
+ });
48
+
49
+ return jsonData;
50
+ };
51
+
52
+ setData = (jsonData) => {
53
+ ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
54
+ console.log("------", el);
55
+ el.removeEventListener("input", this.#changeHandler);
56
+ el.addEventListener("input", this.#changeHandler);
57
+ });
58
+
59
+ if (!jsonData || typeof jsonData !== 'object') {
60
+ console.error("setData: Invalid data provided. Expected an object.");
61
+ return;
62
+ }
63
+
64
+ let bChanged = false;
65
+ ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
66
+ const key = el.name;
67
+ if (!key || !jsonData.hasOwnProperty(key)) return;
68
+
69
+ const value = jsonData[key];
70
+
71
+ // 폼 요소에만 데이터를 설정합니다.
72
+ if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
73
+ if (el.type === "checkbox" || el.type === "radio") {
74
+ if (el.checked !== (el.value === String(value))) bChanged = true;
75
+ el.checked = (el.value === String(value));
76
+ } else {
77
+ if (el.value !== value) bChanged = true;
78
+ el.value = value;
79
+ }
80
+ } else {
81
+ // 폼 요소가 아닌 경우, textContent를 사용합니다.
82
+ if (el.textContent !== value) bChanged = true;
83
+ el.textContent = value;
84
+ }
85
+ });
86
+
87
+ if (bChanged) this.#changed(bChanged);
88
+ };
89
+
90
+ initData = (jsonData) => {
91
+ this.setData(jsonData);
92
+ this.#changed(false);
93
+ };
94
+
95
+ #changed = (v) => {
96
+ const parent = this.closest(".detail-wrapper");
97
+ if (parent) {
98
+ const el = parent.querySelector("nx-title2");
99
+ if (el) el.changed = v;
100
+ }
101
+ }
102
+
103
+ #changeHandler = (e) => {
104
+ this.#changed(true);
105
+ }
106
+
107
+ #init = () => {
108
+
109
+ //console.log(this);
110
+ //console.log(this.querySelectorAll("input[name], textarea[name], select[name]"));
111
+
112
+ /**
113
+ * css style 적용
114
+ */
115
+ for (const attr of this.attributes) {
116
+ if (attr.name.startsWith("css-")) {
117
+ // "css-" 접두사를 제거하고 CSS 속성명으로 변환
118
+ this.style.setProperty(attr.name.substring(4), attr.value);
119
+ }
120
+ }
121
+
122
+ this.originContents = this.innerHTML.trim();
123
+ this.innerHTML = ""; // 기존 내부 HTML 제거
124
+ };
125
+ }
@@ -1,29 +1,38 @@
1
1
  import ninegrid from "../index.js";
2
- import {nxDiv} from "./_nxDiv.js";
2
+ import { nxDiv } from "./_nxDiv.js";
3
3
 
4
4
  class nxButtons extends nxDiv {
5
-
6
5
  constructor() {
7
6
  super();
8
7
  }
9
8
 
10
9
  connectedCallback() {
11
10
  if (super.connectedCallback()) this.#init();
12
- };
11
+ }
13
12
 
14
13
  #init = () => {
15
- const htmlTmpl = document.createElement("template");
16
- htmlTmpl.innerHTML = `
17
- <style>
18
- @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
19
- ${ninegrid.getCustomPath(this,"nxButtons.css")}
20
- </style>
21
-
22
- ${this.originContents}
14
+ // 1. 스타일과 내용을 합친 템플릿 생성
15
+ const styleContent = `
16
+ <style>
17
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
18
+ ${ninegrid.getCustomPath(this, "nxButtons.css")}
19
+ </style>
23
20
  `;
21
+ console.log("11111")
22
+ const htmlTmpl = document.createElement("template");
24
23
 
25
- this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
24
+ // Shadow DOM일 때는 originContents를 옮겨야 하고,
25
+ // Light DOM일 때는 이미 본문에 있으므로 스타일만 추가하면 됨
26
+ if (this.shadowRoot) {
27
+ htmlTmpl.innerHTML = `${styleContent}${this.originContents}`;
28
+ this.root.appendChild(htmlTmpl.content.cloneNode(true));
29
+ } else {
30
+ // Light DOM 모드일 때: 스타일만 상단에 추가
31
+ const styleDiv = document.createElement("div");
32
+ styleDiv.innerHTML = styleContent;
33
+ this.root.prepend(styleDiv);
34
+ }
26
35
  }
27
36
  }
28
37
 
29
- customElements.define("nx-buttons", nxButtons);
38
+ customElements.define("nx-buttons", nxButtons);
@@ -0,0 +1,29 @@
1
+ import ninegrid from "../index.js";
2
+ import {nxDiv} from "./_nxDiv.js";
3
+
4
+ class nxButtons extends nxDiv {
5
+
6
+ constructor() {
7
+ super();
8
+ }
9
+
10
+ connectedCallback() {
11
+ if (super.connectedCallback()) this.#init();
12
+ };
13
+
14
+ #init = () => {
15
+ const htmlTmpl = document.createElement("template");
16
+ htmlTmpl.innerHTML = `
17
+ <style>
18
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
19
+ ${ninegrid.getCustomPath(this,"nxButtons.css")}
20
+ </style>
21
+
22
+ ${this.originContents}
23
+ `;
24
+
25
+ this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
26
+ }
27
+ }
28
+
29
+ customElements.define("nx-buttons", nxButtons);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ninegrid2",
3
3
  "type": "module",
4
- "version": "6.1248.0",
4
+ "version": "6.1250.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -653,8 +653,6 @@ export class NineGridContainer extends HTMLElement
653
653
  this.querySelectorAll("nx-buttons *").forEach(v => {v.grid = this;});
654
654
  $(this.shadowRoot.querySelector("ng-head").shadowRoot.querySelector("ng-custom")).append(this.querySelectorAll("nx-buttons"));
655
655
 
656
-
657
-
658
656
  this.#prepare();
659
657
 
660
658
  this.createTemplate();
package/src/nx/_nxDiv.js CHANGED
@@ -1,32 +1,47 @@
1
1
  import ninegrid from "../index.js";
2
2
 
3
- export class nxDiv extends HTMLElement
4
- {
3
+ export class nxDiv extends HTMLElement {
5
4
  originContents;
6
5
  #isInitialized = false;
6
+ #root; // Shadow DOM 사용 여부에 따라 shadowRoot 또는 this를 가리킴
7
7
 
8
- constructor () {
8
+ constructor() {
9
9
  super();
10
- this.attachShadow({ mode: 'open' });
10
+ // 1. 'use-shadow' 속성이 "false"가 아니면 기본적으로 Shadow DOM을 사용하도록 설정
11
+ const useShadow = this.getAttribute("use-shadow") !== "false";
12
+
13
+ if (useShadow) {
14
+ this.attachShadow({ mode: 'open' });
15
+ this.#root = this.shadowRoot;
16
+ } else {
17
+ this.#root = this;
18
+ }
11
19
  }
12
-
20
+
13
21
  connectedCallback() {
14
22
  if (!this.#isInitialized) {
15
23
  this.#init();
16
- this.#isInitialized = true; // 3. 초기화 후 플래그를 true로 변경합니다.
24
+ this.#isInitialized = true;
17
25
  return true;
18
26
  }
19
-
20
27
  return false;
21
28
  }
22
29
 
30
+ // 공통 쿼리 함수: 현재 root(Shadow 또는 Light DOM)에서 요소를 찾음
31
+ #getElements() {
32
+ return ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.#root);
33
+ }
34
+
35
+ // 자식 클래스에서 접근할 수 있도록 getter 제공
36
+ get root() {
37
+ return this.#root;
38
+ }
39
+
23
40
  getData = () => {
24
41
  const jsonData = {};
25
-
26
- // Shadow DOM 내의 폼 요소만 선택
27
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
42
+ this.#getElements().forEach(el => {
28
43
  const key = el.name;
29
- if (!key) return; // name이 없는 요소는 건너뜁니다.
44
+ if (!key) return;
30
45
 
31
46
  let value;
32
47
  if (el.tagName === "INPUT" && (el.type === "checkbox" || el.type === "radio")) {
@@ -35,50 +50,40 @@ export class nxDiv extends HTMLElement
35
50
  value = el.value;
36
51
  }
37
52
 
38
- // 중복 name을 대비한 배열 처리
39
53
  if (jsonData[key]) {
40
- if (!Array.isArray(jsonData[key])) {
41
- jsonData[key] = [jsonData[key]];
42
- }
54
+ if (!Array.isArray(jsonData[key])) jsonData[key] = [jsonData[key]];
43
55
  jsonData[key].push(value);
44
56
  } else {
45
57
  jsonData[key] = value;
46
58
  }
47
59
  });
48
-
49
60
  return jsonData;
50
61
  };
51
62
 
52
63
  setData = (jsonData) => {
53
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
54
- console.log("------", el);
64
+ this.#getElements().forEach(el => {
55
65
  el.removeEventListener("input", this.#changeHandler);
56
66
  el.addEventListener("input", this.#changeHandler);
57
67
  });
58
68
 
59
- if (!jsonData || typeof jsonData !== 'object') {
60
- console.error("setData: Invalid data provided. Expected an object.");
61
- return;
62
- }
69
+ if (!jsonData || typeof jsonData !== 'object') return;
63
70
 
64
71
  let bChanged = false;
65
- ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
72
+ this.#getElements().forEach(el => {
66
73
  const key = el.name;
67
74
  if (!key || !jsonData.hasOwnProperty(key)) return;
68
75
 
69
76
  const value = jsonData[key];
70
-
71
- // 폼 요소에만 데이터를 설정합니다.
72
77
  if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
73
78
  if (el.type === "checkbox" || el.type === "radio") {
74
- if (el.checked !== (el.value === String(value))) bChanged = true;
75
- el.checked = (el.value === String(value));
79
+ const isChecked = (String(el.value) === String(value));
80
+ if (el.checked !== isChecked) bChanged = true;
81
+ el.checked = isChecked;
76
82
  } else {
77
83
  if (el.value !== value) bChanged = true;
78
84
  el.value = value;
79
85
  }
80
86
  } else {
81
- // 폼 요소가 아닌 경우, textContent를 사용합니다.
82
87
  if (el.textContent !== value) bChanged = true;
83
88
  el.textContent = value;
84
89
  }
@@ -105,21 +110,21 @@ export class nxDiv extends HTMLElement
105
110
  }
106
111
 
107
112
  #init = () => {
108
-
109
- //console.log(this);
110
- //console.log(this.querySelectorAll("input[name], textarea[name], select[name]"));
111
-
112
- /**
113
- * css style 적용
114
- */
113
+ // CSS Style 적용
115
114
  for (const attr of this.attributes) {
116
115
  if (attr.name.startsWith("css-")) {
117
- // "css-" 접두사를 제거하고 CSS 속성명으로 변환
118
116
  this.style.setProperty(attr.name.substring(4), attr.value);
119
117
  }
120
118
  }
121
119
 
120
+ // 2. HTML 내용 처리
122
121
  this.originContents = this.innerHTML.trim();
123
- this.innerHTML = ""; // 기존 내부 HTML 제거
122
+
123
+ // Shadow DOM을 사용할 경우 내용을 안으로 옮김
124
+ if (this.shadowRoot) {
125
+ this.shadowRoot.innerHTML = this.originContents;
126
+ this.innerHTML = ""; // 외부(Light DOM) 내용은 비움
127
+ }
128
+ // Shadow DOM을 안 쓰면 그대로 유지 (this.#root가 this이므로 별도 처리 불필요)
124
129
  };
125
130
  }
@@ -0,0 +1,125 @@
1
+ import ninegrid from "../index.js";
2
+
3
+ export class nxDiv extends HTMLElement
4
+ {
5
+ originContents;
6
+ #isInitialized = false;
7
+
8
+ constructor () {
9
+ super();
10
+ this.attachShadow({ mode: 'open' });
11
+ }
12
+
13
+ connectedCallback() {
14
+ if (!this.#isInitialized) {
15
+ this.#init();
16
+ this.#isInitialized = true; // 3. 초기화 후 플래그를 true로 변경합니다.
17
+ return true;
18
+ }
19
+
20
+ return false;
21
+ }
22
+
23
+ getData = () => {
24
+ const jsonData = {};
25
+
26
+ // Shadow DOM 내의 폼 요소만 선택
27
+ ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
28
+ const key = el.name;
29
+ if (!key) return; // name이 없는 요소는 건너뜁니다.
30
+
31
+ let value;
32
+ if (el.tagName === "INPUT" && (el.type === "checkbox" || el.type === "radio")) {
33
+ value = el.checked;
34
+ } else {
35
+ value = el.value;
36
+ }
37
+
38
+ // 중복 name을 대비한 배열 처리
39
+ if (jsonData[key]) {
40
+ if (!Array.isArray(jsonData[key])) {
41
+ jsonData[key] = [jsonData[key]];
42
+ }
43
+ jsonData[key].push(value);
44
+ } else {
45
+ jsonData[key] = value;
46
+ }
47
+ });
48
+
49
+ return jsonData;
50
+ };
51
+
52
+ setData = (jsonData) => {
53
+ ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
54
+ console.log("------", el);
55
+ el.removeEventListener("input", this.#changeHandler);
56
+ el.addEventListener("input", this.#changeHandler);
57
+ });
58
+
59
+ if (!jsonData || typeof jsonData !== 'object') {
60
+ console.error("setData: Invalid data provided. Expected an object.");
61
+ return;
62
+ }
63
+
64
+ let bChanged = false;
65
+ ninegrid.querySelectorAll("input[name], textarea[name], select[name]", this.shadowRoot).forEach(el => {
66
+ const key = el.name;
67
+ if (!key || !jsonData.hasOwnProperty(key)) return;
68
+
69
+ const value = jsonData[key];
70
+
71
+ // 폼 요소에만 데이터를 설정합니다.
72
+ if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
73
+ if (el.type === "checkbox" || el.type === "radio") {
74
+ if (el.checked !== (el.value === String(value))) bChanged = true;
75
+ el.checked = (el.value === String(value));
76
+ } else {
77
+ if (el.value !== value) bChanged = true;
78
+ el.value = value;
79
+ }
80
+ } else {
81
+ // 폼 요소가 아닌 경우, textContent를 사용합니다.
82
+ if (el.textContent !== value) bChanged = true;
83
+ el.textContent = value;
84
+ }
85
+ });
86
+
87
+ if (bChanged) this.#changed(bChanged);
88
+ };
89
+
90
+ initData = (jsonData) => {
91
+ this.setData(jsonData);
92
+ this.#changed(false);
93
+ };
94
+
95
+ #changed = (v) => {
96
+ const parent = this.closest(".detail-wrapper");
97
+ if (parent) {
98
+ const el = parent.querySelector("nx-title2");
99
+ if (el) el.changed = v;
100
+ }
101
+ }
102
+
103
+ #changeHandler = (e) => {
104
+ this.#changed(true);
105
+ }
106
+
107
+ #init = () => {
108
+
109
+ //console.log(this);
110
+ //console.log(this.querySelectorAll("input[name], textarea[name], select[name]"));
111
+
112
+ /**
113
+ * css style 적용
114
+ */
115
+ for (const attr of this.attributes) {
116
+ if (attr.name.startsWith("css-")) {
117
+ // "css-" 접두사를 제거하고 CSS 속성명으로 변환
118
+ this.style.setProperty(attr.name.substring(4), attr.value);
119
+ }
120
+ }
121
+
122
+ this.originContents = this.innerHTML.trim();
123
+ this.innerHTML = ""; // 기존 내부 HTML 제거
124
+ };
125
+ }
@@ -1,29 +1,38 @@
1
1
  import ninegrid from "../index.js";
2
- import {nxDiv} from "./_nxDiv.js";
2
+ import { nxDiv } from "./_nxDiv.js";
3
3
 
4
4
  class nxButtons extends nxDiv {
5
-
6
5
  constructor() {
7
6
  super();
8
7
  }
9
8
 
10
9
  connectedCallback() {
11
10
  if (super.connectedCallback()) this.#init();
12
- };
11
+ }
13
12
 
14
13
  #init = () => {
15
- const htmlTmpl = document.createElement("template");
16
- htmlTmpl.innerHTML = `
17
- <style>
18
- @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
19
- ${ninegrid.getCustomPath(this,"nxButtons.css")}
20
- </style>
21
-
22
- ${this.originContents}
14
+ // 1. 스타일과 내용을 합친 템플릿 생성
15
+ const styleContent = `
16
+ <style>
17
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
18
+ ${ninegrid.getCustomPath(this, "nxButtons.css")}
19
+ </style>
23
20
  `;
21
+ console.log("11111")
22
+ const htmlTmpl = document.createElement("template");
24
23
 
25
- this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
24
+ // Shadow DOM일 때는 originContents를 옮겨야 하고,
25
+ // Light DOM일 때는 이미 본문에 있으므로 스타일만 추가하면 됨
26
+ if (this.shadowRoot) {
27
+ htmlTmpl.innerHTML = `${styleContent}${this.originContents}`;
28
+ this.root.appendChild(htmlTmpl.content.cloneNode(true));
29
+ } else {
30
+ // Light DOM 모드일 때: 스타일만 상단에 추가
31
+ const styleDiv = document.createElement("div");
32
+ styleDiv.innerHTML = styleContent;
33
+ this.root.prepend(styleDiv);
34
+ }
26
35
  }
27
36
  }
28
37
 
29
- customElements.define("nx-buttons", nxButtons);
38
+ customElements.define("nx-buttons", nxButtons);
@@ -0,0 +1,29 @@
1
+ import ninegrid from "../index.js";
2
+ import {nxDiv} from "./_nxDiv.js";
3
+
4
+ class nxButtons extends nxDiv {
5
+
6
+ constructor() {
7
+ super();
8
+ }
9
+
10
+ connectedCallback() {
11
+ if (super.connectedCallback()) this.#init();
12
+ };
13
+
14
+ #init = () => {
15
+ const htmlTmpl = document.createElement("template");
16
+ htmlTmpl.innerHTML = `
17
+ <style>
18
+ @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/nxButtons.css";
19
+ ${ninegrid.getCustomPath(this,"nxButtons.css")}
20
+ </style>
21
+
22
+ ${this.originContents}
23
+ `;
24
+
25
+ this.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));
26
+ }
27
+ }
28
+
29
+ customElements.define("nx-buttons", nxButtons);