summaryrefslogtreecommitdiff
path: root/assets/static/vendor/leaflet-fullscreen/Control.FullScreen.umd.js
diff options
context:
space:
mode:
authorDennis Fink2026-07-23 00:18:21 +0200
committerDennis Fink2026-07-23 00:18:21 +0200
commit1fe1d13c600b7dfe421b3b99b833b7d5d1232724 (patch)
tree2e8636160cc1719c907be56f5ef8cbc7e0f10a53 /assets/static/vendor/leaflet-fullscreen/Control.FullScreen.umd.js
parentca77de06be474dfd712402c327dc436864d233a3 (diff)
downloaddennisfink.me-1fe1d13c600b7dfe421b3b99b833b7d5d1232724.tar.gz
dennisfink.me-1fe1d13c600b7dfe421b3b99b833b7d5d1232724.zip
Add GPX trail maps to blog posts
This adds a trail flow block so posts can include attached GPX files as interactive maps with route display, elevation charts, activity summaries, and start/finish markers. The trail assets are loaded only when needed, keeping the shared templates clean while vendoring the Leaflet dependencies required for offline, self-hosted map rendering.
Diffstat (limited to 'assets/static/vendor/leaflet-fullscreen/Control.FullScreen.umd.js')
-rw-r--r--assets/static/vendor/leaflet-fullscreen/Control.FullScreen.umd.js299
1 files changed, 299 insertions, 0 deletions
diff --git a/assets/static/vendor/leaflet-fullscreen/Control.FullScreen.umd.js b/assets/static/vendor/leaflet-fullscreen/Control.FullScreen.umd.js
new file mode 100644
index 0000000..91b081d
--- /dev/null
+++ b/assets/static/vendor/leaflet-fullscreen/Control.FullScreen.umd.js
@@ -0,0 +1,299 @@
+/*!
+ * leaflet.fullscreen
+ * (c) Bruno B.; MIT License
+ * https://github.com/brunob/leaflet.fullscreen
+ */
+/*! GENERATED FILE - DO NOT EDIT DIRECTLY. Edit files in src/ and run 'npm run build' */
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('leaflet')) :
+ typeof define === 'function' && define.amd ? define(['leaflet'], factory) :
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, (global.L = global.L || {}, global.L.Control = global.L.Control || {}, global.L.Control.FullScreen = factory(global.L)));
+})(this, (function (leaflet) { 'use strict';
+
+ if (typeof document === 'undefined') {
+ console.warn('"window.document" is undefined; leaflet.fullscreen requires this object to access the DOM');
+ }
+
+ const nativeAPI = (() => {
+ const methodMap = [
+ // Standard
+ [
+ 'requestFullscreen',
+ 'exitFullscreen',
+ 'fullscreenElement',
+ 'fullscreenEnabled',
+ 'fullscreenchange',
+ 'fullscreenerror'
+ ],
+ // New WebKit
+ [
+ 'webkitRequestFullscreen',
+ 'webkitExitFullscreen',
+ 'webkitFullscreenElement',
+ 'webkitFullscreenEnabled',
+ 'webkitfullscreenchange',
+ 'webkitfullscreenerror'
+ ]
+ ];
+
+ const baseList = methodMap[0];
+ const ret = {};
+
+ for (const methodList of methodMap) {
+ if (methodList[1] in document) {
+ for (let i = 0; i < methodList.length; i++) {
+ ret[baseList[i]] = methodList[i];
+ }
+ return ret;
+ }
+ }
+
+ return false;
+ })();
+
+ const eventNameMap = {
+ change: nativeAPI.fullscreenchange,
+ error: nativeAPI.fullscreenerror,
+ };
+
+ const fullscreenAPI = {
+ // Request fullscreen for a specific element
+ async request(element, options) {
+ element = element || document.documentElement;
+ const requestMethod = nativeAPI.requestFullscreen;
+
+ await this._callNative(() => {
+ return element[requestMethod](options);
+ });
+ },
+ // Exit fullscreen mode
+ async exit() {
+ if (!this.isFullscreen) {
+ return;
+ }
+ const exitMethod = nativeAPI.exitFullscreen;
+
+ await this._callNative(() => {
+ return document[exitMethod]();
+ });
+ },
+ // Helper to handle browser differences (Promise vs Event)
+ async _callNative(action) {
+ const result = action();
+
+ // Modern browsers return a Promise from requestFullscreen/exitFullscreen
+ if (result instanceof Promise) {
+ await result;
+ return;
+ }
+
+ // Fallback for Safari < 16.4 (March 2023) which doesn't return a Promise
+ await new Promise((resolve) => {
+ const listener = () => {
+ this.off('change', listener);
+ resolve();
+ };
+ this.on('change', listener);
+ });
+ },
+ // Add event listener for fullscreen changes
+ on(event, callback) {
+ const eventName = eventNameMap[event];
+ if (eventName) {
+ document.addEventListener(eventName, callback);
+ }
+ },
+ // Remove event listener
+ off(event, callback) {
+ const eventName = eventNameMap[event];
+ if (eventName) {
+ document.removeEventListener(eventName, callback);
+ }
+ },
+ nativeAPI: nativeAPI
+ };
+
+ Object.defineProperties(fullscreenAPI, {
+ isFullscreen: {
+ get() {
+ return Boolean(document[nativeAPI.fullscreenElement]);
+ }
+ },
+ isEnabled: {
+ enumerable: true,
+ get() {
+ // Coerce to boolean in case of old WebKit
+ return Boolean(document[nativeAPI.fullscreenEnabled]);
+ }
+ }
+ });
+
+ const FullScreen = leaflet.Control.extend({
+ options: {
+ position: 'topleft',
+ title: 'Full Screen',
+ titleCancel: 'Exit Full Screen',
+ forceSeparateButton: false,
+ forcePseudoFullscreen: false,
+ fullscreenElement: false
+ },
+
+ _screenfull: fullscreenAPI,
+
+ onAdd(map) {
+ let className = 'leaflet-control-zoom-fullscreen';
+ let container;
+ let content = '';
+
+ if (map.zoomControl && !this.options.forceSeparateButton) {
+ container = map.zoomControl._container;
+ } else {
+ container = document.createElement('div');
+ container.className = 'leaflet-bar';
+ }
+
+ if (this.options.content) {
+ content = this.options.content;
+ } else {
+ className += ' leaflet-fullscreen-icon';
+ }
+
+ this._createButton(this.options.title, className, content, container, this.toggleFullScreen, this);
+ this._map.fullscreenControl = this;
+
+ this._map.on('enterFullscreen exitFullscreen', this._toggleState, this);
+
+ return container;
+ },
+
+ onRemove() {
+ leaflet.DomEvent
+ .off(this.link, 'click', leaflet.DomEvent.stop)
+ .off(this.link, 'click', this.toggleFullScreen, this);
+
+ if (this._screenfull.isEnabled) {
+ leaflet.DomEvent
+ .off(document, this._screenfull.nativeAPI.fullscreenchange, leaflet.DomEvent.stop)
+ .off(document, this._screenfull.nativeAPI.fullscreenchange, this._handleFullscreenChange, this);
+ }
+ },
+
+ _createButton(title, className, content, container, fn, context) {
+ this.link = document.createElement('a');
+ this.link.className = className;
+ container.appendChild(this.link);
+ this.link.href = '#';
+ this.link.title = title;
+ this.link.innerHTML = content;
+
+ this.link.setAttribute('role', 'button');
+ this.link.setAttribute('aria-label', title);
+
+ leaflet.DomEvent.disableClickPropagation(container);
+
+ leaflet.DomEvent
+ .on(this.link, 'click', leaflet.DomEvent.stop)
+ .on(this.link, 'click', fn, context);
+
+ if (this._screenfull.isEnabled) {
+ leaflet.DomEvent
+ .on(document, this._screenfull.nativeAPI.fullscreenchange, leaflet.DomEvent.stop)
+ .on(document, this._screenfull.nativeAPI.fullscreenchange, this._handleFullscreenChange, context);
+ }
+
+ return this.link;
+ },
+
+ async toggleFullScreen() {
+ const map = this._map;
+ const { fullscreenElement, forcePseudoFullscreen } = this.options;
+
+ // Target element: use custom element if provided, otherwise the map container
+ const container = fullscreenElement || map.getContainer();
+
+ // Check if we should use the native Fullscreen API
+ const useNative = this._screenfull.isEnabled && !forcePseudoFullscreen;
+
+ if (map._isFullscreen) {
+ // --- EXIT FULLSCREEN ---
+
+ // Set flag to prevent the 'fullscreenchange' listener from firing a duplicate exit event
+ map._exitFired = true;
+
+ if (useNative) {
+ await this._screenfull.exit();
+ } else {
+ container.classList.remove('leaflet-pseudo-fullscreen');
+ }
+
+ map.invalidateSize();
+ map._isFullscreen = false;
+ map.fire('exitFullscreen');
+ } else {
+ // --- ENTER FULLSCREEN ---
+
+ map._exitFired = false;
+
+ if (useNative) {
+ await this._screenfull.request(container);
+ } else {
+ container.classList.add('leaflet-pseudo-fullscreen');
+ }
+
+ map.invalidateSize();
+ map._isFullscreen = true;
+ map.fire('enterFullscreen');
+ }
+ },
+
+ _toggleState() {
+ const { title, titleCancel } = this.options;
+ const isFullscreen = this._map._isFullscreen;
+
+ // Update Title & Aria Label
+ this.link.title = isFullscreen ? titleCancel : title;
+ this.link.setAttribute('aria-label', this.link.title);
+ this.link.setAttribute('aria-pressed', isFullscreen.toString());
+
+ // Update Icon Class
+ this.link.classList.toggle('leaflet-fullscreen-on', isFullscreen);
+ },
+
+ _handleFullscreenChange() {
+ const map = this._map;
+
+ // Check if fullscreen was exited via browser (ESC key or browser UI)
+ // and we didn't trigger the exit ourselves
+ const wasExitedExternally = !this._screenfull.isFullscreen && map._isFullscreen && !map._exitFired;
+
+ if (wasExitedExternally) {
+ // Sync internal state with browser state
+ map._exitFired = true;
+ map._isFullscreen = false;
+
+ // Notify listeners and adjust map size
+ map.fire('exitFullscreen');
+ map.invalidateSize();
+ }
+ }
+ });
+
+ leaflet.Map.include({
+ toggleFullscreen() {
+ this.fullscreenControl.toggleFullScreen();
+ }
+ });
+
+ leaflet.Map.mergeOptions({
+ fullscreenControl: false
+ });
+
+ leaflet.Map.addInitHook(function() {
+ if (this.options.fullscreenControl) {
+ this.addControl(new FullScreen(this.options.fullscreenControlOptions));
+ }
+ });
+
+ return FullScreen;
+
+}));