Stop The Tories .Vote
A great practical website to help you vote tactically in the upcoming local elections.
A great practical website to help you vote tactically in the upcoming local elections.
This is a very nifty use of a service worker—choose a local folder that you want to navigate using HTTP rather than the file system.
When I was speaking at conferences last year about service workers, I’d introduce the Cache API. I wanted some way of explaining the difference between caching and other kinds of storage.
The way I explained was that, while you might store stuff for a long time, you’d only cache stuff that you knew you were going to need again. So according to that definition, when you make a backup of your hard drive, that’s not caching …becuase you hope you’ll never need to use the backup.
But that explanation never sat well with me. Then more recently, I was chatting with Amber about caching. Once again, we trying to define the difference between, say, the Cache API and things like LocalStorage and IndexedDB. At some point, we realised the fundamental difference: caches are for copies.
Think about it. If you store something in LocalStorage or IndexedDB, that’s the canonical home for that data. But anything you put into a cache must be a copy of something that exists elsewhere. That’s true of the Cache API, the browser cache, and caches on the server. An item in one of those caches is never the original—it’s always a copy of something that has a canonical home elsewhere.
By that definition, backing up your hard drive definitely is caching.
Anyway, I was glad to finally have a working definition to differentiate between caching and storing.
Collusion between three separate services owned by the same company: the Google search engine, the YouTube website, and the Chrome web browser.
Gosh, this kind of information could be really damaging if there were, say, antitrust proceedings initiated.
In the meantime, use Firefox
I added a long-overdue enhancement to The Session recently. Here’s the scenario…
You’re on a web page with a comment form. You type your well-considered thoughts into a textarea
field. But then something happens. Maybe you accidentally navigate away from the page or maybe your network connection goes down right when you try to submit the form.
This is a textbook case for storing data locally on the user’s device …at least until it has safely been transmitted to the server. So that’s what I set about doing.
My first decision was choosing how to store the data locally. There are multiple APIs available: sessionStorage
, IndexedDB
, localStorage
. It was clear that sessionStorage
wasn’t right for this particular use case: I needed the data to be saved across browser sessions. So it was down to IndexedDB
or localStorage
. IndexedDB
is the more versatile and powerful—because it’s asynchronous—but localStorage
is nice and straightforward so I decided on that. I’m not sure if that was the right decision though.
Alright, so I’m going to store the contents of a form in localStorage
. It accepts key/value pairs. I’ll make the key the current URL. The value will be the contents of that textarea
. I can store other form fields too. Even though localStorage
technically only stores one value, that value can be a JSON object so in reality you can store multiple values with one key (just remember to parse the JSON when you retrieve it).
Now I know what I’m going to store (the textarea
contents) and how I’m going to store it (localStorage
). The next question is when should I do it?
I could play it safe and store the comment whenever the user presses a key within the textarea
. But that seems like overkill. It would be more efficient to only save when the user leaves the current page for any reason.
Alright then, I’ll use the unload
event. No! Bad Jeremy! If I use that then the browser can’t reliably add the current page to the cache it uses for faster back-forwards navigations. The page life cycle is complicated.
So beforeunload
then? Well, maybe. But modern browsers also support a pagehide
event that looks like a better option.
In either case, just adding a listener for the event could screw up the caching of the page for back-forwards navigations. I should only listen for the event if I know that I need to store the contents of the textarea
. And in order to know if the user has interacted with the textarea
, I’m back to listening for key presses again.
But wait a minute! I don’t have to listen for every key press. If the user has typed anything, that’s enough for me. I only need to listen for the first key press in the textarea
.
Handily, addEventListener
accepts an object of options. One of those options is called “once
”. If I set that to true
, then the event listener is only fired once.
So I set up a cascade of event listeners. If the user types anything into the textarea
, that fires an event listener (just once) that then adds the event listener for when the page is unloaded—and that’s when the textarea
contents are put into localStorage
.
I’ve abstracted my code into a gist. Here’s what it does:
localStorage
, bail out.localStorage
key to be the current URL.textarea
with the value in localStorage
.textarea
in localStorage
but don’t call the function yet.textarea
, start listening for the page being unloaded.textarea
in localStorage
.localStorage
for the current URL.That last step isn’t something I’m doing on The Session. Instead I’m relying on getting something back from the server to indicate that the form was successfully submitted. If you can do something like that, I’d recommend that instead of listening to the form submission event. After all, something could still go wrong between the form being submitted and the data being received by the server.
Still, this bit of code is better than nothing. Remember, it’s intended as an enhancement. You should be able to drop it into any project and improve the user experience a little bit. Ideally, no one will ever notice it’s there—it’s the kind of enhancement that only kicks in when something goes wrong. A little smidgen of resilient web design. A defensive enhancement.
This is a great case study of the excellent California COVID-19 response site. Accessibility and performance are the watchwords here.
Want to know their secret weapon?
A $20 device running Android 9, with no contract commitment has been one of the most useful and effective tools in our effort to be accessible.
Leaner, faster sites benefit everybody, but making sure your applications run smoothly on low-end hardware makes a massive difference for those users.
The cloud gives us collaboration, but old-fashioned apps give us ownership. Can’t we have the best of both worlds?
We would like both the convenient cross-device access and real-time collaboration provided by cloud apps, and also the personal ownership of your own data embodied by “old-fashioned” software.
This is a very in-depth look at the mindset and the challenges involved in building truly local-first software—something that Tantek has also been thinking about.
Fellow Brightonians, here’s a handy one-stop shop for all the places doing deliveries right now, generated from this spreadsheet by Chris Boakes.
How are you doing? Are you holding up okay?
It’s okay if you’re not. This is a tough time.
It’s very easy to become despondent about the state of the world. If you tend to lean towards pessimism, The Situation certainly seems to be validating your worldview right now.
I’m finding that The Situation is also a kind of Rorschach test. If you’ve always felt that humanity wasn’t deserving of your faith—that “we are the virus”—then there’s plenty happening right now to bolster that opinion. But if you’ve always thought that human beings are fundamentally good and decent, there’s just as much happening to reinforce that viewpoint.
I’ve noticed concentric circles of feelings tied to geography—positive in the centre, and very negative at the edges. What I mean is, if you look at what’s happening in your building and your street, it’s quite amazing how people are pulling together:
Our street (and the guy who runs the nearby corner store) is self-organizing so that everyone’s looking out for each other, checking up on elderly and self-isolating folks, sharing contact details, picking up shopping if necessary, and generally just being good humans.
This goodwill extends just about to the level of city mayorships. But once you look further than that, things turn increasingly sour. At the country level, incompetence and mismanagement seem to be the order of the day. And once you expand out to the whole world, who can blame you for feeling overwhelmed with despair?
But the world is made up of countries, and countries are made up of communities, and these communities are made up of people who are pulling together and helping one another.
Best of all, you can absolutely be part of this wonderful effort. In normal times, civic activism would require you to take action, get out there, and march in the streets. Now you can be a local hero by staying at home.
That’s it. Stay inside, resist the urge to congregate, and chat to your friends and relatives online instead. If you do that, you are being a most excellent human being—the kind that restores your faith in humanity.
I know it feels grim and overwhelming but, again, look at what’s triggering those feelings—is it the national news? International? I know it’s important to stay informed about the big picture—this is a global pandemic, after all—but don’t lose sight of what’s close to hand. Look closer to home and you’ll see the helpers—heck, you are one of the helpers.
On Ev’s blog, Fiona Cameron Lister quotes the president of the Italian Society of Psychiatrists:
Fear of an epidemic is as old as mankind itself. In this case its effect is amplified by incomplete, even false information which has caused public confidence in our institutions to collapse.
She points out that the media are in the business of amplifying the outliers of negative behaviour—panic buying, greed, and worst-case scenarios. But she goes on to say:
It doesn’t take much to start a panic and we are teetering on the brink.
Not to be the “well, actually” guy but …well, actually…
That view of humanity as being poised on the brink of mass panic is the common consensus viewpoint; it even influences public policy. But the data doesn’t support this conclusion. (If you want details, I highly recommend reading Critical Mass: How One Thing Leads to Another by Philip Ball.) Thinking of ordinary people as being one emergency away from panicking is itself giving into fear.
I guess what I’m saying is, if you’re feeling misanthropic about your fellow humans right now, try rebalancing your intake. Yes, it’s good to keep yourself informed about national and global events, but make sure to give plenty of attention to the local level too. You may just find your heart warming and your spirits lifting.
After all, you’re a good person, right? And you probably also think of yourself as a fairly ordinary person, right? So if you’re doing the right thing—making small sacrifices and being concerned for your neighbours—then logic dictates that most other people are too.
When this is over, I hope we will be proud of how well we loved one another.
Tantek documents the features he wants his posting interface to have.
This is brilliant technique by Remy!
If you’ve got a custom offline page that lists previously-visited pages (like I do on my site), you don’t have to choose between localStorage
or IndexedDB
—you can read the metadata straight from the HTML of the cached pages instead!
This seems forehead-smackingly obvious in hindsight. I’m totally stealing this.
- Obey the Law of Locality
- ABD: Anything But Dropdowns
- Pass the Squint Test
- Teach by example
Okay, I knew about the Python shortcut—I mentioned it in Going Offline—but I had no idea it was so easy to do the same thing for PHP. This is a bit of a revelation for me!
Once in the desired directory, run:
php -S localhost:2222
Now you can go to “localhost:2222” in your browser, and if you have an index.html or .php file in your root directory, you’re in business.
Hui Jing describes her motivation for creating the lovely Penang Hokkien site:
People who grew up their whole lives in a community that spoke the same mother tongue as themselves would probably find this hard to relate to, but it really was something else to hear my mother tongue streaming out of the speakers of my computer.
She ends with an impassioned call for more local language websites:
If the Internet is meant to enhance the free flow of information and ideas across the world, then creation of content on the web should not largely be limited to English-speaking communities.
A clever use of localStorage
to stop data from being lost when your visitors are offline.
A really deep dive into the lang
attribute, and the :lang()
pseudo-class (hitherto unknown to me). This is all proving really useful for a little side project I’m working on.
A directory of the regular science, technology, and creative events happening in Brighton.
My back-up strategy is similar to Brendan’s (using Super Duper and Backblaze):
In backup parlance there’s a thing called 3-2-1. That is, you should three copies of your files — two locally on different devices and one off site.
But I only do my local back-ups once a week (eek!)—I should do better.
A new webby meet-up in Brighton organised by Davs Howard. It’ll be one the first Thursday of the month at The Joker. I often find myself in The Joker on Thursday nights anyway (for the wings) so I’ll be heading along to the inaugural event on February 1st.
Practical advice from Ire on localising web pages.