changeset 1696:572652803929

bootstrapping the Stone Web viewer configuration file
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 27 Nov 2020 09:34:02 +0100
parents a691ab50d416
children c2802561d7f9
files Applications/StoneWebViewer/NOTES.txt Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/configuration.json Applications/StoneWebViewer/WebAssembly/CMakeLists.txt
diffstat 4 files changed, 102 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/NOTES.txt	Thu Nov 26 19:46:33 2020 +0100
+++ b/Applications/StoneWebViewer/NOTES.txt	Fri Nov 27 09:34:02 2020 +0100
@@ -47,3 +47,38 @@
   If the "selectedStudies" is not provided, then all the studies are
   displayed at the startup.
 
+
+Dynamic actions using messages
+==============================
+
+Some actions can be dynamically triggered in the Stone Web viewer from
+another Web page. This is done by using the "window.postMessage()"
+primitive of JavaScript:
+https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
+
+Each message must be a JSON object containing at least the "type"
+field. The latter field indicates the type of action to be triggered.
+
+For security, the "ExpectedMessageOrigin" configuration option of the
+Stone Web viewer must have been set to the expected origin of the
+messages. Otherwise, the Stone Web viewer will reject the message.
+
+
+Action of type "show-osirix-annotations"
+----------------------------------------
+
+This action loads a set of ROIs exported from OsiriX. The ROIs must
+use the XML file format of OsiriX.
+
+The parent DICOM study containing the annotation(s) must have been
+loaded by the Stone Web viewer beforehand. The Stone Web viewer shall
+automatically focus on one instance that is associated with the ROIs.
+
+The JSON message must contain the following fields:
+
+- "type" must be equal to "show-osirix-annotations"
+
+- "xml" must contain the XML file generated by OsiriX
+
+- "clear" is a Boolean to indicate whether to clear the annotations
+  that have previously been opened.
--- a/Applications/StoneWebViewer/WebApplication/app.js	Thu Nov 26 19:46:33 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/app.js	Fri Nov 27 09:34:02 2020 +0100
@@ -19,6 +19,9 @@
  **/
 
 
+var CONFIGURATION_SOURCE = 'configuration.json';
+var WASM_SOURCE = 'StoneWebViewer.js';
+  
 var COLORS = [ 'blue', 'red', 'green', 'yellow', 'violet' ];
 var SERIES_INSTANCE_UID = '0020,000e';
 var STUDY_INSTANCE_UID = '0020,000d';
@@ -28,6 +31,8 @@
 // Registry of the PDF series for which the instance metadata is still waiting
 var pendingSeriesPdf_ = {};
 
+var globalConfiguration_ = {};
+
 
 function getParameterFromUrl(key) {
   var url = window.location.search.substring(1);
@@ -809,6 +814,16 @@
 
 
 
+function ParseJsonWithComments(json)
+{
+  if (typeof(json) == 'string') {
+    // https://stackoverflow.com/a/62945875/881731
+    return JSON.parse(json.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g,
+                                   (m, g) => g ? "" : m));
+  } else {
+    return json;
+  }
+}
 
 
 $(document).ready(function() {
@@ -821,31 +836,36 @@
 
   //app.modalWarning = true;
 
+  axios.get(CONFIGURATION_SOURCE)
+    .then(function(response) {
+      globalConfiguration_ = ParseJsonWithComments(response.data);
+      
+      // Option 1: Loading script using plain HTML
+      
+      /*
+        var script = document.createElement('script');
+        script.src = WASM_SOURCE;
+        script.type = 'text/javascript';
+        document.body.appendChild(script);
+      */
 
-  var wasmSource = 'StoneWebViewer.js';
-  
-  // Option 1: Loading script using plain HTML
-  
-  /*
-    var script = document.createElement('script');
-    script.src = wasmSource;
-    script.type = 'text/javascript';
-    document.body.appendChild(script);
-  */
+      // Option 2: Loading script using AJAX (gives the opportunity to
+      // explicitly report errors)
 
-  // Option 2: Loading script using AJAX (gives the opportunity to
-  // report explicit errors)
-
-  axios.get(wasmSource)
-    .then(function (response) {
-      var script = document.createElement('script');
-      script.innerHTML = response.data;
-      script.type = 'text/javascript';
-      document.body.appendChild(script);
+      axios.get(WASM_SOURCE)
+        .then(function (response) {
+          var script = document.createElement('script');
+          script.innerHTML = response.data;
+          script.type = 'text/javascript';
+          document.body.appendChild(script);
+        })
+        .catch(function (error) {
+          alert('Cannot load the WebAssembly framework');
+        });
     })
     .catch(function (error) {
-      alert('Cannot load the WebAssembly framework');
-    });
+      alert('Cannot load the configuration file');
+    });  
 });
 
 
