-
Notifications
You must be signed in to change notification settings - Fork 1
/
program-1.html
125 lines (116 loc) · 3.1 KB
/
program-1.html
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
<!DOCTYPE html>
<html>
<head>
<title>Program 1</title>
<style>
body {
text-align: center;
}
div#container {
display: inline-block;
padding: 0.5em;
margin-top: 3em;
margin-bottom: 3em;
border: 0.1em solid #555;
}
button {
margin-left: 1em;
}
</style>
</head>
<body>
<div id="container">
<div id="display"></div>
<div id="button"></div>
</div>
</body>
<script type="text/javascript">
"use strict";
/*
Program 1 - Views
In this program we add a simple UI around the counter, consisting
of text displaying the value of the counter, and a button that
increments the counter.
*/
var Observable = {
initializeObservable: function() {
this.observers = new Set();
},
addObserver: function(observer) {
this.observers.add(observer);
},
deleteObserver: function(observer) {
this.observers.delete(observer);
},
notify: function() {
this.observers.forEach(function(observer) {
observer.update();
});
}
};
var Counter = Object.create(Observable);
Counter.initializeObservable();
Counter.count = 0;
Counter.increment = function() {
this.count += 1;
this.notify();
};
/*
Views need to have an 'update' method for the observable to call,
and a method to draw themselves.
*/
var CounterDisplay = {
writeOver: function(el) {
var span = document.createElement('span');
span.appendChild(document.createTextNode('Counter: '));
this.text = document.createTextNode(Counter.count);
span.appendChild(this.text);
el.parentNode.replaceChild(span, el);
},
update: function() {
if (this.text) {
var newText = document.createTextNode(Counter.count);
this.text.parentNode.replaceChild(newText, this.text);
this.text = newText;
}
},
};
Counter.addObserver(CounterDisplay);
/*
CounterDisplay is optimized so only a single text node is changed
on update. We will illustrate a cruder approach with the button,
where we simply replace the entire element on each update. We could
easily optimize the button the same way, but in some complicated cases,
the simplicity of fully redrawing may outweigh any performance loss.
*/
var IncrementButton = {
writeOver: function(el) {
var button = document.createElement('button');
button.appendChild(document.createTextNode('Increment'));
button.onclick = function() {
Counter.increment();
};
this.el = button;
el.parentNode.replaceChild(button, el);
},
update: function() {
if (this.el) {
this.writeOver(this.el);
}
}
};
Counter.addObserver(IncrementButton);
/*
Some implementations pass the parent element of a view instead of the
element it should replace, but doing so makes the trivial update
function above more complicated.
Finally, we need to actually write the views to the DOM. We need
the DOM to be ready, though, so we add a callback on the DOMContentLoaded
event.
*/
document.addEventListener('DOMContentLoaded', function() {
CounterDisplay.writeOver(document.getElementById('display'));
IncrementButton.writeOver(document.getElementById('button'));
});
</script>
</html>