Skip to content

Commit

Permalink
refactor: extracting some file to reduce pressure on minifier
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent Boutour <[email protected]>
  • Loading branch information
ViBiOh committed Nov 3, 2022
1 parent 4e598a6 commit 023dcd3
Show file tree
Hide file tree
Showing 10 changed files with 646 additions and 635 deletions.
2 changes: 1 addition & 1 deletion cmd/fibr/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func newConfig() (configuration, error) {
logger: logger.Flags(fs, "logger"),
tracer: tracer.Flags(fs, "tracer"),
prometheus: prometheus.Flags(fs, "prometheus", flags.NewOverride("Gzip", false)),
owasp: owasp.Flags(fs, "", flags.NewOverride("FrameOptions", "SAMEORIGIN"), flags.NewOverride("Csp", "default-src 'self'; base-uri 'self'; script-src 'self' 'httputils-nonce' unpkg.com/[email protected]/dist-cjs/ unpkg.com/[email protected]/dist/ unpkg.com/[email protected]/; style-src 'httputils-nonce' unpkg.com/[email protected]/dist/ unpkg.com/[email protected]/; img-src 'self' data: a.tile.openstreetmap.org b.tile.openstreetmap.org c.tile.openstreetmap.org")),
owasp: owasp.Flags(fs, "", flags.NewOverride("FrameOptions", "SAMEORIGIN"), flags.NewOverride("Csp", "default-src 'self'; base-uri 'self'; script-src 'self' 'httputils-nonce' unpkg.com/[email protected]/dist-cjs/ unpkg.com/[email protected]/dist/ unpkg.com/[email protected]/; style-src 'self' 'httputils-nonce' unpkg.com/[email protected]/dist/ unpkg.com/[email protected]/; img-src 'self' data: a.tile.openstreetmap.org b.tile.openstreetmap.org c.tile.openstreetmap.org")),
basic: basicMemory.Flags(fs, "auth", flags.NewOverride("Profiles", "1:admin")),
crud: crud.Flags(fs, ""),
share: share.Flags(fs, "share"),
Expand Down
132 changes: 132 additions & 0 deletions cmd/fibr/static/scripts/async-image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// from https://developers.google.com/speed/webp/faq#how_can_i_detect_browser_support_for_webp
function isWebPCompatible() {
const animatedImage =
'UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA';

return new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => {
if (image.width > 0 && image.height > 0) {
resolve();
} else {
reject();
}
};

image.onerror = reject.bind(null, true);
image.src = `data:image/webp;base64,${animatedImage}`;
});
}

// From https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read#example_2_-_handling_text_line_by_line
async function* readLineByLine(response) {
const utf8Decoder = new TextDecoder('utf-8');
const reader = response.body.getReader();
let { value: chunk, done: readerDone } = await reader.read();
chunk = chunk ? utf8Decoder.decode(chunk, { stream: true }) : '';

let re = /\r\n|\n|\r/gm;
let startIndex = 0;

for (;;) {
const result = re.exec(chunk);
if (!result) {
if (readerDone) {
break;
}

const remainder = chunk.substr(startIndex);
({ value: chunk, done: readerDone } = await reader.read());
chunk =
remainder + (chunk ? utf8Decoder.decode(chunk, { stream: true }) : '');
startIndex = re.lastIndex = 0;
continue;
}

yield chunk.substring(startIndex, result.index);
startIndex = re.lastIndex;
}

if (startIndex < chunk.length) {
yield chunk.substr(startIndex);
}
}

/**
* Async image loading
*/
async function fetchThumbnail() {
let fetchURL = document.location.search;
if (fetchURL.includes('?')) {
if (!fetchURL.endsWith('&')) {
fetchURL += '&';
}
fetchURL += 'thumbnail';
} else {
fetchURL += '?thumbnail';
}

const response = await fetch(fetchURL, { credentials: 'same-origin' });

if (response.status >= 400) {
throw new Error('unable to load thumbnails');
}

for await (let line of readLineByLine(response)) {
const parts = line.split(',');
if (parts.length != 2) {
console.error('invalid line for thumbnail:', line);
continue;
}

const picture = document.getElementById(`picture-${parts[0]}`);
if (!picture) {
continue;
}

const img = new Image();
img.src = `data:image/webp;base64,${parts[1]}`;
img.alt = picture.dataset.alt;
img.dataset.src = picture.dataset.src;
img.classList.add('thumbnail', 'full', 'block');

replaceContent(picture, img);
}
}

window.addEventListener(
'load',
async () => {
const thumbnailsElem = document.querySelectorAll('[data-thumbnail]');
if (!thumbnailsElem) {
return;
}

thumbnailsElem.forEach((picture) => {
replaceContent(picture, generateThrobber(['throbber-white']));
});

try {
await fetchThumbnail();
} catch (e) {
console.error(e);
}

try {
await isWebPCompatible();
} catch (e) {
await resolveScript(
'https://unpkg.com/[email protected]/dist-cjs/webp-hero.bundle.js',
'sha512-DA6h9H5Sqn55/uVn4JI4aSPFnAWoCQYYDXUnvjOAMNVx11///hX4QaFbQt5yWsrIm9hSI5fLJYfRWt3KXneSXQ==',
'anonymous',
);

const webpMachine = new webpHero.WebpMachine();
webpMachine.polyfillDocument();
webpMachine.clearCache();
}

window.dispatchEvent(new Event('thumbnail-done'));
},
false,
);
129 changes: 129 additions & 0 deletions cmd/fibr/static/scripts/map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
async function fetchGeoJSON(geoURL) {
const response = await fetch(geoURL, { credentials: 'same-origin' });

if (response.status >= 400) {
throw new Error('unable to load geojson');
}

if (response.status === 204) {
return null;
}

return response.json();
}