@@ -860,51 +880,29 @@
 document.onselectstart = new Function ('return false');
 
 
-
-
-
-
-
-//var expectedOrigin = 'http://localhost:8042';
-var expectedOrigin = '';   // TODO - INSECURE - CONFIGURATION
-
 window.addEventListener('message', function(e) {
   if ('type' in e.data) {
-    if (expectedOrigin != '' &&
-        e.origin !== expectedOrigin) {
-      alert('Bad origin for the message');
-      return;
+    var expectedOrigin = globalConfiguration_['ExpectedMessageOrigin'];
+    
+    if (expectedOrigin === undefined) {
+      alert('Dynamic actions are disabled in the Stone Web viewer, ' +
+            'set the configuration option "ExpectedMessageOrigin".');
+    }    
+    else if (expectedOrigin != '*' &&
+             e.origin !== expectedOrigin) {
+      alert('Bad origin for a dynamic action in the Stone Web viewer: "' + e.origin +
+            '", whereas the message must have origin: "' + expectedOrigin + '"');
     }
-    
-    if (e.data.type == 'show-osirix-annotations') {
+    else if (e.data.type == 'show-osirix-annotations') {
       var clear = true;  // Whether to clear previous annotations
       if ('clear' in e.data) {
         clear = e.data.clear;
       }
       
       app.LoadOsiriXAnnotations(e.data.xml, clear);
-    } else {
-      console.log('Unknown message type: ' + e.data.type);
+    }
+    else {
+      alert('Unknown type of dynamic action in the Stone Web viewer: ' + e.data.type);
     }
   }
 });
-
-
-function Test()
-{
-  var s = [ 'length.xml', 'arrow.xml', 'text.xml', 'angle.xml' ];
-
-  for (var i = 0; i < s.length; i++) {
-    axios.get(s[i])
-      .then(function (response) {
-        //var targetOrigin = 'http://localhost:8000';
-        var targetOrigin = '*';  // TODO - INSECURE
-        
-        window.postMessage({
-          'type': 'show-osirix-annotations',
-          'xml': response.data,
-          'clear': false
-        }, targetOrigin);
-      });
-  }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/StoneWebViewer/WebApplication/configuration.json	Fri Nov 27 09:34:02 2020 +0100
@@ -0,0 +1,11 @@
+{
+  /**
+   * The allowed origin for messages corresponding to dynamic actions
+   * triggered by another Web page using "window.postMessage()". The
+   * special value "*" will allow any origin, which is an insecure
+   * value to be used only during development. If this option is not
+   * set, all the requests for dynamic actions will be rejected.
+   * https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
+   **/
+  "ExpectedMessageOrigin" : "http://localhost:8042"
+}
--- a/Applications/StoneWebViewer/WebAssembly/CMakeLists.txt	Thu Nov 26 19:46:33 2020 +0100
+++ b/Applications/StoneWebViewer/WebAssembly/CMakeLists.txt	Fri Nov 27 09:34:02 2020 +0100
@@ -157,6 +157,7 @@
   ${CMAKE_SOURCE_DIR}/../WebApplication/app-fixes.css
   ${CMAKE_SOURCE_DIR}/../WebApplication/app.css
   ${CMAKE_SOURCE_DIR}/../WebApplication/app.js
+  ${CMAKE_SOURCE_DIR}/../WebApplication/configuration.json
   ${CMAKE_SOURCE_DIR}/../WebApplication/index.html
   ${CMAKE_SOURCE_DIR}/../WebApplication/open-sans.css
   ${CMAKE_SOURCE_DIR}/../WebApplication/pdf-viewer.js