From 94b1246a3431d62a72d8ec00d6d1b75da432ebb9 Mon Sep 17 00:00:00 2001
From: Vincent Bechu <vincent.bechu@nexedi.com>
Date: Thu, 3 Aug 2017 13:42:18 +0000
Subject: [PATCH] [erp5_officejs] Bootloader retry and inform on error

---
 .../gadget_officejs_bootloader.html.html      |   4 +-
 .../gadget_officejs_bootloader.html.xml       |   4 +-
 .../gadget_officejs_bootloader_appcache.xml   | 352 ------------------
 .../gadget_officejs_bootloader_js.js          | 264 ++++++-------
 .../gadget_officejs_bootloader_js.xml         |   4 +-
 ...get_officejs_bootloader_presentation_js.js |  29 +-
 ...et_officejs_bootloader_presentation_js.xml |   4 +-
 ...et_officejs_bootloader_serviceworker_js.js |  21 +-
 ...t_officejs_bootloader_serviceworker_js.xml |   4 +-
 .../gadget_officejs_jio_appcachestorage_js.js | 152 +++++---
 ...gadget_officejs_jio_appcachestorage_js.xml |   4 +-
 11 files changed, 235 insertions(+), 607 deletions(-)
 delete mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_appcache.xml

diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader.html.html
index 132b8d2a24..3b10983b60 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader.html.html
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader.html.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html manifest="gadget_officejs_bootloader.appcache">
+<html>
   <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -21,7 +21,5 @@
     <script data-install-configuration="redirect_url" type="text/x-renderjs-configuration">${redirect_url}/</script>
     <script data-install-configuration="cache_file" type="text/x-renderjs-configuration">${cache_file}</script>
     <script data-install-configuration="app_name" type="text/x-renderjs-configuration">${application_name}</script>
-    <script data-install-configuration="landing_page" type="text/x-renderjs-configuration">${landing_page}</script>
-    <script data-install-configuration="sub_app_installer" type="text/x-renderjs-configuration">${sub_gadget_installer}</script>
   </body>
 </html>
