PageSourceSearch

https://handwerkspreis.at/media/plg_content_phocagalleryslideshow/js/fadeslideshow.js?eb1c40

js handwerkspreis.at collected 2026-10-06 06:04:45 UTC 9,030 bytes, 330 lines download raw bytes

1/*!
2 * fadeslideshow.js – lightweight fade slideshow wrapper for Phoca Gallery Slideshow Plugin
3 *
4 * Purpose:
5 * - Provides a compatible `fadeSlideShow({...})` constructor used by the Phoca Gallery Slideshow content plugin.
6 * - Replaces the legacy "Ultimate Fade In Slideshow" dependency which is no longer shipped with recent Phoca/Joomla setups.
7 *
8 * Features:
9 * - Fade transitions, autoplay
10 * - Hover pause (desktop)
11 * - Swipe (touch) + optional mouse drag swipe
12 * - Lazy loading / deferred start
13 *
14 * Compatibility:
15 * - Joomla 5/6, modern browsers
16 *
17 * Maintainer: Andy Marchand - Feuerwehr Worb (community patch)
18 * Version: 4.4.0-j6fix.1 (2026-01-06)
19 * License: GNU/GPL v2 or later
20 */
21 (function () {
22  function toInt(v, fallback) {
23    var n = parseInt(v, 10);
24    return isNaN(n) ? fallback : n;
25  }
26
27  function pickImageUrl(entry) {
28    if (!entry) return null;
29    if (typeof entry === "string") return entry;
30    if (Array.isArray(entry)) return entry[0] || null;
31    return null;
32  }
33
34  function pickDesc(entry) {
35    if (Array.isArray(entry)) return entry[3] || "";
36    return "";
37  }
38
39  function absolutizeUrl(url) {
40    if (!url) return url;
41
42    // already absolute or special schemes
43    if (/^(https?:)?\/\//i.test(url) || /^data:/i.test(url) || /^blob:/i.test(url)) {
44      return url;
45    }
46
47    // root-relative
48    if (url.charAt(0) === "/") {
49      return window.location.origin + url;
50    }
51
52    // relative to current path
53    var base = window.location.href.split("#")[0].split("?")[0];
54    base = base.substring(0, base.lastIndexOf("/") + 1);
55    return base + url;
56  }
57
58  function clampIndex(i, len) {
59    if (!len) return 0;
60    i = i % len;
61    if (i < 0) i += len;
62    return i;
63  }
64
65  // Public API expected by the plugin: new fadeSlideShow({ ... })
66  window.fadeSlideShow = function (settings) {
67    settings = settings || {};
68    var wrapperId = settings.wrapperid || settings.wrapperId;
69    var wrapper = wrapperId ? document.getElementById(wrapperId) : null;
70    if (!wrapper) return;
71
72    var images = Array.isArray(settings.imagearray) ? settings.imagearray.slice() : [];
73    images = images
74      .map(function (e) {
75        var u = pickImageUrl(e);
76        return { url: absolutizeUrl(u), desc: pickDesc(e) };
77      })
78      .filter(function (x) {
79        return !!x.url;
80      });
81
82    if (!images.length) return;
83
84    var pause = toInt(settings.displaymode && settings.displaymode.pause, 3000);
85    var fadeDuration = toInt(settings.fadeduration, 600);
86    var randomize = !!(settings.displaymode && settings.displaymode.randomize);
87
88    if (randomize) {
89      images.sort(function () {
90        return Math.random() - 0.5;
91      });
92    }
93
94    // Wrapper styling + UX
95    wrapper.style.position = "relative";
96    wrapper.style.overflow = "hidden";
97    if (!wrapper.style.width) wrapper.style.width = "100%";
98    if (!wrapper.style.height) wrapper.style.height = "100%";
99
100    // Cursor + selection/drag behaviour on desktop
101    wrapper.style.cursor = "grab";
102    wrapper.style.userSelect = "none";
103    wrapper.style.webkitUserSelect = "none";
104    wrapper.style.msUserSelect = "none";
105    wrapper.style.webkitUserDrag = "none";
106    wrapper.style.touchAction = "pan-y"; // allow vertical scroll, we handle horizontal swipe
107
108    // Prevent native dragstart inside wrapper (image ghost-drag)
109    wrapper.addEventListener(
110      "dragstart",
111      function (e) {
112        e.preventDefault();
113      },
114      { passive: false }
115    );
116
117    function makeImg() {
118      var img = document.createElement("img");
119      img.style.position = "absolute";
120      img.style.inset = "0";
121      img.style.width = "100%";
122      img.style.height = "100%";
123      img.style.objectFit = "contain";
124      img.style.opacity = "0";
125      img.style.transition = "opacity " + fadeDuration + "ms ease";
126      img.style.willChange = "opacity";
127      img.alt = "";
128
129      // prevent native dragging
130      img.draggable = false;
131      img.style.userSelect = "none";
132      img.style.webkitUserDrag = "none";
133      img.style.pointerEvents = "auto";
134      return img;
135    }
136
137    var imgA = makeImg();
138    var imgB = makeImg();
139    wrapper.innerHTML = "";
140    wrapper.appendChild(imgA);
141    wrapper.appendChild(imgB);
142
143    var idx = 0;
144    var front = imgA;
145    var back = imgB;
146
147    var isHoverPaused = false;
148    var isPointerDown = false;
149    var pointerId = null;
150    var startX = 0;
151    var startY = 0;
152    var lastX = 0;
153    var dragDetected = false;
154
155    var SWIPE_THRESHOLD = 35; // px
156    var VERTICAL_GUARD = 45;  // px (ignore if mostly vertical)
157
158    function setCursor(state) {
159      wrapper.style.cursor = state === "down" ? "grabbing" : "grab";
160    }
161
162    function show(i, first) {
163      var item = images[i];
164      if (!item) return;
165
166      if (first) {
167        front.onload = function () {
168          front.style.opacity = "1";
169          front.style.zIndex = "2";
170          back.style.opacity = "0";
171          back.style.zIndex = "1";
172        };
173        front.onerror = function () {
174          front.onload = front.onerror = null;
175          idx = (idx + 1) % images.length;
176          show(idx, true);
177        };
178        front.src = item.url;
179        return;
180      }
181
182      back.onload = function () {
183        back.style.zIndex = "2";
184        front.style.zIndex = "1";
185        back.style.opacity = "1";
186        front.style.opacity = "0";
187      };
188
189      back.onerror = function () {
190        back.onload = back.onerror = null;
191        idx = (idx + 1) % images.length;
192
193        var tmp = front;
194        front = back;
195        back = tmp;
196
197        show(idx, false);
198      };
199
200      back.src = item.url;
201    }
202
203    function swapLayers() {
204      var tmp = front;
205      front = back;
206      back = tmp;
207    }
208
209    function next() {
210      idx = clampIndex(idx + 1, images.length);
211      swapLayers();
212      show(idx, false);
213    }
214
215    function prev() {
216      idx = clampIndex(idx - 1, images.length);
217      swapLayers();
218      show(idx, false);
219    }
220
221    // First render
222    show(idx, true);
223
224    // Timer
225    var timer = setInterval(function () {
226      if (!isHoverPaused && !isPointerDown) {
227        next();
228      }
229    }, pause);
230
231    function restartTimer() {
232      clearInterval(timer);
233      timer = setInterval(function () {
234        if (!isHoverPaused && !isPointerDown) {
235          next();
236        }
237      }, pause);
238    }
239
240    // Hover pause (desktop)
241    wrapper.addEventListener("mouseenter", function () {
242      isHoverPaused = true;
243    });
244    wrapper.addEventListener("mouseleave", function () {
245      isHoverPaused = false;
246    });
247
248    // Pointer-based swipe (mouse + touch)
249    wrapper.addEventListener(
250      "pointerdown",
251      function (e) {
252        // only primary button for mouse
253        if (e.pointerType === "mouse" && e.button !== 0) return;
254
255        isPointerDown = true;
256        pointerId = e.pointerId;
257        startX = lastX = e.clientX;
258        startY = e.clientY;
259        dragDetected = false;
260
261        setCursor("down");
262
263        try {
264          wrapper.setPointerCapture(pointerId);
265        } catch (_) {}
266
267        // prevent text selection / native interactions
268        e.preventDefault();
269      },
270      { passive: false }
271    );
272
273    wrapper.addEventListener(
274      "pointermove",
275      function (e) {
276        if (!isPointerDown || e.pointerId !== pointerId) return;
277
278        lastX = e.clientX;
279        var dx = lastX - startX;
280        var dy = e.clientY - startY;
281
282        // If it becomes clearly vertical, let scroll happen (especially touch)
283        if (!dragDetected && Math.abs(dy) > VERTICAL_GUARD && Math.abs(dy) > Math.abs(dx)) {
284          // release drag mode
285          return;
286        }
287
288        if (Math.abs(dx) > 6) {
289          dragDetected = true;
290        }
291
292        // If dragging horizontally, stop browser from doing weird things
293        if (dragDetected) {
294          e.preventDefault();
295        }
296      },
297      { passive: false }
298    );
299
300    function endPointer(e) {
301      if (!isPointerDown || e.pointerId !== pointerId) return;
302
303      isPointerDown = false;
304      pointerId = null;
305
306      setCursor("up");
307
308      var dx = lastX - startX;
309      var dy = e.clientY - startY;
310
311      // Only treat as swipe if mostly horizontal and above threshold
312      if (Math.abs(dx) >= SWIPE_THRESHOLD && Math.abs(dx) > Math.abs(dy)) {
313        if (dx < 0) {
314          next();
315        } else {
316          prev();
317        }
318        restartTimer();
319      }
320    }
321
322    wrapper.addEventListener("pointerup", endPointer, { passive: true });
323    wrapper.addEventListener("pointercancel", endPointer, { passive: true });
324
325    // public stop() like original library
326    this.stop = function () {
327      clearInterval(timer);
328    };
329  };
330})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.