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 });