?
Solved

Cache Manifest Progress Bar

Posted on 2014-03-29
7
Medium Priority
?
1,889 Views
Last Modified: 2014-04-25
Hi am starting to use the cache manifest file to make a simple offline webapp for the iapd.
I want to implement a progress bar for when the user first visits the page (online)...

I have created some javascript but the progress bar goes to 100% straight away...

Could someone look at what I have done and suggest any improvements:


<script type="text/javascript">
window.addEventListener('load', function(e) {

    if (window.applicationCache) {
        //alert ("ddd");
        window.applicationCache.addEventListener('updateready', function(e) {

            if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {

                // Browser downloaded a new app cache.
                // Swap it in and reload the page to get the new hotness.
                window.applicationCache.swapCache();
                if (confirm('A new version of this site is available. Load it?')) {
                    window.location.reload();
                }
            } else {
                // Manifest didn't changed. Nothing new to server.
            }
        }, false);
    }
}, false);





window.applicationCache.onprogress = function (e) {               
    var message = 'Downloading offline resources.. ';

    if (e.lengthComputable) {
        updateProgress(Math.round(e.loaded / e.total * 100));
    } else {
        alert(message);
    };
};







var cacheStatusValues = [];
cacheStatusValues[0] = 'uncached';
cacheStatusValues[1] = 'idle';
cacheStatusValues[2] = 'checking';
cacheStatusValues[3] = 'downloading';
cacheStatusValues[4] = 'updateready';
cacheStatusValues[5] = 'obsolete';

var cache = window.applicationCache;
cache.addEventListener('cached', logEvent, false);
cache.addEventListener('checking', logEvent, false);
cache.addEventListener('downloading', logEvent, false);
cache.addEventListener('error', logEvent, false);
cache.addEventListener('noupdate', logEvent, false);
cache.addEventListener('obsolete', logEvent, false);
cache.addEventListener('progress', logEvent, false);
cache.addEventListener('updateready', logEvent, false);

 



function updateProgress(p) {
    var progress;
    progress = $("#progressbar")
    .progressbar("option","value");
        $("#progressbar")
        .progressbar("option", "value", progress = p);
} 



function logEvent(e) {

    //console.log(event.loaded + " of " + event.total + " downloaded.");

    var online, status, type, message;
    online = (navigator.onLine) ? 'yes' : 'no';
    status = cacheStatusValues[cache.status];
    type = e.type;
    message = 'online: ' + online;
    message+= ', event: ' + type;
    message+= ', status: ' + status;
    if (type == 'error' && navigator.onLine) {
        message+= ' There was an unknown error, check your Cache Manifest.';
    }
    console.debug(message);
}












$(function() {
    $("#progressbar").progressbar({ value: 0 });
});


 
</script>

Open in new window

0
Comment
Question by:Steve Tinsley
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
7 Comments
 
LVL 43

Accepted Solution

by:
Rob earned 2000 total points
ID: 39995683
i did this a while ago but I have just been going through the code to refresh myself.

To cut a long story short (I hope) I ended up using an iframe as is done with other offline apps such as Angry Birds... Load it up in Chrome and view source.

The paradox is that you have to load the page to know how much is loaded but by then you have 100% loaded! sounds dumb doesn't it!  So what you do is have a very basic "index.html" file and an iframe just inside the <body> tag:

<body>
<div id="tooltip"></div>
<iframe id="appcacheInstaller" style="display: none;" src="http://www.domain.com/ApplicationCacheInstaller.html"></iframe>

Open in new window


ApplicationCacheInstaller.html takes care of al the manifest stuff AND the progress of it loading:

<!DOCTYPE html>
<html manifest="tool.manifest">
	<head></head>
	<body style="background-color: #0f0; margin: 0px;">
    ApplicationCacheInstaller.html
    <pre id='status'></pre>
    <script type="text/javascript">
var appcache = window.applicationCache;
appcache.addEventListener('cached', logEvent, false);
appcache.addEventListener('checking', logEvent, false);
appcache.addEventListener('downloading', logEvent, false);
appcache.addEventListener('error', logEvent, false);
appcache.addEventListener('noupdate', logEvent, false);
appcache.addEventListener('obsolete', logEvent, false);
appcache.addEventListener('progress', logEvent, false);
appcache.addEventListener('updateready', logEvent, false);

if (window.applicationCache !== undefined && window.applicationCache.status == window.applicationCache.IDLE){
	changeButtonToInstalled();
}

function setStatus(message) {
    window.parent.document.getElementById("tooltip").innerHTML = message;
}

