/* Multiverse by HTML5 UP html5up.net | @ajlkn Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) Enhanced for dynamic gallery loading - Mischkomposition by Tom Misch */ (function ($) { var $window = $(window), $body = $("body"), $wrapper = $("#wrapper"); // Breakpoints. breakpoints({ xlarge: ["1281px", "1680px"], large: ["981px", "1280px"], medium: ["737px", "980px"], small: ["481px", "736px"], xsmall: [null, "480px"], }); // Hack: Enable IE workarounds. if (browser.name == "ie") $body.addClass("ie"); // Touch? if (browser.mobile) $body.addClass("touch"); // Transitions supported? if (browser.canUse("transition")) { // Play initial animations on page load. $window.on("load", function () { window.setTimeout(function () { $body.removeClass("is-preload"); }, 100); }); // Prevent transitions/animations on resize. var resizeTimeout; $window.on("resize", function () { window.clearTimeout(resizeTimeout); $body.addClass("is-resizing"); resizeTimeout = window.setTimeout(function () { $body.removeClass("is-resizing"); }, 100); }); } // Scroll back to top. $window.scrollTop(0); // Panels. var $panels = $(".panel"); $panels.each(function () { var $this = $(this), $toggles = $('[href="#' + $this.attr("id") + '"]'), $closer = $('
').appendTo($this); // Closer. $closer.on("click", function (event) { $this.trigger("---hide"); }); // Events. $this .on("click", function (event) { event.stopPropagation(); }) .on("---toggle", function () { if ($this.hasClass("active")) $this.triggerHandler("---hide"); else $this.triggerHandler("---show"); }) .on("---show", function () { if ($body.hasClass("content-active")) $panels.trigger("---hide"); $this.addClass("active"); $toggles.addClass("active"); $body.addClass("content-active"); }) .on("---hide", function () { $this.removeClass("active"); $toggles.removeClass("active"); $body.removeClass("content-active"); }); // Toggles. $toggles .removeAttr("href") .css("cursor", "pointer") .on("click", function (event) { event.preventDefault(); event.stopPropagation(); $this.trigger("---toggle"); }); }); // Global events. $body.on("click", function (event) { if ($body.hasClass("content-active")) { event.preventDefault(); event.stopPropagation(); $panels.trigger("---hide"); } }); $window.on("keyup", function (event) { if (event.keyCode == 27 && $body.hasClass("content-active")) { event.preventDefault(); event.stopPropagation(); $panels.trigger("---hide"); } }); // Header. var $header = $("#header"); $header.find("a").each(function () { var $this = $(this), href = $this.attr("href"); if (!href || href.charAt(0) == "#") return; $this .removeAttr("href") .css("cursor", "pointer") .on("click", function (event) { event.preventDefault(); event.stopPropagation(); window.location.href = href; }); }); // Footer. var $footer = $("#footer"); $footer.find(".copyright").each(function () { var $this = $(this), $parent = $this.parent(), $lastParent = $parent.parent().children().last(); breakpoints.on("<=medium", function () { $this.appendTo($lastParent); }); breakpoints.on(">medium", function () { $this.appendTo($parent); }); }); // Main - Dynamische Galerie var $main = $("#main"), exifDatas = {}; var imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp']; function loadGallery() { $.ajax({ url: '/images/fulls/', dataType: 'json', cache: false, success: function(files) { if(files.length === 0) { $main.html('

Noch keine Bilder vorhanden.

'); return; } var images = files.filter(function(f) { if (f.type !== 'file') return false; var ext = f.name.split('.').pop().toLowerCase(); return imageExtensions.indexOf(ext) !== -1; }); if (images.length === 0) { $main.html('

Es wurden noch keine passenden Bilder für diesen Account hochgeladen oder zugewiesen.

'); return; } images.sort(function(a, b) { return a.name.localeCompare(b.name); }); images.forEach(function(file) { var article = $('
'); article.attr('data-name', file.name); if (file.folder) article.attr('data-folder', file.folder); var prefix = file.folder ? encodeURIComponent(file.folder) + '/' : ''; var fullPath = '/images/fulls/' + prefix + encodeURIComponent(file.name); var thumbPath = '/images/thumbs/' + prefix + encodeURIComponent(file.name); var link = $(''); var img = $(''); link.append(img); article.append(link); $main.append(article); }); initThumbs(); initSelectionMode(images); initPoptrox(); }, error: function() { $main.html('

Keine Bilder gefunden. Lade Bilder in deinen Nextcloud-Ordner hoch.

'); } }); } function initThumbs() { $main.children(".thumb").each(function () { var $this = $(this), $image = $this.find(".image"), $image_img = $image.children("img"), x; if ($image.length == 0) return; $image.css("background-image", "url('" + $image_img.attr("src") + "')"); if ((x = $image_img.data("position"))) $image.css("background-position", x); $image_img.hide(); // Fallback: Wenn Thumbnail fehlt, Vollbild als Vorschau nutzen $image_img[0].addEventListener("error", function() { var fullUrl = $image.attr("href"); if (fullUrl) { $image.css("background-image", "url('" + fullUrl + "')"); } }); $image_img[0].addEventListener("load", function() { EXIF.getData($image_img[0], function () { exifDatas[$image_img.data('name')] = getExifDataMarkup(this); }); }); }); } function initPoptrox() { $main.poptrox({ baseZIndex: 20000, caption: function ($a) { var $image_img = $a.children('img'); var data = exifDatas[$image_img.data('name')]; if (data === undefined) { EXIF.getData($image_img[0], function () { data = exifDatas[$image_img.data('name')] = getExifDataMarkup(this); }); } var downBtn = '
Bild Speichern '; return data !== undefined ? '

' + data + downBtn + '

' : '

' + downBtn + '

'; }, fadeSpeed: 300, onPopupClose: function () { $body.removeClass("modal-active"); }, onPopupOpen: function () { $body.addClass("modal-active"); }, overlayOpacity: 0, popupCloserText: "", popupHeight: 150, popupLoaderText: "", popupSpeed: 300, popupWidth: 150, selector: ".thumb > a.image", usePopupCaption: true, usePopupCloser: true, usePopupDefaultStyling: false, usePopupForceClose: true, usePopupLoader: true, usePopupNav: true, windowMargin: 50, }); breakpoints.on("<=xsmall", function () { $main[0]._poptrox.windowMargin = 0; }); breakpoints.on(">xsmall", function () { $main[0]._poptrox.windowMargin = 50; }); } function getExifDataMarkup(img) { var exif = $('#main').data('exif'); var template = ''; for (var current in exif) { var current_data = exif[current]; var exif_data = EXIF.getTag(img, current_data['tag']); if (typeof exif_data !== "undefined") { template += ' ' + exif_data + '  '; } } return template; } // ==================== SELECTION MODE ==================== function initSelectionMode(allImages) { var selectedImages = []; var selectionActive = false; // Toolbar erstellen (versteckt) var $toolbar = $('
'); $toolbar.html( '0 ausgewaehlt' + '' + '' ); $('body').append($toolbar); // Selection-Toggle Button im Header var $selectToggle = $('
  • ' + '
  • '); $('#header nav > ul').prepend($selectToggle); // Ordner-Download Buttons (nur wenn Ordner-Bilder vorhanden) var folders = []; allImages.forEach(function(img) { if (img.folder && folders.indexOf(img.folder) === -1) { folders.push(img.folder); } }); if (folders.length > 0) { folders.forEach(function(folder) { var $folderBtn = $('
  • ' + '
  • '); $('#header nav > ul').prepend($folderBtn); }); } // Selection-Mode toggle $(document).on('click', '#select-mode-toggle', function(e) { e.preventDefault(); e.stopPropagation(); selectionActive = !selectionActive; $('body').toggleClass('selection-mode', selectionActive); if (!selectionActive) clearSelection(); $toolbar.toggleClass('visible', selectionActive); }); // Klick auf Thumbnail im Selection-Mode // Capture-Phase auf document: faengt JEDEN Klick ab bevor Poptrox ihn sieht document.addEventListener('click', function(e) { if (!selectionActive) return; var thumb = e.target.closest('#main .thumb'); if (!thumb) return; e.preventDefault(); e.stopImmediatePropagation(); var $thumb = $(thumb); var imgName = $thumb.attr('data-name'); var folder = $thumb.attr('data-folder') || null; var idx = -1; for (var i = 0; i < selectedImages.length; i++) { if (selectedImages[i].name === imgName && selectedImages[i].folder === folder) { idx = i; break; } } if (idx !== -1) { selectedImages.splice(idx, 1); $thumb.removeClass('selected'); } else { selectedImages.push({ name: imgName, folder: folder }); $thumb.addClass('selected'); } updateToolbar(); }, true); function updateToolbar() { var count = selectedImages.length; $('#sel-count').text(count + ' ausgewaehlt'); $('#sel-download').prop('disabled', count === 0); if (count > 3) { $('#sel-download').html(' Als ZIP (' + count + ')'); } else if (count > 0) { $('#sel-download').html(' Herunterladen (' + count + ')'); } else { $('#sel-download').html(' Herunterladen'); } } function clearSelection() { selectedImages = []; $('.thumb').removeClass('selected'); updateToolbar(); } // Download-Button (direkt gebunden, nicht delegiert) $toolbar.on('click', '#sel-download', function() { if (selectedImages.length === 0) return; var payload = JSON.stringify({ images: selectedImages }); if (selectedImages.length <= 3) { // 1-3 Bilder: normales AJAX, Server gibt JSON mit URLs $.ajax({ url: '/api/download/selected', type: 'POST', contentType: 'application/json', data: payload, success: function(resp) { if (resp.mode === 'individual') { resp.urls.forEach(function(url, i) { setTimeout(function() { var a = document.createElement('a'); a.href = url; a.download = url.split('/').pop(); document.body.appendChild(a); a.click(); document.body.removeChild(a); }, i * 500); }); } }, error: function(xhr) { var msg = (xhr.responseJSON && xhr.responseJSON.error) || 'Download fehlgeschlagen'; alert(msg); } }); } else { // 4+ Bilder: Blob-Download fuer ZIP var xhr = new XMLHttpRequest(); xhr.open('POST', '/api/download/selected', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.responseType = 'blob'; xhr.onload = function() { if (xhr.status === 200) { var url = window.URL.createObjectURL(xhr.response); var a = document.createElement('a'); a.href = url; a.download = 'mischkomposition-auswahl.zip'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } else { // Fehler-Blob als Text lesen var reader = new FileReader(); reader.onload = function() { try { var resp = JSON.parse(this.result); alert(resp.error || 'Download fehlgeschlagen'); } catch(e) { alert('Download fehlgeschlagen (Status ' + xhr.status + ')'); } }; reader.readAsText(xhr.response); } }; xhr.onerror = function() { alert('Netzwerkfehler beim Download'); }; xhr.send(payload); } }); // Abbrechen-Button (direkt gebunden) $toolbar.on('click', '#sel-cancel', function() { selectionActive = false; $('body').removeClass('selection-mode'); $toolbar.removeClass('visible'); clearSelection(); }); // Ordner-Download $(document).on('click', '.folder-download-btn', function(e) { e.preventDefault(); e.stopPropagation(); var folder = $(this).data('folder'); var a = document.createElement('a'); a.href = '/api/download/folder/' + encodeURIComponent(folder); a.download = folder + '.zip'; document.body.appendChild(a); a.click(); document.body.removeChild(a); }); } // Galerie laden loadGallery(); // Theme Toggle var currentTheme = localStorage.getItem('mischkomposition_theme') || 'main'; updateThemeIcon(currentTheme); $('#theme-toggle').click(function(e) { e.preventDefault(); currentTheme = currentTheme === 'main' ? 'light' : 'main'; localStorage.setItem('mischkomposition_theme', currentTheme); $('#theme-style').attr('href', 'assets/css/' + currentTheme + '.min.css'); updateThemeIcon(currentTheme); }); function updateThemeIcon(theme) { if (theme === 'light') { $('#theme-toggle i').removeClass('fa-sun').addClass('fa-moon'); } else { $('#theme-toggle i').removeClass('fa-moon').addClass('fa-sun'); } } // Login Handling $.get('/api/auth/me').done(function(u) { $('#login-username, #login-password, #login-submit').hide(); $('#logout-btn').show().css('display', 'inline-block'); $('#pw-change-section').show(); if(u.role === 'admin') { $('#admin-link').html('Admin-Dashboard'); } $('#login-nav').html('Account '); }); $('#login-form').submit(function(e) { e.preventDefault(); $.post('/api/auth/login', { username: $('#login-username').val(), password: $('#login-password').val() }) .done(function() { window.location.reload(); }) .fail(function(xhr) { var msg = 'Login fehlgeschlagen.'; if (xhr.responseJSON && xhr.responseJSON.error === 'Account abgelaufen') { msg = 'Dein Account ist abgelaufen. Bitte kontaktiere den Administrator.'; } alert(msg); }); }); $('#logout-btn').click(function(e) { e.preventDefault(); $.post('/api/auth/logout').done(function() { window.location.reload(); }); }); $('#pw-change-form').submit(function(e) { e.preventDefault(); var newPw = $('#pw-new').val(); var confirmPw = $('#pw-confirm').val(); if (newPw !== confirmPw) { alert('Passwoerter stimmen nicht ueberein.'); return; } $.post('/api/auth/change-password', { old_password: $('#pw-old').val(), new_password: newPw }) .done(function() { alert('Passwort geaendert!'); $('#pw-old, #pw-new, #pw-confirm').val(''); }) .fail(function(xhr) { alert(xhr.responseJSON ? xhr.responseJSON.error : 'Fehler'); }); }); })(jQuery);