HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<!-- Using a picture element to fetch the smallest supported image format - .avif is about half the size of a .jpg -->
<aside>
<picture>
<!-- Prevent downloading desktop image on mobile -->
<source media="(max-width:59.99em)" srcset="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==">
<!-- .avif < .webp < .jpg -->
<source srcset=https://websemantics.uk/swanage-blues/img/swanage-blues.5.avif type=image/avif>
<source srcset=https://websemantics.uk/swanage-blues/img/swanage-blues.5.webp type=image/webp>
<!-- fetchPriority works very well in Chrome! -->
<img fetchpriority=high onload="this.classList.add('show')" src=https://websemantics.uk/swanage-blues/img/swanage-blues.5.jpg width=1536 height=1536 alt="Swan and an electric guitar in dark tones of blue">
</picture>
</aside>
<header>
<div>
<h1>The 37th Swanage Blues Festival <span>Interactive Schedule</span> <span><time datetime=2023-03-02>2</time>–<time datetime=2023-03-05>5 March 2023</time></span></h1>
<!-- Codepen include latest -->
[[[https://codepen.io/2kool2/pen/zYymQMP]]]
</div>
</header>
<main>
<div>
<div id=content>
<!-- Generating data table, rather than flat HTML, significantly reduced the HTML file size, far less repetition -->
<!-- Added empty containers to reduce CLS (to 0), and improve TBT too -->
<!-- Note: The JS doesn't rely upon these containers existing, or being the correct number, but it really helps! -->
<details>
<summary></summary>
</details>
<details>
<summary></summary>
</details>
<details>
<summary></summary>
</details>
<details>
<summary></summary>
</details>
</div>
<details>
<summary id=map>
<div>Swanage Venues</div>
</summary>
<div>
<!-- Don't load nonessential data until it is required! -->
<iframe aria-labelledby=map></iframe>
</div>
</details>
</div>
</main>
<footer>
<!-- Optimised and inlined SVGs for performance -->
<div>
<p>Proposed schedule and subject to change. Last update: <time datetime=2023-02-21>21/02/2023</time> v1.04</p>
<ul role=list class=flex-wrap>
<li><a href="https://www.facebook.com/pages/Swanage-Blues-Festival/189492404413425"><svg aria-hidden=true viewBox="0 0 512 512">
<path d="m356 330 11-74h-71v-48c0-20 10-40 42-40h32v-63s-29-5-57-5c-59 0-97 35-97 100v56h-65v74h65v182h80V330h60z" />
</svg> Facebook</a></li>
<li><a href="https://twitter.com/swanageblues"><svg aria-hidden=true viewBox="0 0 512 512">
<path d="M437 152a72 72 0 0 1-40 12 72 72 0 0 0 32-40 72 72 0 0 1-45 17 72 72 0 0 0-122 65 200 200 0 0 1-145-74 72 72 0 0 0 22 94 72 72 0 0 1-32-7 72 72 0 0 0 56 69 72 72 0 0 1-32 1 72 72 0 0 0 67 50 200 200 0 0 1-105 29 200 200 0 0 0 309-179 200 200 0 0 0 35-37" />
</svg> Twitter</a></li>
<li><a href="https://www.swanage-blues.org/"><svg aria-hidden=true viewBox="0 0 317 237"><path d="M230 18c14-1 44 6 35 42l-4 10v11l1 1v12l-3-1c-5-8-9-17-12-28l-15-19c-21 2-6 42-6 42 8 20 57 43 58 88 0 3 6 33-29 38l-22 1s-104 0-131-3c-26-3-57-22-71-36l2-4 5-1-9-7c-5-5-7-12-6-23l25 6s-10-4-7-6c15-9 31 7 31 7 1-10 22-5 22-5a53 53 0 0 1-18-32c20-2 74 0 74 0s-49-4-63-13c-2-1-1-6-1-6l16 3c64 5 96 19 131 60l4 1c3-1 3-3 2-8l-5-10c-38-52-42-55-40-84 2-33 36-36 36-36Z"/></svg> Swanage Blues</a></li>
</ul>
<p>Design & code: <a href="https://www.linkedin.com/in/mikefoskett">Mike Foskett</a>  for <a href="https://websemantics.uk/">webSemantics</a></p>
</div>
</footer>
<!-- <script defer src="https://codepen.io/2kool2/pen/ZEMGxwg.js"></script> -->
/* Compress with: https://cssminifier.org/ */
:root {
/* 1.125rem(18px) @ 40.75rem(652px) increasing to 1.6875rem(27px) @ 120rem(1920px) */
font-size: clamp(1.125rem, calc(1.125rem + (1.6875 - 1.125) * ((100vw - 40.75rem) / (120 - 40.75))), 1.6875rem)
/* Where: calc = min_font_size_in_rem + (max_font_size - min_font_size) * ((100vw - min_viewport_in_rem) / (max_viewport - min_viewport)) */
}
html {
--sans-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif;
--content-width: 70ch;
--v-space: 1rem;
--v-space-0_25: calc(var(--v-space) / 4);
--v-space-0_5: calc(var(--v-space) / 2);
--v-space-2: calc(var(--v-space) * 2);
--h-space: 8px;
--h-space-0_5: calc(var(--h-space) / 2);
--h-space-0_25: calc(var(--h-space) / 4);
--bg: #1a1a1a;
--accent-bg: #292929;
--bg-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2056 2056'%3E%3Cfilter id='b73'%3E%3CfeTurbulence type='fractalnoise' baseFrequency='.3' result='n73'/%3E%3CfeDiffuseLighting in='n73' lighting-color='hsl(0,0%,14%)'%3E%3CfeDistantLight azimuth='30' elevation='50'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='100%' height='100%' filter='url(%23b73)'/%3E%3C/svg%3E");
--border: #6666;
--border-gradient: linear-gradient(140deg, #ff09, #f609);
--linear-gradient-1: linear-gradient(-3deg,#0a0a0a, #3a3a3a, #222);
--linear-gradient-2: linear-gradient(-1deg,#0a0a0a,#3a3a3a,#222);
--linear-gradient-3: linear-gradient(-0.7deg,#000,#3337,#111);
--accent: #f90;
--accent-hover: #fe6;
--selectionColor: #000;
--selectionBg: #cdf;
--FocusRing-outline-color: #ee0;
--highlight-bg: #000;
--highlight-color: #fff;
background-color: var(--bg);
color: #ddd;
color-scheme: dark;
font-family: var(--sans-font);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
*,
:after,
:before {
box-sizing: border-box;
margin: 0;
}
body {
background-image: var(--bg-image);
hyphens: auto;
line-height: 1.7;
min-height: 0;
overflow-wrap: break-word;
text-shadow: 0 1px 3px #000, 0 0 4px #000;
word-break: break-word;
}
picture {
display: none;
}
@media(min-width:40em) {
body {
--h-space: 1rem;
hyphens: initial;
}
}
@media(min-width:60em) {
body {
--accent-bg: #29292966;
--bg: #1a1a1a99;
--border-gradient: linear-gradient(140deg,#ff06,#f609);
--linear-gradient-1: linear-gradient(-3deg,#0a0a0a55,#3a3a3acc,#2229);
--linear-gradient-2: linear-gradient(-1deg,#0a0a0a77,#3a3a3a99,#222c);
position: relative;
}
picture {
display: block;
height: 100%;
opacity: .8;
overflow: hidden;
position: absolute;
width: 100%;
}
picture > img {
filter: none;
left: 50%;
max-height: 1536px;
max-width: 1536px;
position: absolute;
transform: translate3d(-50%,0,0);
width: 100%;
transition-duration: .5s;
}
}
header,
main,
footer {
background: var(--linear-gradient-1);
border-top: 1px solid var(--border);
border-image: var(--border-gradient) 1;
position: relative;
}
main {
background: transparent;
}
:is(header, main, footer) > div {
max-width: var(--content-width);
margin: 0 auto;
padding: var(--v-space)var(--h-space);
text-align: center;
}
h1,
summary {
font-weight: 400;
line-height: calc(4px + 2ex);
}
h1 {
color: #bbb;
font-size: 1.25rem;
letter-spacing: -0.03em;
}
h1 > * {
display: block;
margin-top: var(--v-space-0_25);
}
h1 > :first-child {
color: #eee;
font-size: 1.5rem;
}
h1 > :last-child {
font-size: 1.1rem;
}
::marker,
a,
a:visited {
color: var(--accent);
display: inline-block;
text-decoration-skip-ink: auto;
}
a,
a > * {
transition: all .3s ease-out;
}
a:is(:focus, :hover) {
color: var(--accent-hover);
text-decoration-color: #0000;
}
a[rel=external][target=_blank]:after {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='40'><path d='M28,4 39,4 39,15 M39,4 23,20 M28,9 7,9 7,34 35,34 35,15' fill='none' stroke='%23808080' stroke-width='3'/></svg>");
background-repeat: no-repeat;
background-size: 1em 1em;
content: "";
display: inline-block;
height: 1em;
margin: 0 0 0 .125em;
width: 1em;
}
button {
background-color: var(--bg);
border: 1px solid transparent;
border-radius: 0;
color: var(--accent);
font-size: inherit;
padding: var(--h-space-0_25) 0;
padding-left: calc(var(--h-space) / 4);
width: 100%;
}
button:is(:focus, :hover) {
--FocusRing-outline-offset: -2px;
border-image: linear-gradient(173deg, #ff0, #f60) 1;
color: var(--accent-hover);
cursor: pointer;
position: relative;
}
@media(min-width:20em) {
button:is(:focus, :hover) {
--FocusRing-outline-offset: 2px;
}
}
button:first-letter {
text-transform: capitalize;
}
details {
border: 1px solid var(--border);
border-image: var(--border-gradient) 1;
background: var(--accent-bg);
margin: var(--v-space) 0;
padding: 0;
text-align: left;
}
* + details {
margin-top: var(--v-space-2);
}
td details {
background-color: transparent;
border: 0;
margin: 0;
}
::-webkit-details-marker {
color: var(--accent);
}
summary {
--FocusRing-outline-offset: 3px;
background: var(--linear-gradient-2);
cursor: pointer;
display: list-item;
padding: var(--v-space-0_5)var(--v-space);
}
td summary {
background: inherit;
padding: 0;
}
td summary ~ * {
font-size: smaller;
}
summary > div {
display: inline-block;
pointer-events: none;
vertical-align: top;
width: calc(100% - 1.2em);
}
td summary > div {
margin-left: -4px;
width: calc(100% - 1em);
}
td details > div {
background-color: var(--bg);
border: 1px solid var(--border);
box-shadow: 0 0 4px black;
left: 0;
margin: 2px 14px;
padding: var(--v-space-0_5) var(--h-space);
position: absolute;
width: calc(100% - var(--h-space) * 3);
z-index: 1;
}
@media(min-width:30em) {
td details > div {
background-color: inherit;
border: 0;
box-shadow: none;
margin: var(--v-space-0_5) 0 var(--v-space-0_25);
position: initial;
padding: 0;
width: auto;
}
details button {
display: none;
}
}
@media(min-width:40em) {
td details > div {
padding: 0 var(--h-space-0_5);
}
}
td details > div * + * {
margin-top: var(--v-space-0_5);
}
details button {
border-color: var(--border);
}
img {
display: block;
height: auto;
margin: 0 auto;
max-width: 100%;
opacity: 0;
transition: opacity .3s ease-out;
}
img.show {
opacity: 1;
}
a,
button,
summary {
-ms-touch-action: manipulation;
touch-action: manipulation;
}
.responsive_wrap {
max-width: 100%;
margin: 0;
overflow: auto hidden;
}
@media(min-width:20em) {
.responsive_wrap {
overflow: initial;
}
}
table {
border-collapse: collapse;
min-width: 16rem;
width: 100%;
}
tr:nth-child(2n) {
background:var(--bg);
}
tr:nth-child(2n+1) {
background: var(--linear-gradient-3);
}
tr.current-time {
background: var(--highlight-bg);
color: var(--highlight-color);
}
tr.current-time > .time {
border-left: 4px solid var(--accent);
}
tr:last-child td {
border-bottom: 0;
}
th {
background: var(--accent-bg);
font-size: smaller;
letter-spacing: .02em;
padding: 0;
white-space: nowrap;
}
th,
td {
border-top: 1px solid var(--border);
}
th + th,
td + td {
border-left: 1px solid var(--border);
}
td {
letter-spacing: -.04em;
line-height: calc(6px + 2ex);
padding: var(--v-space-0_25)var(--h-space-0_5);
vertical-align: top;
}
.time {
min-width: 3.4rem;
}
.artist {
letter-spacing: 0;
width: 100%;
}
.venue {
color: #aaa;
min-width: 6.1em;
}
@media(min-width:40em) {
td {
padding: var(--v-space-0_5)var(--h-space-0_5);
}
.time {
min-width: 6em;
white-space: nowrap;
}
.artist {
min-width: 6em;
}
.venue {
max-width: 8.5em;
min-width: 7em;
white-space: nowrap;
}
}
@media(prefers-reduced-motion:no-preference) {
body {
--FocusRing-transition-duration: .3s;
}
}
:is(a[href], button, summary, .responsive_wrap) {
outline: transparent solid var(--FocusRing-outline-width, 2px);
outline-offset: var(--FocusRing-transition-offset, 5px);
transition: all var(--FocusRing-transition-duration, 0) ease-out;
}
:focus-visible,
:is(a[href], button, summary, .responsive_wrap):focus {
outline-color: var(--FocusRing-outline-color, #00f);
outline-offset: var(--FocusRing-outline-offset, 2px);
}
@supports selector(:focus-visible) {
:is(a[href], button, summary, .responsive_wrap):focus:not(:focus-visible) {
outline: 0;
}
}
iframe {
border: 0;
border-top: 1px solid var(--border);
display: block;
height: 90vh;
max-height: 90vh;
min-height: 300px;
width: 100%;
}
footer {
border-bottom: 1px solid var(--border);
font-size: smaller;
}
footer ul {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: space-evenly;
list-style: none;
padding: 0;
}
footer > div > * + * {
margin-top: var(--v-space);
}
footer a {
text-decoration: none;
}
footer svg {
background-color:var(--accent);
border-radius:4px;
display: inline-block;
fill:#fff;
height:2em;
vertical-align: middle;
width: 2em;
}
a:is(:hover, :focus) svg {
background-color: var(--accent-hover);
fill: #292929;
}
::selection {
background-color: var(--selectionBg);
color: var(--selectionColor);
opacity: 1;
text-shadow: none;
}
.-visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
white-space: nowrap;
width: 1px;
position: absolute;
overflow: hidden;
}
q {
font-style: italic;
font-weight: 500;
}
// https://try.terser.org/
// output: {quote_style: 1},
// console.clear();
const year = '2023';
const d = document;
const content = d.getElementById('content');
const dateDataFunctions = (_ => {
const datesArr=[
{
date:'Thursday 2nd March',
acts:[
{
time:'16:00',
artist:' Geoff\'s Jam',
venue:'Globe Inn'
},
{
time:'20:30',
artist:'The Million Dollar Bash',
venue:'The Legion'
},
{
time:'21:00',
artist:'Ray Drury & Jon Walsh',
venue:'Red Lion'
}
]
},
{
date:'Friday 3rd March',
acts:[
{
time:'14:00 -16:30',
artist:'Back Porch',
venue:'The Legion'
},
{
time:'14:00',
artist:'Open Mic with Andy Bradshaw',
venue:'Red Lion'
},
{
time:'15:00',
artist:'Robert Hokum',
venue:'White Swan'
},
{
time:'16:00 -18:00',
artist:'The Robin Bibi Band',
venue:'Showbar'
},
{
time:'17:30 -20:00',
artist:'Chicago 9 Rhythm & Blues Band',
venue:'Con Club'
},
{
time:'19:00',
artist:'Pete Harris & Ray Drury',
venue:'Tawny\'s'
},
{
time:'20:00',
artist:'Jon Storey Band',
venue:'Globe Inn'
},
{
time:'20:00',
artist:'The Fabulous Duck Brothers',
venue:'IoP Golf Club'
},
{
time:'20:30',
artist:'Zoë Schwarz Blue Commotion',
venue:'Grand Hotel'
},
{
time:'20:30',
artist:'Blue Touch',
venue:'The Legion'
},
{
time:'20:30 -23:00',
artist:'Vince Lee & the Big Combo',
venue:'Showbar'
},
{
time:'21:00',
artist:'Back Porch',
venue:'Herston Camping'
},
{
time:'21:00',
artist:'Tommy Allen Duo with Jon Vaughan',
venue:'Red Lion'
},
{
time:'21:00',
artist:'The Mustangs',
venue:'White Horse'
},
{
time:'21:00',
artist:'George Hall Trio',
venue:'White Swan'
}
]
},
{
date:'Saturday 4th March',
acts:[
{
time:'12:00',
artist:'Will Killeen',
venue:'The Centre'
},
{
time:'13:00',
artist:'Lee Signey',
venue:'The Centre'
},
{
time:'13:00 -15:30',
artist:'The Robin Bibi Band\'s Electric Jam Session',
venue:'Con Club'
},
{
time:'13:00',
artist:'Vince Lee & the Big Combo',
venue:'The Legion'
},
{
time:'14:00',
artist:'Liam Ward & Malcolm Thorp',
venue:'The Centre'
},
{
time:'14:00',
artist:'Lewis Cohen',
venue:'Greyhound'
},
{
time:'14:00',
artist:'Born Healer',
venue:'Herston Camping'
},
{
time:'14:00',
artist:'Open Mic with Andy Bradshaw',
venue:'Red Lion'
},
{
time:'14:00',
artist:'Thomas Heppell Band',
venue:'YHA'
},
{
time:'14:30',
artist:'Robert Hokum\'s Acoustic Blues Bonanza',
venue:'Grand Hotel'
},
{
time:'15:00',
artist:'Geoff Garbow Band',
venue:'White Swan'
},
{
time:'15:30',
artist:'Ben White & Thomas Lucas',
venue:'The Centre'
},
{
time:'16:00 -18:30',
artist:'The Fabulous Duck Brothers',
venue:'Showbar'
},
{
time:'16:30',
artist:'Gary Fletcher Trio',
venue:'The Centre'
},
{
time:'16:30',
artist:'Pete Harris Blues Band with Jon Vaughan & Ray Drury',
venue:'The Legion'
},
{
time:'17:30 -20:00',
artist:'Back Porch',
venue:'Con Club'
},
{
time:'19:00',
artist:'Lewis Cohen & Spencer Couzens',
venue:'Tawny\'s'
},
{
time:'22:00',
artist:'Jon Storey Band',
venue:'Globe Inn'
},
{
time:'20:30',
artist:'Robert Hokum\'s Electric Blues Bonanza',
venue:'Grand Hotel'
},
{
time:'20:30',
artist:'The Robin Bibi Band',
venue:'The Legion'
},
{
time:'20:30 -23:00',
artist:'Blue Touch',
venue:'Showbar'
},
{
time:'21:00',
artist:'Tommy Allen Duo with Ray Dury',
venue:'Herston Camping'
},
{
time:'21:00',
artist:'Isobel Thatcher Duo',
venue:'Red Lion'
},
{
time:'21:00',
artist:'The Milk Men',
venue:'White Horse'
},
{
time:'21:00',
artist:'Chicago 9 Rhythm & Blues Band',
venue:'White Swan'
}
]
},
{
date:'Sunday 5th March',
acts:[
{
time:'12:00',
artist:'Jonathan Townsend',
venue:'The Centre'
},
{
time:'13:00',
artist:'Greg Brice',
venue:'The Centre'
},
{
time:'13:00 -15:30',
artist:'Hugh Budden & the Blue Chords',
venue:'Con Club'
},
{
time:'13:00',
artist:'Open Mic with Andy Bradshaw',
venue:'Red Lion'
},
{
time:'14:00',
artist:'Ben White & Thomas Lucas',
venue:'Greyhound'
},
{
time:'14:00',
artist:'The Robin Bibi Band\'s Electric Jam Session',
venue:'The Legion'
},
{
time:'14:15',
artist:'Joff Watkins Duo',
venue:'The Centre'
},
{
time:'14:30 -17:00',
artist:'Vince Lee & Sophie Lord',
venue:'Grand Hotel'
},
{
time:'15:00',
artist:'Thomas Heppell Band',
venue:'Black Swan'
},
{
time:'15:00',
artist:'Tommy Allen Duo with Jon Vaughan',
venue:'White Swan'
},
{
time:'15:30',
artist:'Mark Harrison & Charles Benfield',
venue:'The Centre'
},
{
time:'16:30',
artist:'Fran McGillivray & Mike Burke',
venue:'The Centre'
},
{
time:'20:00',
artist:'Pete Harris & Jon Vaughan',
venue:'Red Lion'
},
{
time:'20:30 -23:00',
artist:'Hugh Budden & the Blue Chords',
venue:'Grand Hotel'
},
{
time:'20:30',
artist:'Tommy Allen Band',
venue:'The Legion'
}
]
}
];
function getDateFromString(dateString){
const dateArr = dateString.split(' ');
const date = new Date(Date.parse(`${dateArr[2]} ${parseInt(dateArr[1], 10)}, ${year}`));
const formatDate = date.toLocaleString('en-UK', {
dateStyle: 'short',
hour12: false
});
formatDateArr = formatDate.split('/');
return `${formatDateArr[2]}-${formatDateArr[1]}-${formatDateArr[0]}`;
}
function addSummary(details, summary, title) {
const div = d.createElement('div');
const time = d.createElement('time');
time.setAttribute('datetime', getDateFromString(title));
time.textContent = title;
div.appendChild(time);
summary.appendChild(div);
details.appendChild(summary);
return details;
}
function dayDetails(title, details) {
const container = details || d.createElement('details');
const summary = details ? details.querySelector('summary') : d.createElement('summary');
const div = d.createElement('div');
const time = d.createElement('time');
time.setAttribute('datetime', getDateFromString(title));
time.textContent = title;
div.appendChild(time);
summary.appendChild(div);
container.appendChild(summary);
return container;
}
const generateDates = (_ => {
const domDetails = content.querySelectorAll('details');
requestAnimationFrame(_ => {
const fragment = new DocumentFragment();
let count = 0;
for (const date of datesArr) {
const details = dayDetails(date.date, domDetails[count++]);
details.date = date;
fragment.appendChild(details);
}
content.appendChild(fragment);
});
})();
})();
const venueDataFunctions = (_ => {
const venuesArr = [
{
name: 'The Legion',
address: '150 High Street<br>BH19 2PA',
url: 'https://ul.waze.com/ul?place=ChIJUWWfK2wJc0gRpNf9siO6A4I&ll=50.60833330%2C-1.96583330'
},
{
name: 'Red Lion',
address: '63 High Street<br>BH19 2LY',
url: 'https://ul.waze.com/ul?place=ChIJDURTg2UJc0gRnNkGgrAf8ME&ll=50.60825080%2C-1.95841470'
},
{
name: 'White Swan',
address: '31 High Street<br>BH19 2LJ',
url: 'https://ul.waze.com/ul?place=ChIJ488Gq2UJc0gRxmYERQmRqM0&ll=50.60795970%2C-1.95672460'
},
{
name: 'Globe Inn',
address: '3 Bell St<br>BH19 2RY',
url: 'https://ul.waze.com/ul?place=ChIJ488Gq2UJc0gRxmYERQmRqM0&ll=50.60795970%2C-1.95672460'
},
{
name: 'Tawny\'s',
address: '52 High Street<br>BH19 2NX',
url: 'https://ul.waze.com/ul?place=ChIJzThYnWUJc0gRhNUBDbpzHhA&ll=50.60842930%2C-1.95846890'
},
{
name: 'Old Stables',
address: '37 Commercial Rd<br>BH19 1DF',
url: 'https://ul.waze.com/ul?place=ChIJL-qjb2UJc0gRaBWVC7d9sm0&ll=50.60929090%2C-1.95841840'
},
{
name: 'Grand Hotel',
address: 'Burlington Road<br>BH19 1LU',
url: 'https://ul.waze.com/ul?place=ChIJtdER9ngJc0gRda-rGciMNx8&ll=50.61937160%2C-1.95632680'
},
{
name: 'Herston Camping',
address: 'Washpond Lane<br>BH19 3DJ',
url: 'https://ul.waze.com/ul?place=ChIJh2TGDQkJc0gRGh8nbRq5scY&ll=50.61819760%2C-1.97932100'
},
{
name: 'White Horse',
address: '11 High Street<br>BH19 2LP',
url: 'https://ul.waze.com/ul?place=ChIJI19wRGQJc0gR-j_fNUStbHk&ll=50.60770100%2C-1.95513100'
},
{
name: 'The Centre',
address: '7 Chapel Lane<br>BH19 2PW',
url: 'https://ul.waze.com/ul?place=ChIJF-uMEW8Jc0gRFv8etp2iQCg&ll=50.60772200%2C-1.96104200'
},
{
name: 'Greyhound',
address: 'The Square<br>Corfe Castle<br>Wareham<br>BH20 5EZ',
url: 'https://ul.waze.com/ul?place=ChIJCTNUqzUGc0gRafGDIYi6xN0&ll=50.63857700%2C-2.05725430'
},
{
name: 'IoP Golf Club',
address: 'Corfe Road<br>Studland<br>BH19 3AB',
url: 'https://ul.waze.com/ul?place=ChIJK4rxKroJc0gRTeRAj89diz8&ll=50.63663490%2C-1.98246030'
},
{
name: 'Black Swan',
address: '159 High Street<br>BH19 2NE',
url: 'https://ul.waze.com/ul?place=ChIJh9BBjW4Jc0gRqusdkuR0bbQ&ll=50.60777280%2C-1.96368560'
},
{
name: 'YHA',
address: '159 High Street<br>BH19 2NE',
url: 'https://ul.waze.com/ul?place=ChIJmc5g4KQBc0gRu__z8PwgzvI&ll=50.60606750%2C-1.95783700'
},
{
name: 'Con Club',
address: '27 Kings Rd West<br>BH19 1HE',
url: 'https://ul.waze.com/ul?place=ChIJmc5g4KQBc0gRu__z8PwgzvI&ll=50.60606750%2C-1.95783700'
},
{
name: 'Showbar',
address: 'Shore Road<br>BH19 1DD',
url: 'https://ul.waze.com/ul?place=ChIJW2Rp4WYJc0gRn7y4WEcooV8&ll=50.60945670%2C-1.95671470'
}
];
function generateTableRows(table, data) {
for (const element of data) {
let row = table.insertRow();
for (const key in element) {
const cell = row.insertCell();
cell.className = key;
const text = d.createTextNode(element[key]);
cell.appendChild(text)
}
}
return table;
}
function createSortButton(text) {
const button = d.createElement('button')
button.className = 'btn-sort';
button.setAttribute('aria-label', 'Sort timetable by ' + text);
button.textContent = text + '⭥';
return button;
}
function generateTableHead(table, data) {
const thead = table.createTHead();
const row = thead.insertRow();
for (const key of data) {
let th = d.createElement('th')
th.className = key;
th.setAttribute('scope', 'col');
const button = createSortButton(key);
th.appendChild(button);
row.appendChild(th);
}
return table;
}
function createTableCaption(table, date) {
const caption = d.createElement('caption');
caption.className = '-visually-hidden';
caption.textContent = date.date + ': Acts appearing, time and location.';
table.appendChild(caption);
return table;
}
function generateTable(date) {
let table = d.createElement('table');
table = createTableCaption(table, date);
table = generateTableRows(table, date.acts);
const data = Object.keys(date.acts[0]);
table = generateTableHead(table, data);
return table;
}
const addDataToDetailsDiv = (_ => {
requestAnimationFrame(_ => {
const details = content.querySelectorAll('details');
for (const detail of details) {
const table = generateTable(detail.date);
const div = d.createElement('div')
div.className = 'responsive_wrap';
div.appendChild(table);
div.detail = detail;
detail.appendChild(div);
}
});
})();
function createVenueCell(venue) {
const div = d.createElement('div');
const link = d.createElement('a');
link.href = venue.url;
link.innerHTML = venue.address;
div.appendChild(link);
const details = d.createElement('details');
const summary = d.createElement('summary');
const summaryDiv = d.createElement('div');
summaryDiv.textContent = venue.name;
summary.appendChild(summaryDiv);
details.appendChild(summary);
details.appendChild(div);
return details;
}
const generateVenueDetails = (_ => {
requestAnimationFrame(_ => {
const tds = d.querySelectorAll('td.venue');
for (const td of tds) {
const name = td.textContent.trim();
const venue = venuesArr.find(item => item.name === name);
if (!venue) continue;
requestAnimationFrame(_ => {
const cell = createVenueCell(venue);
td.textContent = '';
td.appendChild(cell);
});
}
});
})();
})();
const liveFunctions = (_ => {
const openTodayTimetable = (e => {
requestAnimationFrame(_ => {
const n = new Date;
const day = n.toLocaleDateString('en-GB', {
weekday: 'long'
});
const details = d.querySelectorAll('#content > details');
for (const detail of details) {
if (detail.date.date.trim().split(' ')[0] === day) {
detail.setAttribute('open', true);
break;
}
}
});
})();
const highlightCurrentHour = (_ => {
function highlight() {
requestAnimationFrame(_ => {
const highlightClass = 'current-time';
const date = new Date;
const [dayName, hour, minutes] = [date.toLocaleDateString('en-GB', {
weekday: 'long'
}), date.getHours(), date.getMinutes()];
const tables = d.querySelectorAll('table');
for (const table of tables) {
let caption = table.querySelector('caption').textContent;
if (!caption) continue;
caption = caption.trim().split(' ')[0];
if (caption !== dayName) continue;
const trs = table.querySelectorAll('tbody tr');
for (const tr of trs) {
const trTime = tr.querySelector('.time').textContent;
const trHour = trTime.trim().substring(0, 2);
tr.classList.remove(highlightClass);
if (trHour === hour + '') {
tr.classList.add(highlightClass)
}
}
}
});
}
requestAnimationFrame(_ => {
highlight();
setInterval(highlight, 6e4);
});
})();
})();
const artistDataFunctions = (_ => {
const imgFolder = 'https://websemantics.uk/swanage-blues/img/artists/';
const artistsArr = [
{
name: 'Back Porch',
photo: 'back-porch.jpg',
biog: '<p>Foot-stomping, danceable rhythms and a lot of fun, Back Porch will make you laugh, cry and tap your feet! It\'s a stripped-down line-up of harp, washboard and guitars – just some mates sitting on a back porch, playing the blues.</p>',
url: 'http://www.backporchuk.com/'
}, {
name: 'The Robin Bibi Band',
photo: 'robin-bibi.271.jpg',
width: '720',
height: '271',
biog: '<p>Explosive, passionate, dynamic and entertaining! Stalwart of UK Blues Rock, award winning singer guitarist Robin Bibi is an amazing crowd puller who has played every Swanage Blues Festival since 2007.</p>',
url: 'https://robinbibiband.co.uk/'
}, {
name: 'The Robin Bibi Band\'s Electric Jam Session',
biog: '<p>Some of the finest impromptu music of the weekend with one of the best <i>Jam Masters</i> I\'ve ever seen. Check in with Robin at the Jam Sessions, drummers bring your own sticks.</p>',
}, {
name: 'Will Killeen',
photo: 'will-killeen.jpg',
biog: '<p>Celtic roots, American blues, Dylan classics by a unique singer/guitarist.</p>',
url: 'http://willkilleen.weebly.com/'
}, {
name: 'The Milk Men',
photo: 'the-milk-men.jpg',
biog: '<p>The Milk Men is a band made up from the cream of British R\'n\'B talent and pedigree. With members of the Mustangs and Pirates on board, the band draws its influences from a wide range of classic bands from Dr Feelgood to Fleetwood Mac. Their original music is classic blues rock, but always played with attack, energy, melody and a sense of fun. Their latest album Spin The Bottle, has received rave reviews from the critics and looks set to cement their place at the forefront of the UK Blues Rock music scene.</p>',
url: 'https://www.themilkmenmusic.com/'
}, {
name: 'Zoë Schwarz Blue Commotion',
photo: 'zoe-schwartz.jpg',
biog: '<p>Vibrant and melodic funky rocking blues featuring Rob Koral – guitar, Pete Whittaker – Hammond-organ, Dave Mayne – drums complimenting the commanding vocal delivery of Zoë Schwarz. The band refresh the blues genre with eclectic arrangements, virtuosic playing and vocal prowess; expect an exciting live set based around rootsy original songs, strong catchy riffs and exciting grooves, they mix old school tradition with contemporary flare and sophistication. <q>Powerful singing and a stylish performer, great guitar work, phenomenal Hammond… a great set</q> – Live at Carlisle Blues & Rock Festival, Blues Matters</p>',
url: 'https://www.zoeschwarzmusic.com/'
}, {
name: 'Blue Touch',
photo: 'blue-touch.jpg',
biog: '<p>Blue Touch delivers heavy duty blues rock with a blend of original and re-worked classic blues songs in an entertaining stage show with Andrea Maria on vocals.</p>',
url: 'https://www.bluetouch.info/'
}, {
name: 'Chicago 9 Rhythm & Blues Band',
photo: 'chicago-9-rhythm-blues-band.jpg',
biog: '<p>Formed in 2002 from friendship and musical respect and led from the front by skilled guitar and saxophone interplay, driven by a solid backbeat and enhanced by keyboards and Angela\'s superb vocals.</p>',
url: 'https://www.facebook.com/chicago9bluesband'
}, {
name: 'The Fabulous Duck Brothers',
photo: 'fabulous-duck-brothers.jpg',
biog: '<p>The Fabulous Duck Bros are a collection of professional and experienced musicians that wish to pay tribute to their love and appreciation of the solo career of Eric Clapton. Fronted by long term Clapton fan Phil Astles, the band concentrate on the songs produced by Eric throughout his long career including his hits from the 80\'s, 90\'s and modern era.</p><p><q>Light and shade throughout every number and the volume just about as perfect as possible</q> <q>Close your eyes and it\'s like Eric and his band are in the room</q>.</p>'
}, {
name: 'The Mustangs',
photo: 'the-mustangs.jpg',
biog: '<p>With over 20 years together, the Mustangs are one of the most established and best-loved blues rock bands in the UK. They have toured Europe, won awards and even played Glastonbury. The band\'s jam-packed nights in Swanage have become tradition, with the band playing a huge range of songs from originals, rock, blues and even often improvising covers and requests from the audience. Perfect let your hair down fun.</p>',
url: 'https://www.themustangsband.co.uk/'
}, {
name: 'Ben White & Thomas Lucas',
photo: 'ben-white-thomas-lucas.jpg',
biog: '<p>Young performers whose enthusiasm, ability, wit and charm were very well received last festival. Enjoy good original material, paying homage to classic Chicago blues.</p>'
}, {
name: 'Vince Lee & the Big Combo',
photo: 'vince-lee.720.jpg',
biog: '<p>A variety of blues, R\'n\'B, swing, jazz, slide and more from this excellent guitarist singer with his band. Come see for yourself!</p>',
url: 'http://www.vinceleebigcombo.co.uk/'
}, {
name: 'Vince Lee & Sophie Lord',
photo: 'vince-lee-sophie-lord.jpg',
biog: '<p>A voice, a guitar and a double bass… some of their YouTube videos have achieved over 500,000 views in just a few days! A variety of blues-based material and all excellent.</p>',
url: 'https://www.youtube.com/@vinceleeblues'
}, {
name: 'Mark Harrison & Charles Benfield',
photo: 'mark-harrison-charles-benfield.jpg',
biog: '<p>Each song is a snapshot of life or has a story to tell, like a 3-minute film or novel. Mark Harrison, one of the most original and interesting singer-guitarists around, brings his unique music back to Swanage Blues Festival, this time with singer and double bassist Charles Benfield.</p>',
url: 'https://www.markharrisonrootsmusic.com/'
}, {
name: 'Robert Hokum',
photo: 'robert-hokum.jpg',
biog: '<p>An informal but up-tempo, goodtime, foot-tappin acoustic Blues session with Bob, Geoff Garbow and the <a href="https://www.facebook.com/thegreatwestgroove">Great West Groove</a> to kick off the weekend!</p>',
url: 'http://www.roberthokum.co.uk/'
}, {
name: 'Robert Hokum\'s Acoustic Blues Bonanza',
biog: '<p>Acoustic blues led by Robert Hokum, with Robert Hokum, Tim Staffell, Hugh Budden, Paul Cook and David Stone – all bandleaders in their own right – get together for a mega "Revue style" blues gig backed by <a href="https://www.facebook.com/thegreatwestgroove">Great West Groove</a> rhythm section of Paul White & Steve King.</p>',
url: 'http://www.roberthokum.co.uk/'
}, {
name: 'Robert Hokum\'s Electric Blues Bonanza',
biog: '<p>Electric blues led by Robert Hokum, with Robert Hokum, Tim Staffell, Hugh Budden, Paul Cook and David Stone – all bandleaders in their own right – get together for a mega "Revue style" blues gig backed by <a href="https://www.facebook.com/thegreatwestgroove">Great West Groove</a> rhythm section of Paul White & Steve King.</p>',
url: 'http://www.roberthokum.co.uk/'
}, {
name: 'Pete Harris Blues Band with Jon Vaughan & Ray Drury',
photo: 'pete-harris-band.jpg',
biog: '<p>The Pete Harris Blues Band plays Chicago-style Blues with both Ray and Jon plus Henk Leerink on bass and Brian Wright on drums.</p>',
url: 'https://www.facebook.com/pete.harris.33'
}, {
name: 'Pete Harris & Ray Drury',
photo: 'pete-harris-ray-drury.jpg',
biog: '<p>Top bluesman, great voice, great guitar, great band leader! Pete & Ray play blues, soul and rock\'n\'roll.</p>'
}, {
name: 'Pete Harris & Jon Vaughan',
photo: 'pete-harris-jon-vaughan.jpg',
biog: '<p>Pete & Jon play Ragtime with a hint of Gospel and Americana.</p>'
}, {
name: 'George Hall Trio',
photo: 'george-hall-trio.720.jpg',
width: '720',
height: '720',
biog: '<p>The trio seek to put a modern twist to blues, funk and rock of bygone days.</p><p><q>George Hall gives some of the greatest guitarists alive a run for their money and can simultaneously switch from swaggering rock to blistering blues</q> – BeCider Seaside</p>',
url: 'https://georgehalltrio.co.uk/'
}, {
name: 'Hugh Budden & the Blue Chords',
photo: 'hugh-budden-blue-chords.jpg',
biog: '<p>Hugh will also be MC, host, guest artist and sound, lighting & stage manager at the Grand Hotel all weekend. He is the hardest working harmonica and vocals man I know, no doubt due to his style, showmanship and sheer professionalism! Make sure you catch him at least once!</p>',
url: 'https://hughbudden.wixsite.com/hugh-budden/home-page'
}, {
name: 'Jonathan Townsend',
photo: 'jonathan-townsend.jpg',
biog: '<p>Jonathan\'s performance of acoustic blues styles last festival rightly drew rapturous applause from the discerning audience. Expect early blues to Rory Gallagher and his own compositions.</p>',
url: 'https://www.facebook.com/jonathan.townsend.773'
}, {
name: 'Lewis Cohen',
photo: 'lewis-cohen.jpg',
biog: '<p>Lewis Cohen plays an eclectic mix of acoustic and electric country blues. As a solo performer, Lewis has built a strong reputation at home and abroad thanks to his powerful and versatile vocals and mastery of roots guitar styles which enthral, excite and above all, entertain.</p>',
url: 'https://www.facebook.com/lewiscohen72'
}, {
name: 'Lewis Cohen & Spencer Couzens',
photo: 'lewis-cohen.jpg',
biog: '<p>As a solo performer Lewis built a strong reputation thanks to his powerful and versatile vocals and mastery of roots guitar styles to enthral, excite and above all, entertain.</p><p>Spencer is a without doubt a marvellous, talented and versatile country & blues guitarist.</p>'
}, {
name: 'Ray Drury & Jon Walsh',
photo: 'jon-walsh.jpg',
biog: '<p>Jon\'s ability to play guitar, sing, and write his own songs demonstrates his deep connection to jazz and blues, and loves to express himself through his art.</p><p><a href="https://www.raydrury.co.uk/">Ray Drury</a> is an incredibly talented and versatile keyboardist! With a wide range of styles and moods, he is clearly able to adapt to different genres of music, including soul, blues, jazz, funk, and more.</p>'
}, {
name: 'Tommy Allen Duo with Jon Vaughan',
photo: 'tommy-allen-jon-vaughan.jpg',
biog: '<p>Tommy Allen covering vocals, guitar and foot drums. If harmonica blues is more your flavour then Jon Vaughan with his soulful tone, crying out Big Walter Horton and Sonny Boy Williamson, will please your ears and leave you wanting more.</p>',
url: 'https://tommyallenmusic.com/'
}, {
name: 'Tommy Allen Duo with Ray Dury',
photo: 'tommy-allen.jpg',
biog: '<p>Tommy Allen covering vocals, guitar and foot drums, with Ray Drury, who, with his amazing piano skills, will keep you on the dance floor boogying till the sun comes up.</p>',
url: 'https://tommyallenmusic.com/'
}, {
name: 'Tommy Allen Band',
photo: 'tommy-allen.jpg',
biog: '<p>The heart of the band and their music ventures beyond the blues stereotypes with their contemporary guitar driven gutsy blues rock, that inspires the soul. The bands music is rooted within the blues through Tommy\'s own influences, for example, Robert Johnson and BB King to name a few. However, it\'s in Tommy\'s own interpretation of these artists that the crossover really begins to take place and it\'s his individual adaptation that adds a distinct edge to his music.</p>',
url: 'https://tommyallenmusic.com/tommy-allen-band/'
}, {
name: 'Fran McGillivray & Mike Burke',
photo: 'fran-mcgillivray-mike-burke.jpg',
biog: '<p>Exciting and compelling performers who have developed a unique take on blues and roots music, and an amazing empathy on stage and on record.</p>',
url: 'https://www.franmike.com/'
}, {
name: 'Lee Signey',
photo: 'lee-signey.jpg',
biog: '<p>AKA The Infamous Rooster Fish! <q>Most original country blues I\'ve heard in years</q> – Kent Duchaine. <q>Highly original blues delivered with passion and aplomb</q> – Banbury Blues Club. <q>Great voice, great songs</q> – Richard Harris, Folk & Blues Show.</p>'
}, {
name: 'Thomas Heppell Band',
photo: 'thomas-heppell.jpg',
biog: '<p>Thomas Heppell is a Berkshire based musician who performs Blues, Jazz and Rock & Roll solo or in his band, alongside his own compositions.</p>',
url: 'https://thomasheppell.wixsite.com/thomasheppellmusic'
}, {
name: 'Isobel Thatcher Duo',
photo: 'isobel-thatcher.jpg',
biog: '<p>Isobel has been appearing at our open mics and jam sessions for 10 years and we are pleased to see her in her own named slot with her brother Domonic on saxophone. Sonja Christina of Curved Air said: <q>A confident performer with a sparkling voice and well-crafted songs. It was a pleasure to hear and to have a good reason to return to the Troubadour after 20 years. Congratulations.</q></p>',
url: 'https://isobelthatcher.com/'
}, {
name: 'Greg Brice',
photo: 'greg-brice.jpg',
biog: '<p>The Nominations are in for The UK Blues Awards 2023, and Greg is in the top 20 over 3 categories.</p><p>…the rest of the UK Blues scene will soon realise – that Greg Brice is a proper talent…</p>',
url: 'https://www.facebook.com/gregbricemusic'
}, {
name: 'Gary Fletcher Trio',
photo: 'gary-fletcher-trio.jpg',
biog: '<p>From The Blues Band, Gary Fletcher, guitar, slide and banjo, together with Alan Glen, harmonica and Nick Ritchie, guitar, play their take on blues & roots.</p>',
url: 'https://www.garyfletchermusic.net/'
}, {
name: 'Joff Watkins Duo',
photo: 'joff-watkins-duo.jpg',
biog: '<p>Joff Watkins on harmonica and vox and CJ Williams on guitar make a sound inspired by North Mississippi, New Orleans and South London. Joff is one of the best harmonica players on the scene and CJ is a uniquely talented guitarist. Both are members of Jimmy Regal and the Royals, one of the most exciting blues acts at the moment who have been playing festivals and venues up and down the UK.</p>',
url: 'https://www.facebook.com/joff.watkins'
}, {
name: 'Jon Storey Band',
photo: 'jon-storey-band.jpg',
biog: '<p>Based in Portugal and Spain, so it\'s a great pleasure and all credit to the Globe Inn for attracting them to Swanage! Quality, strong and hard rock-blues with contributions from other genres.</p>',
url: 'https://jonstoreyguitar.wixsite.com/jon-storey'
}, {
name: 'Born Healer',
photo: 'born-healer.jpg',
biog: '<p>Blues and blues rock. <q>Blistering blues-laced soul… stunning</q> – Blues in Britain</p> <p><q>Helen Turner\'s voice remains in a different class</q> – Classic Rock.</p>',
url: 'http://www.bornhealer.com/'
}, {
name: 'Geoff Garbow Band',
photo: 'geoff-garbow-blues-band.jpg',
biog: '<p>The Geoff Garbow Band both experiment with and respect blues traditions but their vibe is distinctly West London – whether in environmental protest over Heathrow expansion or just singing the blues about life, love and toil.</p>',
url: 'https://www.geoffgarbowband.com/'
}, {
name: 'Open Mic with Andy Bradshaw',
biog: '<p>A fantastic opportunity for musicians, and music lovers, to enjoy some great tunes. A supportive, fun and encouraging event for people to share their talents and express themselves in front of a live audience.</p><p><a href="https://www.swanage-blues.org/default.aspx?p=festivalartists">Participation details</a></p>',
}, {
name: 'Geoff\'s Jam',
biog: '<p>An informal gathering of musicians coming together to play music, often improvising and experimenting with different sounds and styles, but less focused on individual performances and more about the collaborative experience.</p>',
}, {
name: 'Liam Ward & Malcolm Thorp',
photo: 'liam-ward-malcolm-thorp.jpg',
biog: '<p>Combine the authentic blues sound with rich lyrical originals to serve up a modern take on the classic harp-guitar duo. Together these young men will take you on a compelling and memorable musical journey.</p>',
url: 'https://www.liamwardmusic.com/ward-thorne'
}, {
name: 'The Million Dollar Bash',
biog: '<p>George Hall and Robbie McIntosh (ex-Pretenders and Wings) on guitar, Chris "Kipper" Roberts and Roye Membury on vocals, Chris Lonergan bass, Ady Millward vocals & drums, Thomas Hughes vocals & keyboards, all celebrate the fine music of Bob Dylan and The Band in their own unique style, with some blues favourites thrown in!</p>',
url: 'https://www.facebook.com/groups/208460715834039'
}
];
const updateArtistImageFolder = (_ => {
requestAnimationFrame(_ => {
for (const artist of artistsArr) {
if (!artist.photo || artist.photo.startsWith('http')) continue;
artist.photo = imgFolder + artist.photo;
}
});
})();
const imageFormatTest = (_ => {
requestAnimationFrame(_ => {
const testData = {
avif: 'data:image/avif;base64,AAAAHGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZgAAAPBtZXRhAAAAAAAAAChoZGxyAAAAAAAAAABwaWN0AAAAAAAAAAAAAAAAbGliYXZpZgAAAAAOcGl0bQAAAAAAAQAAAB5pbG9jAAAAAEQAAAEAAQAAAAEAAAEUAAAAFQAAAChpaW5mAAAAAAABAAAAGmluZmUCAAAAAAEAAGF2MDFDb2xvcgAAAABoaXBycAAAAElpcGNvAAAAFGlzcGUAAAAAAAAAAQAAAAEAAAAOcGl4aQAAAAABCAAAAAxhdjFDgQAcAAAAABNjb2xybmNseAABAAEAAQAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAAB1tZGF0EgAKBxgADlgICAkyCB/xgAAghQm0',
webp: 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA'
}
const setImg = format => {
// Format supported... do something!
for (const artist of artistsArr) {
if (!artist.photo || !artist.photo.startsWith(imgFolder)) continue;
artist.photo = artist.photo.replace('.jpg', '.' + format);
}
// Add a class to the <html> so CSS can enjoy smaller images too.
d.documentElement.classList.add(format + 'Supported')
};
const webpTest = _ => {
const webp = new Image();
webp.addEventListener('load', _ => setImg('webp'), {once: true});
// Is already .jpg, no error fallback required.
webp.src = testData.webp;
};
const avif = new Image();
avif.addEventListener('load', _ => setImg('avif'), {once: true});
avif.addEventListener('error', webpTest, {once: true});
avif.src = testData.avif;
});
})();
function generatePhoto(artist) {
// Max width: 1049px @ 1920 * 200%
if (!artist.photo) return false;
const image = d.createElement('img');
image.width = artist.width || '720';
image.height = artist.height || '480';
image.alt = artist.name;
image.addEventListener('load', e => {
e.target.classList.add('show');
});
image.src = artist.photo;
return image;
}
function closeButton(summary) {
const button = document.createElement('button');
button.textContent = 'Close Artist';
button.addEventListener('click', e => {
summary.click();
summary.focus();
});
return button;
}
// function closeDetails() {
// // If screen-width < 480 then close any open details
// if (!window.matchMedia('(min-width: 30em)').matches) {
// const openDetails = content.querySelectorAll('td.artist > details[open]');
// console.log(openDetails.length)
// for (const details of openDetails) {
// details.removeAttribute('open');
// }
// }
// }
function artistSummaryClicked(e) {
const summary = e.target;
summary.focus();
// closeDetails();
const div = summary.nextElementSibling;
div.appendChild(closeButton(summary));
// Fetch image only when it's required.
const photo = generatePhoto(summary.artist);
if (!photo) return;
div.insertBefore(photo, div.children[0]);
div.insertBefore(closeButton(summary), photo);
}
function createDetails(artist) {
const details = d.createElement('details');
const summary = d.createElement('summary');
const summaryDiv = d.createElement('div');
summaryDiv.textContent = artist.name;
summary.appendChild(summaryDiv);
details.appendChild(summary);
summary.artist = artist;
summary.addEventListener('click', artistSummaryClicked, {
once: true
});
return details;
}
function createArtistCell(artist) {
const div = d.createElement('div');
div.innerHTML = artist.biog || '';
if (artist.url) {
const link = d.createElement('a');
link.href = artist.url;
link.innerHTML = artist.name;
div.appendChild(link);
}
const cell = createDetails(artist);
cell.appendChild(div);
return cell;
}
const generateArtistDetails = (_ => {
requestAnimationFrame(_ => {
const tds = d.querySelectorAll('td.artist');
for (const td of tds) {
const name = td.textContent.trim();
const artist = artistsArr.find(item => item.name === name);
if (!artist) continue;
requestAnimationFrame(_ => {
const cell = createArtistCell(artist);
td.textContent = '';
td.appendChild(cell);
});
}
// External links
requestAnimationFrame(_ => {
const links = document.querySelectorAll('a:not([href^="/"])');
for (const a of links) {
a.setAttribute('target', '_blank');
a.setAttribute('rel', 'external');
a.setAttribute('title', 'Opens in new window');
}
});
});
})();
})();
const postLoadJS = (_ => {
// d.addEventListener('onload', _ => {
// const links = document.querySelectorAll('a');
// for (const a of links) {
// a.setAttribute('target', '_blank');
// a.setAttribute('rel', 'external');
// a.setAttribute('title', 'Opens in new window');
// }
// });
const sortTableByColumnHeading = (_ => {
requestAnimationFrame(_ => {
const getCellValue = (tr, idx) => tr.children[idx].textContent;
const comparer = (idx, asc) => (a, b) => ((v1, v2) => v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2))(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));
d.querySelectorAll('th button').forEach(btn => btn.addEventListener('click', _ => {
const th = btn.closest('th');
const table = btn.closest('table');
const tbody = table.querySelector('tbody');
Array.from(tbody.querySelectorAll('tr')).sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc)).forEach(tr => tbody.appendChild(tr))
}))
});
})();
const lateLoadGoogleMap = (_ => {
requestAnimationFrame(_ => {
const map_src = 'https://snazzymaps.com/embed/461112';
const summary = d.querySelector('#map');
if (!summary) return;
summary.addEventListener('click', _ => {
d.querySelector('iframe').src = map_src
}, {
once: true
})
});
})();
// If artist data gets too large, use a separate file
// const loadArtistData = (_ => {
// // d.addEventListener("DOMContentLoaded", _ => {
// const script = d.createElement('script');
// script.src = 'artist.min.js';
// d.body.appendChild(script);
// // })
// })();
})();
Also see: Tab Triggers