\ No newline at end of file
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader.html.xml
index d73b1462af..d4ac5be8f0 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader.html.xml
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader.html.xml
@@ -241,7 +241,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>959.27737.62903.2116</string> </value>
+                <value> <string>961.282.28573.14114</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -259,7 +259,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1496242886.73</float>
+                        <float>1501754635.21</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_appcache.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_appcache.xml
deleted file mode 100644
index 744c356f2d..0000000000
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_appcache.xml
+++ /dev/null
@@ -1,352 +0,0 @@
-<?xml version="1.0"?>
-<ZopeData>
-  <record id="1" aka="AAAAAAAAAAE=">
-    <pickle>
-      <global name="Web Manifest" module="erp5.portal_type"/>
-    </pickle>
-    <pickle>
-      <dictionary>
-        <item>
-            <key> <string>_Access_contents_information_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Anonymous</string>
-                <string>Assignee</string>
-                <string>Assignor</string>
-                <string>Associate</string>
-                <string>Auditor</string>
-                <string>Manager</string>
-                <string>Owner</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>_Add_portal_content_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Assignor</string>
-                <string>Manager</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>_Change_local_roles_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Assignor</string>
-                <string>Manager</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>_Modify_portal_content_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Manager</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>_View_Permission</string> </key>
-            <value>
-              <tuple>
-                <string>Anonymous</string>
-                <string>Assignee</string>
-                <string>Assignor</string>
-                <string>Associate</string>
-                <string>Auditor</string>
-                <string>Manager</string>
-                <string>Owner</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>categories</string> </key>
-            <value>
-              <tuple>
-                <string>contributor/person_module/1</string>
-              </tuple>
-            </value>
-        </item>
-        <item>
-            <key> <string>content_md5</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>default_reference</string> </key>
-            <value> <string>gadget_officejs_bootloader.appcache</string> </value>
-        </item>
-        <item>
-            <key> <string>description</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>id</string> </key>
-            <value> <string>gadget_officejs_bootloader_appcache</string> </value>
-        </item>
-        <item>
-            <key> <string>language</string> </key>
-            <value> <string>en</string> </value>
-        </item>
-        <item>
-            <key> <string>portal_type</string> </key>
-            <value> <string>Web Manifest</string> </value>
-        </item>
-        <item>
-            <key> <string>short_title</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>text_content</string> </key>
-            <value> <string>CACHE MANIFEST\n
-# generated on Wed, 26 Apr 2017 11:45:33 +0000\n
-# XXX + fonts\n
-# images/ajax-loader.gif\n
-CACHE:\n
-/\n
-development/jiodev.js\n
-development/rsvp.js\n
-development/renderjs.js\n
-gadget_erp5_nojqm.css\n
-gadget_officejs_bootloader.js\n
-gadget_officejs_bootloader_presentation.html\n
-gadget_officejs_bootloader_presentation.js\n
-gadget_officejs_bootloader_presentation.css\n
-gadget_officejs_bootloader_serviceworker.js\n
-jio_appcachestorage.js\n
-NETWORK:\n
-*</string> </value>
-        </item>
-        <item>
-            <key> <string>title</string> </key>
-            <value> <string>Gadget Bootloader AppCache</string> </value>
-        </item>
-        <item>
-            <key> <string>url_string</string> </key>
-            <value>
-              <none/>
-            </value>
-        </item>
-        <item>
-            <key> <string>version</string> </key>
-            <value> <string>001</string> </value>
-        </item>
-        <item>
-            <key> <string>workflow_history</string> </key>
-            <value>
-              <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
-            </value>
-        </item>
-      </dictionary>
-    </pickle>
-  </record>
-  <record id="2" aka="AAAAAAAAAAI=">
-    <pickle>
-      <global name="PersistentMapping" module="Persistence.mapping"/>
-    </pickle>
-    <pickle>
-      <dictionary>
-        <item>
-            <key> <string>data</string> </key>
-            <value>
-              <dictionary>
-                <item>
-                    <key> <string>document_publication_workflow</string> </key>
-                    <value>
-                      <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
-                    </value>
-                </item>
-                <item>
-                    <key> <string>edit_workflow</string> </key>
-                    <value>
-                      <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
-                    </value>
-                </item>
-                <item>
-                    <key> <string>processing_status_workflow</string> </key>
-                    <value>
-                      <persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
-                    </value>
-                </item>
-              </dictionary>
-            </value>
-        </item>
-      </dictionary>
-    </pickle>
-  </record>
-  <record id="3" aka="AAAAAAAAAAM=">
-    <pickle>
-      <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
-    </pickle>
-    <pickle>
-      <tuple>
-        <none/>
-        <list>
-          <dictionary>
-            <item>
-                <key> <string>action</string> </key>
-                <value> <string>publish</string> </value>
-            </item>
-            <item>
-                <key> <string>actor</string> </key>
-                <value> <string>zope</string> </value>
-            </item>
-            <item>
-                <key> <string>comment</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>error_message</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>time</string> </key>
-                <value>
-                  <object>
-                    <klass>
-                      <global name="DateTime" module="DateTime.DateTime"/>
-                    </klass>
-                    <tuple>
-                      <none/>
-                    </tuple>
-                    <state>
-                      <tuple>
-                        <float>1493728283.88</float>
-                        <string>UTC</string>
-                      </tuple>
-                    </state>
-                  </object>
-                </value>
-            </item>
-            <item>
-                <key> <string>validation_state</string> </key>
-                <value> <string>published</string> </value>
-            </item>
-          </dictionary>
-        </list>
-      </tuple>
-    </pickle>
-  </record>
-  <record id="4" aka="AAAAAAAAAAQ=">
-    <pickle>
-      <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
-    </pickle>
-    <pickle>
-      <tuple>
-        <none/>
-        <list>
-          <dictionary>
-            <item>
-                <key> <string>action</string> </key>
-                <value> <string>edit</string> </value>
-            </item>
-            <item>
-                <key> <string>actor</string> </key>
-                <value> <string>zope</string> </value>
-            </item>
-            <item>
-                <key> <string>comment</string> </key>
-                <value>
-                  <none/>
-                </value>
-            </item>
-            <item>
-                <key> <string>error_message</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>serial</string> </key>
-                <value> <string>959.48233.9194.50227</string> </value>
-            </item>
-            <item>
-                <key> <string>state</string> </key>
-                <value> <string>current</string> </value>
-            </item>
-            <item>
-                <key> <string>time</string> </key>
-                <value>
-                  <object>
-                    <klass>
-                      <global name="DateTime" module="DateTime.DateTime"/>
-                    </klass>
-                    <tuple>
-                      <none/>
-                    </tuple>
-                    <state>
-                      <tuple>
-                        <float>1496245831.78</float>
-                        <string>UTC</string>
-                      </tuple>
-                    </state>
-                  </object>
-                </value>
-            </item>
-          </dictionary>
-        </list>
-      </tuple>
-    </pickle>
-  </record>
-  <record id="5" aka="AAAAAAAAAAU=">
-    <pickle>
-      <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
-    </pickle>
-    <pickle>
-      <tuple>
-        <none/>
-        <list>
-          <dictionary>
-            <item>
-                <key> <string>action</string> </key>
-                <value> <string>detect_converted_file</string> </value>
-            </item>
-            <item>
-                <key> <string>actor</string> </key>
-                <value> <string>zope</string> </value>
-            </item>
-            <item>
-                <key> <string>comment</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>error_message</string> </key>
-                <value> <string></string> </value>
-            </item>
-            <item>
-                <key> <string>external_processing_state</string> </key>
-                <value> <string>converted</string> </value>
-            </item>
-            <item>
-                <key> <string>serial</string> </key>
-                <value> <string>0.0.0.0</string> </value>
-            </item>
-            <item>
-                <key> <string>time</string> </key>
-                <value>
-                  <object>
-                    <klass>
-                      <global name="DateTime" module="DateTime.DateTime"/>
-                    </klass>
-                    <tuple>
-                      <none/>
-                    </tuple>
-                    <state>
-                      <tuple>
-                        <float>1493199934.66</float>
-                        <string>UTC</string>
-                      </tuple>
-                    </state>
-                  </object>
-                </value>
-            </item>
-          </dictionary>
-        </list>
-      </tuple>
-    </pickle>
-  </record>
-</ZopeData>
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_js.js
index 730e65f335..cae8c86247 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_js.js
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_js.js
@@ -1,32 +1,29 @@
-/*globals window, document, RSVP, rJS, navigator, jIO, MessageChannel, ProgressEvent, console*/
+/*globals window, document, RSVP, rJS, navigator, jIO, URL*/
 /*jslint indent: 2, maxlen: 80, nomen: true*/
 var repair = false;
