I wanted to make my website mobile and offline friendly. The mobile friendliness is already there. Thanks to Hugo, this website is very performant. The page designs are also mobile friendly.

However, there wasn’t a good option for offline use. I had a service worker implemented already. It would cache any file that the user visited. But that could accumulate to be a lot of pages cached. I didn’t want that to happen for the user. I wanted the user to be able to control which pages they cached.

At one point I realized that I could use the JS Cache API in normal scripts! My mind started to roll. This could work! I downloaded some icons from Feather Icons. I placed those icons in the top right hand corner of each page. Then I set up the following script for each page.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const trash = document.querySelector(".trash");
const download = document.querySelector(".download");

trash.style.display = "none";
download.style.display = "none";

// refer to service worker for cache name.
const APP_CACHE = caches.open("blog_cache");

download.addEventListener("click", evt => {
    APP_CACHE.then(cache => {
        cache.add(window.location.pathname);
        trash.style.display = "block";
        download.style.display = "none";
    });
});

trash.addEventListener("click", evt => {
    APP_CACHE.then(cache => {
        const CACHE_KEYS = cache.keys();
        CACHE_KEYS.then(keyList => {
            const itemToDelete = 
                keyList.find(key => key.url === window.location.href);
            cache.delete(itemToDelete);
            trash.style.display = "none";
            download.style.display = "block";
        });
    });
});

APP_CACHE.then(cache => {
    const CACHE_KEYS = cache.keys();
    CACHE_KEYS.then(keyList => {
        const existPageInCache = 
            keyList.find(key => key.url === window.location.href);

        if (existPageInCache) {
            trash.style.display = "block";
        } else {
            download.style.display = "block";
        }
    });
});

For this page downloader script to work, the cache name has to be the same name as what is set up in the service worker. The service worker could serve any cached files that the user has already cached by their choice. The rest of the script is simple. Add click events to each icon container, and those click events may place the page in cache or remove the page from cache. Those click events will also reverse the icons as needed. The end of the script will deterrmine if this page is cached or not so that the script can display the right icon.

I have my own custom hugo theme called Atomic Duck. I am a little bit inspired by ducks. Maybe I can explain Atomic Duck in another post! I should.

Anyway, this downloader script was placed within Atomic Duck, so that I can use this same thing across many other sites that I am managing. And since I put this section of code with the theme, I surrounded the downloader script with a conditional from the developer’s configuration file. If the developer wants to use it, add downloader = true to the configuration! And a service worker too.

1
2
3
4
5
{{ if .Site.Params.downloader }}

    //downloader script

{{ end }}

Yeah I should definitely explain my Hugo theme in another post.

I like this. I like Hugo. Static Site Generators are a for real game changer in handling static content. If you can be creative, there is so much to take advantage of with Static Site Generators.