-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathweb-component.js
More file actions
133 lines (120 loc) · 4.36 KB
/
web-component.js
File metadata and controls
133 lines (120 loc) · 4.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
var CSS = require("../utils/css.js");
var XCompProto = Object.create(HTMLElement.prototype);
XCompProto.createdCallback = function() {
this.root = this.createShadowRoot();
this.root.appendChild( CSS.XML3DStyleElement() );
var clone = document.importNode(this.template.content, true);
this.root.appendChild(clone);
this.handlers = {};
for (var i = 0; i < this.template.attributes.length; i++) {
var attr = this.template.attributes[i];
var attrName = attr.localName;
var place = this.place('.//node()[text()="{{'+attrName+'}}"]');
if (!place){
place = this.place('.//@*[.="{{'+attrName+'}}"]');
}
if (!place) {
continue;
}
var handler = (function(elem, value) {
return function (newValue) {
if (!newValue) newValue = value;
elem.textContent = newValue;
};
})(place, attr.textContent);
handler(this.getAttribute(attrName));
this.handlers[attrName] = handler;
}
if (this._configured) {
// This element was already initialized by XML3D before it was properly defined as a web component, we need to trigger a
// cleanup and re-initialization
var parent = this.parentElement;
var nextChild = this.nextElementSibling;
parent.removeChild(this);
if (nextChild) {
parent.insertBefore(this, nextChild);
} else {
parent.appendChild(this);
}
}
};
XCompProto.place = function (path) {
var context = this.root.firstElementChild;
while (context) {
node = document.evaluate(path, context, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (node) return node;
context = context.nextElementSibling;
}
};
XCompProto.attributeChangedCallback = function(attr, oldValue, newValue) {
var handler = this.handlers[attr];
if (!handler) return;
handler(newValue);
};
function registerComponent(source, opt) {
if (typeof source === "string") {
return registerComponentURL(source, opt);
} else if (source instanceof HTMLElement) {
registerComponentElem(source, opt);
} else {
XML3D.debug.logError("Must provide a template element or a URL to a template element when registering a component!");
}
}
function registerComponentURL(url, opt) {
return new Promise(function(resolve, reject) {
fetch(url).then(function (response) {
return response.text();
}).then(function (text) {
var div = document.createElement("div");
div.innerHTML = text;
var template = div.querySelector("template");
if (template) {
resolve(registerComponentElem(template, opt));
} else {
XML3D.debug.logError("No component template element found at url " +url);
reject();
}
}).catch(function (exception) {
XML3D.debug.logError("Error while registering web component: ", exception);
reject(url);
});
});
}
function registerComponentElem(element, opt) {
if (!element) {
return;
}
if (typeof opt === "string") {
opt = { name: opt };
}
opt = opt || {};
var name = opt.name || element.getAttribute("name");
var proto = Object.create(XCompProto);
proto.template = element;
if (opt.proto) {
extendComponentPrototype(proto, opt.proto);
}
document.registerElement(name, { prototype: proto });
return name;
}
function extendComponentPrototype(baseProto, extension) {
for (var field in extension) {
if (!extension.hasOwnProperty(field)) {
continue;
}
if (field === "createdCallback") {
baseProto.createdCallback = function () {
XCompProto.createdCallback.call(this);
extension.createdCallback.call(this);
}
} else if (field === "attributeChangedCallback") {
baseProto.attributeChangedCallback = function(attr, oldValue, newValue) {
XCompProto.attributeChangedCallback.call(this, attr, oldValue, newValue);
extension.attributeChangedCallback.call(this, attr, oldValue, newValue);
}
} else {
baseProto[field] = extension[field];
}
}
}
module.exports = registerComponent;