-(function (window, document, RSVP, rJS, jIO, navigator, MessageChannel,
-  ProgressEvent, console) {
+(function (window, document, RSVP, rJS, jIO, navigator, URL) {
   "use strict";
 
-  var remote_storage = {
-    type: "erp5",
-    url: window.location.origin +
-      window.location.pathname + "hateoasnoauth",
-    default_view_reference: "jio_view"
-  };
-
-  function createStorage(version_url, manifest) {
+  function createStorage(gadget) {
     return jIO.createJIO({
       type: "replicate",
-      conflict_handling: 2,
       parallel_operation_attachment_amount: 10,
-      check_remote_attachment_modification: false,
+      parallel_operation_amount: 1,
+      conflict_handling: 2,
+      signature_hash_key: 'hash',
+      check_remote_attachment_modification: true,
       check_remote_attachment_creation: true,
-      check_remote_modification: false,
+      check_remote_attachment_deletion: false,
       check_remote_deletion: false,
       check_local_creation: false,
       check_local_deletion: false,
       check_local_modification: false,
-      signature_storage: {
-        type: "indexeddb",
-        database: window.location.pathname + version_url + "_hash"
+      signature_sub_storage: {
+        type: "query",
+        sub_storage: {
+          type: "indexeddb",
+          database: "officejs-hash"
+        }
       },
       local_sub_storage: {
         type: "query",
@@ -34,185 +31,140 @@ var repair = false;
           type: "uuid",
           sub_storage: {
             type: "indexeddb",
-            database: window.location.origin + window.location.pathname +
-              version_url
+            database: "ojs_source_code"
           }
         }
       },
       remote_sub_storage: {
         type: "appcache",
-        manifest: manifest,
-        version: version_url
+        manifest: gadget.state.cache_file,
+        version: gadget.state.version_url
       }
     });
   }
 
   rJS(window)
     .ready(function (gadget) {
-      var element_list =
-        gadget.element.querySelectorAll("[data-install-configuration]"),
-        i,
-        key,
-        value,
-        gadget_list = [];
-      gadget.props = {};
-      gadget.props.cached_url = [];
-      gadget.gadget_list = [];
-      gadget.props.query_list = [];
-
-      function pushGadget(url, i) {
-        var element = document.createElement("div");
-        element.setAttribute("style", "display: none");
-        gadget.element.appendChild(element);
-        return gadget.declareGadget(url,
-          {
-            "scope": "sub_app_installer_" + i,
-            "element": element,
-            "sandbox": "iframe"
-          })
-          .push(function (sub_gadget) {
-            gadget.gadget_list.push(sub_gadget);
-            return sub_gadget.setSubInstall();
-          });
-      }
+      var i,
+        state = {},
+        sub_gadget_list = [],
+        element_list =
+        gadget.element.querySelectorAll('[data-install-configuration]');
+      window.Bootloader = gadget;
 
       for (i = 0; i < element_list.length; i += 1) {
-        key = element_list[i].getAttribute('data-install-configuration');
-        value = element_list[i].textContent;
-        if (key === "sub_app_installer") {
-          if (value !== "") {
-            gadget_list = value.split('\n');
-          }
-        } else {
-          gadget.props[key] = value;
-        }
+        state[element_list[i].getAttribute('data-install-configuration')] =
+          element_list[i].textContent;
       }
-
-      return gadget.render()
-        .push(function () {
-          var promise_list = [];
-          for (i = 0; i < gadget_list.length; i += 1) {
-            promise_list.push(pushGadget(gadget_list[i], i + 1));
-          }
-          return RSVP.all(promise_list);
-        });
-    })
-
-    .declareMethod("render", function () {
-      var gadget = this,
-        element = document.createElement("div");
-      element.className = "presentation";
-      gadget.element.insertBefore(element, gadget.element.firstChild);
-      return gadget.declareGadget(
-        "gadget_officejs_bootloader_presentation.html",
-        {"scope": "presentation", "element": element}
-      )
-        .push(function (presentation_gadget) {
-          return presentation_gadget.render(
-            {"app_name": gadget.props.app_name}
-          );
-        });
+      state.redirect_url = new URL(window.location);
+      state.redirect_url.pathname += state.version_url;
+      return gadget.changeState(state);
     })
 
-    .declareMethod("setSubInstall", function () {
-      this.props.sub = true;
+    .allowPublicAcquisition('isChildren', function () {
+      return true;
     })
+    .declareAcquiredMethod('isChildren', 'isChildren')
 
-    .declareMethod("mainInstall", function () {
+    .declareService(function () {
       var gadget = this;
-
       return new RSVP.Queue()
         .push(function () {
-          if (gadget.props.document_version) {
-            return gadget.install();
-          }
+/* Workaround for renderjs issue,
+sub gadget does not have all aquired Method at this point*/
+          return RSVP.delay(500);
         })
         .push(function () {
-          var promise_list = [], i;
-          for (i = 0; i < gadget.gadget_list.length; i += 1) {
-            promise_list.push(gadget.gadget_list[i].waitInstall());
-          }
-          return RSVP.all(promise_list);
-        })
-        .push(function () {
-          gadget.props.is_installed = true;
-          if (gadget.installing !== undefined) {
-            gadget.installing.resolve();
-          }
-          if (!gadget.props.sub) {
-            window.location.pathname += gadget.props.version_url;
-          }
-          return;
+          return gadget.isChildren();
         })
         .push(undefined, function (error) {
-          if (error instanceof ProgressEvent) {
-            if (gadget.props.sub === undefined) {
-              window.location.pathname += gadget.props.version_url;
-            }
-            return;
+          if (error instanceof rJS.AcquisitionError) {
+            return RSVP.all([
+              new RSVP.Queue()
+                .push(function () {
+                  return RSVP.delay(600);
+                })
+                .push(function () {
+                  return gadget.changeState({retry: 0});
+                }),
+              gadget.install()
+                .push(function () {
+                  window.location = gadget.state.redirect_url;
+                })
+            ]);
           }
           throw error;
         });
     })
 
-    .declareMethod("waitInstall", function () {
-      if (this.props.is_installed) {
-        return;
+    .onStateChange(function () {
+      var gadget = this, element;
+      if (gadget.state.retry !== undefined) {
+        return new RSVP.Queue()
+          .push(function () {
+            if (gadget.state.retry === 0) {
+              element = document.createElement("div");
+              element.className = "presentation";
+              gadget.element.insertBefore(element, gadget.element.firstChild);
+              return gadget.declareGadget(
+                "gadget_officejs_bootloader_presentation.html",
+                {"scope": "view_gadget", "element": element}
+              );
+            }
+            return gadget.getDeclaredGadget('view_gadget');
+          })
+          .push(function (view_gadget) {
+            return view_gadget.render({
+              app_name: gadget.state.app_name,
+              retry: gadget.state.retry,
+              error: gadget.state.error,
+              redirect_url: gadget.state.redirect_url
+            });
+          });
       }
-      this.installing = RSVP.defer();
-      return this.installing.promise;
     })
 
-    .declareMethod("install", function () {
-      var gadget = this;
+    .declareMethod('declareAndInstall', function (url) {
+      var element = document.createElement("div");
+      element.setAttribute("style", "display: none");
+      this.element.appendChild(element);
+      return this.declareGadget(url,
+        {
+          "element": element,
+          "sandbox": "iframe"
+        })
+        .push(function (sub_gadget) {
+          return sub_gadget.install();
+        });
+    })
 
-      gadget.props.storage = createStorage(
-        gadget.props.version_url,
-        gadget.props.cache_file
-      );
+    .declareMethod("install", function () {
+      var gadget = this,
+        storage = createStorage(gadget);
       return new RSVP.Queue()
         .push(function () {
           return navigator.serviceWorker.register(
-              "gadget_officejs_bootloader_serviceworker.js",
-              {"scope": gadget.props.version_url}
-            );
-        })
-        .push(function (registration) {
-          if (registration.installing) {
-            gadget.props.serviceWorker = registration.installing;
-          } else if (registration.waiting) {
-            gadget.props.serviceWorker = registration.waiting;
-          } else if (registration.active) {
-            gadget.props.serviceWorker = registration.active;
-          }
-          return gadget.props.storage.repair();
+            "gadget_officejs_bootloader_serviceworker.js"
+          );
         })
         .push(function () {
-          // remove base if present
-          if (document.querySelector("base")) {
-            document.querySelector("head").removeChild(
-              document.querySelector("base")
-            );
+          return storage.repair();
+        })
+        .push(undefined, function (error) {
+          if (gadget.state.retry !== undefined) {
+            return gadget.changeState({
+              retry: gadget.state.retry += 1,
+              error: error
+            })
+            .push(function () {
+              return RSVP.delay(1000);
+            })
+            .push(function () {
+              return gadget.install();
+            });
           }
+          throw error;
         });
-    })
-
-    .declareService(function () {
-      var gadget = this;
-
-      function redirect() {
-        window.location.pathname += gadget.props.version_url;
-      }
-
-      if (navigator.serviceWorker === undefined) {
-        window.applicationCache.addEventListener("cached", redirect);
-        window.applicationCache.addEventListener('noupdate', redirect);
-        window.setTimeout(redirect, 10000);
-      } else {
-        return this.mainInstall();
-      }
     });
 
-
-}(window, document, RSVP, rJS, jIO, navigator, MessageChannel, ProgressEvent,
-  console));
\ No newline at end of file
+}(window, document, RSVP, rJS, jIO, navigator, URL));
\ No newline at end of file
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_js.xml
index 7b8d71542e..9b9dca562a 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_js.xml
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_js.xml
@@ -236,7 +236,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>960.25484.60987.38638</string> </value>
+                <value> <string>961.10581.61261.18995</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -254,7 +254,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1499245437.8</float>
+                        <float>1501763880.35</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_presentation_js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_presentation_js.js
index 28d9b7910c..8aae6b7f1e 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_presentation_js.js
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_presentation_js.js
@@ -5,18 +5,8 @@ var IMAGE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABUCAYAAAACoiByA
   "use strict";
 
   rJS(window)
-    .ready(function (g) {
-      g.props = {};
-    })
-    .ready(function (g) {
-      return g.getElement()
-        .push(function (element) {
-          g.props.element = element;
-        });
-    })
     .declareMethod('render', function (options) {
-      this.props.element.querySelector("center")
-        .innerHTML =
+      var inner =
         "<header>OfficeJS Installer</header>" +
         "<br>" +
         "<br>" +
@@ -27,10 +17,21 @@ var IMAGE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABUCAYAAAACoiByA
         "<br>" +
         '<img width="100" height="100" title="" alt="" src="' + IMAGE + '" />' +
         "<br>" +
-        '<div>Installing ' + options.app_name + '</div>' +
+        '<div> Preparing ' + options.app_name + '</div>' +
         "<br> We prepare your application for a 100 % offline mode" +
-        '<div class="loader"></div>';
-      return {};
+        '<div class="loader"></div>',
+          error_message;
+      if (options.retry > 0) {
+        error_message = options.error.message || 'Unknow Error';
+        inner += "<br>" +
+          "<div> Last Error: " + error_message + "</div>" +
+          "<div>Retry n° " + options.retry + "</div>";
+      }
+      inner += '<div><a href="' +
+        options.redirect_url + '">Skip</a></div>';
+      this.element.querySelector("center")
+        .innerHTML = inner;
+      return;
     });
 
 }(window, rJS));
\ No newline at end of file
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_presentation_js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_presentation_js.xml
index 02a829c5b9..9514b44cbe 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_presentation_js.xml
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_presentation_js.xml
@@ -236,7 +236,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>956.64509.32061.2201</string> </value>
+                <value> <string>961.10577.42640.30924</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -254,7 +254,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1485770737.14</float>
+                        <float>1501764672.06</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_serviceworker_js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_serviceworker_js.js
index a2f55eea73..ec39e3f5ec 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_serviceworker_js.js
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_serviceworker_js.js
@@ -5,8 +5,6 @@ var global = self, window = self;
 (function (self, fetch, Request, Response) {
   "use strict";
 
-  self.IDBTransaction = self.IDBTransaction || self.webkitIDBTransaction || self.msIDBTransaction || {READ_WRITE: "readwrite"};
-  self.IDBKeyRange = self.IDBKeyRange || self.webkitIDBKeyRange || self.msIDBKeyRange;
   self.DOMParser = {};
   self.sessionStorage = {};
   self.localStorage = {};
@@ -41,13 +39,17 @@ var global = self, window = self;
     if (relative_url === "") {
       relative_url = "/";
     }
+    if (relative_url === 'no-cache') {
+      event.respondWith(new Response(self.cache_list));
+      return;
+    }
     event.respondWith(
       new self.RSVP.Queue()
         .push(function () {
           if (self.storage.get === undefined) {
-            self.storage = createStorage(self.registration.scope);
+            self.storage = createStorage("ojs_source_code");
           }
-          return self.storage.getAttachment("/", relative_url)
+          return self.storage.getAttachment(self.registration.scope, relative_url)
             .push(function (blob) {
               return new Response(blob, {
                 'headers': {
@@ -58,12 +60,11 @@ var global = self, window = self;
         })
         .push(undefined, function (error) {
           if (error instanceof self.jIO.util.jIOError) {
-            self.console.log(
-              "Relative_Url: ",
-              relative_url,
-              "\nCause: ",
-              error.message
-            );
+            if (relative_url.indexOf('http') === -1) {
+              if (self.cache_list.indexOf(relative_url) === -1) {
+                self.cache_list.push(relative_url);
+              }
+            }
             return fetch(event.request);
           }
           return new Response(error, {"statusText": error.message, "status": 500});
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_serviceworker_js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_serviceworker_js.xml
index 1b61986209..0d62bd06a2 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_serviceworker_js.xml
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_bootloader_serviceworker_js.xml
@@ -227,7 +227,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>960.4199.25759.2730</string> </value>
+                <value> <string>961.10426.22931.29952</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -245,7 +245,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1497613210.46</float>
+                        <float>1501754543.53</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_appcachestorage_js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_appcachestorage_js.js
index 8fcec718f9..8fe3cdde4a 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_appcachestorage_js.js
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_appcachestorage_js.js
@@ -1,110 +1,138 @@
 /*jslint indent:2, maxlen: 80, nomen: true */
-/*global jIO, RSVP, window, console, Blob */
-(function (window, jIO, RSVP, console, Blob) {
+/*global jIO, RSVP, window, Rusha, Blob, URL */
+(function (window, jIO, RSVP, Rusha, Blob, URL) {
   "use strict";
 
+  var rusha = new Rusha();
+
   function AppCacheStorage(spec) {
     this._manifest = spec.manifest;
+    this._gadget = spec.gadget;
     this._take_installer = spec.take_installer || false;
-    this._origin_url = spec.origin_url !== undefined ? spec.origin_url :
-      (window.location.origin + window.location.pathname +
-      (window.location.pathname.endsWith('/') ? '' : '/') +
-      ((spec.version !== undefined) ?
-      (spec.version + (spec.version.endsWith('/') ? '' : '/')) : ""));
-    this._prefix = spec.prefix || "";
-    this._relative_url_list = ["/", this._prefix + spec.manifest];
-    if (this._take_installer) {
-      this._relative_url_list = [
-        this._prefix || "/",
-        this._prefix + "development/" + spec.manifest,
-        this._prefix + "development/",
-        this._prefix + "gadget_officejs_bootloader.js",
-        this._prefix + "gadget_officejs_bootloader.appcache",
-        this._prefix + "gadget_officejs_bootloader_presentation.html",
-        this._prefix + "gadget_officejs_bootloader_presentation.js",
-        this._prefix + "gadget_officejs_bootloader_presentation.css",
-        this._prefix + "gadget_officejs_bootloader_serviceworker.js",
-        this._prefix + "gadget_erp5_nojqm.css",
-        this._prefix + "jio_appcachestorage.js"
-      ];
-    }
+    this._origin_url = spec.origin_url !== undefined ?
+        spec.origin_url : new URL(window.location);
+    this._version = spec.version || "";
+    this._gadget_list = [];
+    this._documents = {};
+    // Harcoded here, find a better way.
+    this._relative_url_list = [
+      "/",
+      "gadget_officejs_bootloader.js",
+      "gadget_officejs_bootloader_presentation.html",
+      "gadget_officejs_bootloader_presentation.js",
+      "gadget_officejs_bootloader_presentation.css",
+      "gadget_officejs_bootloader_serviceworker.js",
+      "gadget_erp5_nojqm.css",
+      "jio_appcachestorage.js"
+    ];
   }
 
   AppCacheStorage.prototype.get = function (id) {
-    return {};
+    if (this._documents.hasOwnProperty(id)) {
+      return this._documents[id];
+    }
+    throw new jIO.util.jIOError('can not find document : ' + id, 404);
   };
 
-  AppCacheStorage.prototype.hasCapacity = function (name) {
-    return (name === "list");
+  AppCacheStorage.prototype.hasCapacity = function () {
+    return true;
   };
 
-  AppCacheStorage.prototype.getAttachment = function (doc_id, attachment_id) {
-    var storage = this, url = attachment_id;
+  AppCacheStorage.prototype.getAttachment = function (origin_url,
+                                                       relative_url) {
+    var storage = this;
+    if (storage._gadget_list.indexOf(relative_url) >= 0) {
+      return window.Bootloader.declareAndInstall(relative_url)
+        .push(function () {
+          return new Blob([]);
+        });
+    }
     return new RSVP.Queue()
-    .push(function () {
-      return jIO.util.ajax({
-        type: "GET",
-        url: ((url.startsWith("http") || url.startsWith("//")) ?
-          url : storage._origin_url) + url,
-        dataType: "blob"
+      .push(function () {
+        return jIO.util.ajax({
+          type: "GET",
+          url: (relative_url.startsWith("http") ||
+                relative_url.startsWith("//")) ?
+                relative_url : origin_url + relative_url,
+          dataType: "blob"
+        });
+      })
+      .push(function (result) {
+        return result.target.response;
       });
-    })
-    .push(function (result) {
-      return result.target.response;
-    });
   };
 
-  AppCacheStorage.prototype.allAttachments = function (url) {
+  AppCacheStorage.prototype.allAttachments = function () {
     var result = {}, i, len = this._relative_url_list.length;
     for (i = 0; i < len; i += 1) {
       result[this._relative_url_list[i]] = {};
     }
+    for (i = 0; i < this._gadget_list.length; i += 1) {
+      result[this._gadget_list[i]] = {};
+    }
     return result;
   };
 
-  AppCacheStorage.prototype.buildQuery = function (options) {
-    return [{id: "/", doc: {}, value: {}}];
+  AppCacheStorage.prototype.buildQuery = function () {
+    var result = [], id;
+    for (id in this._documents) {
+      if (this._documents.hasOwnProperty(id)) {
+        result.push({
+          'id': id,
+          'value': this._documents[id],
+          'doc': this._documents[id]
+        });
+      }
+    }
+    return result;
   };
 
   AppCacheStorage.prototype.repair = function () {
-    var storage = this,
-      prefix = storage._prefix +
-        (storage._take_installer ? "development/" : "");
+    var storage = this;
     return new RSVP.Queue()
       .push(function () {
         return jIO.util.ajax({
           type: "GET",
-          url: storage._origin_url + storage._prefix + storage._manifest
+          url: storage._origin_url + storage._version + storage._manifest
         });
       })
       .push(function (response) {
         var text = response.target.responseText,
-          relative_url_list = text.split('\r\n'),
+          relative_url_list = text.split('\n'),
           i,
-          take = false;
-        if (relative_url_list.length === 1) {
-          relative_url_list = text.split('\n');
-        }
-        if (relative_url_list.length === 1) {
-          relative_url_list = text.split('\r');
-        }
+          take = false,
+          hash = rusha.digestFromString(text);
+        storage._documents[storage._origin_url] = {'hash': hash};
+        storage._relative_url_list.push(storage._version);
+        storage._relative_url_list.push(storage._version + storage._manifest);
         for (i = 0; i < relative_url_list.length; i += 1) {
           if (relative_url_list[i].indexOf("NETWORK:") >= 0) {
-            take = false;
-          }
-          if (take &&
-              relative_url_list[i] !== "" &&
+            take = 3;
+          } else if (relative_url_list[i].indexOf('GADGET:') >= 0) {
+            take = 2;
+          } else if (relative_url_list[i] !== "" &&
               relative_url_list[i].charAt(0) !== '#' &&
               relative_url_list[i].charAt(0) !== ' ') {
-            relative_url_list[i].replace("\r", "");
-            storage._relative_url_list.push(prefix + relative_url_list[i]);
+            if (take === 1) {
+              storage._relative_url_list.push(
+                storage._version + relative_url_list[i]
+              );
+            } else if (take === 2) {
+              storage._gadget_list.push(relative_url_list[i]);
+            }
           }
           if (relative_url_list[i].indexOf("CACHE:") >= 0) {
-            take = true;
+            take = 1;
           }
         }
+      })
+      .push(undefined, function (error) {
+        if (!error.message) {
+          error.message = "Can't get manifest";
+        }
+        throw error;
       });
   };
 
   jIO.addStorage('appcache', AppCacheStorage);
-}(window, jIO, RSVP, console, Blob));
\ No newline at end of file
+}(window, jIO, RSVP, Rusha, Blob, URL));
diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_appcachestorage_js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_appcachestorage_js.xml
index 87820e9321..d354b026d0 100644
--- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_appcachestorage_js.xml
+++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_appcachestorage_js.xml
@@ -239,7 +239,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>960.14254.57744.3293</string> </value>
+                <value> <string>961.10590.54524.11827</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -257,7 +257,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1498139825.46</float>
+                        <float>1501764524.91</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
-- 
2.30.9