4002852354f680c431e65f711f4809882ede4be8
[WebKit-https.git] / Source / WebInspectorUI / Tools / PrettyPrinting / index.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4     <title>Debug</title>
5     <link rel="stylesheet" href="codemirror.css">
6     <link rel="stylesheet" href="codemirror-additions.css">
7     <script src="codemirror.js"></script>
8     <script src="javascript.js"></script>
9     <script src="css.js"></script>
10     <script src="Utilities.js"></script>
11     <script src="Formatter.js"></script>
12     <script src="FormatterDebug.js"></script>
13     <script src="FormatterContentBuilder.js"></script>
14     <script src="CodeMirrorFormatters.js"></script>
15 </head>
16 <body>
17
18     <h1>Debug Pretty Printing</h1>
19
20     <!-- Controls -->
21     <select id="mode">
22         <option selected value="text/javascript">JavaScript</option>
23         <option value="text/css">CSS</option>
24     </select>
25     <button id="populate">Populate</button>
26     <button id="run-tests">Run Tests</button>
27     <button id="clear">Clear</button>
28     <button id="select-output">Select Output</button>
29     <button id="run-again">Run Again</button>
30     <button id="save-as-url">Save URL</button>
31     <button id="save-local-storage">Save to Storage</button>
32     <button id="clear-local-storage">Clear Storage</button>
33     <small id="time"></small>
34
35     <br><br>
36
37     <!-- Editor -->
38     <textarea id="code" name="code"></textarea>
39
40     <!-- Output -->
41     <pre id="pretty"></pre>
42     <pre id="debug"></pre>
43
44     <script>
45     // Editor.
46     var cm = CodeMirror.fromTextArea(document.getElementById("code"), {
47         lineNumbers: true,
48     });
49
50     // Initial values from URL.
51     var queryParams = {};
52     if (window.location.search.length > 0) {
53         var searchString = window.location.search.substring(1);
54         var groups = searchString.split("&");
55         for (var i = 0; i < groups.length; ++i) {
56             var pair = groups[i].split("=");
57             queryParams[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
58         }
59     }
60
61     // Initial mode and string.
62     var mode = "text/javascript";
63     var content = "(function() { var a=1; return a+1; })();";
64     var updatePicker = false;
65     if (queryParams.content || queryParams.mode) {
66         content = queryParams.content || "";
67         mode = queryParams.mode || "text/javascript";
68         updatePicker = true;
69     } else if (localStorage.content || localStorage.mode) {
70         content = localStorage.content || "";
71         mode = localStorage.mode || "text/javascript";
72         updatePicker = true;
73     }
74
75     // Initial mode picker value.
76     var modePicker = document.getElementById("mode");
77     if (updatePicker) {
78         for (var i = 0; i < modePicker.options.length; ++i) {
79             if (modePicker.options[i].value === mode) {
80                 modePicker.options[i].selected = true;
81                 break;
82             }
83         }
84     }
85
86     // Set on CodeMirror.
87     cm.setValue(content);
88     cm.setOption("mode", mode);
89
90     // Changing the mode.
91     modePicker.addEventListener("change", function(event) {
92         cm.setValue("");
93         cm.setOption("mode", modePicker.value);
94         refresh();
95     });
96
97     // Populate button to populate with some canned content.
98     document.getElementById("populate").addEventListener("click", function(event) {
99         switch (modePicker.value) {
100             case "text/javascript":
101                 var url = "populate/jquery.min.js";
102                 break;
103             case "text/css":
104                 var url = "populate/apple.css";
105                 break;
106         }
107
108         var xhr = new XMLHttpRequest;
109         xhr.open("GET", url, true);
110         xhr.onload = function() {
111             cm.setValue(xhr.responseText);
112             setTimeout(refresh);
113         }
114         xhr.send();
115     });
116
117     // Run Tests button.
118     document.getElementById("run-tests").addEventListener("click", function(event) {
119         cm.setValue("Running Tests...");
120         refresh();
121         runTests();
122     });
123
124     // Clear button.
125     document.getElementById("clear").addEventListener("click", function(event) {
126         cm.setValue("");
127         refresh();
128     });
129
130     // Select output button.
131     document.getElementById("select-output").addEventListener("click", function(event) {
132         var range = document.createRange();
133         range.selectNodeContents(document.getElementById("pretty"));
134         var selection = window.getSelection();
135         selection.removeAllRanges();
136         selection.addRange(range);
137     });
138
139     // Run again button.
140     document.getElementById("run-again").addEventListener("click", function(event) {
141         refresh();
142     });
143
144     // Save as URL button.
145     document.getElementById("save-as-url").addEventListener("click", function(event) {
146         var mode = modePicker.value;
147         var content = cm.getValue();
148         window.location.search = "?mode=" + window.encodeURIComponent(mode) + "&content=" + window.encodeURIComponent(content);
149     });
150
151     // Save to localStorage.
152     document.getElementById("save-local-storage").addEventListener("click", function(event) {
153         localStorage.mode = modePicker.value;
154         localStorage.content = cm.getValue();
155     });
156
157     // Clear localStorage.
158     document.getElementById("clear-local-storage").addEventListener("click", function(event) {
159         localStorage.removeItem("mode");
160         localStorage.removeItem("content");
161     });
162
163     // Button helpers.
164     var buttons = ["mode", "populate", "run-tests", "clear", "select-output", "run-again"];
165     function disableButtons() {
166         console.log("disableButtons");
167         buttons.forEach(function(id) {
168             document.getElementById(id).disabled = true;
169         });
170     }
171     function enableButtons() {
172         console.log("enableButtons");
173         buttons.forEach(function(id) {
174             document.getElementById(id).disabled = false;
175         });
176     }
177
178     // Refresh after changes after a short delay.
179     var timer = null;
180     cm.on("change", function(codeMirror, change) {
181         if (timer)
182             clearTimeout(timer)
183         timer = setTimeout(function() {
184             clearTimeout(timer);
185             timer = null;
186             refresh();
187         }, 500);
188     });
189
190     // Output elements.
191     var timeOutput = document.getElementById("time");
192     var prettyPre = document.getElementById("pretty");
193     var debugPre = document.getElementById("debug");
194
195     function refresh() {
196         if (timer)
197             clearTimeout(timer);
198
199         const start = {line: 0, ch: 0};
200         const end = {line: cm.lineCount() - 1};
201
202         // Setup.
203         const indentString = "    ";
204         var originalLineEndings = [];
205         var formattedLineEndings = [];
206         var mapping = {original: [0], formatted: [0]};
207         var builder = new FormatterContentBuilder(mapping, originalLineEndings, formattedLineEndings, 0, 0, indentString);
208         var formatter = new Formatter(cm, builder);
209
210         // Time the formatter.
211         var startTime = Date.now();
212         formatter.format(start, end);
213         var endTime = Date.now();
214
215         // Gather debug information.
216         var debug = formatter.debug(start, end);
217
218         // Output the results.
219         timeOutput.innerText = (endTime - startTime) + "ms";
220         prettyPre.innerText = builder.formattedContent;
221         debugPre.innerText = debug;
222     }
223
224     setTimeout(refresh);
225
226     // Tests.
227     function runTests() {
228         disableButtons();
229         function completedCallback() {
230             enableButtons();
231         }
232
233         if (modePicker.value === "text/javascript")
234             runJavaScriptTests(completedCallback);
235         else
236             runCSSTests(completedCallback);
237     }
238     function runJavaScriptTests(callback) {
239         _runTests(callback, [
240             "js-tests/block-comment.js",
241             "js-tests/single-statement-blocks.js",
242             "js-tests/switch-case-default.js",
243         ]);
244     }
245     function runCSSTests(callback) {
246         _runTests(callback, []);
247     }
248     function _runTests(callback, manifest) {
249         var index = -1;
250         var results = [];
251         setTimeout(runNextTest, 0);
252
253         function runNextTest() {
254             // Next test.
255             index++;
256
257             // Done.
258             if (index >= manifest.length) {
259                 if (!index)
260                     results.push("/* No tests for mode: " + modePicker.value);
261                 printResults();
262                 return;
263             }
264
265             // Load test and expected results.
266             var test = manifest[index];
267             var expected = test.replace(/\.js$/, "-expected.js");
268             var xhr1 = new XMLHttpRequest;
269             xhr1.open("GET", test, false);
270             xhr1.send();
271             var testData = xhr1.responseText;
272             var xhr2 = new XMLHttpRequest;
273             xhr2.open("GET", expected, false);
274             xhr2.send();
275             var expectedData = xhr2.responseText;
276
277             // Run the test.
278             var editor = CodeMirror(document.createElement("div"));
279             editor.setOption("mode", modePicker.value);
280             editor.setValue(testData);
281             const start = {line: 0, ch: 0};
282             const end = {line: editor.lineCount() - 1};
283             const indentString = "    ";
284             var originalLineEndings = [];
285             var formattedLineEndings = [];
286             var mapping = {original: [0], formatted: [0]};
287             var builder = new FormatterContentBuilder(mapping, originalLineEndings, formattedLineEndings, 0, 0, indentString);
288             var formatter = new Formatter(editor, builder);
289             formatter.format(start, end);
290
291             // Compare results.
292             var pass = builder.formattedContent === expectedData;
293             results.push("/* " + (pass ? "PASS" : "FAIL") + ": " + test + " */");
294             runNextTest();
295         }
296
297         function printResults() {
298             cm.setValue(results.join("\n"));
299             cm.refresh();
300             callback();
301         }
302     }
303
304     </script>
305 </body>
306 </html>