Skip to content
Snippets Groups Projects
index.html 13.2 KiB
Newer Older
francois.grand's avatar
francois.grand committed
<!doctype html>
<html lang="en">
francois.grand's avatar
francois.grand committed

   <base href="">
   <meta charset="utf-8">
   <title>Cassiopée</title>

   <link rel="apple-touch-icon" sizes="180x180" href="assets/icons/apple-touch-icon.png">
   <link rel="icon" type="image/png" sizes="512x512" href="assets/icons/android-chrome-512x512.png">
   <link rel="icon" type="image/png" sizes="192x192" href="assets/icons/android-chrome-192x192.png">
   <link rel="icon" type="image/png" sizes="32x32" href="assets/icons/favicon-32x32.png">
   <link rel="icon" type="image/png" sizes="16x16" href="assets/icons/favicon-16x16.png">
   <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#ffffff">

   <meta name="viewport" content="width=device-width, initial-scale=1">
   <nghyd-app>
      <style type="text/css">
         body,
         html {
            height: 100%;
         }

         .app-loading {
            position: relative;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100%;
            border: solid red 100%;
            font-family: Arial, Helvetica, sans-serif;
         }

         .app-loading>.logo {
            margin-bottom: 10px;
         }
      </style>
      <div class="app-loading">
         <div class="logo">
            <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#"
               xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg"
               xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
               xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg3406" version="1.1"
               inkscape:version="0.92.3 (2405546, 2018-03-11)" width="167.55714" height="167.55714"
               viewBox="0 0 167.55714 167.55714" sodipodi:docname="cassiopee_logo.svg">
               <metadata id="metadata3412">
                  <rdf:RDF>
                     <cc:Work rdf:about="">
                        <dc:format>image/svg+xml</dc:format>
                        <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" ></dc:type>
                        <dc:title></dc:title>
                     </cc:Work>
                  </rdf:RDF>
               </metadata>
               <g inkscape:groupmode="layer" id="layer1" inkscape:label="background">
                  <rect
                     style="fill:#003a80;stroke:none;stroke-width:8;stroke-miterlimit:4;stroke-dasharray:none;fill-opacity:1;stroke-opacity:1;stroke-linejoin:round"
                     id="fond" width="165.55714" height="165.55714" x="1" y="1"></rect>
               </g>
               <g inkscape:groupmode="layer" id="calque_traits" inkscape:label="traits">
                  <path
                     style="fill:#80b3ff;fill-rule:evenodd;stroke:#4dbbe9;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
                     d="M 16.234557,39.786389 36.297745,77.631687" id="trait_1" inkscape:connector-curvature="0"></path>
                  <path
                     style="fill:#80b3ff;fill-rule:evenodd;stroke:#4dbbe9;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
                     d="m 47.234816,83.975938 27.27422,0.39174" id="trait_2" inkscape:connector-curvature="0"></path>
                  <path
                     style="fill:#80b3ff;fill-rule:evenodd;stroke:#4dbbe9;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
                     d="M 85.615846,92.002058 101.01379,128.05358" id="trait_3" inkscape:connector-curvature="0"></path>
                  <path
                     style="fill:#80b3ff;fill-rule:evenodd;stroke:#4dbbe9;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
                     d="m 145.82968,107.86632 -35.62153,23.78874" id="trait_4" inkscape:connector-curvature="0"></path>
               </g>
               <g inkscape:groupmode="layer" id="calque_points" inkscape:label="points">
                  <circle
                     style="fill:#ffffff;stroke:#003a80;stroke-width:10;stroke-miterlimit:66;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
                     id="point_1" cx="12.879179" cy="34.64555" r="6"></circle>
                  <circle
                     style="fill:#ffffff;stroke:#003a80;stroke-width:10;stroke-miterlimit:66;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
                     id="point_2" cx="39.734871" cy="83.581924" r="10"></circle>
                  <circle
                     style="fill:#ffffff;stroke:#003a80;stroke-width:10;stroke-linejoin:round;stroke-miterlimit:66;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
                     id="point_3" cx="82.500542" cy="84.860001" r="10"></circle>
                  <circle
                     style="fill:#ffffff;stroke:#003a80;stroke-width:10;stroke-miterlimit:66;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
                     id="point_4" cx="104.12913" cy="135.35852" r="10"></circle>
                  <circle
                     style="fill:#ffffff;stroke:#003a80;stroke-width:10;stroke-miterlimit:66;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
                     id="point_5" cx="151.57199" cy="103.73587" r="10"></circle>
               </g>
            </svg>
         </div>
         Loading Cassiopée…
      <script type="text/javascript">
         // animation du logo

         // CONFIG
         var elements1 = [ "trait_1", "trait_2", "trait_3", "trait_4", "point_1", "point_2", "point_3", "point_4", "point_5" ];
         var elements2 = [ "point_1", "point_2", "point_3", "point_4", "point_5", "trait_1", "trait_2", "trait_3", "trait_4" ];
         var delayB = 100; // delay betweeen elements
         var delayO = 40;  // delay between opacity change
         var stepO = 0.1;  // opacity change step
         var minOpacity = 0.15;
         var animationTime = (elements1.length * delayB + (1 / stepO) * delayO);

         oneAnimation();
         var animationLoop = setInterval(() => {
            // do one animation
            oneAnimation();
            // if DOM elements are gone (Angular has loaded), stop animation loop
            var testElt = document.getElementById(elements1[0]);
            if (! testElt) {
               clearInterval(animationLoop);
            }
         }, 2 * animationTime);

         function oneAnimation() {
            hideSequence(elements1, delayB, delayO, stepO);
            setTimeout(() => {
               showSequence(elements2, delayB, delayO, stepO);
            }, animationTime);
         }

         function hideSequence(ids, delayBetween = 500, delay = 100, step = 0.1) {
            callSequence(hideSmooth, ids, delayBetween, delay, step);
         }

         function showSequence(ids, delayBetween = 500, delay = 100, step = 0.1) {
            callSequence(showSmooth, ids, delayBetween, delay, step);
         }

         function callSequence(func, ids, delayBetween = 500, delay = 100, step = 0.1) {
            for (var i = 0; i < ids.length; i++) {
               var id = ids[i];
               var d;
               if (i === 0) {
                  d = 0;
               } else {
                  d += delayBetween;
               }
               ((locId) => {
                  setTimeout(() => {
                     func(locId, delay, step);
                  }, d);
               })(id);
            }
         }

         function hideSmooth(id, delay = 100, step = 0.1) {
            var element = document.getElementById(id);
            if (element) {
               element.style.opacity = 1;
               var loopHandle = setInterval(() => {
                  if (element.style.opacity > minOpacity) {
                     element.style.opacity = String(Number(element.style.opacity) - Number(step));
                  } else {
                     clearInterval(loopHandle);
                  }
               }, delay);
            }
         }

         function showSmooth(id, delay = 100, step = 0.1) {
            var element = document.getElementById(id);
            if (element) {
               element.style.opacity = minOpacity;
               var loopHandle = setInterval(() => {
                  if (element.style.opacity < 1) {
                     element.style.opacity = String(Number(step) + Number(element.style.opacity));
                  } else {
                     clearInterval(loopHandle);
                  }
               }, delay);
            }
         }

      </script>
   </nghyd-app>

   <script type="text/javascript">
      /**
       * Compares semver strings
       * @see https://github.com/substack/semver-compare
       */
      function semverCompare(a, b) {
         var pa = a.split('.');
         var pb = b.split('.');
         for (var i = 0; i < 3; i++) {
            var na = Number(pa[i]);
            var nb = Number(pb[i]);
            if (na > nb) return 1;
            if (nb > na) return -1;
            if (!isNaN(na) && isNaN(nb)) return 1;
            if (isNaN(na) && !isNaN(nb)) return -1;
         }
         return 0;
      }
      /**
       * Calls the Cassiopee update server to check for available updates;
       * if so, displays a desktop notification which, if clicked, will
       * trigger the download of the latest version installer for the
       * current platform
       * 
       * Web updates system prerequisites
       * --------------------------------
       * 
       * ${URL} should point to an http-accessible directory containing:
       * 
       *  1. a file named "releases.json" with a contents of the form
       *    {
       *      "latest": "4.5.0",
       *      "4.5.0": {
       *        "darwin": "cassiopee-setup-4.5.0.dmg",
       *        "linux": "fr.irstea.cassiopee_4.5.0_amd64.deb",
       *        "win32": "Cassiopée Setup 4.5.0.exe"
       *      },
       *      "4.4.2": {
       *        "darwin": "cassiopee-setup-4.4.2.dmg",
       *        "linux": "fr.irstea.cassiopee_4.4.2_amd64.deb",
       *        "win32": "Cassiopée Setup 4.4.2.exe"
       *      }
       *    }
       * 
       *  2. all platform-dependent installer files specified in "releases.json",
       *     at the root of the directory (ex: "fr.irstea.cassiopee_4.5.0_amd64.deb")
       */
      const lookForUpdates = function() {
         console.log("looking for updates");
         // Web update resources root directory
         const URL = "https://cassiopee.g-eau.fr/cassiopee-releases/";

         // detect current app version and platform
         let version = "4.4.2"; // debug
         cordova.getAppVersion.getVersionNumber((versionNumber) => {
            version = versionNumber;
            console.log("current version", version);
            // fetch releases information
            const options = {
               method: 'get',
               headers: { "Cache-Control": "no-cache" }
            };
            cordova.plugin.http.sendRequest(URL + "releases.json", options, (response) => {
               var data = JSON.parse(response.data); // This is the resultant JSON in useful form
               // alert(`Youpi ! ${response.status} version=${version}, latest=${data.latest}, comp=${semverCompare(data.latest, version)}`);
               console.log("latest version", data !== undefined ? data.latest : "err");
               // compare current version to latest version
               if (data.latest && semverCompare(data.latest, version) == 1) {
                  // get download link for latest version, depending on platform
                  if (data[data.latest] && data[data.latest]["android"]) {
                     const latestVersionURL = URL + data[data.latest]["android"];
                     // show notification
                     cordova.plugins.notification.local.schedule({
                        title: `Cassiopee version ${data.latest} is available`,
                        text: "Download update installer",
                        foreground: true,
                        smallIcon: "res://ic_stat_notify",
                        icon: "res://icon"
                     });
                     cordova.plugins.notification.local.on("click", () => {
                        // ask system to open URL with default browser
                        // @TODO find a way to get rid of "are you sure you want to leave this page ?" prompt
                        window.open(latestVersionURL, "_system");
                     });
                  } // else could not find link, silent fail
               } // else you already have the latest version
            }, (response) => { /* silent fail */});
         });
      };

      // execute on Cordova (mobile app) only
      if (window.cordova && cordova.platformId !== "browser") {
         document.addEventListener("deviceready", function () {
            // check updates at app startup
            lookForUpdates();
         });
      }
   </script>