function changeButtonToInstalled() {
    //window.parent.document.getElementById("installButton").id = "offlineInstalled";
}

function logEvent(e) {
    switch (e.type) {
      case "progress":
        message = "Installing offline version...";
        if (e.lengthComputable) {
          message += Math.round(e.loaded / e.total * 100) + "%";
        }
        break;
      case "noupdate":
        message = "You're running the latest offline capable version.";
        changeButtonToInstalled();
        break;
      case "obsolete":
        message = "Offline mode has been uninstalled.";
        break;
      case "cached":
        message = "We're ready to play offline!";
        changeButtonToInstalled();
        break;
      case "checking":
        message = "Checking for a new version...";
        break;
      case "downloading":
        message = "Downloading...";
        break;
      case "updateready":
        message = "A new version is ready. Click to <a href='javascript:window.location.reload();' onclick='return confirm(\"This will restart your game. Continue?\");'>upgrade</a>.";
        window.parent.appCacheUpdateReady();
        break;
      case "error":
        switch (window.applicationCache.status) {
          case window.applicationCache.IDLE:
            message = "We're ready to play offline!";
            break;
          case window.applicationCache.UNCACHED:
            message = "Error loading offline version. Please <a href='javascript:window.location.reload();' onclick='return confirm(\"This will restart your game. Continue?\");'>try again</a>.";
            break;
          case window.applicationCache.CHECKING:
          case window.applicationCache.DOWNLOADING:
          case window.applicationCache.UPDATEREADY:
          case window.applicationCache.OBSOLETE:
          default:
            message = "Error " + window.applicationCache.status + " loading offline version. Please <a href='javascript:window.location.reload();' onclick='return confirm(\"This will restart your game. Continue?\");'>try again</a>.";
            break;
        }
        break;
      default:
        message = "[" + e.type + "]";
    }
    document.getElementById("status").innerHTML += e.type + ": " + message + "\n";
    setStatus(message);
}
    </script>
  </body>
</html>

Open in new window

0
 

Author Comment

by:Steve Tinsley
ID: 40018518
Hi Rob,

Thanks for the help. I have been playing with the code today and beginning to put something together.... But i'm at a head scratching point. Would you mind looking at my code:

cacher.html
<!DOCTYPE html>
<html lang="en" manifest="offline.manifest">

<head>
    
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="apple-mobile-web-app-capable" content="yes" /> <!-- Run in full-screen mode. -->
    <meta name="apple-mobile-web-app-status-bar-style" content="black" /> <!-- Make the status bar black with white text. -->
    <meta name="apple-mobile-web-app-title" content="Menu"> <!-- Customize home screen title. -->
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <!-- Set viewport. -->
        
    <!-- STARTUP IMAGES & ICONS -->
    <link rel="apple-touch-icon" sizes="76x76" href="webapp/images/webapp/touch-icon-ipad.png">
    <link rel="apple-touch-icon" sizes="152x152" href="webapp/images/webapp/touch-icon-ipad-retina.png">
    <!-- iPad (portrait) SPLASHSCREEN-->
    <link href="webapp/apple-touch-startup-image-768x1004.png" media="(device-width: 768px) and (orientation: portrait)" rel="apple-touch-startup-image">
    <!-- iPad (landscape) SPLASHSCREEN-->
    <link href="webapp/apple-touch-startup-image-748x1024.png" media="(device-width: 768px) and (orientation: landscape)" rel="apple-touch-startup-image">
    <!-- iPad (Retina, portrait) SPLASHSCREEN-->
    <link href="webapp/apple-touch-startup-image-1536x2008.png" media="(device-width: 1536px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
    <!-- iPad (Retina, landscape) SPLASHSCREEN-->
    <link href="webapp/apple-touch-startup-image-2048x1496.png" media="(device-width: 1536px)  and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">

	<link rel="stylesheet" href="webapp/includes/jquery-ui-1.10.4.min.css" type="text/css" rel="stylesheet" />
	<script src="webapp/includes/jquery.min.js" type="text/javascript"></script>
	<script src="webapp/includes/jquery-ui-1.10.4.min.js" type="text/javascript"></script>
	<script src="webapp/includes/jquery.stayInWebApp.min.js" type="text/javascript"></script>
	<script src="webapp/includes/fastclick.js" type="text/javascript"></script>
	<script src="webapp/includes/scripts_v1.js"></script>
	<link href="webapp/includes/style.css" type="text/css" rel="stylesheet" >

</head>

<body>