async function addStyle(src, integrity, crossorigin) {
return new Promise((resolve) => {
const style = document.createElement('link');
style.rel = 'stylesheet';
style.href = src;
style.onload = resolve;

if (integrity) {
style.integrity = integrity;
style.crossOrigin = crossorigin;
}

document.querySelector('head').appendChild(style);
});
}

async function loadLeaflet() {
const leafletVersion = '1.9.2';

await addStyle(
`https://unpkg.com/leaflet@${leafletVersion}/dist/leaflet.css`,
'sha512-UkezATkM8unVC0R/Z9Kmq4gorjNoFwLMAWR/1yZpINW08I79jEKx/c8NlLSvvimcu7SL8pgeOnynxfRpe+5QpA==',
'anonymous',
);
await addStyle(
'https://unpkg.com/[email protected]/dist/MarkerCluster.Default.css',
'sha512-6ZCLMiYwTeli2rVh3XAPxy3YoR5fVxGdH/pz+KMCzRY2M65Emgkw00Yqmhh8qLGeYQ3LbVZGdmOX9KUjSKr0TA==',
'anonymous',
);
await resolveScript(
`https://unpkg.com/leaflet@${leafletVersion}/dist/leaflet.js`,
'sha512-KMraOVM0qMVE0U1OULTpYO4gg5MZgazwPAPyMQWfOkEshpwlLQFCHZ/0lBXyviDNVL+pBGwmeXQnuvGK8Fscvg==',
'anonymous',
);
await resolveScript(
'https://unpkg.com/[email protected]/dist/leaflet.markercluster.js',
'sha512-+Zr0llcuE/Ho6wXRYtlWypMyWSEMxrWJxrYgeAMDRSf1FF46gQ3PAVOVp5RHdxdzikZXuHZ0soHpqRkkPkI3KA==',
'anonymous',
);
}

let map;
async function renderMap(geoURL) {
if (map) {
map.invalidateSize(); // force re-render
return;
}

const container = document.getElementById('map-container');
const throbber = generateThrobber(['map-throbber', 'throbber-white']);
if (container) {
container.appendChild(throbber);
}

await loadLeaflet();

// create Leaflet map
map = L.map('map-container', {
center: [46.227638, 2.213749], // France 🇫🇷
zoom: 5,
});

// add the OpenStreetMap tiles
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution:
'&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>',
}).addTo(map);

const geojson = await fetchGeoJSON(geoURL);
if (!geojson || !geojson.features) {
return;
}

const markers = L.markerClusterGroup({
zoomToBoundsOnClick: false,
});

const bounds = [];
geojson.features.map((f) => {
const coord = L.GeoJSON.coordsToLatLng(f.geometry.coordinates);

bounds.push(coord);
markers.addLayer(
L.circleMarker(coord).bindPopup(
`<a href="${f.properties.url}?browser">
<img src="${f.properties.url}?thumbnail" alt="Image thumbnail" class="thumbnail-img">
</a>
<br>
<span>${f.properties.date}</span>`,
{
maxWidth: 'auto',
closeButton: false,
className: 'thumbnail-popup',
},
),
);
});

markers.on('clusterclick', (a) => {
map.fitBounds(a.layer.getAllChildMarkers().map((m) => m.getLatLng()));
});

// fit bounds of map
if (bounds.length) {
map.once('zoomend', () => {
container.removeChild(throbber);
});
map.fitBounds(bounds);
} else {
container.removeChild(throbber);
}

map.addLayer(markers);
}
62 changes: 62 additions & 0 deletions cmd/fibr/static/scripts/navigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Async loading of a script
* @param {String} src URL of script
* @param {String} integrity Integrity of script
* @param {String} crossorigin Crossorigin of script
* @return Promise when script is either loaded or on error
*/
function resolveScript(src, integrity, crossorigin) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
script.async = true;
script.onload = resolve.bind(null, true);
script.onerror = reject.bind(null, true);

if (integrity) {
script.integrity = integrity;
script.crossOrigin = crossorigin;
}

document.querySelector('head').appendChild(script);
});
}

/**
* Handle Previous/next.
*/
window.onkeyup = (e) => {
switch (e.key) {
case 'ArrowLeft':
goToPrevious();
break;

case 'ArrowRight':
goToNext();
break;

case 'Escape':
if (typeof abort === 'function') {
abort(e);
} else {
goBack();
}
break;
}
};

/**
* Remove all child and append given one.
* @param {Element} element Element to clear
* @param {Element} newContent Element to put in place
*/
function replaceContent(element, newContent) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}

if (newContent) {
element.appendChild(newContent);
}
}
Loading

0 comments on commit 023dcd3

Please sign in to comment.