Mercurial > hg > orthanc-stone
comparison Applications/StoneWebViewer/WebApplication/app.js @ 2023:e0b7b2a8b914
support generation of ZIP archives in the presence of authorization tokens
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sat, 03 Dec 2022 21:00:36 +0100 |
parents | 96d20b42e740 |
children | 04148de691a7 f36de3ba43c8 |
comparison
equal
deleted
inserted
replaced
2022:96d20b42e740 | 2023:e0b7b2a8b914 |
---|---|
51 var MOUSE_TOOL_CREATE_ELLIPSE_PROBE = 10; // New in 2.4 | 51 var MOUSE_TOOL_CREATE_ELLIPSE_PROBE = 10; // New in 2.4 |
52 var MOUSE_TOOL_CREATE_RECTANGLE_PROBE = 11; // New in 2.4 | 52 var MOUSE_TOOL_CREATE_RECTANGLE_PROBE = 11; // New in 2.4 |
53 var MOUSE_TOOL_CREATE_TEXT_ANNOTATION = 12; // New in 2.4 | 53 var MOUSE_TOOL_CREATE_TEXT_ANNOTATION = 12; // New in 2.4 |
54 var MOUSE_TOOL_MAGNIFYING_GLASS = 13; // New in 2.4 | 54 var MOUSE_TOOL_MAGNIFYING_GLASS = 13; // New in 2.4 |
55 | 55 |
56 var hasAuthorizationToken = false; | |
57 var axiosHeaders = {}; | |
58 | |
56 | 59 |
57 function getParameterFromUrl(key) { | 60 function getParameterFromUrl(key) { |
58 var url = window.location.search.substring(1); | 61 var url = window.location.search.substring(1); |
59 var args = url.split('&'); | 62 var args = url.split('&'); |
60 for (var i = 0; i < args.length; i++) { | 63 for (var i = 0; i < args.length; i++) { |
146 $('[data-toggle="tooltip"]').tooltip({ | 149 $('[data-toggle="tooltip"]').tooltip({ |
147 placement: 'bottom', | 150 placement: 'bottom', |
148 container: 'body', | 151 container: 'body', |
149 trigger: 'hover' | 152 trigger: 'hover' |
150 }); | 153 }); |
154 } | |
155 | |
156 | |
157 function TriggerDownloadFromUri(uri, filename, mime) | |
158 { | |
159 if (hasAuthorizationToken) { | |
160 axios.get(uri, { | |
161 headers: axiosHeaders, | |
162 responseType: 'arraybuffer' | |
163 }) | |
164 .then(function(response) { | |
165 const blob = new Blob([ response.data ], { type: mime }); | |
166 const url = URL.createObjectURL(blob); | |
167 | |
168 //window.open(url, '_blank'); | |
169 | |
170 // https://stackoverflow.com/a/19328891 | |
171 var a = document.createElement("a"); | |
172 document.body.appendChild(a); | |
173 a.style = "display: none"; | |
174 a.href = url; | |
175 a.download = filename; | |
176 a.click(); | |
177 window.URL.revokeObjectURL(url); | |
178 }); | |
179 | |
180 } else { | |
181 // This version was used in Stone Web viewer <= 2.4, but doesn't | |
182 // work with authorization headers | |
183 | |
184 /** | |
185 * The use of "window.open()" below might be blocked (depending on | |
186 * the browser criteria to block popup). As a consequence, we | |
187 * prefer to set "window.location". | |
188 * https://www.nngroup.com/articles/the-top-ten-web-design-mistakes-of-1999/ | |
189 **/ | |
190 // window.open(uri, '_blank'); | |
191 window.location.href = uri; | |
192 } | |
151 } | 193 } |
152 | 194 |
153 | 195 |
154 /** | 196 /** |
155 * The "mousemove" and "mouseup" events were added in Stone Web viewer | 197 * The "mousemove" and "mouseup" events were added in Stone Web viewer |
278 else if (newVal.series.type == stone.ThumbnailType.VIDEO) { | 320 else if (newVal.series.type == stone.ThumbnailType.VIDEO) { |
279 this.status = 'video'; | 321 this.status = 'video'; |
280 this.videoUri = ''; | 322 this.videoUri = ''; |
281 if (this.globalConfiguration.OrthancApiRoot) { | 323 if (this.globalConfiguration.OrthancApiRoot) { |
282 var that = this; | 324 var that = this; |
283 axios.post(that.globalConfiguration.OrthancApiRoot + '/tools/find', | 325 axios.post(that.globalConfiguration.OrthancApiRoot + '/tools/find', { |
284 { | 326 Level : 'Instance', |
285 Level : 'Instance', | 327 Query : { |
286 Query : { | 328 StudyInstanceUID: studyInstanceUid |
287 StudyInstanceUID: studyInstanceUid | 329 } |
288 } | 330 }, { |
289 }) | 331 headers: axiosHeaders |
332 }) | |
290 .then(function(response) { | 333 .then(function(response) { |
291 if (response.data.length != 1) { | 334 if (response.data.length != 1) { |
292 throw(''); | 335 throw(''); |
293 } | 336 } |
294 else { | 337 else { |
295 that.videoUri = that.globalConfiguration.OrthancApiRoot + '/instances/' + response.data[0] + '/frames/0/raw'; | 338 var uri = that.globalConfiguration.OrthancApiRoot + '/instances/' + response.data[0] + '/frames/0/raw'; |
339 | |
340 if (hasAuthorizationToken) { | |
341 axios.get(uri, { | |
342 headers: axiosHeaders, | |
343 responseType: 'arraybuffer' | |
344 }) | |
345 .then(function(response) { | |
346 const blob = new Blob([ response.data ]); | |
347 that.videoUri = URL.createObjectURL(blob); | |
348 }); | |
349 } else { | |
350 that.videoUri = uri; | |
351 } | |
296 } | 352 } |
297 }) | 353 }) |
298 .catch(function(error) { | 354 .catch(function(error) { |
299 alert('Cannot find the video in Orthanc'); | 355 alert('Cannot find the video in Orthanc'); |
300 }); | 356 }); |
1158 { | 1214 { |
1159 if (this.creatingArchive && | 1215 if (this.creatingArchive && |
1160 this.archiveJob.length > 0) { | 1216 this.archiveJob.length > 0) { |
1161 | 1217 |
1162 var that = this; | 1218 var that = this; |
1163 axios.get(that.globalConfiguration.OrthancApiRoot + '/jobs/' + that.archiveJob) | 1219 axios.get(that.globalConfiguration.OrthancApiRoot + '/jobs/' + that.archiveJob, { |
1220 headers: axiosHeaders | |
1221 }) | |
1164 .then(function(response) { | 1222 .then(function(response) { |
1165 console.log('Progress of archive job ' + that.archiveJob + ': ' + response.data['Progress'] + '%'); | 1223 console.log('Progress of archive job ' + that.archiveJob + ': ' + response.data['Progress'] + '%'); |
1166 var state = response.data['State']; | 1224 var state = response.data['State']; |
1167 if (state == 'Success') { | 1225 if (state == 'Success') { |
1168 that.creatingArchive = false; | 1226 that.creatingArchive = false; |
1169 var uri = that.globalConfiguration.OrthancApiRoot + '/jobs/' + that.archiveJob + '/archive'; | 1227 var uri = that.globalConfiguration.OrthancApiRoot + '/jobs/' + that.archiveJob + '/archive'; |
1170 | 1228 TriggerDownloadFromUri(uri, that.archiveJob + '.zip', 'application/zip'); |
1171 /** | |
1172 * The use of "window.open()" below might be blocked | |
1173 * (depending on the browser criteria to block popup). | |
1174 * As a consequence, we prefer to set "window.location". | |
1175 * https://www.nngroup.com/articles/the-top-ten-web-design-mistakes-of-1999/ | |
1176 **/ | |
1177 // window.open(uri, '_blank'); | |
1178 window.location = uri; | |
1179 } | 1229 } |
1180 else if (state == 'Running') { | 1230 else if (state == 'Running') { |
1181 setTimeout(that.CheckIsDownloadComplete, 1000); | 1231 setTimeout(that.CheckIsDownloadComplete, 1000); |
1182 } | 1232 } |
1183 else { | 1233 else { |
1195 DownloadStudy: function(studyInstanceUid, event) | 1245 DownloadStudy: function(studyInstanceUid, event) |
1196 { | 1246 { |
1197 console.log('Creating archive for study: ' + studyInstanceUid); | 1247 console.log('Creating archive for study: ' + studyInstanceUid); |
1198 | 1248 |
1199 var that = this; | 1249 var that = this; |
1200 axios.post(this.globalConfiguration.OrthancApiRoot + '/tools/lookup', studyInstanceUid) | 1250 axios.post(this.globalConfiguration.OrthancApiRoot + '/tools/lookup', studyInstanceUid, { |
1251 headers: axiosHeaders | |
1252 }) | |
1201 .then(function(response) { | 1253 .then(function(response) { |
1202 if (response.data.length != 1) { | 1254 if (response.data.length != 1) { |
1203 throw(''); | 1255 throw(''); |
1204 } | 1256 } |
1205 else { | 1257 else { |
1214 | 1266 |
1215 if (that.orthancSystem.ApiVersion >= 13) { | 1267 if (that.orthancSystem.ApiVersion >= 13) { |
1216 // ZIP streaming is available (this is Orthanc >= | 1268 // ZIP streaming is available (this is Orthanc >= |
1217 // 1.9.4): Simply give the hand to Orthanc | 1269 // 1.9.4): Simply give the hand to Orthanc |
1218 event.preventDefault(); | 1270 event.preventDefault(); |
1219 window.location.href = uri; | 1271 TriggerDownloadFromUri(uri, orthancId + '.zip', 'application/zip'); |
1220 | |
1221 } else { | 1272 } else { |
1222 // ZIP streaming is not available: Create a job to create the archive | 1273 // ZIP streaming is not available: Create a job to create the archive |
1223 axios.post(uri, { | 1274 axios.post(uri, { |
1224 'Asynchronous' : true | 1275 'Asynchronous' : true |
1276 }, { | |
1277 headers: axiosHeaders | |
1225 }) | 1278 }) |
1226 .then(function(response) { | 1279 .then(function(response) { |
1227 that.creatingArchive = true; | 1280 that.creatingArchive = true; |
1228 that.archiveJob = response.data.ID; | 1281 that.archiveJob = response.data.ID; |
1229 setTimeout(that.CheckIsDownloadComplete, 1000); | 1282 setTimeout(that.CheckIsDownloadComplete, 1000); |
1429 } | 1482 } |
1430 | 1483 |
1431 // Bearer token is new in Stone Web viewer 2.0 | 1484 // Bearer token is new in Stone Web viewer 2.0 |
1432 var token = getParameterFromUrl('token'); | 1485 var token = getParameterFromUrl('token'); |
1433 if (token !== undefined) { | 1486 if (token !== undefined) { |
1487 hasAuthorizationToken = true; | |
1434 stone.AddHttpHeader('Authorization', 'Bearer ' + token); | 1488 stone.AddHttpHeader('Authorization', 'Bearer ' + token); |
1435 } | 1489 axiosHeaders['Authorization'] = 'Bearer ' + token; |
1436 | 1490 } |
1491 | |
1492 if (app.globalConfiguration.OrthancApiRoot) { | |
1493 axios.get(app.globalConfiguration.OrthancApiRoot + '/system', { | |
1494 headers: axiosHeaders | |
1495 }) | |
1496 .then(function (response) { | |
1497 app.orthancSystem = response.data; | |
1498 }); | |
1499 } | |
1500 | |
1437 | 1501 |
1438 /** | 1502 /** |
1439 * Calls to "stone.XXX()" can be reordered after this point. | 1503 * Calls to "stone.XXX()" can be reordered after this point. |
1440 **/ | 1504 **/ |
1441 | 1505 |
1602 document.body.appendChild(script); | 1666 document.body.appendChild(script); |
1603 }) | 1667 }) |
1604 .catch(function (error) { | 1668 .catch(function (error) { |
1605 alert('Cannot load the WebAssembly framework'); | 1669 alert('Cannot load the WebAssembly framework'); |
1606 }); | 1670 }); |
1607 | |
1608 if (app.globalConfiguration.OrthancApiRoot) { | |
1609 axios.get(app.globalConfiguration.OrthancApiRoot + '/system') | |
1610 .then(function (response) { | |
1611 app.orthancSystem = response.data; | |
1612 }); | |
1613 } | |
1614 }) | 1671 }) |
1615 .catch(function (error) { | 1672 .catch(function (error) { |
1616 alert('Cannot load the configuration file'); | 1673 alert('Cannot load the configuration file'); |
1617 }); | 1674 }); |
1618 }); | 1675 }); |