OLD | NEW |
1 /** | 1 /** |
2 * Common JS that talks XHR back to the server and runs the code and receives | 2 * Common JS that talks XHR back to the server and runs the code and receives |
3 * the results. | 3 * the results. |
4 */ | 4 */ |
5 | 5 |
6 | 6 |
7 /** | 7 /** |
8 * All the functionality is wrapped up in this anonymous closure, but we need | 8 * All the functionality is wrapped up in this anonymous closure, but we need |
9 * to be told if we are on the workspace page or a normal try page, so the | 9 * to be told if we are on the workspace page or a normal try page, so the |
10 * workspaceName is passed into the closure, it must be set in the global | 10 * workspaceName is passed into the closure, it must be set in the global |
11 * namespace. If workspaceName is the empty string then we know we aren't | 11 * namespace. If workspaceName is the empty string then we know we aren't |
12 * running on a workspace page. | 12 * running on a workspace page. |
13 * | 13 * |
14 * If we are on a workspace page we also look for a 'history' | 14 * If we are on a workspace page we also look for a 'history' |
15 * variable in the global namespace which contains the list of tries | 15 * variable in the global namespace which contains the list of tries |
16 * that are included in this workspace. That variable is used to | 16 * that are included in this workspace. That variable is used to |
17 * populate the history list. | 17 * populate the history list. |
18 */ | 18 */ |
19 (function() { | 19 (function() { |
20 function onLoad() { | 20 function onLoad() { |
21 var run = document.getElementById('run'); | 21 var run = document.getElementById('run'); |
22 var permalink = document.getElementById('permalink'); | 22 var permalink = document.getElementById('permalink'); |
23 var embed = document.getElementById('embed'); | 23 var embed = document.getElementById('embed'); |
24 var embedButton = document.getElementById('embedButton'); | 24 var embedButton = document.getElementById('embedButton'); |
25 var code = document.getElementById('code'); | 25 var code = document.getElementById('code'); |
26 var output = document.getElementById('output'); | 26 var output = document.getElementById('output'); |
27 var stdout = document.getElementById('stdout'); | 27 var stdout = document.getElementById('stdout'); |
28 var img = document.getElementById('img'); | 28 var img = document.getElementById('img'); |
29 var tryHistory = document.getElementById('tryHistory'); | 29 var tryHistory = document.getElementById('tryHistory'); |
30 var parser = new DOMParser(); | 30 var parser = new DOMParser(); |
31 var tryTemplate = document.getElementById('tryTemplate'); | 31 var tryTemplate = document.getElementById('tryTemplate'); |
| 32 var sourcesTemplate = document.getElementById('sourcesTemplate'); |
32 | 33 |
33 var editor = CodeMirror.fromTextArea(code, { | 34 var enableSource = document.getElementById('enableSource'); |
34 theme: "default", | 35 var selectedSource = document.getElementById('selectedSource'); |
35 lineNumbers: true, | 36 var sourceCode = document.getElementById('sourceCode'); |
36 matchBrackets: true, | 37 var chooseSource = document.getElementById('chooseSource'); |
37 mode: "text/x-c++src", | 38 var chooseList = document.getElementById('chooseList'); |
38 indentUnit: 4, | |
39 }); | |
40 | 39 |
41 // Match the initial textarea size. | 40 // Id of the source image to use, 0 if no source image is used. |
42 editor.setSize(editor.defaultCharWidth() * code.cols, | 41 var sourceId = 0; |
43 editor.defaultTextHeight() * code.rows); | 42 |
| 43 sourceId = parseInt(enableSource.getAttribute('data-id')); |
| 44 if (sourceId) { |
| 45 sourceSelectByID(sourceId); |
| 46 } |
| 47 |
44 | 48 |
45 function beginWait() { | 49 function beginWait() { |
46 document.body.classList.add('waiting'); | 50 document.body.classList.add('waiting'); |
47 run.disabled = true; | 51 run.disabled = true; |
48 } | 52 } |
49 | 53 |
50 | 54 |
51 function endWait() { | 55 function endWait() { |
52 document.body.classList.remove('waiting'); | 56 document.body.classList.remove('waiting'); |
53 run.disabled = false; | 57 run.disabled = false; |
54 } | 58 } |
55 | 59 |
56 | 60 |
| 61 function sourceSelectByID(id) { |
| 62 sourceId = id; |
| 63 if (id > 0) { |
| 64 enableSource.checked = true; |
| 65 selectedSource.innerHTML = '<img with=64 height=64 src="/i/image-'+sou
rceId+'.png" />'; |
| 66 selectedSource.classList.add('show'); |
| 67 sourceCode.classList.add('show'); |
| 68 chooseSource.classList.remove('show'); |
| 69 } else { |
| 70 enableSource.checked = false; |
| 71 selectedSource.classList.remove('show'); |
| 72 sourceCode.classList.remove('show'); |
| 73 } |
| 74 } |
| 75 |
| 76 |
| 77 /** |
| 78 * A selection has been made in the choiceList. |
| 79 */ |
| 80 function sourceSelect() { |
| 81 sourceSelectByID(parseInt(this.getAttribute('data-id'))); |
| 82 } |
| 83 |
| 84 |
| 85 /** |
| 86 * Callback when the loading of the image sources is complete. |
| 87 * |
| 88 * Fills in the list of images from the data returned. |
| 89 */ |
| 90 function sourcesComplete(e) { |
| 91 endWait(); |
| 92 // The response is JSON of the form: |
| 93 // [ |
| 94 // {"id": 1}, |
| 95 // {"id": 3}, |
| 96 // ... |
| 97 // ] |
| 98 body = JSON.parse(e.target.response); |
| 99 // Clear out the old list if present. |
| 100 while (chooseList.firstChild) { |
| 101 chooseList.removeChild(chooseList.firstChild); |
| 102 } |
| 103 body.forEach(function(source) { |
| 104 var id = 'i'+source.id; |
| 105 var imgsrc = '/i/image-'+source.id+'.png'; |
| 106 var clone = sourcesTemplate.content.cloneNode(true); |
| 107 clone.querySelector('img').src = imgsrc; |
| 108 clone.querySelector('button').setAttribute('id', id); |
| 109 clone.querySelector('button').setAttribute('data-id', source.id); |
| 110 chooseList.insertBefore(clone, chooseList.firstChild); |
| 111 chooseList.querySelector('#'+id).addEventListener('click', sourceSelect
, true); |
| 112 }); |
| 113 chooseSource.classList.add('show'); |
| 114 } |
| 115 |
| 116 |
| 117 /** |
| 118 * Toggle the use of a source image, or select a new source image. |
| 119 * |
| 120 * If enabling source images then load the list of available images via |
| 121 * XHR. |
| 122 */ |
| 123 function sourceClick(e) { |
| 124 selectedSource.classList.remove('show'); |
| 125 sourceCode.classList.remove('show'); |
| 126 if (enableSource.checked) { |
| 127 beginWait(); |
| 128 var req = new XMLHttpRequest(); |
| 129 req.addEventListener('load', sourcesComplete); |
| 130 req.addEventListener('error', xhrError); |
| 131 req.overrideMimeType('application/json'); |
| 132 req.open('GET', '/sources/', true); |
| 133 req.send(); |
| 134 } else { |
| 135 sourceId = 0; |
| 136 } |
| 137 } |
| 138 |
| 139 enableSource.addEventListener('click', sourceClick, true); |
| 140 selectedSource.addEventListener('click', sourceClick, true); |
| 141 |
| 142 |
| 143 var editor = CodeMirror.fromTextArea(code, { |
| 144 theme: "default", |
| 145 lineNumbers: true, |
| 146 matchBrackets: true, |
| 147 mode: "text/x-c++src", |
| 148 indentUnit: 4, |
| 149 }); |
| 150 |
| 151 // Match the initial textarea size. |
| 152 editor.setSize(editor.defaultCharWidth() * code.cols, |
| 153 editor.defaultTextHeight() * code.rows); |
| 154 |
| 155 |
57 /** | 156 /** |
58 * Callback when there's an XHR error. | 157 * Callback when there's an XHR error. |
59 * @param e The callback event. | 158 * @param e The callback event. |
60 */ | 159 */ |
61 function xhrError(e) { | 160 function xhrError(e) { |
62 endWait(); | 161 endWait(); |
63 alert('Something bad happened: ' + e); | 162 alert('Something bad happened: ' + e); |
64 } | 163 } |
65 | 164 |
66 function clearOutput() { | 165 function clearOutput() { |
(...skipping 26 matching lines...) Expand all Loading... |
93 // The response is JSON of the form: | 192 // The response is JSON of the form: |
94 // { | 193 // { |
95 // "hash": "unique id for a try", | 194 // "hash": "unique id for a try", |
96 // "code": "source code for try" | 195 // "code": "source code for try" |
97 // } | 196 // } |
98 endWait(); | 197 endWait(); |
99 body = JSON.parse(e.target.response); | 198 body = JSON.parse(e.target.response); |
100 code.value = body.code; | 199 code.value = body.code; |
101 editor.setValue(body.code); | 200 editor.setValue(body.code); |
102 img.src = '/i/'+body.hash+'.png'; | 201 img.src = '/i/'+body.hash+'.png'; |
| 202 sourceSelectByID(body.source); |
103 if (permalink) { | 203 if (permalink) { |
104 permalink.href = '/c/' + body.hash; | 204 permalink.href = '/c/' + body.hash; |
105 } | 205 } |
106 } | 206 } |
107 | 207 |
108 | 208 |
109 /** | 209 /** |
110 * Add the given try image to the history of a workspace. | 210 * Add the given try image to the history of a workspace. |
111 */ | 211 */ |
112 function addToHistory(hash, imgUrl) { | 212 function addToHistory(hash, imgUrl) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 | 265 |
166 function onSubmitCode() { | 266 function onSubmitCode() { |
167 beginWait(); | 267 beginWait(); |
168 clearOutput(); | 268 clearOutput(); |
169 var req = new XMLHttpRequest(); | 269 var req = new XMLHttpRequest(); |
170 req.addEventListener('load', codeComplete); | 270 req.addEventListener('load', codeComplete); |
171 req.addEventListener('error', xhrError); | 271 req.addEventListener('error', xhrError); |
172 req.overrideMimeType('application/json'); | 272 req.overrideMimeType('application/json'); |
173 req.open('POST', '/', true); | 273 req.open('POST', '/', true); |
174 req.setRequestHeader('content-type', 'application/json'); | 274 req.setRequestHeader('content-type', 'application/json'); |
175 req.send(JSON.stringify({'code': editor.getValue(), 'name': workspaceNam
e})); | 275 req.send(JSON.stringify({'code': editor.getValue(), 'name': workspaceNam
e, 'source': sourceId})); |
176 } | 276 } |
177 run.addEventListener('click', onSubmitCode); | 277 run.addEventListener('click', onSubmitCode); |
178 | 278 |
179 | 279 |
180 function onEmbedClick() { | 280 function onEmbedClick() { |
181 embed.style.display='inline'; | 281 embed.style.display='inline'; |
182 } | 282 } |
183 | 283 |
184 if (embedButton) { | 284 if (embedButton) { |
185 embedButton.addEventListener('click', onEmbedClick); | 285 embedButton.addEventListener('click', onEmbedClick); |
186 } | 286 } |
187 | 287 |
188 // Add the images to the history if we are on a workspace page. | 288 // Add the images to the history if we are on a workspace page. |
189 if (tryHistory && history) { | 289 if (tryHistory && history) { |
190 for (var i=0; i<history.length; i++) { | 290 for (var i=0; i<history.length; i++) { |
191 addToHistory(history[i].hash, '/i/'+history[i].hash+'.png'); | 291 addToHistory(history[i].hash, '/i/'+history[i].hash+'.png'); |
192 } | 292 } |
193 } | 293 } |
194 } | 294 } |
195 | 295 |
196 // If loaded via HTML Imports then DOMContentLoaded will be long done. | 296 // If loaded via HTML Imports then DOMContentLoaded will be long done. |
197 if (document.readyState != "loading") { | 297 if (document.readyState != "loading") { |
198 onLoad(); | 298 onLoad(); |
199 } else { | 299 } else { |
200 this.addEventListener('DOMContentLoaded', onLoad); | 300 this.addEventListener('DOMContentLoaded', onLoad); |
201 } | 301 } |
202 | 302 |
203 })(); | 303 })(); |
OLD | NEW |