-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrender.js
More file actions
112 lines (96 loc) · 3.18 KB
/
render.js
File metadata and controls
112 lines (96 loc) · 3.18 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
/** @jsx createElement */
/**
* Render Methods
*/
/**
* This renders an element to the dom
* @method render
* @param {object} element this is the element to render
* @param {Object} parentDom A dom object
* @return {void} executes a side effect
*/
import {createElement} from './createElement';
const ELEMENT_NODE_TYPE = 1
const TEXT_NODE_TYPE = 3
export function render(element, parentDom) {
const { type, props } = element;
// Create the DOM element
const isTextElement = type == "TEXT ELEMENT";
const dom = isTextElement
? document.createTextNode("")
: document.createElement(type);
// Add event listeners
const isListener = name => name.startsWith("on");
Object.keys(props)
.filter(isListener)
.forEach(name => {
const eventType = name.toLowerCase().substring(2);
dom.addEventListener(eventType, props[name]);
});
// Set Props only on HTML elements and skip text nodes
if (dom.nodeType == ELEMENT_NODE_TYPE) {
const isAttribute = name => !isListener(name) && name != "children";
Object.keys(props)
.filter(isAttribute)
.forEach(name => {
dom.setAttribute(name, props[name]);
});
}
// Set the text element's node value type
if (dom.nodeType == TEXT_NODE_TYPE) {
dom['nodeValue'] = props['nodeValue']
}
// Render children
const childElements = props.children || [];
childElements.forEach(childElement => render(childElement, dom));
// Append to parent
parentDom.appendChild(dom);
}
// Brute force reconcile
export function reconcile(parentDom, instance, element) {
// If no instance exists, create one and append
// it's dom representation to the parent node.
if( instance == null) {
const newInstance = instantiate(element);
parentDom.appendChild(newInstance.dom)
return newInstance
// If an instance does exist, recreate a new one
// and replace the current version of it with new one.
} else {
const newInstance = instantiate(element);
parentDom.replaceChild(newInstance.dom, instance.dom)
return newInstance;
}
}
export const instantiate = (element) => {
const {type, props} = element;
// Create the DOM element
const isTextElement = type == "TEXT ELEMENT";
const dom = isTextElement
? document.createTextNode("")
: document.createElement(type);
// Add event listeners
const isListener = name => name.startsWith("on");
Object.keys(props)
.filter(isListener)
.forEach(name => {
const eventType = name.toLowerCase().substring(2);
dom.addEventListener(eventType, props[name]);
});
// Set Props only on HTML elements and skip text nodes
if (dom.nodeType == ELEMENT_NODE_TYPE) {
const isAttribute = name => !isListener(name) && name != "children";
Object.keys(props)
.filter(isAttribute)
.forEach(name => {
dom.setAttribute(name, props[name]);
});
}
// Instantiate and append children
const childElements = props.children || [];
const childInstances = childElements.map(instantiate);
const childDoms = childInstances.map(childInstance => childInstance.dom);
childDoms.forEach(childDom => dom.appendChild(childDom));
const instance = { dom, element, childInstances };
return instance;
}