|
85 | 85 | } |
86 | 86 |
|
87 | 87 | function showLoadingError(text) { |
88 | | - promptText.style.display = 'block'; |
89 | | - toolbar.style.display = 'none'; |
90 | | - statusBar.style.display = 'none'; |
91 | | - canvas.style.display = 'none'; |
| 88 | + resetLoadingState(); |
92 | 89 | errorText.style.display = 'block'; |
93 | 90 | errorText.textContent = text; |
94 | | - } |
95 | 91 |
|
96 | | - async function startLoading(files) { |
97 | | - if (files.length === 1) { |
98 | | - const file0 = files[0]; |
99 | | - const code = await loadFile(file0); |
100 | | - |
101 | | - // Check for both "//" and "/*" comments |
102 | | - let match = /\/\/#\s*sourceMappingURL=data:([^,]+),([^ ]+)/.exec(code); |
103 | | - if (!match) match = /\/\*#\s*sourceMappingURL=data:((?:[^,*]|\*[^/])+),((?:[^ *]|\*[^/])+)(?:[^*]|\*[^/])*\*\//.exec(code); |
104 | | - |
105 | | - // Check for a non-empty data URL payload |
106 | | - if (match && match[2]) { |
107 | | - const parts = match[1].split(';'); |
108 | | - const map = parts.indexOf('base64') >= 0 ? utf8ToUTF16(atob(match[2])) : decodeURIComponent(match[2]); |
109 | | - finishLoading(code, map); |
| 92 | + // Push an empty hash since the state has been cleared |
| 93 | + if (location.hash !== '') { |
| 94 | + try { |
| 95 | + history.pushState({}, '', location.pathname); |
| 96 | + } catch (e) { |
110 | 97 | } |
| 98 | + } |
| 99 | + } |
111 | 100 |
|
112 | | - else if (match = /\/([/*])#\s*sourceMappingURL=data:/.exec(code)) { |
113 | | - showLoadingError(`Could not find any base64 data in the embedded "/${match[1]}# sourceMappingURL=" comment.`); |
| 101 | + async function finishLoadingCodeWithEmbeddedSourceMap(code, file) { |
| 102 | + // Check for both "//" and "/*" comments |
| 103 | + let match = /\/(\/)[#@] *sourceMappingURL=([^\s]+)/.exec(code); |
| 104 | + if (!match) match = /\/(\*)[#@] *sourceMappingURL=((?:[^\s*]|\*[^/])+)(?:[^*]|\*[^/])*\*\//.exec(code); |
| 105 | + |
| 106 | + // Check for a non-empty data URL payload |
| 107 | + if (match && match[2]) { |
| 108 | + let map; |
| 109 | + try { |
| 110 | + // Use "new URL" to ensure that the URL has a protocol (e.g. "data:" or "https:") |
| 111 | + map = await fetch(new URL(match[2])).then(r => r.text()); |
| 112 | + } catch (e) { |
| 113 | + showLoadingError(`Failed to parse the URL in the "/${match[1]}# sourceMappingURL=" comment: ${e && e.message || e}`); |
| 114 | + return; |
114 | 115 | } |
| 116 | + finishLoading(code, map); |
| 117 | + } |
115 | 118 |
|
116 | | - else if (match = /\/([/*])#\s*sourceMappingURL=/.exec(code)) { |
117 | | - showLoadingError(`The embedded "/${match[1]}# sourceMappingURL=" comment does not contain an inline source map. ` + |
118 | | - `You must import both the JavaScript file and the source map file that goes with it.`); |
119 | | - } |
| 119 | + else if (file && isProbablySourceMap(file)) { |
| 120 | + // Allow loading a source map without a generated file because why not |
| 121 | + finishLoading('', code); |
| 122 | + } |
120 | 123 |
|
121 | | - else if (isProbablySourceMap(file0)) { |
122 | | - // Allow loading a source map without a generated file because why not |
123 | | - finishLoading('', code); |
124 | | - } |
| 124 | + else { |
| 125 | + const c = file && file.name.endsWith('ss') ? '*' : '/'; |
| 126 | + showLoadingError(`Failed to find an embedded "/${c}# sourceMappingURL=" comment in the ${file ? 'imported file' : 'pasted text'}.`); |
| 127 | + } |
| 128 | + } |
125 | 129 |
|
126 | | - else { |
127 | | - const c = file0.name.endsWith('ss') ? '*' : '/'; |
128 | | - showLoadingError(`Failed to find an embedded "/${c}# sourceMappingURL=" comment in the imported file.`); |
129 | | - } |
| 130 | + async function startLoading(files) { |
| 131 | + if (files.length === 1) { |
| 132 | + const file0 = files[0]; |
| 133 | + const code = await loadFile(file0); |
| 134 | + finishLoadingCodeWithEmbeddedSourceMap(code, file0); |
130 | 135 | } |
131 | 136 |
|
132 | 137 | else if (files.length === 2) { |
|
159 | 164 | } |
160 | 165 | } |
161 | 166 |
|
| 167 | + document.body.addEventListener('paste', e => { |
| 168 | + e.preventDefault(); |
| 169 | + const code = e.clipboardData.getData('text/plain'); |
| 170 | + finishLoadingCodeWithEmbeddedSourceMap(code, null); |
| 171 | + }); |
| 172 | + |
162 | 173 | // Accelerate VLQ decoding with a lookup table |
163 | 174 | const vlqTable = new Uint8Array(128); |
164 | 175 | const vlqChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; |
|
0 commit comments