<script type="text/javascript">
	$(document).ready(function(){  

        var progressLabel =  $( ".progress-label" );
        $("#progressbar").progressbar({
        	value: 0,

        	complete: function() {
            	progressLabel.text( "Complete!" );
          	}
        });


		$("#details").click(function(){
			var txt = $("#appcacheInstaller").is(':visible') ? 'Show Details' : 'Hide Details';
			$("#details").text(txt);
			$("#appcacheInstaller").toggle();
		});


	});

</script>









<div id="container">
	<div id="content">


		<h1>Offline Downloader</h1><br>

		<div id="tooltip"></div>
		<div id="progressbar" style="display:none;"><div class="progress-label">Loading...</div></div>
		<br><a href="javascript:void(0)" id="details" style="float: right;">Show Details</a><br>
				

		<iframe id="appcacheInstaller" frameborder="0" style="display:none; border:1px dotted #000; width:100%; -webkit-box-sizing: border-box;" src="ApplicationCacheInstaller.html"></iframe>

		


	</div>
</div>

<div id="footer">
	<a href='#' onclick='location.reload(true); return false;'>Refresh</a>
</div>


<div id="help" title="Help">
	<ul>
		<li>When downloading the webapp it is best to be on a fast wifi connection rather then mobile internet.</li>
		<li>If you see no activity for a few minutes you may need to reload your browser.</li>
	</ul>
</div>


</body>

</html>

Open in new window



ApplicationCacheInstaller.html
<!DOCTYPE html>
<html lang="en" manifest="offline.manifest">
	<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
	<body>



    <pre id='status'></pre>

    <script type="text/javascript">


      if (window.applicationCache !== undefined && window.applicationCache.status == window.applicationCache.IDLE){
      	alert("(201)");
        //cacheComplete();
      }


      function updateProgressBar(percentage) {
        window.parent.$( "#progressbar" ).show();
        var progress;
        progress = window.parent.$("#progressbar")
        .progressbar("option","value");
        window.parent.$("#progressbar").progressbar("option", "value", progress = percentage);
      } 

      function setStatus(message) {
          window.parent.document.getElementById("tooltip").innerHTML = message;
      }

      function cacheComplete() {
        window.parent.$( "#content" ).load( "launch.html" ).fadeIn('slow');
        //window.parent.document.getElementById("installButton").id = "offlineInstalled";
      }

      function logEvent(e) {
          switch (e.type) {

            case "progress":
              
              message = "<div class=\"alert-box notice\">Installing offline version...";
              if (e.lengthComputable) {
                percentage = Math.round(e.loaded / e.total * 100);
                message += percentage + "%";
                updateProgressBar(percentage);
              } else {
                alert ("Error (199)");
              }
              message += "<br><br>Please be patient as this is a LARGE download and can take sometime.</div>";
              break;
            case "noupdate":
              message = "<div class=\"alert-box success\">You're already running the latest offline webapp. Click to <a href='webapp/'>continue</a>.</div>";
              //cacheComplete();
              break;
            case "obsolete":
              message = "<div class=\"alert-box notice\">Offline mode has been uninstalled.</div>";
              break;
            case "cached":
              message = "<div class=\"alert-box success\">Webapp is ready to use offline. Click to <a href='webapp/'>continue</a>.</div>";
              //cacheComplete();
              break;
            case "checking":
              message = "<div class=\"alert-box notice\">Checking for a new version, please wait.</div>";
              break;
            case "downloading":
              message = "<div class=\"alert-box notice\">Please be patient, the webapp is downloading...</div>";
              break;
            case "updateready":
              message = "<div class=\"alert-box success\">The webapp has been downloaded. Click to <a href='webapp/'>continue</a>.</div>";
              //window.parent.appCacheUpdateReady();
              break;
            case "error":
              switch (window.applicationCache.status) {
                case window.applicationCache.IDLE:
              message = "<div class=\"alert-box notice\">Click to <a href='webapp/'>continue</a>.</div";
                  break;
                case window.applicationCache.UNCACHED:
                  message = "<div class=\"alert-box error\">Error (102) loading offline version. Please <a href='javascript:window.location.reload();' onclick='return confirm(\"This will restart your download. Continue?\");'>try again</a>.</div>";
                  break;
                case window.applicationCache.CHECKING:
                case window.applicationCache.DOWNLOADING:
                case window.applicationCache.UPDATEREADY:
                case window.applicationCache.OBSOLETE:
                default:
                  message = "<div class=\"alert-box error\">Error (103)" + window.applicationCache.status + " loading offline version. Please <a href='javascript:window.location.reload();' onclick='return confirm(\"This will restart your sync. Continue?\");'>try again</a>.</div>";
                  break;
              }
              break;
            default:
              message = "[" + e.type + "]";
          }
          document.getElementById("status").innerHTML += e.type + ": " + message + "\n";
          //console.log(message);
          setStatus(message);
      }


      var appcache = window.applicationCache;
      appcache.addEventListener('cached', logEvent, false);
      appcache.addEventListener('checking', logEvent, false);
      appcache.addEventListener('downloading', logEvent, false);
      appcache.addEventListener('error', logEvent, false);
      appcache.addEventListener('noupdate', logEvent, false);
      appcache.addEventListener('obsolete', logEvent, false);
      appcache.addEventListener('progress', logEvent, false);
      appcache.addEventListener('updateready', logEvent, false);


    </script>



  </body>
