changeset 3112:1bedab6993d4 db-changes

integration mainline->db-changes
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 11 Jan 2019 11:01:55 +0100
parents 897d539ae0e9 (current diff) 495ec3d3893d (diff)
children 388409fd0d47
files NEWS
diffstat 8 files changed, 826 insertions(+), 710 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Jan 10 18:03:04 2019 +0100
+++ b/.hgignore	Fri Jan 11 11:01:55 2019 +0100
@@ -3,3 +3,4 @@
 CMakeLists.txt.user
 *.cpp.orig
 *.h.orig
+.vs/
--- a/Core/DicomNetworking/Internals/FindScp.cpp	Thu Jan 10 18:03:04 2019 +0100
+++ b/Core/DicomNetworking/Internals/FindScp.cpp	Fri Jan 11 11:01:55 2019 +0100
@@ -166,6 +166,28 @@
     }
 
 
+    static void FixFindQuery(DicomMap& target,
+                             const DicomMap& source)
+    {
+      // "The definition of a Data Set in PS3.5 specifically excludes
+      // the range of groups below group 0008, and this includes in
+      // particular Meta Information Header elements such as Transfer
+      // Syntax UID (0002,0010)."
+      // http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_C.4.html#sect_C.4.1.1.3
+      // https://groups.google.com/d/msg/orthanc-users/D3kpPuX8yV0/_zgHOzkMEQAJ
+
+      DicomArray a(source);
+
+      for (size_t i = 0; i < a.GetSize(); i++)
+      {
+        if (a.GetElement(i).GetTag().GetGroup() >= 0x0008)
+        {
+          target.SetValue(a.GetElement(i).GetTag(), a.GetElement(i).GetValue());
+        }
+      }
+    }
+
+
 
     void FindScpCallback(
       /* in */ 
@@ -255,7 +277,10 @@
               DicomMap input;
               FromDcmtkBridge::ExtractDicomSummary(input, *requestIdentifiers);
 
-              data.findHandler_->Handle(data.answers_, input, sequencesToReturn,
+              DicomMap filtered;
+              FixFindQuery(filtered, input);
+
+              data.findHandler_->Handle(data.answers_, filtered, sequencesToReturn,
                                         *data.remoteIp_, *data.remoteAet_,
                                         *data.calledAet_, modality.GetManufacturer());
               ok = true;
--- a/Core/DicomParsing/DicomDirWriter.cpp	Thu Jan 10 18:03:04 2019 +0100
+++ b/Core/DicomParsing/DicomDirWriter.cpp	Fri Jan 11 11:01:55 2019 +0100
@@ -410,7 +410,14 @@
       switch (level)
       {
         case ResourceType_Patient:
-          found = GetUtf8TagValue(id, dataset, encoding, DCM_PatientID);
+          if (!GetUtf8TagValue(id, dataset, encoding, DCM_PatientID))
+          {
+            // Be tolerant about missing patient ID. Fixes issue #124
+            // (GET /studies/ID/media fails for certain dicom file).
+            id = "";
+          }
+
+          found = true;
           type = ERT_Patient;
           break;
 
--- a/NEWS	Thu Jan 10 18:03:04 2019 +0100
+++ b/NEWS	Fri Jan 11 11:01:55 2019 +0100
@@ -14,7 +14,10 @@
 Maintenance
 -----------
 
+* Don't consider tags whose group is below 0x0008 in C-FIND SCP
+* Fix issue #21 (DICOM files missing after uploading with Firefox)
 * Fix issue #118 (Wording in Configuration.json regarding SynchronousCMove)
+* Fix issue #124 (GET /studies/ID/media fails for certain dicom file)
 * Fixed Orthanc Explorer on IE and Firefox: Explorer always show "too many results"
   and it's therefore impossible to browse the content.
 * Upgraded dependencies for static and Windows builds:
--- a/OrthancExplorer/explorer.html	Thu Jan 10 18:03:04 2019 +0100
+++ b/OrthancExplorer/explorer.html	Fri Jan 11 11:01:55 2019 +0100
@@ -1,627 +1,642 @@
 <!DOCTYPE html>
 
 <html>
-  <head>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1">
-    <title>Orthanc Explorer</title>
+
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>Orthanc Explorer</title>
 
-    <link rel="stylesheet" href="libs/jquery.mobile.min.css" />
-    <link rel="stylesheet" href="libs/jqtree.css" />
-    <link rel="stylesheet" href="libs/jquery.mobile.simpledialog.min.css" />
-    <link rel="stylesheet" href="libs/jquery-file-upload/css/style.css" />
-    <link rel="stylesheet" href="libs/jquery-file-upload/css/jquery.fileupload-ui.css" />
-    <link rel="stylesheet" href="libs/slimbox2/slimbox2.css" />
-
-    <script src="libs/jquery.min.js"></script>
-    <script src="libs/jquery.mobile.min.js"></script>
-    <script src="libs/jqm.page.params.js"></script>
-    <script src="libs/tree.jquery.js"></script>
-    <script src="libs/date.js"></script>
-    <script src="libs/jquery.mobile.simpledialog2.js"></script>
-    <script src="libs/slimbox2.js"></script>
-    <script src="libs/jquery.blockui.js"></script>
+  <link rel="stylesheet" href="libs/jquery.mobile.min.css" />
+  <link rel="stylesheet" href="libs/jqtree.css" />
+  <link rel="stylesheet" href="libs/jquery.mobile.simpledialog.min.css" />
+  <link rel="stylesheet" href="libs/jquery-file-upload/css/style.css" />
+  <link rel="stylesheet" href="libs/jquery-file-upload/css/jquery.fileupload-ui.css" />
+  <link rel="stylesheet" href="libs/slimbox2/slimbox2.css" />
 
-    <!-- https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin -->
-    <script src="libs/jquery-file-upload/js/vendor/jquery.ui.widget.js"></script>
-    <script src="libs/jquery-file-upload/js/jquery.iframe-transport.js"></script>
-    <script src="libs/jquery-file-upload/js/jquery.fileupload.js"></script>
+  <script src="libs/jquery.min.js"></script>
+  <script src="libs/jquery.mobile.min.js"></script>
+  <script src="libs/jqm.page.params.js"></script>
+  <script src="libs/tree.jquery.js"></script>
+  <script src="libs/date.js"></script>
+  <script src="libs/jquery.mobile.simpledialog2.js"></script>
+  <script src="libs/slimbox2.js"></script>
+  <script src="libs/jquery.blockui.js"></script>
+
+  <!-- https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin -->
+  <script src="libs/jquery-file-upload/js/vendor/jquery.ui.widget.js"></script>
+  <script src="libs/jquery-file-upload/js/jquery.iframe-transport.js"></script>
+  <script src="libs/jquery-file-upload/js/jquery.fileupload.js"></script>
 
-    <link rel="stylesheet" href="explorer.css" />
-    <script src="file-upload.js"></script>
-    <script src="explorer.js"></script>
-    <script src="query-retrieve.js"></script>
-    <script src="../plugins/explorer.js"></script>
-  </head>
-  <body>
-    <div data-role="page" id="lookup" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>Lookup studies</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right"> 
-          <a href="#upload" data-icon="gear" data-role="button">Upload</a>
-          <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
-          <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
-        </div>
+  <link rel="stylesheet" href="explorer.css" />
+  <script src="file-upload.js"></script>
+  <script src="explorer.js"></script>
+  <script src="query-retrieve.js"></script>
+  <script src="../plugins/explorer.js"></script>
+</head>
+
+<body>
+  <div data-role="page" id="lookup">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>Lookup studies</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
       </div>
-      <div data-role="content">
-        <form data-ajax="false" id="lookup-form">
-          <div data-role="fieldcontain">
-	    <label for="lookup-patient-id">Patient ID:</label>
-	    <input type="text" name="lookup-patient-id" id="lookup-patient-id" value=""  />
-	  </div>
-
-          <div data-role="fieldcontain">
-	    <label for="lookup-patient-name">Patient Name:</label>
-	    <input type="text" name="lookup-patient-name" id="lookup-patient-name" value=""  />
-	  </div>
-
-          <div data-role="fieldcontain">
-	    <label for="lookup-accession-number">Accession Number:</label>
-	    <input type="text" name="lookup-accession-number" id="lookup-accession-number" value=""  />
-	  </div>
-
-          <div data-role="fieldcontain">
-	    <label for="lookup-study-description">Study Description:</label>
-	    <input type="text" name="lookup-study-description" id="lookup-study-description" value=""  />
-	  </div>
-
-          <div data-role="fieldcontain">
-	    <label for="lookup-study-date">Study Date:</label>
-            <select name="lookup-study-date" id="lookup-study-date">
-            </select>
-	  </div>
-
-          <fieldset class="ui-grid-b">
-	    <div class="ui-block-a">
-              <a href="#find-patients" data-role="button" data-theme="b" data-direction="reverse">All patients</a>
-            </div>
-	    <div class="ui-block-b">
-              <a href="#find-studies" data-role="button" data-theme="b" data-direction="reverse">All studies</a>
-            </div>
-	    <div class="ui-block-c">
-              <button id="lookup-submit" type="submit" data-theme="e">Do lookup</button>
-            </div>
-	  </fieldset>
-          <div>&nbsp;</div>
-        </form>
-        <div id="lookup-result">
-          <div id="lookup-alert">
-            <div class="ui-bar ui-bar-e">
-              <h3>Warning:</h3> Your lookup led to many results!
-              Showing only <span id="lookup-count">?</span> studies to
-              avoid performance issue. Please make your query more
-              specific, then relaunch the lookup.
-            </div>
-            <div>&nbsp;</div>
-          </div>
-          <ul data-role="listview" data-inset="true" data-filter="true">
-          </ul>
-        </div>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right">
+        <a href="#upload" data-icon="gear" data-role="button">Upload</a>
+        <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
+        <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
       </div>
     </div>
+    <div data-role="content">
+      <form data-ajax="false" id="lookup-form">
+        <div data-role="fieldcontain">
+          <label for="lookup-patient-id">Patient ID:</label>
+          <input type="text" name="lookup-patient-id" id="lookup-patient-id" value="" />
+        </div>
 
-    <div data-role="page" id="find-patients" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>All patients</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+        <div data-role="fieldcontain">
+          <label for="lookup-patient-name">Patient Name:</label>
+          <input type="text" name="lookup-patient-name" id="lookup-patient-name" value="" />
+        </div>
+
+        <div data-role="fieldcontain">
+          <label for="lookup-accession-number">Accession Number:</label>
+          <input type="text" name="lookup-accession-number" id="lookup-accession-number" value="" />
+        </div>
+
+        <div data-role="fieldcontain">
+          <label for="lookup-study-description">Study Description:</label>
+          <input type="text" name="lookup-study-description" id="lookup-study-description" value="" />
         </div>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right"> 
-          <a href="#upload" data-icon="gear" data-role="button">Upload</a>
-          <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
-          <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
+
+        <div data-role="fieldcontain">
+          <label for="lookup-study-date">Study Date:</label>
+          <select name="lookup-study-date" id="lookup-study-date">
+          </select>
         </div>
-      </div>
-      <div data-role="content">
-        <div id="alert-patients">
+
+        <fieldset class="ui-grid-b">
+          <div class="ui-block-a">
+            <a href="#find-patients" data-role="button" data-theme="b" data-direction="reverse">All patients</a>
+          </div>
+          <div class="ui-block-b">
+            <a href="#find-studies" data-role="button" data-theme="b" data-direction="reverse">All studies</a>
+          </div>
+          <div class="ui-block-c">
+            <button id="lookup-submit" type="submit" data-theme="e">Do lookup</button>
+          </div>
+        </fieldset>
+        <div>&nbsp;</div>
+      </form>
+      <div id="lookup-result">
+        <div id="lookup-alert">
           <div class="ui-bar ui-bar-e">
-            <h3>Warning:</h3> This is a large Orthanc server. Showing
-            only <span id="count-patients">?</span> patients to avoid
-            performance issue. Make sure to use lookup if targeting
-            specific patients!
+            <h3>Warning:</h3> Your lookup led to many results!
+            Showing only <span id="lookup-count">?</span> studies to
+            avoid performance issue. Please make your query more
+            specific, then relaunch the lookup.
           </div>
           <div>&nbsp;</div>
         </div>
-        <ul id="all-patients" data-role="listview" data-inset="true" data-filter="true">
-        </ul>
-      </div>
-    </div>
-
-    <div data-role="page" id="find-studies" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>All studies</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right"> 
-          <a href="#upload" data-icon="gear" data-role="button">Upload</a>
-          <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
-          <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
-        </div>
-      </div>
-      <div data-role="content">
-        <div id="alert-studies">
-          <div class="ui-bar ui-bar-e">
-            <h3>Warning:</h3> This is a large Orthanc server. Showing
-            only <span id="count-studies">?</span> studies to avoid
-            performance issue. Make sure to use lookup if targeting
-            specific studies!
-          </div>
-          <div>&nbsp;</div>
-        </div>
-        <ul id="all-studies" data-role="listview" data-inset="true" data-filter="true">
+        <ul data-role="listview" data-inset="true" data-filter="true">
         </ul>
       </div>
     </div>
+  </div>
 
-    <div data-role="page" id="upload">
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>Upload DICOM files</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
+  <div data-role="page" id="find-patients">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>All patients</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
       </div>
-      <div data-role="content">
-        <div style="display:none">
-          <input id="fileupload" type="file" name="files[]" data-url="../instances/" multiple>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right">
+        <a href="#upload" data-icon="gear" data-role="button">Upload</a>
+        <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
+        <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
+      </div>
+    </div>
+    <div data-role="content">
+      <div id="alert-patients">
+        <div class="ui-bar ui-bar-e">
+          <h3>Warning:</h3> This is a large Orthanc server. Showing
+          only <span id="count-patients">?</span> patients to avoid
+          performance issue. Make sure to use lookup if targeting
+          specific patients!
         </div>
-        <p>
-          <ul data-role="listview" data-inset="true">
-            <li data-icon="arrow-r" data-theme="e"><a href="#" id="upload-button">Start the upload</a></li>
-            <!--li data-icon="gear" data-theme="e"><a href="#" id="upload-abort" class="ui-disabled">Abort the current upload</a></li-->
-            <li data-icon="delete" data-theme="e"><a href="#" id="upload-clear">Clear the pending uploads</a></li>
-          </ul>
-          <div id="progress" class="ui-corner-all">
-            <span class="bar ui-corner-all"></span>
-            <div class="label"></div>
-          </div>
-        </p>
-        <ul id="upload-list" data-role="listview" data-inset="true">
-          <li data-role="list-divider">Drag and drop DICOM files here</li>
-        </ul>
+        <div>&nbsp;</div>
+      </div>
+      <ul id="all-patients" data-role="listview" data-inset="true" data-filter="true">
+      </ul>
+    </div>
+  </div>
+
+  <div data-role="page" id="find-studies">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>All studies</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+      </div>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right">
+        <a href="#upload" data-icon="gear" data-role="button">Upload</a>
+        <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
+        <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
+      </div>
+    </div>
+    <div data-role="content">
+      <div id="alert-studies">
+        <div class="ui-bar ui-bar-e">
+          <h3>Warning:</h3> This is a large Orthanc server. Showing
+          only <span id="count-studies">?</span> studies to avoid
+          performance issue. Make sure to use lookup if targeting
+          specific studies!
+        </div>
+        <div>&nbsp;</div>
+      </div>
+      <ul id="all-studies" data-role="listview" data-inset="true" data-filter="true">
+      </ul>
+    </div>
+  </div>
+
+  <div data-role="page" id="upload">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>Upload DICOM files</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
       </div>
     </div>
+    <div data-role="content">
+      <div>
+        <!-- It's very difficult to style a "file" input so we
+        actually hide it and create a "proxy" button that is
+        forwarding its click to the "file" input -->
+        <input id="fileupload" type="file" name="files[]" data-url="../instances/" style="display:none" multiple>
+      </div>
+      <p>
+        <ul data-role="listview" data-inset="true">
+          <li id="fileupload-proxy" onclick="$('#fileupload').click()" data-icon="arrow-r" data-theme="e">
+            <a href="#">Select files to upload ...</a>
+          </li>
+          <li data-icon="arrow-r" data-theme="e"><a href="#" id="upload-button">Start the upload</a></li>
+          <!--li data-icon="gear" data-theme="e"><a href="#" id="upload-abort" class="ui-disabled">Abort the current upload</a></li-->
+          <li data-icon="delete" data-theme="d"><a href="#" id="upload-clear">Clear the pending uploads</a></li>
+        </ul>
+        <div id="progress" class="ui-corner-all">
+          <span class="bar ui-corner-all"></span>
+          <div class="label"></div>
+        </div>
+      </p>
+      <div class="ui-bar ui-bar-e" id="issue-21-warning">
+        <h3>Warning:</h3> Orthanc issue #21: On Firefox, especially on
+        Linux & OSX systems, files might be missing if using
+        drag-and-drop. Please use the "Select files to upload" button
+        instead, or use the command-line "ImportDicomFiles.py" script.
+      </div>
+      <ul id="upload-list" data-role="listview" data-inset="true">
+        <li data-role="list-divider">Drag and drop DICOM files here</li>
+      </ul>
+    </div>
+  </div>
 
-    <div data-role="page" id="patient" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>Patient</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right"> 
-          <a href="#upload" data-icon="gear" data-role="button">Upload</a>
-          <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
-          <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
-        </div>
+  <div data-role="page" id="patient">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>Patient</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
       </div>
-      <div data-role="content">
-        <div class="ui-grid-a">
-          <div class="ui-block-a" style="width:30%">
-            <div style="padding-right:10px">
-              <ul data-role="listview" data-inset="true" data-theme="a"  id="patient-info">
-              </ul>
-              <p>
-                <div class="switch-container">
-                  <select name="protection" id="protection" data-role="slider">
-	            <option value="off">Unprotected</option>
-	            <option value="on">Protected</option>
-                  </select>
-                </div>
-              </p>
-              <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
-                <li data-role="list-divider">Interact</li>
-                <li data-icon="delete"><a href="#" id="patient-delete">Delete this patient</a></li>
-                <li data-icon="forward"><a href="#" id="patient-store">Send to remote modality</a></li>
-                <li data-icon="star"><a href="#" id="patient-anonymize">Anonymize</a></li>
-              </ul>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right">
+        <a href="#upload" data-icon="gear" data-role="button">Upload</a>
+        <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
+        <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
+      </div>
+    </div>
+    <div data-role="content">
+      <div class="ui-grid-a">
+        <div class="ui-block-a" style="width:30%">
+          <div style="padding-right:10px">
+            <ul data-role="listview" data-inset="true" data-theme="a" id="patient-info">
+            </ul>
+            <p>
+              <div class="switch-container">
+                <select name="protection" id="protection" data-role="slider">
+                  <option value="off">Unprotected</option>
+                  <option value="on">Protected</option>
+                </select>
+              </div>
+            </p>
+            <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
+              <li data-role="list-divider">Interact</li>
+              <li data-icon="delete"><a href="#" id="patient-delete">Delete this patient</a></li>
+              <li data-icon="forward"><a href="#" id="patient-store">Send to remote modality</a></li>
+              <li data-icon="star"><a href="#" id="patient-anonymize">Anonymize</a></li>
+            </ul>
 
-              <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
-                <li data-role="list-divider">Access</li>
-                <li data-icon="info" data-theme="e" style="display:none">
-                  <a href="#" id="patient-anonymized-from">Before anonymization</a>
-                </li>
-                <li data-icon="info" data-theme="e" style="display:none">
-                  <a href="#" id="patient-modified-from">Before modification</a>
-                </li>
-                <li data-icon="gear"><a href="#" id="patient-archive">Download ZIP</a></li>
-                <li data-icon="gear"><a href="#" id="patient-media">Download DICOMDIR</a></li>
-              </ul>
-            </div>
+            <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
+              <li data-role="list-divider">Access</li>
+              <li data-icon="info" data-theme="e" style="display:none">
+                <a href="#" id="patient-anonymized-from">Before anonymization</a>
+              </li>
+              <li data-icon="info" data-theme="e" style="display:none">
+                <a href="#" id="patient-modified-from">Before modification</a>
+              </li>
+              <li data-icon="gear"><a href="#" id="patient-archive">Download ZIP</a></li>
+              <li data-icon="gear"><a href="#" id="patient-media">Download DICOMDIR</a></li>
+            </ul>
           </div>
-          <div class="ui-block-b" style="width:70%">
-            <div style="padding:10px">
-              <ul id="list-studies" data-role="listview" data-inset="true" data-filter="true">
-              </ul>
-            </div>
+        </div>
+        <div class="ui-block-b" style="width:70%">
+          <div style="padding:10px">
+            <ul id="list-studies" data-role="listview" data-inset="true" data-filter="true">
+            </ul>
           </div>
         </div>
       </div>
     </div>
+  </div>
 
-    <div data-role="page" id="study">
-      <div data-role="header">
-	<h1>
-          <span class="orthanc-name"></span>
-          <a href="#" class="patient-link">Patient</a> &raquo; 
-          Study
-        </h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+  <div data-role="page" id="study">
+    <div data-role="header">
+      <h1>
+        <span class="orthanc-name"></span>
+        <a href="#" class="patient-link">Patient</a> &raquo;
+        Study
+      </h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+      </div>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right">
+        <a href="#upload" data-icon="gear" data-role="button">Upload</a>
+        <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
+        <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
+      </div>
+    </div>
+    <div data-role="content">
+      <div class="ui-grid-a">
+        <div class="ui-block-a" style="width:30%">
+          <div style="padding-right:10px">
+            <ul data-role="listview" data-inset="true" data-theme="a" id="study-info">
+            </ul>
+
+            <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
+              <li data-role="list-divider">Interact</li>
+              <li data-icon="delete"><a href="#" id="study-delete">Delete this study</a></li>
+              <li data-icon="forward"><a href="#" id="study-store">Send to DICOM modality</a></li>
+              <li data-icon="star"><a href="#" id="study-anonymize">Anonymize</a></li>
+            </ul>
+
+            <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
+              <li data-role="list-divider">Access</li>
+              <li data-icon="info" data-theme="e" style="display:none">
+                <a href="#" id="study-anonymized-from">Before anonymization</a>
+              </li>
+              <li data-icon="info" data-theme="e" style="display:none">
+                <a href="#" id="study-modified-from">Before modification</a>
+              </li>
+              <li data-icon="gear"><a href="#" id="study-archive">Download ZIP</a></li>
+              <li data-icon="gear"><a href="#" id="study-media">Download DICOMDIR</a></li>
+            </ul>
+          </div>
         </div>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right"> 
-          <a href="#upload" data-icon="gear" data-role="button">Upload</a>
-          <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
-          <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
+        <div class="ui-block-b" style="width:70%">
+          <div style="padding:10px">
+            <ul id="list-series" data-role="listview" data-inset="true" data-filter="true">
+            </ul>
+          </div>
         </div>
       </div>
-      <div data-role="content">
-        <div class="ui-grid-a">
-          <div class="ui-block-a" style="width:30%">
-            <div style="padding-right:10px">
-              <ul data-role="listview" data-inset="true" data-theme="a" id="study-info">
-              </ul>
+    </div>
+  </div>
 
-              <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
-                <li data-role="list-divider">Interact</li>
-                <li data-icon="delete"><a href="#" id="study-delete">Delete this study</a></li>
-                <li data-icon="forward"><a href="#" id="study-store">Send to DICOM modality</a></li>
-                <li data-icon="star"><a href="#" id="study-anonymize">Anonymize</a></li>
-              </ul>
+  <div data-role="page" id="series">
+    <div data-role="header">
+      <h1>
+        <span class="orthanc-name"></span>
+        <a href="#" class="patient-link">Patient</a> &raquo;
+        <a href="#" class="study-link">Study</a> &raquo;
+        Series
+      </h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+      </div>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right">
+        <a href="#upload" data-icon="gear" data-role="button">Upload</a>
+        <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
+        <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
+      </div>
+    </div>
+    <div data-role="content">
+      <div class="ui-grid-a">
+        <div class="ui-block-a" style="width:30%">
+          <div style="padding-right:10px">
+            <ul data-role="listview" data-inset="true" data-theme="a" id="series-info">
+            </ul>
+
+            <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
+              <li data-role="list-divider">Interact</li>
+              <li data-icon="delete"><a href="#" id="series-delete">Delete this series</a></li>
+              <li data-icon="forward"><a href="#" id="series-store">Send to DICOM modality</a></li>
+              <li data-icon="star"><a href="#" id="series-anonymize">Anonymize</a></li>
+            </ul>
 
-              <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
-                <li data-role="list-divider">Access</li>
-                <li data-icon="info" data-theme="e" style="display:none">
-                  <a href="#" id="study-anonymized-from">Before anonymization</a>
-                </li>
-                <li data-icon="info" data-theme="e" style="display:none">
-                  <a href="#" id="study-modified-from">Before modification</a>
-                </li>
-                <li data-icon="gear"><a href="#" id="study-archive">Download ZIP</a></li>
-                <li data-icon="gear"><a href="#" id="study-media">Download DICOMDIR</a></li>
-              </ul>
-            </div>
+            <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
+              <li data-role="list-divider">Access</li>
+              <li data-icon="info" data-theme="e" style="display:none">
+                <a href="#" id="series-anonymized-from">Before anonymization</a>
+              </li>
+              <li data-icon="info" data-theme="e" style="display:none">
+                <a href="#" id="series-modified-from">Before modification</a>
+              </li>
+              <li data-icon="search"><a href="#" id="series-preview">Preview this series</a></li>
+              <li data-icon="gear"><a href="#" id="series-archive">Download ZIP</a></li>
+              <li data-icon="gear"><a href="#" id="series-media">Download DICOMDIR</a></li>
+            </ul>
+          </div>
+        </div>
+        <div class="ui-block-b" style="width:70%">
+          <div style="padding:10px">
+            <ul id="list-instances" data-role="listview" data-inset="true" data-filter="true">
+            </ul>
           </div>
-          <div class="ui-block-b" style="width:70%">
-            <div style="padding:10px">
-              <ul id="list-series" data-role="listview" data-inset="true" data-filter="true">
-              </ul>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <div data-role="page" id="instance">
+    <div data-role="header">
+      <h1>
+        <span class="orthanc-name"></span>
+        <a href="#" class="patient-link">Patient</a> &raquo;
+        <a href="#" class="study-link">Study</a> &raquo;
+        <a href="#" class="series-link">Series</a> &raquo;
+        Instance
+      </h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+      </div>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right">
+        <a href="#upload" data-icon="gear" data-role="button">Upload</a>
+        <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
+        <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
+      </div>
+    </div>
+    <div data-role="content">
+      <div class="ui-grid-a">
+        <div class="ui-block-a" style="width:30%">
+          <div style="padding-right:10px">
+            <ul data-role="listview" data-inset="true" data-theme="a" id="instance-info">
+            </ul>
+
+            <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
+              <li data-role="list-divider">Interact</li>
+              <li data-icon="delete"><a href="#" id="instance-delete">Delete this instance</a></li>
+              <li data-icon="forward"><a href="#" id="instance-store">Send to DICOM modality</a></li>
+            </ul>
+
+            <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
+              <li data-role="list-divider">Access</li>
+              <li data-icon="info" data-theme="e" style="display:none">
+                <a href="#" id="instance-anonymized-from">Before anonymization</a>
+              </li>
+              <li data-icon="info" data-theme="e" style="display:none">
+                <a href="#" id="instance-modified-from">Before modification</a>
+              </li>
+              <li data-icon="arrow-d"><a href="#" id="instance-download-dicom">Download the DICOM file</a></li>
+              <li data-icon="arrow-d"><a href="#" id="instance-download-json">Download the JSON file</a></li>
+              <li data-icon="search"><a href="#" id="instance-preview">Preview the instance</a></li>
+            </ul>
+          </div>
+        </div>
+        <div class="ui-block-b" style="width:70%">
+          <div style="padding:10px">
+            <div class="ui-body ui-body-b">
+              <h1>DICOM Tags</h1>
+              <p align="right">
+                <input type="checkbox" id="show-tag-name" checked="checked" class="custom" data-mini="true" />
+                <label for="show-tag-name">Show tag description</label>
+              </p>
+              <div id="dicom-tree"></div>
             </div>
           </div>
         </div>
       </div>
     </div>
-
-    <div data-role="page" id="series">
-      <div data-role="header">
-	<h1>
-          <span class="orthanc-name"></span>
-          <a href="#" class="patient-link">Patient</a> &raquo; 
-          <a href="#" class="study-link">Study</a> &raquo; 
-          Series
-        </h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right"> 
-          <a href="#upload" data-icon="gear" data-role="button">Upload</a>
-          <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
-          <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
-        </div>
-      </div>
-      <div data-role="content">
-        <div class="ui-grid-a">
-          <div class="ui-block-a" style="width:30%">
-            <div style="padding-right:10px">
-              <ul data-role="listview" data-inset="true" data-theme="a" id="series-info">
-              </ul>
+  </div>
 
-              <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
-                <li data-role="list-divider">Interact</li>
-                <li data-icon="delete"><a href="#" id="series-delete">Delete this series</a></li>
-                <li data-icon="forward"><a href="#" id="series-store">Send to DICOM modality</a></li>
-                <li data-icon="star"><a href="#" id="series-anonymize">Anonymize</a></li>
-              </ul>
+  <div data-role="page" id="plugins">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>Plugins</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+      </div>
+    </div>
+    <div data-role="content">
+      <ul id="all-plugins" data-role="listview" data-inset="true" data-filter="true">
+      </ul>
+    </div>
+  </div>
 
-              <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
-                <li data-role="list-divider">Access</li>
-                <li data-icon="info" data-theme="e" style="display:none">
-                  <a href="#" id="series-anonymized-from">Before anonymization</a>
-                </li>
-                <li data-icon="info" data-theme="e" style="display:none">
-                  <a href="#" id="series-modified-from">Before modification</a>
-                </li>
-                <li data-icon="search"><a href="#" id="series-preview">Preview this series</a></li>
-                <li data-icon="gear"><a href="#" id="series-archive">Download ZIP</a></li>
-                <li data-icon="gear"><a href="#" id="series-media">Download DICOMDIR</a></li>
-              </ul>
-            </div>
-          </div>
-          <div class="ui-block-b" style="width:70%">
-            <div style="padding:10px">
-              <ul id="list-instances" data-role="listview" data-inset="true" data-filter="true">
-              </ul>
-            </div>
-          </div>
-        </div>
+  <div data-role="page" id="query-retrieve">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (1/4)</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
       </div>
     </div>
+    <div data-role="content">
+      <form data-ajax="false">
+        <div data-role="fieldcontain">
+          <label for="qr-server">DICOM server:</label>
+          <select name="qr-server" id="qr-server">
+          </select>
+        </div>
 
-    <div data-role="page" id="instance">
-      <div data-role="header">
-	<h1>
-          <span class="orthanc-name"></span>
-          <a href="#" class="patient-link">Patient</a> &raquo; 
-          <a href="#" class="study-link">Study</a> &raquo; 
-          <a href="#" class="series-link">Series</a> &raquo; 
-          Instance
-        </h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+        <div data-role="fieldcontain" id="qr-fields">
+          <fieldset data-role="controlgroup">
+            <legend>Field of interest:</legend>
+            <input type="radio" name="qr-field" id="qr-patient-id" value="PatientID" checked="checked" />
+            <label for="qr-patient-id">Patient ID</label>
+            <input type="radio" name="qr-field" id="qr-patient-name" value="PatientName" />
+            <label for="qr-patient-name">Patient Name</label>
+            <input type="radio" name="qr-field" id="qr-accession-number" value="AccessionNumber" />
+            <label for="qr-accession-number">Accession Number</label>
+            <input type="radio" name="qr-field" id="qr-study-description" value="StudyDescription" />
+            <label for="qr-study-description">Study Description</label>
+          </fieldset>
         </div>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right"> 
-          <a href="#upload" data-icon="gear" data-role="button">Upload</a>
-          <a href="#query-retrieve" data-icon="search" data-role="button">Query/Retrieve</a>
-          <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
-        </div>
-      </div>
-      <div data-role="content">
-        <div class="ui-grid-a">
-          <div class="ui-block-a" style="width:30%">
-            <div style="padding-right:10px">
-              <ul data-role="listview" data-inset="true" data-theme="a"  id="instance-info">
-              </ul>
 
-              <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
-                <li data-role="list-divider">Interact</li>
-                <li data-icon="delete"><a href="#" id="instance-delete">Delete this instance</a></li>
-                <li data-icon="forward"><a href="#" id="instance-store">Send to DICOM modality</a></li>
-              </ul>
+        <div data-role="fieldcontain">
+          <label for="qr-value">Value for this field:</label>
+          <input type="text" name="qr-value" id="qr-value" value="*" />
+        </div>
+
+        <div data-role="fieldcontain">
+          <label for="qr-date">Study date:</label>
+          <select name="qr-date" id="qr-date">
+          </select>
+        </div>
 
-              <ul data-role="listview" data-inset="true" data-theme="d" data-divider-theme="c">
-                <li data-role="list-divider">Access</li>
-                <li data-icon="info" data-theme="e" style="display:none">
-                  <a href="#" id="instance-anonymized-from">Before anonymization</a>
-                </li>
-                <li data-icon="info" data-theme="e" style="display:none">
-                  <a href="#" id="instance-modified-from">Before modification</a>
-                </li>
-                <li data-icon="arrow-d"><a href="#" id="instance-download-dicom">Download the DICOM file</a></li>
-                <li data-icon="arrow-d"><a href="#" id="instance-download-json">Download the JSON file</a></li>
-                <li data-icon="search"><a href="#" id="instance-preview">Preview the instance</a></li>
-              </ul>
-            </div>
-          </div>
-          <div class="ui-block-b" style="width:70%">
-            <div style="padding:10px">
-              <div class="ui-body ui-body-b">
-                <h1>DICOM Tags</h1>
-                <p align="right">
-                  <input type="checkbox" id="show-tag-name" checked="checked" class="custom" data-mini="true" />
-                  <label for="show-tag-name">Show tag description</label>
-                </p>
-                <div id="dicom-tree"></div>
-              </div>
-            </div>
+        <div data-role="fieldcontain" id="qr-modalities">
+          <div data-role="fieldcontain">
+            <fieldset data-role="controlgroup" data-type="horizontal">
+              <legend>Modalities:</legend>
+              <input type="checkbox" name="CR" id="qr-cr" class="custom" /> <label for="qr-cr">CR</label>
+              <input type="checkbox" name="CT" id="qr-ct" class="custom" /> <label for="qr-ct">CT</label>
+              <input type="checkbox" name="MR" id="qr-mr" class="custom" /> <label for="qr-mr">MR</label>
+              <input type="checkbox" name="NM" id="qr-nm" class="custom" /> <label for="qr-nm">NM</label>
+              <input type="checkbox" name="PT" id="qr-pt" class="custom" /> <label for="qr-pt">PT</label>
+              <input type="checkbox" name="US" id="qr-us" class="custom" /> <label for="qr-us">US</label>
+              <input type="checkbox" name="XA" id="qr-xa" class="custom" /> <label for="qr-xa">XA</label>
+              <input type="checkbox" name="DR" id="qr-dr" class="custom" /> <label for="qr-dr">DR</label>
+              <input type="checkbox" name="DX" id="qr-dx" class="custom" /> <label for="qr-dx">DX</label>
+            </fieldset>
           </div>
         </div>
-      </div>
+
+        <fieldset class="ui-grid-a">
+          <div class="ui-block-a">
+            <button id="qr-echo" data-theme="a">Test Echo</button>
+          </div>
+          <div class="ui-block-b">
+            <button id="qr-submit" type="submit" data-theme="b">Search studies</button>
+          </div>
+        </fieldset>
+      </form>
     </div>
+  </div>
+
 
-    <div data-role="page" id="plugins" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>Plugins</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
+  <div data-role="page" id="query-retrieve-2">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (2/4)</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
       </div>
-      <div data-role="content">
-        <ul id="all-plugins" data-role="listview" data-inset="true" data-filter="true">
-        </ul>
+      <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
+    </div>
+    <div data-role="content">
+      <ul data-role="listview" data-inset="true" data-filter="true" data-split-icon="arrow-d" data-split-theme="b">
+      </ul>
+    </div>
+  </div>
+
+
+  <div data-role="page" id="query-retrieve-3">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (3/4)</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
       </div>
+      <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
+    </div>
+    <div data-role="content">
+      <ul data-role="listview" data-inset="true" data-filter="true">
+      </ul>
+    </div>
+  </div>
+
+
+  <div data-role="page" id="query-retrieve-4">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (4/4)</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+      </div>
+      <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
     </div>
 
-    <div data-role="page" id="query-retrieve" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (1/4)</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-      </div>
-      <div data-role="content">
-        <form data-ajax="false">
-          <div data-role="fieldcontain">
-	    <label for="qr-server">DICOM server:</label>
-            <select name="qr-server" id="qr-server">
-            </select>
-	  </div>
-
-          <div data-role="fieldcontain" id="qr-fields">
-	    <fieldset data-role="controlgroup">
-	      <legend>Field of interest:</legend>
-	      <input type="radio" name="qr-field" id="qr-patient-id" value="PatientID" checked="checked" />
-	      <label for="qr-patient-id">Patient ID</label>
-	      <input type="radio" name="qr-field" id="qr-patient-name" value="PatientName" />
-	      <label for="qr-patient-name">Patient Name</label>
-	      <input type="radio" name="qr-field" id="qr-accession-number" value="AccessionNumber" />
-	      <label for="qr-accession-number">Accession Number</label>
-	      <input type="radio" name="qr-field" id="qr-study-description" value="StudyDescription" />
-	      <label for="qr-study-description">Study Description</label>
-	    </fieldset>
-	  </div>
-
-          <div data-role="fieldcontain">
-	    <label for="qr-value">Value for this field:</label>
-	    <input type="text" name="qr-value" id="qr-value" value="*"  />
-	  </div>
-
-          <div data-role="fieldcontain">
-	    <label for="qr-date">Study date:</label>
-            <select name="qr-date" id="qr-date">
-            </select>
-	  </div>
-
-          <div data-role="fieldcontain" id="qr-modalities">
-            <div data-role="fieldcontain">
-	      <fieldset data-role="controlgroup" data-type="horizontal">
-                <legend>Modalities:</legend>
-	        <input type="checkbox" name="CR" id="qr-cr" class="custom" /> <label for="qr-cr">CR</label>
-	        <input type="checkbox" name="CT" id="qr-ct" class="custom" /> <label for="qr-ct">CT</label>
-	        <input type="checkbox" name="MR" id="qr-mr" class="custom" /> <label for="qr-mr">MR</label>
-	        <input type="checkbox" name="NM" id="qr-nm" class="custom" /> <label for="qr-nm">NM</label>
-	        <input type="checkbox" name="PT" id="qr-pt" class="custom" /> <label for="qr-pt">PT</label>
-	        <input type="checkbox" name="US" id="qr-us" class="custom" /> <label for="qr-us">US</label>
-	        <input type="checkbox" name="XA" id="qr-xa" class="custom" /> <label for="qr-xa">XA</label>
-	        <input type="checkbox" name="DR" id="qr-dr" class="custom" /> <label for="qr-dr">DR</label>
-	        <input type="checkbox" name="DX" id="qr-dx" class="custom" /> <label for="qr-dx">DX</label>
-	      </fieldset>
-            </div>
-          </div>
-
-          <fieldset class="ui-grid-a">
-	    <div class="ui-block-a">
-              <button id="qr-echo" data-theme="a">Test Echo</button>
-            </div>
-	    <div class="ui-block-b">
-              <button id="qr-submit" type="submit" data-theme="b">Search studies</button>
-            </div>
-	  </fieldset>
-        </form>
-      </div>
-    </div>
-
-
-    <div data-role="page" id="query-retrieve-2" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (2/4)</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+    <div data-role="content">
+      <form data-ajax="false" id="retrieve-form">
+        <div data-role="fieldcontain">
+          <label for="retrieve-target">Target AET:</label>
+          <input type="text" name="retrieve-target" id="retrieve-target"></input>
         </div>
-        <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
-      </div>
-      <div data-role="content">
-        <ul data-role="listview" data-inset="true" data-filter="true" data-split-icon="arrow-d" data-split-theme="b">
-        </ul>
-      </div>
-    </div>
-
-
-    <div data-role="page" id="query-retrieve-3" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (3/4)</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-        <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
-      </div>
-      <div data-role="content">
-        <ul data-role="listview" data-inset="true" data-filter="true">
-        </ul>
-      </div>
-    </div>
-
-
-    <div data-role="page" id="query-retrieve-4" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (4/4)</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-        <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
-      </div>
-
-      <div data-role="content">
-        <form data-ajax="false" id="retrieve-form">
-          <div data-role="fieldcontain">
-	    <label for="retrieve-target">Target AET:</label>
-            <input type="text" name="retrieve-target" id="retrieve-target"></input>
-	  </div>
-
-          <fieldset class="ui-grid-b">
-	    <div class="ui-block-a"></div>
-	    <div class="ui-block-b">
-              <button id="retrieve-submit" type="submit" data-theme="b">Retrieve</button>
-            </div>
-	    <div class="ui-block-c"></div>
-	  </fieldset>
-        </form>
-      </div>
-    </div>
-
-    
-    <div data-role="page" id="jobs" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>Jobs</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-      </div>
-      <div data-role="content">
-        <ul id="all-jobs" data-role="listview" data-inset="true" data-filter="true">
-        </ul>
-      </div>
-    </div>
-
-    <div data-role="page" id="job" >
-      <div data-role="header" >
-	<h1><span class="orthanc-name"></span>Job</h1>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
-          <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
-          <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
-        </div>
-        <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right"> 
-          <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
-        </div>
-      </div>
-      <div data-role="content">
-        <ul data-role="listview" data-inset="true" data-filter="true" id="job-info">
-        </ul>
 
         <fieldset class="ui-grid-b">
           <div class="ui-block-a"></div>
-	  <div class="ui-block-b">
-            <button id="job-cancel" data-theme="b">Cancel job</button>         
-            <button id="job-resubmit" data-theme="b">Resubmit job</button>         
-            <button id="job-pause" data-theme="b">Pause job</button>         
-            <button id="job-resume" data-theme="b">Resume job</button>         
+          <div class="ui-block-b">
+            <button id="retrieve-submit" type="submit" data-theme="b">Retrieve</button>
           </div>
           <div class="ui-block-c"></div>
-	</fieldset>
+        </fieldset>
+      </form>
+    </div>
+  </div>
+
+
+  <div data-role="page" id="jobs">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>Jobs</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+      </div>
+    </div>
+    <div data-role="content">
+      <ul id="all-jobs" data-role="listview" data-inset="true" data-filter="true">
+      </ul>
+    </div>
+  </div>
+
+  <div data-role="page" id="job">
+    <div data-role="header">
+      <h1><span class="orthanc-name"></span>Job</h1>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-left">
+        <a href="#lookup" data-icon="arrow-r" data-role="button" data-direction="reverse">Lookup</a>
+        <a href="#plugins" data-icon="grid" data-role="button" data-direction="reverse">Plugins</a>
+      </div>
+      <div data-type="horizontal" data-role="controlgroup" class="ui-btn-right">
+        <a href="#jobs" data-icon="refresh" data-role="button" data-direction="reverse">Jobs</a>
       </div>
     </div>
+    <div data-role="content">
+      <ul data-role="listview" data-inset="true" data-filter="true" id="job-info">
+      </ul>
 
-    <div id="peer-store" style="display:none;" class="ui-body-c">
-      <p align="center"><b>Sending to Orthanc peer...</b></p>
-      <p><img src="libs/images/ajax-loader.gif" alt="" /></p>
-    </div>
-
-    <div id="dicom-store" style="display:none;" class="ui-body-c">
-      <p align="center"><b>Sending to DICOM modality...</b></p>
-      <p><img src="libs/images/ajax-loader.gif" alt="" /></p>
+      <fieldset class="ui-grid-b">
+        <div class="ui-block-a"></div>
+        <div class="ui-block-b">
+          <button id="job-cancel" data-theme="b">Cancel job</button>
+          <button id="job-resubmit" data-theme="b">Resubmit job</button>
+          <button id="job-pause" data-theme="b">Pause job</button>
+          <button id="job-resume" data-theme="b">Resume job</button>
+        </div>
+        <div class="ui-block-c"></div>
+      </fieldset>
     </div>
+  </div>
 
-    <div id="info-retrieve" style="display:none;" class="ui-body-c">
-      <p align="center"><b>Retrieving images from DICOM modality...</b></p>
-      <p><img src="libs/images/ajax-loader.gif" alt="" /></p>
-    </div>
+  <div id="peer-store" style="display:none;" class="ui-body-c">
+    <p align="center"><b>Sending to Orthanc peer...</b></p>
+    <p><img src="libs/images/ajax-loader.gif" alt="" /></p>
+  </div>
+
+  <div id="dicom-store" style="display:none;" class="ui-body-c">
+    <p align="center"><b>Sending to DICOM modality...</b></p>
+    <p><img src="libs/images/ajax-loader.gif" alt="" /></p>
+  </div>
 
-    <div id="dialog" style="display:none" >
-    </div>
-  </body>
+  <div id="info-retrieve" style="display:none;" class="ui-body-c">
+    <p align="center"><b>Retrieving images from DICOM modality...</b></p>
+    <p><img src="libs/images/ajax-loader.gif" alt="" /></p>
+  </div>
+
+  <div id="dialog" style="display:none">
+  </div>
+</body>
+
 </html>
--- a/OrthancExplorer/explorer.js	Thu Jan 10 18:03:04 2019 +0100
+++ b/OrthancExplorer/explorer.js	Fri Jan 11 11:01:55 2019 +0100
@@ -27,10 +27,12 @@
 
 function ChangePage(page, options)
 {
-  let first = true;
+  var first = true;
+  var value;
+
   if (options) {
-    for (let key in options) {
-      let value = options[key];
+    for (var key in options) {
+      value = options[key];
       if (first) {
         page += '?';
         first = false;
@@ -63,7 +65,7 @@
 
 
 $(document).ready(function() {
-  let $tree = $('#dicom-tree');
+  var $tree = $('#dicom-tree');
   $tree.tree({
     autoEscape: false
   });
@@ -124,7 +126,7 @@
   if (s == undefined)
     return "No date";
 
-  let d = ParseDicomDate(s);
+  var d = ParseDicomDate(s);
   if (d == null)
     return '?';
   else
@@ -134,16 +136,16 @@
 
 function Sort(arr, fieldExtractor, isInteger, reverse)
 {
-  let defaultValue;
+  var defaultValue;
   if (isInteger)
     defaultValue = 0;
   else
     defaultValue = '';
 
   arr.sort(function(a, b) {
-    let ta = fieldExtractor(a);
-    let tb = fieldExtractor(b);
-    let order;
+    var ta = fieldExtractor(a);
+    var tb = fieldExtractor(b);
+    var order;
 
     if (ta == undefined)
       ta = defaultValue;
@@ -226,11 +228,13 @@
 
 function FormatMainDicomTags(target, tags, tagsToIgnore)
 {
-  for (let i in tags)
+  var v;
+  
+  for (var i in tags)
   {
     if (tagsToIgnore.indexOf(i) == -1)
     {
-      let v = tags[i];
+      v = tags[i];
 
       if (i == "PatientBirthDate" ||
           i == "StudyDate" ||
@@ -254,7 +258,7 @@
 
 function FormatPatient(patient, link, isReverse)
 {
-  let node = $('<div>').append($('<h3>').text(patient.MainDicomTags.PatientName));
+  var node = $('<div>').append($('<h3>').text(patient.MainDicomTags.PatientName));
 
   FormatMainDicomTags(node, patient.MainDicomTags, [ 
     "PatientName"
@@ -268,7 +272,8 @@
 
 function FormatStudy(study, link, isReverse, includePatient)
 {
-  let label;
+  var label;
+  var node;
 
   if (includePatient) {
     label = study.Label;
@@ -276,7 +281,7 @@
     label = study.MainDicomTags.StudyDescription;
   }
 
-  let node = $('<div>').append($('<h3>').text(label));
+  node = $('<div>').append($('<h3>').text(label));
 
   if (includePatient) {
     FormatMainDicomTags(node, study.PatientMainDicomTags, [ 
@@ -296,7 +301,9 @@
 
 function FormatSeries(series, link, isReverse)
 {
-  let c;
+  var c;
+  var node;
+
   if (series.ExpectedNumberOfInstances == null ||
       series.Instances.length == series.ExpectedNumberOfInstances)
   {
@@ -307,7 +314,7 @@
     c = series.Instances.length + '/' + series.ExpectedNumberOfInstances;
   }
   
-  let node = $('<div>')
+  node = $('<div>')
       .append($('<h3>').text(series.MainDicomTags.SeriesDescription))
       .append($('<p>').append($('<em>')
                            .text('Status: ')
@@ -328,7 +335,7 @@
 
 function FormatInstance(instance, link, isReverse)
 {
-  let node = $('<div>').append($('<h3>').text('Instance: ' + instance.IndexInSeries));
+  var node = $('<div>').append($('<h3>').text('Instance: ' + instance.IndexInSeries));
 
   FormatMainDicomTags(node, instance.MainDicomTags, [
     "AcquisitionNumber", 
@@ -364,7 +371,7 @@
 
 $('#lookup').live('pagebeforeshow', function() {
   // NB: "GenerateDicomDate()" is defined in "query-retrieve.js"
-  let target = $('#lookup-study-date');
+  var target = $('#lookup-study-date');
   $('option', target).remove();
   target.append($('<option>').attr('value', '*').text('Any date'));
   target.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today'));
@@ -380,9 +387,11 @@
 
 
 $('#lookup-submit').live('click', function() {
+  var lookup;
+
   $('#lookup-result').hide();
 
-  let lookup = {
+  lookup = {
     'Level' : 'Study',
     'Expand' : true,
     'Limit' : LIMIT_RESOURCES + 1,
@@ -432,12 +441,14 @@
 
 $('#find-patients').live('pagebeforeshow', function() {
   GetResource('/patients?expand&since=0&limit=' + (LIMIT_RESOURCES + 1), function(patients) {
-    let target = $('#all-patients');
+    var target = $('#all-patients');
+    var count, showAlert, p;
+
+
     $('li', target).remove();
     
     SortOnDicomTag(patients, 'PatientName', false, false);
 
-    let count, showAlert;
     if (patients.length <= LIMIT_RESOURCES) {
       count = patients.length;
       showAlert = false;
@@ -447,8 +458,8 @@
       showAlert = true;
     }
 
-    for (let i = 0; i < count; i++) {
-      let p = FormatPatient(patients[i], '#patient?uuid=' + patients[i].ID);
+    for (var i = 0; i < count; i++) {
+      p = FormatPatient(patients[i], '#patient?uuid=' + patients[i].ID);
       target.append(p);
     }
 
@@ -467,14 +478,17 @@
 
 function FormatListOfStudies(targetId, alertId, countId, studies)
 {
-  let target = $(targetId);
+  var target = $(targetId);
+  var patient, study, s;
+  var count, showAlert;
+
   $('li', target).remove();
 
-  for (let i = 0; i < studies.length; i++) {
-    let patient = studies[i].PatientMainDicomTags.PatientName;
-    let study = studies[i].MainDicomTags.StudyDescription;
+  for (var i = 0; i < studies.length; i++) {
+    patient = studies[i].PatientMainDicomTags.PatientName;
+    study = studies[i].MainDicomTags.StudyDescription;
 
-    let s;
+    s = "";
     if (typeof patient === 'string') {
       s = patient;
     }
@@ -492,8 +506,6 @@
 
   Sort(studies, function(a) { return a.Label }, false, false);
 
-
-  let count, showAlert;
   if (studies.length <= LIMIT_RESOURCES) {
     count = studies.length;
     showAlert = false;
@@ -503,9 +515,9 @@
     showAlert = true;
   }
 
-  for (let i = 0; i < count; i++) {
-    let p = FormatStudy(studies[i], '#study?uuid=' + studies[i].ID, false, true);
-    target.append(p);
+  for (var i = 0; i < count; i++) {
+    s = FormatStudy(studies[i], '#study?uuid=' + studies[i].ID, false, true);
+    target.append(s);
   }
 
   target.listview('refresh');
@@ -546,8 +558,10 @@
 
 function RefreshPatient()
 {
+  var pageData, target, v;
+
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
     GetResource('/patients/' + pageData.uuid, function(patient) {
       GetResource('/patients/' + pageData.uuid + '/studies', function(studies) {
@@ -559,10 +573,10 @@
           .append(FormatPatient(patient))
           .listview('refresh');
 
-        let target = $('#list-studies');
+        target = $('#list-studies');
         $('li', target).remove();
         
-        for (let i = 0; i < studies.length; i++) {
+        for (var i = 0; i < studies.length; i++) {
           if (i == 0 || studies[i].MainDicomTags.StudyDate != studies[i - 1].MainDicomTags.StudyDate)
           {
             target.append($('<li>')
@@ -586,7 +600,7 @@
           async: false,
           cache: false,
           success: function (s) {
-            let v = (s == '1') ? 'on' : 'off';
+            v = (s == '1') ? 'on' : 'off';
             $('#protection').val(v).slider('refresh');
           }
         });
@@ -601,8 +615,10 @@
 
 function RefreshStudy()
 {
+  var pageData, target;
+
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
     GetResource('/studies/' + pageData.uuid, function(study) {
       GetResource('/patients/' + study.ParentPatient, function(patient) {
@@ -621,9 +637,9 @@
           SetupAnonymizedOrModifiedFrom('#study-anonymized-from', study, 'study', 'AnonymizedFrom');
           SetupAnonymizedOrModifiedFrom('#study-modified-from', study, 'study', 'ModifiedFrom');
 
-          let target = $('#list-series');
+          target = $('#list-series');
           $('li', target).remove();
-          for (let i = 0; i < series.length; i++) {
+          for (var i = 0; i < series.length; i++) {
             if (i == 0 || series[i].MainDicomTags.SeriesDate != series[i - 1].MainDicomTags.SeriesDate)
             {
               target.append($('<li>')
@@ -646,8 +662,10 @@
 
 function RefreshSeries() 
 {
+  var pageData, target;
+
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
     GetResource('/series/' + pageData.uuid, function(series) {
       GetResource('/studies/' + series.ParentStudy, function(study) {
@@ -671,9 +689,9 @@
             SetupAnonymizedOrModifiedFrom('#series-anonymized-from', series, 'series', 'AnonymizedFrom');
             SetupAnonymizedOrModifiedFrom('#series-modified-from', series, 'series', 'ModifiedFrom');
 
-            let target = $('#list-instances');
+            target = $('#list-instances');
             $('li', target).remove();
-            for (let i = 0; i < instances.length; i++) {
+            for (var i = 0; i < instances.length; i++) {
               target.append(FormatInstance(instances[i], '#instance?uuid=' + instances[i].ID));
             }
             target.listview('refresh');
@@ -690,7 +708,7 @@
 
 function EscapeHtml(value)
 {
-  let ENTITY_MAP = {
+  var ENTITY_MAP = {
     '&': '&amp;',
     '<': '&lt;',
     '>': '&gt;',
@@ -709,11 +727,12 @@
 
 function ConvertForTree(dicom)
 {
-  let result = [];
+  var result = [];
+  var label, c;
 
-  for (let i in dicom) {
+  for (var i in dicom) {
     if (dicom[i] != null) {
-      let label = (i + '<span class="tag-name"> (<i>' +
+      label = (i + '<span class="tag-name"> (<i>' +
                    EscapeHtml(dicom[i]["Name"]) +
                    '</i>)</span>: ');
 
@@ -740,8 +759,8 @@
       }
       else if (dicom[i]["Type"] == 'Sequence')
       {
-        let c = [];
-        for (let j = 0; j < dicom[i]["Value"].length; j++) {
+        c = [];
+        for (var j = 0; j < dicom[i]["Value"].length; j++) {
           c.push({
             label: 'Item ' + j,
             children: ConvertForTree(dicom[i]["Value"][j])
@@ -762,8 +781,10 @@
 
 function RefreshInstance()
 {
+  var pageData;
+
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
     GetResource('/instances/' + pageData.uuid, function(instance) {
       GetResource('/series/' + instance.ParentSeries, function(series) {
@@ -837,7 +858,7 @@
     dataType: 'json',
     async: false,
     success: function(s) {
-      let ancestor = s.RemainingAncestor;
+      var ancestor = s.RemainingAncestor;
       if (ancestor == null)
         $.mobile.changePage('#lookup');
       else
@@ -912,10 +933,12 @@
 
 
 $('#instance-preview').live('click', function(e) {
+  var pageData, pdf, images;
+
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
-    let pdf = '../instances/' + pageData.uuid + '/pdf';
+    pdf = '../instances/' + pageData.uuid + '/pdf';
     $.ajax({
       url: pdf,
       cache: false,
@@ -937,8 +960,8 @@
           {
             // Viewing a multi-frame image
 
-            let images = [];
-            for (let i = 0; i < frames.length; i++) {
+            images = [];
+            for (var i = 0; i < frames.length; i++) {
               images.push([ '../instances/' + pageData.uuid + '/frames/' + i + '/preview' ]);
             }
 
@@ -958,15 +981,17 @@
 
 
 $('#series-preview').live('click', function(e) {
+  var pageData, images;
+
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
     GetResource('/series/' + pageData.uuid, function(series) {
       GetResource('/series/' + pageData.uuid + '/instances', function(instances) {
         Sort(instances, function(x) { return x.IndexInSeries; }, true, false);
 
-        let images = [];
-        for (let i = 0; i < instances.length; i++) {
+        images = [];
+        for (var i = 0; i < instances.length; i++) {
           images.push([ '../instances/' + instances[i].ID + '/preview',
                         (i + 1).toString() + '/' + instances.length.toString() ])
         }
@@ -988,9 +1013,9 @@
 
 function ChooseDicomModality(callback)
 {
-  let clickedModality = '';
-  let clickedPeer = '';
-  let items = $('<ul>')
+  var clickedModality = '';
+  var clickedPeer = '';
+  var items = $('<ul>')
     .attr('data-divider-theme', 'd')
     .attr('data-role', 'listview');
 
@@ -1002,13 +1027,15 @@
     async: false,
     cache: false,
     success: function(modalities) {
+      var name, item;
+      
       if (modalities.length > 0)
       {
         items.append('<li data-role="list-divider">DICOM modalities</li>');
 
-        for (let i = 0; i < modalities.length; i++) {
-          let name = modalities[i];
-          let item = $('<li>')
+        for (var i = 0; i < modalities.length; i++) {
+          name = modalities[i];
+          item = $('<li>')
             .html('<a href="#" rel="close">' + name + '</a>')
             .attr('name', name)
             .click(function() { 
@@ -1026,13 +1053,15 @@
         async: false,
         cache: false,
         success: function(peers) {
+          var name, item;
+
           if (peers.length > 0)
           {
             items.append('<li data-role="list-divider">Orthanc peers</li>');
 
-            for (let i = 0; i < peers.length; i++) {
-              let name = peers[i];
-              let item = $('<li>')
+            for (var i = 0; i < peers.length; i++) {
+              name = peers[i];
+              item = $('<li>')
                 .html('<a href="#" rel="close">' + name + '</a>')
                 .attr('name', name)
                 .click(function() { 
@@ -1052,7 +1081,7 @@
             width: '100%',
             blankContent: items,
             callbackClose: function() {
-              let timer;
+              var timer;
               function WaitForDialogToClose() {
                 if (!$('#dialog').is(':visible')) {
                   clearInterval(timer);
@@ -1071,10 +1100,8 @@
 
 $('#instance-store,#series-store,#study-store,#patient-store').live('click', function(e) {
   ChooseDicomModality(function(modality, peer) {
-    let pageData = DeepCopy($.mobile.pageData);
-
-    let url;
-    let loading;
+    var pageData = DeepCopy($.mobile.pageData);
+    var url, loading;
 
     if (modality != '')
     {
@@ -1113,7 +1140,7 @@
 
 
 $('#show-tag-name').live('change', function(e) {
-  let checked = e.currentTarget.checked;
+  var checked = e.currentTarget.checked;
   if (checked)
     $('.tag-name').show();
   else
@@ -1155,7 +1182,7 @@
 
 
 $('#protection').live('change', function(e) {
-  let isProtected = e.target.value == "on";
+  var isProtected = e.target.value == "on";
   $.ajax({
     url: '../patients/' + $.mobile.pageData.uuid + '/protected',
     type: 'PUT',
@@ -1233,7 +1260,7 @@
     async: false,
     cache: false,
     success: function(plugins) {
-      let target = $('#all-plugins');
+      var target = $('#all-plugins');
       $('li', target).remove();
 
       plugins.map(function(id) {
@@ -1243,8 +1270,8 @@
           async: false,
           cache: false,
           success: function(plugin) {
-            let li = $('<li>');
-            let item = li;
+            var li = $('<li>');
+            var item = li;
 
             if ('RootUri' in plugin)
             {
@@ -1272,12 +1299,12 @@
 
 function ParseJobTime(s)
 {
-  let t = (s.substr(0, 4) + '-' +
+  var t = (s.substr(0, 4) + '-' +
            s.substr(4, 2) + '-' +
            s.substr(6, 5) + ':' +
            s.substr(11, 2) + ':' +
            s.substr(13));
-  let utc = new Date(t);
+  var utc = new Date(t);
 
   // Convert from UTC to local time
   return new Date(utc.getTime() - utc.getTimezoneOffset() * 60000);
@@ -1311,18 +1338,20 @@
     async: false,
     cache: false,
     success: function(jobs) {
-      let target = $('#all-jobs');
+      var target = $('#all-jobs');
+      var running, pending, inactive;
+
       $('li', target).remove();
 
-      let running = $('<li>')
+      running = $('<li>')
           .attr('data-role', 'list-divider')
           .text('Currently running');
 
-      let pending = $('<li>')
+      pending = $('<li>')
           .attr('data-role', 'list-divider')
           .text('Pending jobs');
 
-      let inactive = $('<li>')
+      inactive = $('<li>')
           .attr('data-role', 'list-divider')
           .text('Inactive jobs');
 
@@ -1331,8 +1360,9 @@
       target.append(inactive);
 
       jobs.map(function(job) {
-        let li = $('<li>');
-        let item = $('<a>');
+        var li = $('<li>');
+        var item = $('<a>');
+        
         li.append(item);
         item.attr('href', '#job?uuid=' + job.ID);
         item.append($('<h1>').text(job.Type));
@@ -1368,8 +1398,10 @@
 
 
 $('#job').live('pagebeforeshow', function() {
+  var pageData, target;
+
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
     $.ajax({
       url: '../jobs/' + pageData.uuid,
@@ -1377,7 +1409,9 @@
       async: false,
       cache: false,
       success: function(job) {
-        let target = $('#job-info');
+        var block, value;
+        
+        target = $('#job-info');
         $('li', target).remove();
 
         target.append($('<li>')
@@ -1385,8 +1419,8 @@
                       .text('General information about the job'));
 
         {                       
-          let block = $('<li>');
-          for (let i in job) {
+          block = $('<li>');
+          for (var i in job) {
             if (i == 'CreationTime' ||
                 i == 'CompletionTime' ||
                 i == 'EstimatedTimeOfArrival') {
@@ -1406,10 +1440,10 @@
                       .text('Detailed information'));
 
         {
-          let block = $('<li>');
+          block = $('<li>');
 
-          for (let item in job.Content) {
-            let value = job.Content[item];
+          for (var item in job.Content) {
+            var value = job.Content[item];
             if (typeof value !== 'string') {
               value = JSON.stringify(value);
             }
--- a/OrthancExplorer/file-upload.js	Thu Jan 10 18:03:04 2019 +0100
+++ b/OrthancExplorer/file-upload.js	Fri Jan 11 11:01:55 2019 +0100
@@ -27,16 +27,13 @@
       $('#progress .label').text('Failure');
     })
     .bind('fileuploaddrop', function (e, data) {
-      let target = $('#upload-list');
-      $.each(data.files, function (index, file) {
-        target.append('<li class="pending-file">' + file.name + '</li>');
-      });
-      target.listview('refresh');
+      console.log("dropped " + data.files.length + " files");
+      appendFilesToUploadList(data.files);
     })
     .bind('fileuploadsend', function (e, data) {
       // Update the progress bar. Note: for some weird reason, the
       // "fileuploadprogressall" does not work under Firefox.
-      let progress = parseInt(currentUpload / totalUploads * 100, 10);
+      var progress = parseInt(currentUpload / totalUploads * 100, 10);
       currentUpload += 1;
       $('#progress .label').text('Uploading: ' + progress + '%');
       $('#progress .bar')
@@ -45,14 +42,34 @@
     });
 });
 
+function appendFilesToUploadList(files) {
+  var target = $('#upload-list');
+  $.each(files, function (index, file) {
+    target.append('<li class="pending-file">' + file.name + '</li>');
+  });
+  target.listview('refresh');
+}
 
+$('#fileupload').live('change', function (e) {
+  appendFilesToUploadList(e.target.files);
+})
+
+
+function ClearUploadProgress()
+{
+  $('#progress .label').text('');
+  $('#progress .bar').css('width', '0%').css('background-color', '#333');
+}
+
+$('#upload').live('pagebeforeshow', function() {
+  if (navigator.userAgent.toLowerCase().indexOf('firefox') == -1) {
+    $("#issue-21-warning").css('display', 'none');
+  }
+
+  ClearUploadProgress();
+});
 
 $('#upload').live('pageshow', function() {
-  alert('WARNING - This page is currently affected by Orthanc issue #21: ' +
-        '"DICOM files might be missing after uploading with Mozilla Firefox." ' +
-        'Do not use this upload feature for clinical uses, or carefully ' +
-        'check that all instances have been properly received by Orthanc. ' +
-        'Please use the command-line "ImportDicomFiles.py" script to circumvent this issue.');
   $('#fileupload').fileupload('enable');
 });
 
@@ -62,13 +79,12 @@
 
 
 $('#upload-button').live('click', function() {
-  let pu = pendingUploads;
+  var pu = pendingUploads;
   pendingUploads = [];
 
   $('.pending-file').remove();
   $('#upload-list').listview('refresh');
-  $('#progress .bar').css('width', '0%');
-  $('#progress .label').text('');
+  ClearUploadProgress();
 
   currentUpload = 1;
   totalUploads = pu.length + 1;
@@ -77,7 +93,7 @@
     //$('#upload-abort').removeClass('ui-disabled');
   }
 
-  for (let i = 0; i < pu.length; i++) {
+  for (var i = 0; i < pu.length; i++) {
     pu[i].submit();
   }
 });
--- a/OrthancExplorer/query-retrieve.js	Thu Jan 10 18:03:04 2019 +0100
+++ b/OrthancExplorer/query-retrieve.js	Fri Jan 11 11:01:55 2019 +0100
@@ -1,53 +1,57 @@
 function JavascriptDateToDicom(date)
 {
-  let s = date.toISOString();
+  var s = date.toISOString();
   return s.substring(0, 4) + s.substring(5, 7) + s.substring(8, 10);
 }
 
 function GenerateDicomDate(days)
 {
-  let today = new Date();
-  let other = new Date(today);
+  var today = new Date();
+  var other = new Date(today);
   other.setDate(today.getDate() + days);
   return JavascriptDateToDicom(other);
 }
 
 
 $('#query-retrieve').live('pagebeforeshow', function() {
+  var targetDate;
+
   $.ajax({
     url: '../modalities',
     dataType: 'json',
     async: false,
     cache: false,
     success: function(modalities) {
-      let target = $('#qr-server');
-      $('option', target).remove();
+      var targetServer = $('#qr-server');
+      var option;
 
-      for (let i = 0; i < modalities.length; i++) {
-        let option = $('<option>').text(modalities[i]);
-        target.append(option);
+      $('option', targetServer).remove();
+
+      for (var i = 0; i < modalities.length; i++) {
+        option = $('<option>').text(modalities[i]);
+        targetServer.append(option);
       }
 
-      target.selectmenu('refresh');
+      targetServer.selectmenu('refresh');
     }
   });
 
-  let target = $('#qr-date');
-  $('option', target).remove();
-  target.append($('<option>').attr('value', '*').text('Any date'));
-  target.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year'));
-  target.selectmenu('refresh');
+  targetDate = $('#qr-date');
+  $('option', targetDate).remove();
+  targetDate.append($('<option>').attr('value', '*').text('Any date'));
+  targetDate.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today'));
+  targetDate.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday'));
+  targetDate.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days'));
+  targetDate.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days'));
+  targetDate.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months'));
+  targetDate.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year'));
+  targetDate.selectmenu('refresh');
 });
 
 
 $('#qr-echo').live('click', function() {
-  let server = $('#qr-server').val();
-  let message = 'Error: The C-Echo has failed!';
+  var server = $('#qr-server').val();
+  var message = 'Error: The C-Echo has failed!';
 
   $.ajax({
     url: '../modalities/' + server + '/echo',
@@ -75,7 +79,9 @@
 
 
 $('#qr-submit').live('click', function() {
-  let query = {
+  var query, server, modalities, field;
+
+  query = {
     'Level' : 'Study',
     'Query' : {
       'AccessionNumber' : '*',
@@ -88,12 +94,13 @@
     }
   };
 
-  let field = $('#qr-fields input:checked').val();
+  modalities = '';
+
+  field = $('#qr-fields input:checked').val();
   query['Query'][field] = $('#qr-value').val().toUpperCase();
 
-  let modalities = '';
   $('#qr-modalities input:checked').each(function() {
-    let s = $(this).attr('name');
+    var s = $(this).attr('name');
     if (modalities == '')
       modalities = s;
     else
@@ -105,7 +112,7 @@
   }
 
 
-  let server = $('#qr-server').val();
+  server = $('#qr-server').val();
   $.ajax({
     url: '../modalities/' + server + '/query',
     type: 'POST', 
@@ -129,28 +136,30 @@
 
 
 $('#query-retrieve-2').live('pagebeforeshow', function() {
+  var pageData, uri;
+  
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
-    let uri = '../queries/' + pageData.uuid + '/answers';
+    uri = '../queries/' + pageData.uuid + '/answers';
 
     $.ajax({
       url: uri,
       dataType: 'json',
       async: false,
       success: function(answers) {
-        let target = $('#query-retrieve-2 ul');
+        var target = $('#query-retrieve-2 ul');
         $('li', target).remove();
 
-        for (let i = 0; i < answers.length; i++) {
+        for (var i = 0; i < answers.length; i++) {
           $.ajax({
             url: uri + '/' + answers[i] + '/content?simplify',
             dataType: 'json',
             async: false,
             success: function(study) {
-              let series = '#query-retrieve-3?server=' + pageData.server + '&uuid=' + study['StudyInstanceUID'];
+              var series = '#query-retrieve-3?server=' + pageData.server + '&uuid=' + study['StudyInstanceUID'];
 
-              let content = ($('<div>')
+              var content = ($('<div>')
                              .append($('<h3>').text(study['PatientID'] + ' - ' + study['PatientName']))
                              .append($('<p>').text('Accession number: ')
                                      .append($('<b>').text(study['AccessionNumber'])))
@@ -163,10 +172,10 @@
                              .append($('<p>').text('Study date: ')
                                      .append($('<b>').text(FormatDicomDate(study['StudyDate'])))));
 
-              let info = $('<a>').attr('href', series).html(content);
+              var info = $('<a>').attr('href', series).html(content);
               
-              let answerId = answers[i];
-              let retrieve = $('<a>').text('Retrieve all study').click(function() {
+              var answerId = answers[i];
+              var retrieve = $('<a>').text('Retrieve all study').click(function() {
                 ChangePage('query-retrieve-4', {
                   'query' : pageData.uuid,
                   'answer' : answerId,
@@ -187,10 +196,12 @@
 
 
 $('#query-retrieve-3').live('pagebeforeshow', function() {
+  var pageData, query;
+
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
+    pageData = DeepCopy($.mobile.pageData);
 
-    let query = {
+    query = {
       'Level' : 'Series',
       'Query' : {
         'Modality' : '*',
@@ -211,8 +222,8 @@
         alert('Error during query (C-Find)');
       },
       success: function(answer) {
-        let queryUuid = answer['ID'];
-        let uri = '../queries/' + answer['ID'] + '/answers';
+        var queryUuid = answer['ID'];
+        var uri = '../queries/' + answer['ID'] + '/answers';
 
         $.ajax({
           url: uri,
@@ -220,25 +231,25 @@
           async: false,
           success: function(answers) {
             
-            let target = $('#query-retrieve-3 ul');
+            var target = $('#query-retrieve-3 ul');
             $('li', target).remove();
 
-            for (let i = 0; i < answers.length; i++) {
+            for (var i = 0; i < answers.length; i++) {
               $.ajax({
                 url: uri + '/' + answers[i] + '/content?simplify',
                 dataType: 'json',
                 async: false,
                 success: function(series) {
-                  let content = ($('<div>')
+                  var content = ($('<div>')
                                  .append($('<h3>').text(series['SeriesDescription']))
                                  .append($('<p>').text('Modality: ')
                                          .append($('<b>').text(series['Modality'])))
                                  .append($('<p>').text('ProtocolName: ')
                                          .append($('<b>').text(series['ProtocolName']))));
 
-                  let info = $('<a>').html(content);
+                  var info = $('<a>').html(content);
 
-                  let answerId = answers[i];
+                  var answerId = answers[i];
                   info.click(function() {
                     ChangePage('query-retrieve-4', {
                       'query' : queryUuid,
@@ -264,9 +275,11 @@
 
 
 $('#query-retrieve-4').live('pagebeforeshow', function() {
+  var pageData, uri;
+  
   if ($.mobile.pageData) {
-    let pageData = DeepCopy($.mobile.pageData);
-    let uri = '../queries/' + pageData.query + '/answers/' + pageData.answer + '/retrieve';
+    var pageData = DeepCopy($.mobile.pageData);
+    var uri = '../queries/' + pageData.query + '/answers/' + pageData.answer + '/retrieve';
 
     $.ajax({
       url: '../system',
@@ -277,9 +290,11 @@
         $('#retrieve-target').val(system['DicomAet']);
 
         $('#retrieve-form').submit(function(event) {
+          var aet;
+
           event.preventDefault();
 
-          let aet = $('#retrieve-target').val();
+          aet = $('#retrieve-target').val();
           if (aet.length == 0) {
             aet = system['DicomAet'];
           }