Skip to content

Commit

Permalink
Merge pull request #58 from shgysk8zer0/feature/wfd-mayor-events
Browse files Browse the repository at this point in the history
Add WF Mayor funcs & other enhancements
  • Loading branch information
shgysk8zer0 authored Jan 22, 2024
2 parents 43f6f73 + 4291889 commit 280848d
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 18 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [v0.3.2] - 2024-01-22

### Added
- `createWFDMayorEvents()` to embed `https://whsikeyflatdays.com/mayors/embed/`
- `getWFDMayorEventsICalFile()` to create iCalendar files from WF Mayor Candidate Events
- `resize()` as a wrapper around `ResizeObserver`

### Changed
- Update/improve `toSpinalCase()` & `toCamelCase()`
- Allow WF Mayor Events embed URL in `krv#embed` policy
- Update CSP and TrustedTypes Policies & importmap

## [v0.3.1] 2024-01-12

### Fixed
Expand Down
20 changes: 19 additions & 1 deletion dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ export function intersect(what, callback, { root, rootMargin, signal, threshold
throw new DOMException('IntersectionObserver not supported');
} else {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry, index) => callback.apply(null, [entry, observer, index]));
entries.forEach((entry, index) => callback.apply(observer, [entry, observer, index]));
}, { root, rootMargin, threshold });

each(what, item => observer.observe(item));
Expand Down Expand Up @@ -585,6 +585,24 @@ export function mutate(what, callback, options = {}) {
}
}

export function resize(what, callback, { signal, base = document } = {}) {
if (signal instanceof AbortSignal && signal.aborted) {
return query(what, base);
} else {
const observer = new ResizeObserver((entries, observer) => {
entries.forEach(entry => callback.apply(observer, [entry, observer]));
});

each(what, el => observer.observe(el), { base });

if (signal instanceof AbortSignal) {
signal.addEventListener('abort', () => observer.disconnect(), { once: true });
}

return observer;
}
}

