- A long Twitter thread about how strange Facebook's HTML is with lots of arguments about generating HTML vs. readability of source code and performance
- Playwright is a Node.js module that allows you to remotely drive Chromium, Firefox and Webkit browsers. Great for automated testing.
- CSDB - The Commodore 64 Scene Database - like IMDB, but for Commodore 64 Demoscene stuff - not changed since 1997 or so and my inspiration to do something about that.
- The CSDB Preview Bookmarklet adds a preview into this page
- Overrides in Chromium Devtools
Using fetch() to check if a png image exists and load a gif if it doesn't. Using HEAD
means you don't load the image, you just check that it exists.
let url = `https://csdb.dk/gfx/releases/${folderid}/${id}.png`;
fetch(url, { method: 'HEAD' })
.then(res => {
if (res.ok) {
out = `<img src="${url}" alt="">`;
} else {
url = url.replace('.png','.gif');
out = `<img src="${url}" alt="">`;
}
}).catch(err => console.log('Error:', err));
Got some HTML soup you want to work with? Use the HTML5 DOM parser in JavaScript instead of RegEx:
let parser = new DOMParser();
let parsed = parser.parseFromString(html, 'text/html');
Hosting projects on GitHub Pages is a lot easier now than it used to be
Bookmarklets are a simple way to inject content into a third party page. Here's the code to use as the link url to inject the code:
javascript:(
function(){
document.body.appendChild(document.createElement('script'))
.src='https://codepo8.github.io/csdb-preview-bookmarklet/csdb-preview.js';
}
)();
- The Alt Text Rollover Bookmarklet injects a way to easily see if an image has an alternative text or not
- A “right-click to show alt text” browser extension available for Microsoft Edge and Firefox
A quick plain vanilla JS example of a web component <halfstack-nametag>
:
Usage in HTML:
<halfstack-nametag text="Dylan" colour="green"></halfstack-nametag>
<halfstack-nametag text="Chris"></halfstack-nametag>
Usage in JavaScript:
let nametag = document.createElement('halfstack-nametag');
document.body.appendChild(nametag);
nametag.setAttribute('text', "Chris");
nametag.setAttribute('colour' ,"blue");
Full source code of the component:
class halfstacknametag extends HTMLElement {
constructor () { super() }
static get observedAttributes() { return ['text','colour'] }
get text() {return this.hasAttribute('text');}
get colour() {return this.hasAttribute('colour');}
attributeChangedCallback() {
if(this.shadowRoot){
let tag = this.shadowRoot.querySelector('div');
let name = this.shadowRoot.querySelector('h2');
name.innerHTML = this.text ? this.getAttribute('text') : '';
if (this.colour) { tag.style.background = this.getAttribute('colour')}
}
}
connectedCallback () {
let shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<style>
div {
border-radius: 10px;font-family: impact;
background: ${this.getAttribute('colour')||'firebrick'};
padding: 5px; margin: 10px 0;max-width: 40vw;
}
h1 {color:#fff;padding:5px 10px;}
h2 {border-radius: 10px;color: #000;background: #fff;
margin: 5px 10px;padding :10px}
</style>
<div>
<h1>Halfstack</h1><h2>${this.getAttribute('text')}</h2>
</div>
`;
}
}
window.customElements.define('halfstack-nametag', halfstacknametag);
-
"The internet's biggest collection of open source dog pictures" as an API.
-
The Network Console experiment in Microsoft Edge DevTools is a straight forward way to play with APIS and to inspect any network request in more detail.
-
The Dog Browser I wrote.
-
Using a Datalist you can turn any
input
into an autocomplete:<form> <label for="breed">Dog breed:</label> <input list="allbreeds" name="breed" id="breed"></input> <datalist id="allbreeds"> <!-- … --> </datalist> </form>
Populating the datalist using the DOG api:
const getbreeds = _ => { fetch('https://dog.ceo/api/breeds/list/all') .then(response => response.json()) .then(data => { breeds = data.message; seedbreedsform(); }) }; const seedbreedsform = _ => { let out = ''; Object.keys(breeds).forEach(b => { out += `<option value="${ucfirst(b)}"/>`; if (breeds[b].length > 0) { breeds[b].forEach(s => { out += `<option value="${ucfirst(b)} - ${ucfirst(s)}"/>`; }); } }); document.querySelector('#allbreeds').innerHTML = out; };
You may wonder what the
ucfirst
is about. Well, one drawback of datalist is that you can't style it. The Dog API returns the names of the breeds in all lowercase. When using the dependent dropdowns, you can fix that in the CSS:#breed, #sub, button span { text-transform: capitalize; }
This, however doesn't work with datalist(yet), so I needed to do that in JavaScript:
const ucfirst = str => { return str.charAt(0).toUpperCase() + str.slice(1); }
There is also now a more detailed blog post about the dog browser on my blog.
Event Delegation is a trick I've been using since around 2006. It allows you to assign one event listener to a collection of elements and check for their features to act accordingly.
Say you have the following HTML:
<ul id="dogs">
<li><a href="#dog1">Dog1</a></li>
<li><a href="#dog2">Dog2</a></li>
<li><a href="#dog3">Dog3</a></li>
<li><a href="#dog4">Dog4</a></li>
<li><a href="#dog5">Dog5</a></li>
<li><a href="#dog6">Dog6</a></li>
<li><a href="#dog7">Dog7</a></li>
<li><a href="#dog8">Dog8</a></li>
<li><a href="#dog9">Dog9</a></li>
<li><a href="#dog10">Dog10</a></li>
</ul>
You can use the following JavaScript to intercept all these links and code your own actions.
The really useful thing here is that the content of the <ul>
can change any time and you wouldn't need to
re-index and re-apply your functionality. As the event is listening on the parent node all the children will report
once they are available.
document.querySelector('#dogs').
addEventListener('click', e => {
// What was clicked?
let t = e.target;
// does it have an href?
if (t.href) {
console.log(t.innerText); // f.e. "Dog5"
}
// if the list item was clicked
if (t.nodeName === 'LI') {
// print out the link
console.log(t.innerHTML);
}
e.preventDefault(); // Don't follow the links
});
CSS has a lot of excellent features that allows you to avoid having to code functionality yourself. Say for example you want to have a message in between paragraphs in your document:
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Vitae voluptate …</p>
<div class="message"></div>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Vitae voluptate …</p>
Normally what you'd do is to style it with all padding, margin and such and then probably add a class "hidden" to show and hide it. A simpler way may be to use the :empty
selector to hide it. That way empty elements like the one above will not be shown.
.message {
margin: 1em;
border: 2px solid firebrick;
padding:.5em 1em;
color: maroon;
}
.message:empty {
display: none;
}
/* For accessible hiding, see
https://zellwk.com/blog/hide-content-accessibly/
*/
You can show the message by adding a text to it and hide it by removing it, no need to do any styling or class switching in JavaScript.
You can also use attribute selectors to define different states of elements, no need to change the styles or add classes.
For example, to add a red border to all images with an empty alt
attribute and to add a blinking border to all those without an alternative text, all you need is this:
<div id="images">
<img src="https://images.dog.ceo/breeds/samoyed/n02111889_2136.jpg"
alt="Samoyed dog">
<img src="https://images.dog.ceo/breeds/basenji/n02110806_238.jpg"
alt="">
<img src="https://images.dog.ceo/breeds/basenji/n02110806_238.jpg">
<img src="https://images.dog.ceo/breeds/samoyed/n02111889_2136.jpg"
alt="Samoyed dog">
</div>
img[alt=""]{
border: 10px solid firebrick;
}
img:not([alt]) {
border: 50px solid maroon;
animation: fixyourimage .5s step-end infinite alternate;
}
@keyframes fixyourimage {
50% { border-color: firebrick; }
}
By using sensible markup and flex
you can turn basic HTML into something impressive. Take the following HTML:
<div id="browsers">
<input type="radio" checked id="r1" name="browser">
<label for="r1">Microsoft Edge</label>
<input type="radio" id="r2" name="browser">
<label for="r2">Firefox</label>
<input type="radio" id="r3" name="browser">
<label for="r3">Safari</label>
<input type="radio" id="r4" name="browser">
<label for="r4">Chrome</label>
<input type="radio" id="r5" name="browser">
<label for="r5">Brave</label>
</div>
Radio buttons sharing the same name automatically only allow the user to choose one at a time. They also get announced to a screenreader as a group. By using a label connecting the text to the checkbox, we not only make it accessible to screenreaders but we also make it easier for people to hit it - you can click on the text and the radio button gets checked.
Now onto the CSS:
#browsers {
font-family: Arial, Helvetica, sans-serif;
margin: 2em;
min-height: 50px;
/* position needed to hide the radio buttons */
position: relative;
/*
align the items with 10px gap and make them
use the whole space
*/
display: flex;
column-gap: 10px;
align-items: stretch;
}
#browsers label {
border-radius: 10px;
text-align: center;
flex: 1;
line-height: 50px;
}
/* Don't show the radio buttons */
#browsers [type=radio] {
position: absolute;
left: -50vw;
}
/* Each label following a radion button… */
#browsers [type=radio] + label {
background:grey;
color: #fff;
}
/* Each label next to a checked radio button… */
#browsers [type=radio]:checked + label {
background:darkolivegreen;
color: #fff;
}
<ul class="fullclick">
<li>
<h2>Heading</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam
blanditiis molestiae atque maxime nulla quoipsum obcaecati?</p>
<a href="#1">Link #1</a>
</li>
<li>
<h2>Heading</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam
blanditiis molestiae atque maxime nulla quoipsum obcaecati?</p>
<a href="#2">Link #2</a>
</li>
</ul>
.fullclick {
font-family: Arial, Helvetica, sans-serif;
margin: 3em 0;
padding: 0;
}
.fullclick a {
text-align: right;
display: block;
}
.fullclick li {
list-style: none;
margin: .5em 0;
padding: 5px;
background: peachpuff;
/* position needed to allow for overlay */
position: relative;
}
/*
create an overlay after the link with the
same dimensions as the list item.
*/
.fullclick li a::after {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
content: '';
}
/*
If any child element of the list has focus
change the background
*/
.fullclick li:focus-within {
background:mediumorchid;
}