Skip to content
This repository was archived by the owner on Mar 7, 2024. It is now read-only.

Commit 9aec17b

Browse files
committed
j8-* 속성들이 DOM에 남지 않도록 하고, j8-attr-* 속성을 신설
j8-attr-* 속성이 왜 필요하냐 하면 요런 문제 때문이다. angular/angular.js#1050 앵귤러가 해결한 방법을 그대로 따라간다.
1 parent 917bcd3 commit 9aec17b

File tree

1 file changed

+71
-19
lines changed

1 file changed

+71
-19
lines changed

Library/jul8.ts

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,38 @@
6060
let pattern = /({{[^}]+}})/g;
6161

6262
export class Fields {
63-
attrs: { attr: Attr, origValue: string }[] = [];
64-
elems: { elem: Node, origText: string }[] = [];
63+
// elem과 replacedLocalName은 j8-attr-* 속성을 지원하는 용도이다.
64+
// 이들이 설정되어 있으면 아직 DOM에는 해당 attr이 설정되어 있지 않은 것이다.
65+
// 일단 attr이 설정된 뒤에는 그 Attr 노드를 직접 고치면 되므로 elem/replacedLocalName은 null이 된다.
66+
attrs: { attr: Attr, elem: Element, replacedLocalName: string, origValue: string }[] = [];
67+
nodes: { node: Node, origText: string }[] = [];
6568

6669
set(data: any): void {
6770
for (let a of this.attrs) {
68-
var newValue = this.replace(a.origValue, data);
69-
if (a.attr.value !== newValue) {
70-
a.attr.value = newValue;
71+
let newValue = this.replace(a.origValue, data);
72+
if (a.replacedLocalName) {
73+
if (a.attr.namespaceURI !== null) {
74+
a.attr = document.createAttributeNS(a.attr.namespaceURI, a.replacedLocalName);
75+
a.attr.value = newValue;
76+
a.elem.setAttributeNodeNS(a.attr);
77+
} else {
78+
a.attr = document.createAttribute(a.replacedLocalName);
79+
a.attr.value = newValue;
80+
a.elem.setAttributeNode(a.attr);
81+
}
82+
a.elem = null;
83+
a.replacedLocalName = null;
84+
} else {
85+
if (a.attr.value !== newValue) {
86+
a.attr.value = newValue;
87+
}
7188
}
7289
}
73-
for (let e of this.elems) {
90+
91+
for (let e of this.nodes) {
7492
var newText = this.replace(e.origText, data);
75-
if (e.elem.textContent !== newText) {
76-
e.elem.textContent = newText;
93+
if (e.node.textContent !== newText) {
94+
e.node.textContent = newText;
7795
}
7896
}
7997
}
@@ -110,6 +128,7 @@
110128
root.find('[j8-control]').each(
111129
(i, v) => {
112130
let cid = v.getAttribute('j8-control');
131+
v.removeAttribute('j8-control');
113132

114133
if (this.controls[cid]) {
115134
console.error('(Jul8) duplicate control id: [' + cid + ']')
@@ -119,7 +138,7 @@
119138

120139
if (scanFields) {
121140
this.fields = new Fields();
122-
this.visitElem(root.get(0));
141+
this.visitNode(root.get(0));
123142
}
124143
}
125144

@@ -130,6 +149,8 @@
130149

131150
if (elem.hasAttribute('j8-listItem')) {
132151
let itemId = elem.getAttribute('j8-listItem');
152+
elem.removeAttribute('j8-listItem');
153+
elem.removeAttribute('j8-model');
133154
if (this.lists[itemId]) {
134155
console.error('(Jul8) duplicate listItem id: [' + itemId + ']')
135156
}
@@ -145,30 +166,60 @@
145166
}
146167
}
147168

148-
private visitElem(elem: Node) {
149-
let childNodes = elem.childNodes;
169+
private visitNode(node: Node) {
170+
let childNodes = node.childNodes;
150171
if (childNodes.length > 0) {
151172
for (let i = 0; i < childNodes.length; ++i) {
152-
this.visitElem(childNodes[i])
173+
this.visitNode(childNodes[i])
153174
}
154175
}
155176
else {
156-
if (elem.textContent.search(pattern) >= 0) {
157-
let e = { elem: elem, origText: elem.textContent };
158-
this.fields.elems.push(e);
177+
if (node.textContent.search(pattern) >= 0) {
178+
let n = { node: node, origText: node.textContent };
179+
this.fields.nodes.push(n);
159180
}
160181
}
161182

162-
if (elem.attributes) {
183+
if (node.attributes) {
184+
let elem = node as Element;
185+
let replacedAttrs: { name: string, attr: Attr }[] = [];
186+
let removedAttrs: Attr[] = [];
187+
163188
for (let i = 0; i < elem.attributes.length; ++i) {
164189
let attr = elem.attributes[i];
190+
let replacedLocalName = null;
191+
if (attr.localName.substring(0, 8) === 'j8-attr-') {
192+
replacedLocalName = attr.localName.substring(8);
193+
}
165194
if (attr.value.search(pattern) >= 0) {
166-
if (attr.name === 'style') { console.error("(Jul8) can't use {{ ... }} notation in `style` attribute."); }
167-
if (attr.name === 'class') { console.error("(Jul8) can't use {{ ... }} notation in `class` attribute."); }
168-
let a = { attr: attr, origValue: attr.value };
195+
let localName = replacedLocalName || attr.localName;
196+
if (localName === 'style') { console.error("(Jul8) can't use {{ ... }} notation in `style` attribute."); }
197+
if (localName === 'class') { console.error("(Jul8) can't use {{ ... }} notation in `class` attribute."); }
198+
let a = { elem: elem, attr: attr, replacedLocalName: replacedLocalName, origValue: attr.value };
169199
this.fields.attrs.push(a);
200+
if (replacedLocalName) {
201+
// j8-attr-* 속성은 DOM에는 남아 있지 않고 나중에 재구성한다.
202+
removedAttrs.push(attr);
203+
}
204+
} else if (replacedLocalName) {
205+
// j8-attr-XXX="YYY" 속성에 {{}}가 아예 안 들어 있을 수도 있다.
206+
// 이 경우에도 XXX="YYY"로 일괄 처리는 해야 한다.
207+
replacedAttrs.push({ name: replacedLocalName, attr: attr });
170208
}
171209
}
210+
211+
for (let { name, attr } of replacedAttrs) {
212+
elem.removeAttributeNode(attr);
213+
if (attr.namespaceURI !== null) {
214+
elem.setAttributeNS(attr.namespaceURI, name, attr.value);
215+
} else {
216+
elem.setAttribute(name, attr.value);
217+
}
218+
}
219+
220+
for (let attr of removedAttrs) {
221+
elem.removeAttributeNode(attr);
222+
}
172223
}
173224
}
174225

@@ -210,6 +261,7 @@
210261
let j = $(v);
211262
j.detach();
212263
let tid = v.getAttribute('j8-template');
264+
v.removeAttribute('j8-template');
213265
this.templates[tid] = j;
214266
});
215267
}

0 commit comments

Comments
 (0)