export function stripComments(node) {
if (! (node instanceof Node)) {
throw new TypeError('Cannot strip comments from non-node');
Expand Down
36 changes: 35 additions & 1 deletion krv/embed.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @copyright 2023 Chris Zuber <[email protected]>
* @copyright 2023-2024 Chris Zuber <[email protected]>
*/
import { createIframe } from '../elements.js';
import { policy, trustedURLs, trustPolicies } from './policy.js';
Expand Down Expand Up @@ -122,4 +122,38 @@ export function createWFDEvents({
});
}

export function createWFDMayorEvents({
theme, mayor, heading, address = false, description = true, width, height, loading = 'lazy',
fetchPriority = 'auto', title, id, classList, referrerPolicy = 'no-referrer',
credentialless = true, styles, dataset, slot, part,
} = {}) {
const src = new URL(trustedURLs.wfdMayorEvents.href);

if (typeof theme === 'string') {
src.searchParams.set('theme', theme);
}

if (typeof mayor === 'string') {
src.searchParams.set('mayor', mayor);
}

if (typeof heading === 'string') {
src.searchParams.set('heading', heading);
}

if (address) {
src.searchParams.set('address', '');
}

if (description) {
src.searchParams.set('description', '');
}

return createIframe(src.href, {
height, width, referrerPolicy, fetchPriority, loading, title, classList,
id, policy, sandbox: ['allow-scripts', 'allow-popups'], styles, dataset,
slot, part, credentialless,
});
}

export { trustPolicies };
3 changes: 2 additions & 1 deletion krv/policy.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/**
* @copyright 2023 Chris Zuber <[email protected]>
* @copyright 2023-2024 Chris Zuber <[email protected]>
*/
import { createPolicy } from '../trust.js';

export const trustedURLs = {
maps: new URL('/embed', 'https://maps.kernvalley.us'),
events: new URL('/embed/', 'https://events.kernvalley.us'),
wfdEvents: new URL('/embed/', 'https://whiskeyflatdays.com'),
wfdMayorEvents: new URL('/mayors/embed/', 'https://whiskeyflatdays.com'),
};

export const policy = createPolicy('krv#embed', {
Expand Down
18 changes: 17 additions & 1 deletion krv/wfd.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
/**
* @copyright 2023 Chris Zuber <[email protected]>
* @copyright 2023-2024 Chris Zuber <[email protected]>
*/
import { getJSON } from '../http.js';
import { createICalFile, METHOD } from '../iCal.js';
import { ICAL as ICAL_MIME } from '@shgysk8zer0/consts/mimes.js';

export const events = new URL('https://whiskeyflatdays.com/events.json');
export const mayorEvents = new URL('https://whiskeyflatdays.com/mayors/events.json');

export const getEvents = async ({ signal } = {}) => getJSON(events, { signal });
export const getMayorEvents = async ({ signal } = {}) => getJSON(mayorEvents, { signal });

export async function getWFDEventsICalFile({
filename = 'wfd-events.ics',
Expand All @@ -28,3 +30,17 @@ export async function getWFDEventsICalFile({

return createICalFile(events, { filename, method, type });
}

export async function getWFDMayorEventsICalFile({
filename = 'wfd-mayor-events.ics',
method = METHOD.PUBLISH,
type = ICAL_MIME,
signal,
} = {}) {
const events = await getMayorEvents({ signal })
.then(events => events.map(
({ performer, name, ...rest }) => ({ name: `${performer.name} - ${name}`, ...rest })
));

return createICalFile(events, { filename, method, type });
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@shgysk8zer0/kazoo",
"version": "0.3.1",
"version": "0.3.2",
"private": false,
"type": "module",
"description": "A JavaScript monorepo for all the things!",
Expand Down
10 changes: 5 additions & 5 deletions test/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" dir="ltr" data-trusted-policies="empty#html empty#script custom#html sanitizer-raw#html blob#script-url youtube#embed">
<html lang="en" dir="ltr" data-trusted-policies="empty#html empty#script custom#html sanitizer-raw#html blob#script-url youtube#script-url krv#embed">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
Expand All @@ -13,16 +13,16 @@
style-src 'self' https://unpkg.com/ blob:;
font-src cdn.kernvalley.us;
form-action 'none';
frame-src https://www.youtube-nocookie.com/embed/ https://calendar.google.com/calendar/embed https://www.google.com/maps/embed;
frame-src https://www.youtube-nocookie.com/embed/ https://calendar.google.com/calendar/embed https://www.google.com/maps/embed https://whiskeyflatdays.com/embed/ https://whiskeyflatdays.com/mayors/embed/;
object-src 'none';
media-src 'none';
child-src 'self';
worker-src 'self';
frame-ancestors 'none';
connect-src 'self' https://unpkg.com/ https://api.github.com/users/ https://api.github.com/repos/ https://api.pwnedpasswords.com/range/ https://maps.kernvalley.us/places/ https://events.kernvalley.us/events.json https://events.kernvalley.us/cal/krv-events.ics https://whiskeyflatdays.com/events.json;
connect-src 'self' https://unpkg.com/ https://api.github.com/users/ https://api.github.com/repos/ https://api.pwnedpasswords.com/range/ https://maps.kernvalley.us/places/ https://events.kernvalley.us/events.json https://events.kernvalley.us/cal/krv-events.ics https://whiskeyflatdays.com/events.json https://whiskeyflatdays.com/mayors/events.json;
img-src * data: blob:;
require-trusted-types-for 'script';
trusted-types empty#html empty#script default sanitizer-raw#html trust-raw#html youtube#script-url github-user#html github-repo#html blob#script-url goog-cal#script-url goog-maps#script-url;
trusted-types empty#html empty#script default sanitizer-raw#html trust-raw#html youtube#script-url github-user#html github-repo#html blob#script-url goog-cal#script-url goog-maps#script-url krv#embed;
upgrade-insecure-requests;"
/>
<title>Kazoo</title>
Expand All @@ -39,7 +39,7 @@
"@shgysk8zer0/jswaggersheets/": "https://unpkg.com/@shgysk8zer0/[email protected]/",
"@shgysk8zer0/http-status": "https://unpkg.com/@shgysk8zer0/[email protected]/http-status.js",
"@shgysk8zer0/components/": "https://unpkg.com/@shgysk8zer0/[email protected]/",
"@kernvalley/components/": "https://unpkg.com/@kernvalley/components@1.0.2/",
"@kernvalley/components/": "https://unpkg.com/@kernvalley/components@1.1.2/",
"@webcomponents/custom-elements": "https://unpkg.com/@webcomponents/[email protected]/custom-elements.min.js",
"leaflet": "https://unpkg.com/[email protected]/dist/leaflet-src.esm.js",
"firebase/": "https://www.gstatic.com/firebasejs/9.22.2/",
Expand Down
18 changes: 12 additions & 6 deletions utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ export function debounce(callback, { delay = 17, thisArg } = {}) {
if (! (callback instanceof Function)) {
throw new TypeError('Callback must be a function');
} else if (! Number.isFinite(delay) || delay < 0) {
throw new TypeError('Timeout must be a positive intiger');
throw new TypeError('Timeout must be a positive integer');
} else {
let to;
return function(...args) {
Expand Down Expand Up @@ -435,13 +435,19 @@ export function separateString(str, char = ',') {
}
}

export const toSpinalCase = str => str.replace(/[A-Z]/g, (m, i) => i === 0
? m.toLowerCase()
: `-${m.toLowerCase()}`);
export const toSpinalCase = str => typeof str === 'string' && str.trim().length === 0 ? '' : str.toString()
.replaceAll(/(?<=\w)(?:[^-\w_ ]+)(?=\w)/g, '') // Strip out inter-word special chars
.replaceAll(/[A-Z]+/g, str => ` ${str.toLowerCase()}`) // Handle uppercase chars
.replaceAll(/[^a-z\d ]+/g, ' ') // Convert all remaining special chars
.trim() // Removing any leading or trailing spaces
.replaceAll(/ +/g, '-'); // Replace all remaining spaces with single hyphens

export const slugify = toSpinalCase;

export const toCamelCase = str => str.replace(/-[a-z\d]/g, m => m.substr(1).toUpperCase());
export const toCamelCase = str => toSpinalCase(str)
.replaceAll(/-[a-z]/g, c => c.substring(1).toUpperCase());

export const ucFirst = str => str.substr(0, 1).toUpperCase() + str.substr(1);
export const ucFirst = str => str.toString().substring(0, 1).toUpperCase() + str.substring(1);

export async function filterKeys(obj, keys) {
return Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key)));
Expand Down

0 comments on commit 280848d

Please sign in to comment.