|
1 |
| -addEventListener("load", function() { |
2 |
| - var editor = CodeMirror.fromTextArea(document.querySelector("#editor"), { |
| 1 | +addEventListener("load", () => { |
| 2 | + let editor = CodeMirror.fromTextArea(document.querySelector("#editor"), { |
3 | 3 | mode: "javascript",
|
4 | 4 | extraKeys: {
|
5 | 5 | "Ctrl-Enter": runCode
|
6 | 6 | },
|
7 | 7 | matchBrackets: true,
|
8 | 8 | lineNumbers: true
|
9 |
| - }); |
| 9 | + }) |
10 | 10 | function guessType(code) {
|
11 |
| - return /^[\s\w\n:]*</.test(code) ? "html" : "js"; |
| 11 | + return /^[\s\w\n:]*</.test(code) ? "html" : "js" |
12 | 12 | }
|
13 |
| - var reGuess; |
14 |
| - editor.on("change", function() { |
15 |
| - clearTimeout(reGuess); |
16 |
| - reGuess = setTimeout(function() { |
| 13 | + let reGuess |
| 14 | + editor.on("change", () => { |
| 15 | + clearTimeout(reGuess) |
| 16 | + reGuess = setTimeout(() => { |
17 | 17 | if (context.type == null) {
|
18 |
| - var mode = guessType(editor.getValue()) == "html" ? "text/html" : "javascript"; |
| 18 | + let mode = guessType(editor.getValue()) == "html" ? "text/html" : "javascript" |
19 | 19 | if (mode != editor.getOption("mode"))
|
20 |
| - editor.setOption("mode", mode); |
| 20 | + editor.setOption("mode", mode) |
21 | 21 | }
|
22 |
| - }, 500); |
23 |
| - }); |
| 22 | + }, 500) |
| 23 | + }) |
24 | 24 |
|
25 | 25 | function hasIncludes(code, include) {
|
26 |
| - if (!include) return code; |
| 26 | + if (!include) return code |
27 | 27 |
|
28 |
| - var re = /(?:\s|<!--.*?-->)*<script src="([^"]*)"><\/script>/g, m; |
29 |
| - var found = []; |
30 |
| - while (m = re.exec(code)) found.push(m[1]); |
31 |
| - return include.every(function(s) { return found.indexOf(s) > -1; }); |
| 28 | + let re = /(?:\s|<!--.*?-->)*<script src="([^"]*)"><\/script>/g, m |
| 29 | + let found = [] |
| 30 | + while (m = re.exec(code)) found.push(m[1]) |
| 31 | + return include.every(s => found.indexOf(s) > -1) |
32 | 32 | }
|
33 | 33 |
|
34 | 34 | function setEditorCode(code, type) {
|
35 |
| - editor.setValue(code); |
36 |
| - editor.setOption("mode", (type || guessType(code)) == "html" ? "text/html" : "javascript"); |
| 35 | + editor.setValue(code) |
| 36 | + editor.setOption("mode", (type || guessType(code)) == "html" ? "text/html" : "javascript") |
37 | 37 | }
|
38 | 38 |
|
39 | 39 | function opt(value, label) {
|
40 |
| - var node = document.createElement("option"); |
41 |
| - node.value = value; |
42 |
| - node.textContent = label || value; |
43 |
| - return node; |
| 40 | + let node = document.createElement("option") |
| 41 | + node.value = value |
| 42 | + node.textContent = label || value |
| 43 | + return node |
44 | 44 | }
|
45 | 45 |
|
46 | 46 | function getChapter(number) {
|
47 |
| - for (var i = 0; i < chapterData.length; i++) |
| 47 | + for (let i = 0; i < chapterData.length; i++) |
48 | 48 | if (chapterData[i].number == number)
|
49 |
| - return chapterData[i]; |
| 49 | + return chapterData[i] |
50 | 50 | }
|
51 | 51 |
|
52 | 52 | function getURL(url, callback) {
|
53 |
| - var req = new XMLHttpRequest(); |
54 |
| - req.open("GET", url, true); |
55 |
| - req.addEventListener("load", function() { |
| 53 | + let req = new XMLHttpRequest() |
| 54 | + req.open("GET", url, true) |
| 55 | + req.addEventListener("load", () => { |
56 | 56 | if (req.status < 400)
|
57 |
| - callback(null, req.responseText); |
| 57 | + callback(null, req.responseText) |
58 | 58 | else
|
59 |
| - callback(new Error("Request failed: " + req.statusText)); |
60 |
| - }); |
61 |
| - req.addEventListener("error", function() { |
62 |
| - callback(new Error("Network error")); |
63 |
| - }); |
64 |
| - req.send(null); |
| 59 | + callback(new Error("Request failed: " + req.statusText)) |
| 60 | + }) |
| 61 | + req.addEventListener("error", () => { |
| 62 | + callback(new Error("Network error")) |
| 63 | + }) |
| 64 | + req.send(null) |
65 | 65 | }
|
66 | 66 |
|
67 |
| - var per = document.querySelector("#per_chapter"); |
68 |
| - per.addEventListener("change", function() { |
69 |
| - selectContext(per.value); |
70 |
| - document.location.hash = "#" + (per.value == "box" ? chapters.value : per.value); |
71 |
| - }); |
72 |
| - var fileList = document.querySelector("#files"); |
73 |
| - var fileInfo = document.querySelector("#fileInfo"); |
74 |
| - var runLocally = document.querySelector("#runLocally"); |
75 |
| - var localFileList = document.querySelector("#local-files"); |
| 67 | + let per = document.querySelector("#per_chapter") |
| 68 | + per.addEventListener("change", () => { |
| 69 | + selectContext(per.value) |
| 70 | + document.location.hash = "#" + (per.value == "box" ? chapters.value : per.value) |
| 71 | + }) |
| 72 | + let fileList = document.querySelector("#files") |
| 73 | + let fileInfo = document.querySelector("#fileInfo") |
| 74 | + let runLocally = document.querySelector("#runLocally") |
| 75 | + let localFileList = document.querySelector("#local-files") |
76 | 76 |
|
77 | 77 | function addItem(container, link) {
|
78 |
| - var li = container.appendChild(document.createElement("li")); |
79 |
| - var a = li.appendChild(document.createElement("a")); |
80 |
| - a.href = link; |
81 |
| - a.textContent = link.replace(/^code\//, ""); |
| 78 | + let li = container.appendChild(document.createElement("li")) |
| 79 | + let a = li.appendChild(document.createElement("a")) |
| 80 | + a.href = link |
| 81 | + a.textContent = link.replace(/^code\//, "") |
82 | 82 | }
|
83 | 83 |
|
84 | 84 | function selectChapter(number, context) {
|
85 |
| - per.textContent = ""; |
86 |
| - var chapter = getChapter(number); |
| 85 | + per.textContent = "" |
| 86 | + let chapter = getChapter(number) |
87 | 87 | if (chapter.exercises.length) {
|
88 |
| - per.appendChild(opt("box", "Select an exercise")); |
89 |
| - chapter.exercises.forEach(function(exercise) { |
90 |
| - var num = chapter.number + "." + exercise.number; |
91 |
| - per.appendChild(opt(num, num + " " + exercise.name)); |
92 |
| - }); |
| 88 | + per.appendChild(opt("box", "Select an exercise")) |
| 89 | + chapter.exercises.forEach(exercise => { |
| 90 | + let num = chapter.number + "." + exercise.number |
| 91 | + per.appendChild(opt(num, num + " " + exercise.name)) |
| 92 | + }) |
93 | 93 | } else {
|
94 |
| - per.appendChild(opt("box", "This chapter has no exercises")); |
| 94 | + per.appendChild(opt("box", "This chapter has no exercises")) |
95 | 95 | }
|
96 |
| - fileInfo.style.display = runLocally.style.display = "none"; |
97 |
| - fileList.textContent = localFileList.textContent = ""; |
98 |
| - if (chapter.links) chapter.links.forEach(function(file, i) { |
99 |
| - if (!i) runLocally.style.display = ""; |
100 |
| - addItem(localFileList, file); |
101 |
| - }); |
102 |
| - if (chapter.include) chapter.include.forEach(function(file, i) { |
103 |
| - if (!i) fileInfo.style.display = ""; |
104 |
| - addItem(fileList, file); |
105 |
| - }); |
106 |
| - selectContext(context || "box"); |
| 96 | + fileInfo.style.display = runLocally.style.display = "none" |
| 97 | + fileList.textContent = localFileList.textContent = "" |
| 98 | + if (chapter.links) chapter.links.forEach((file, i) => { |
| 99 | + if (!i) runLocally.style.display = "" |
| 100 | + addItem(localFileList, file) |
| 101 | + }) |
| 102 | + if (chapter.include) chapter.include.forEach((file, i) => { |
| 103 | + if (!i) fileInfo.style.display = "" |
| 104 | + addItem(fileList, file) |
| 105 | + }) |
| 106 | + selectContext(context || "box") |
107 | 107 | }
|
108 | 108 |
|
109 | 109 | function findExercise(id, chapter) {
|
110 |
| - var parts = id.split("."); |
111 |
| - if (!chapter) chapter = getChapter(parts[0]); |
112 |
| - for (var i = 0; i < chapter.exercises.length; i++) |
| 110 | + let parts = id.split(".") |
| 111 | + if (!chapter) chapter = getChapter(parts[0]) |
| 112 | + for (let i = 0; i < chapter.exercises.length; i++) |
113 | 113 | if (chapter.exercises[i].number == +parts[1])
|
114 |
| - return chapter.exercises[i]; |
| 114 | + return chapter.exercises[i] |
115 | 115 | }
|
116 | 116 |
|
117 |
| - var context = {include: []}; |
| 117 | + let context = {include: []} |
118 | 118 |
|
119 | 119 | function selectContext(value) {
|
120 |
| - output.clear(); |
121 |
| - clearSandbox(); |
122 |
| - var chapter = getChapter(chapters.value), visible; |
| 120 | + output.clear() |
| 121 | + clearSandbox() |
| 122 | + let chapter = getChapter(chapters.value), visible |
123 | 123 | if (value == "box") {
|
124 |
| - var code = (chapters.value < 20 || chapters.value > 21) |
| 124 | + let code = (chapters.value < 20 || chapters.value > 21) |
125 | 125 | ? "Run code here in the context of Chapter " + chapter.number
|
126 |
| - : "Code from Node.js chapters can't be run in the browser"; |
127 |
| - var guessed = guessType(chapter.start_code); |
| 126 | + : "Code from Node.js chapters can't be run in the browser" |
| 127 | + let guessed = guessType(chapter.start_code) |
128 | 128 | if (guessed == "js")
|
129 |
| - code = "// " + code; |
| 129 | + code = "// " + code |
130 | 130 | else
|
131 |
| - code = "<!-- " + code + "-->"; |
132 |
| - if (chapter.start_code) code += "\n\n" + chapter.start_code; |
133 |
| - context = {include: chapter.include}; |
134 |
| - setEditorCode(code, guessed); |
135 |
| - visible = "box"; |
| 131 | + code = "<!-- " + code + "-->" |
| 132 | + if (chapter.start_code) code += "\n\n" + chapter.start_code |
| 133 | + context = {include: chapter.include} |
| 134 | + setEditorCode(code, guessed) |
| 135 | + visible = "box" |
136 | 136 | } else {
|
137 |
| - var exercise = findExercise(value, chapter); |
| 137 | + let exercise = findExercise(value, chapter) |
138 | 138 | context = {include: chapter.include,
|
139 | 139 | solution: exercise.solution,
|
140 |
| - type: exercise.type}; |
141 |
| - setEditorCode(exercise.code, exercise.type); |
142 |
| - visible = "exercise"; |
143 |
| - var link = document.querySelector("#download"); |
| 140 | + type: exercise.type} |
| 141 | + setEditorCode(exercise.code, exercise.type) |
| 142 | + visible = "exercise" |
| 143 | + let link = document.querySelector("#download") |
144 | 144 | if (/\.zip$/.test(exercise.file))
|
145 | 145 | link.href = exercise.file
|
146 | 146 | else
|
147 |
| - link.href = "data:text/plain;charset=UTF-8," + exercise.solution; |
| 147 | + link.href = "data:text/plain;charset=UTF-8," + exercise.solution |
148 | 148 | }
|
149 |
| - ["box", "exercise"].forEach(function(id) { |
| 149 | + ["box", "exercise"].forEach(id => { |
150 | 150 | document.querySelector("#" + id + "_info").style.display =
|
151 |
| - (id == visible ? "" : "none"); |
152 |
| - }); |
| 151 | + (id == visible ? "" : "none") |
| 152 | + }) |
153 | 153 | }
|
154 | 154 |
|
155 |
| - var outnode = document.querySelector(".sandbox-output"); |
156 |
| - var output = new SandBox.Output(outnode); |
| 155 | + let outnode = document.querySelector(".sandbox-output") |
| 156 | + let output = new SandBox.Output(outnode) |
157 | 157 |
|
158 |
| - document.querySelector("#run").addEventListener("click", runCode); |
| 158 | + document.querySelector("#run").addEventListener("click", runCode) |
159 | 159 |
|
160 |
| - var sandbox; |
| 160 | + let sandbox |
161 | 161 | function clearSandbox() {
|
162 | 162 | if (sandbox) {
|
163 |
| - sandbox.frame.parentNode.removeChild(sandbox.frame); |
164 |
| - sandbox = null; |
| 163 | + sandbox.frame.parentNode.removeChild(sandbox.frame) |
| 164 | + sandbox = null |
165 | 165 | }
|
166 | 166 | }
|
167 | 167 |
|
168 | 168 | function runCode() {
|
169 |
| - clearSandbox(); |
170 |
| - var val = editor.getValue(), type = context.type || guessType(val); |
| 169 | + clearSandbox() |
| 170 | + let val = editor.getValue(), type = context.type || guessType(val) |
171 | 171 | SandBox.create({
|
172 | 172 | loadFiles: hasIncludes(val, context.include) ? [] : context.include,
|
173 | 173 | place: type == "html" &&
|
174 | 174 | function(node) {
|
175 |
| - var out = document.querySelector(".sandbox-output"); |
176 |
| - out.parentNode.insertBefore(node, out); |
| 175 | + let out = document.querySelector(".sandbox-output") |
| 176 | + out.parentNode.insertBefore(node, out) |
177 | 177 | }
|
178 |
| - }.then(box => { |
179 |
| - output.clear(); |
| 178 | + }).then(box => { |
| 179 | + output.clear() |
180 | 180 | if (type == "html")
|
181 |
| - box.setHTML(val, output); |
| 181 | + box.setHTML(val, output) |
182 | 182 | else
|
183 |
| - box.run(val, output); |
| 183 | + box.run(val, output) |
184 | 184 | })
|
185 | 185 | }
|
186 | 186 |
|
187 |
| - document.querySelector("#solution").addEventListener("click", function() { |
188 |
| - setEditorCode(context.solution, context.type); |
189 |
| - }); |
190 |
| - |
191 |
| - var chapters = document.querySelector("#chapters"); |
192 |
| - chapterData.forEach(function(chapter) { |
193 |
| - chapters.appendChild(opt(chapter.number, chapter.number + ". " + chapter.title)); |
194 |
| - chapter.exercises.forEach(function(exercise) { |
195 |
| - exercise.chapter = chapter; |
196 |
| - }); |
197 |
| - }); |
198 |
| - chapters.addEventListener("change", function() { |
199 |
| - selectChapter(chapters.value); |
200 |
| - document.location.hash = "#" + chapters.value; |
201 |
| - }); |
| 187 | + document.querySelector("#solution").addEventListener("click", () => { |
| 188 | + setEditorCode(context.solution, context.type) |
| 189 | + }) |
| 190 | + |
| 191 | + let chapters = document.querySelector("#chapters") |
| 192 | + chapterData.forEach(chapter => { |
| 193 | + chapters.appendChild(opt(chapter.number, chapter.number + ". " + chapter.title)) |
| 194 | + chapter.exercises.forEach(exercise => { |
| 195 | + exercise.chapter = chapter |
| 196 | + }) |
| 197 | + }) |
| 198 | + chapters.addEventListener("change", () => { |
| 199 | + selectChapter(chapters.value) |
| 200 | + document.location.hash = "#" + chapters.value |
| 201 | + }) |
202 | 202 |
|
203 | 203 | function parseFragment() {
|
204 |
| - var hash = document.location.hash.slice(1); |
205 |
| - var valid = /^(\d+)(?:\.(\d+))?$/.exec(hash); |
| 204 | + let hash = document.location.hash.slice(1) |
| 205 | + let valid = /^(\d+)(?:\.(\d+))?$/.exec(hash) |
| 206 | + let chapter, exercise |
206 | 207 | if (valid) {
|
207 |
| - var chapter = getChapter(Number(valid[1])); |
208 |
| - var exercise = chapter && valid[2] && findExercise(hash, chapter); |
209 |
| - if (!chapter || valid[2] && !exercise) valid = null; |
| 208 | + chapter = getChapter(Number(valid[1])) |
| 209 | + exercise = chapter && valid[2] && findExercise(hash, chapter) |
| 210 | + if (!chapter || valid[2] && !exercise) valid = null |
210 | 211 | }
|
211 | 212 | if (valid) {
|
212 |
| - var perValue = exercise ? hash : "box", setPer = false; |
| 213 | + let perValue = exercise ? hash : "box", setPer = false |
213 | 214 | if (chapters.value != valid[1]) {
|
214 |
| - chapters.value = valid[1]; |
215 |
| - selectChapter(Number(valid[1]), perValue); |
216 |
| - setPer = true; |
| 215 | + chapters.value = valid[1] |
| 216 | + selectChapter(Number(valid[1]), perValue) |
| 217 | + setPer = true |
217 | 218 | }
|
218 | 219 | if (per.value != perValue) {
|
219 |
| - per.value = perValue; |
220 |
| - if (!setPer) selectContext(perValue); |
| 220 | + per.value = perValue |
| 221 | + if (!setPer) selectContext(perValue) |
221 | 222 | }
|
222 |
| - return true; |
| 223 | + return true |
223 | 224 | }
|
224 | 225 | }
|
225 | 226 |
|
226 |
| - parseFragment() || selectChapter(0, "box"); |
227 |
| - addEventListener("hashchange", parseFragment); |
228 |
| -}); |
| 227 | + parseFragment() || selectChapter(0, "box") |
| 228 | + addEventListener("hashchange", parseFragment) |
| 229 | +}) |
0 commit comments