</html>

Open in new window



The problem i'm having is that the first time the page is launched as a webapp it doesnt run the progress bar.... I only get as far as CHECKING and DOWNLOADING but i dont get any PROGRESS.

cache problem
If i look at the debugger on safari is shows the data increasing so it seems to be caching.

No other caching status's get run so I have to close safari and reopen the webapp...

When I close the webapp and reload it, it runs the progress bar as expected. After that, when ever i update the cachemanifest file the progress car works fine.

The problem seems to Safari.

Any ideas??
0
 
LVL 43

Expert Comment

by:Rob
ID: 40019202
It is strange but my first thought is you have a lot more going on in your cacher.html than I did.  Before you start modifying that page too much, put the iframe at the top of the body element.  If that makes no difference then remove all the javascript / jquery, script tags, link tags and see if that makes a difference.  If so, add them back one by one until you find the culprit.  My gut says there's just too much going on.  It works on subsequent times because the browser has already cached your cacher.html file.
0
Is Your Team Achieving Their Full Potential?

74% of employees feel they are not achieving their full potential. With Linux Academy, not only will you strengthen your team's core competencies but also their knowledge of of the newest IT topics.

With new material every week, we'll make sure that you stay ahead of the game.

 

Author Comment

by:Steve Tinsley
ID: 40019523
Hi Rob,

After a little more playing i discovered that is was my HTML tag at the top of the cacher.html page that was causing the problem.

When it was like this:
<html lang="en" manifest="offline.manifest">
it failed... But when it was:
<html>
it worked.

So im guessing I dont need the manifest file at the top of that page....

---------------

Next (and hopefully final) problem.

The webapp (fullscreen) is caching 100mb of videos as well as a a few other images and html etc...

When the webapp caches for the first time it gets to 99% and fails. It gives the user the option to retry and then it completes.

This only happens on iPad Safari and not Chrome.

It appears to happen when the cache totals to more then 25mb. But it still goes through all the files (as I can see a PROGRESS for each file.)

When you click try again is caches correctly and works happy from there on.

Any Ideas?
0
 
LVL 43

Expert Comment

by:Rob
ID: 40021536
Oh of course... the manifest is referenced in the iframe...*smacks forehead*
As for your other Issue, have you opened the developer tools to see if there are any errors reported in the console? I still suspect part of the Dom isn't ready when the cache completes but we'd need to confirm that via the console in dev tools
0
 

Author Comment

by:Steve Tinsley
ID: 40022121
I've requested that this question be closed as follows:

Accepted answer: 0 points for sjtinsley83's comment #a40018518

for the following reason:

Hi Rob,
I had another page which was redirecting to the cacher.html page automatically (if the webapp was in full screen / running ios7 / running on ipad etc). I decided to put a link on that page instead, and it works perfectly.
Its running like a dream now!
Thanks for all the help.
Steve
0
 

Author Closing Comment

by:Steve Tinsley
ID: 40022122
Hi Rob,
I had another page which was redirecting to the cacher.html page automatically (if the webapp was in full screen / running ios7 / running on ipad etc). I decided to put a link on that page instead, and it works perfectly.
Its running like a dream now!
Thanks for all the help.
Steve
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Not sure what the best email signature size is? Are you worried about email signature image size? Follow this best practice guide.
Finding original email is quite difficult due to their duplicates. From this article, you will come to know why multiple duplicates of same emails appear and how to delete duplicate emails from Outlook securely and instantly while vital emails remai…
In this tutorial viewers will learn how to style elements, such a divs, with a "drop shadow" effect using the CSS box-shadow property Start with a normal styled element, such as a div.: In the element's style, type the box shadow property: "box-shad…
Video by: Mark
This lesson goes over how to construct ordered and unordered lists and how to create hyperlinks.
Suggested Courses

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question