meta-lightbox/src/js/meta-lightbox.js

687 lines
19 KiB
JavaScript
Executable File

/*
* MetaLightbox
* https://tony.twma.pro
*
*/
// optional:
//=require ../../bower_components/jquery-zoom/jquery.zoom.js
'use strict';
import $ from 'jquery';
import Events from './_events';
const MetaLightboxUI = (($) => {
const W = window;
const $W = $(W);
const D = document;
const $Body = $('body');
const NAME = 'MetaLightboxUI';
const NETWORK_ERROR =
'<div class="meta-lightbox-error"><div class="alert alert-error alert-danger">Connection failure.</div></div>';
class MetaLightboxUI {
static init() {
console.log(`${NAME}: init ...`);
const ui = this;
ui.isMSIE = /*@cc_on!@*/ 0;
try {
ui.isHidpi = ui.is_hdpi();
} catch (e) {
console.log(`${NAME}: catch`);
}
$(`.js${NAME},[data-toggle="lightbox"],[data-lightbox-gallery]`).on(
'click',
(e) => {
e.preventDefault();
e.stopPropagation();
const $link = $(e.currentTarget);
ui.show($link);
},
);
$(`.js${NAME}-close-inline`).on('click', (e) => {
const $el = $(e.currentTarget);
$el.parents('.meta-lightbox-overlay').removeClass('meta-lightbox-open');
});
}
static is_hdpi() {
console.log(`${NAME}: isHidpi`);
const mediaQuery =
'(-webkit-min-device-pixel-ratio: 1.5),\
(min--moz-device-pixel-ratio: 1.5),\
(-o-min-device-pixel-ratio: 3/2),\
(min-resolution: 1.5dppx)';
if (W.devicePixelRatio > 1) return true;
return W.matchMedia && W.matchMedia(mediaQuery).matches;
}
static show($link) {
console.log(`${NAME}: show`);
const ui = this;
const $lightbox = ui.constructLightbox();
if (!$lightbox) return;
const $content = ui.$content;
if (!$content) return;
$Body.addClass(`meta-lightbox-body-effect-fade`);
// Add content
ui.process($content, $link);
// Nav
if ($link.data('lightbox-gallery')) {
const $galleryItems = $(
`[data-lightbox-gallery="${$link.data('lightbox-gallery')}"]`,
);
if ($galleryItems.length === 1) {
$('.meta-lightbox-nav').hide();
} else {
$('.meta-lightbox-nav').show();
}
// Prev
$('.meta-lightbox-prev')
.off('click')
.on('click', (e) => {
e.preventDefault();
const index = $galleryItems.index($link);
let $currentLink = $galleryItems.eq(index - 1);
if (!$currentLink.length) $currentLink = $galleryItems.last();
//ui.hide();
setTimeout(() => {
ui.show($currentLink);
}, 10);
});
// Next
$('.meta-lightbox-next')
.off('click')
.on('click', (e) => {
e.preventDefault();
const index = $galleryItems.index($link);
let $currentLink = $galleryItems.eq(index + 1);
if (!$currentLink.length) $currentLink = $galleryItems.first();
//ui.hide();
setTimeout(() => {
ui.show($currentLink);
}, 10);
});
}
setTimeout(() => {
ui.$overlay.addClass('meta-lightbox-open');
}, 1); // For CSS transitions
}
static constructLightbox() {
console.log(`${NAME}: constructLightbox`);
const ui = this;
const overlay = $('<div>', {
class:
'meta-lightbox-overlay meta-lightbox-theme-default meta-lightbox-effect-fade',
});
const wrap = $('<div>', {
class: 'meta-lightbox-wrap',
});
const content = $('<div>', {
class: 'meta-lightbox-content',
});
const nav = $(
'<a href="#" class="meta-lightbox-nav meta-lightbox-prev"><i class="fas fa fa-chevron-left"></i> <span class="sr-only">Previous</span></a><a href="#" class="meta-lightbox-nav meta-lightbox-next"><i class="fa fas fa-chevron-right"></i> <span class="sr-only">Next</span></a>',
);
const close = $(
'<a href="#" class="meta-lightbox-close fas fa fa-times" title="Close"><span class="sr-only">Close</span></a>',
);
const title = $('<div>', {
class: 'meta-lightbox-title-wrap',
});
if (ui.$overlay) return ui.$overlay;
if (ui.isMSIE) overlay.addClass('meta-lightbox-ie');
wrap.append(content);
wrap.append(title);
overlay.append(wrap);
overlay.append(nav);
overlay.append(close);
$Body.append(overlay);
overlay.on('click', (e) => {
e.preventDefault();
ui.hide();
});
close.on('click', (e) => {
e.preventDefault();
ui.hide();
});
ui.$overlay = overlay;
ui.$content = content;
ui.$title = title;
return ui.$overlay;
}
static setTitle(str) {
const ui = this;
ui.$title.html(str);
}
static process($content, $link) {
console.log(`${NAME}: process`);
const ui = this;
const href =
$link.attr('href') && $link.attr('href').length
? $link.attr('href')
: $link.data('href');
// add custom link specific class
ui.$content.attr('class', 'meta-lightbox-content');
ui.$content.addClass($link.data('lightbox-class'));
if (!href.length) {
console.log($link);
console.error(`${NAME}: href(attr/data) is missing`);
}
const $pageSpinner = $('#PageLoading .loading-spinner');
const loadingContent = $pageSpinner.length ? $pageSpinner.clone() : '';
ui.$content.append(loadingContent).addClass('meta-lightbox-loading');
// Image
if (
href.match(/\.(jpeg|jpg|gif|png|svg)$/i) ||
$link.data('force') === 'image'
) {
$.ajax({
url: href,
success: () => {
const img = $('<img>', { src: href });
const wrap = $('<div class="meta-lightbox-image"></div>');
const imgwrapper = $(
'<span class="meta-lightbox-zoom-wrapper"></span>',
);
imgwrapper.append(img);
wrap.append(imgwrapper);
// Vertically center images
wrap.css({
'line-height': `${$content.height()}px`,
height: `${$content.height()}px`, // For Firefox
});
$W.resize(() => {
wrap.css({
'line-height': `${$content.height()}px`,
height: `${$content.height()}px`, // For Firefox
});
});
if (typeof imgwrapper['zoom'] !== 'undefined') {
imgwrapper.zoom();
} else {
imgwrapper.addClass('no-zoom');
}
ui.$content.html(wrap);
ui.contentLoaded();
},
error: (jqXHR, status) => {
const wrap = $(NETWORK_ERROR);
ui.$content.html(wrap);
ui.contentLoaded();
},
});
// Set the title
const title = $link.data('title')
? $link.data('title')
: $link.attr('title');
ui.setTitle(title);
// google analytics
if (typeof ga === 'function') {
ga('send', 'event', 'meta', 'Image Click', href);
}
}
// Video (Youtube/Vimeo)
else if (
href.match(
/(youtube|youtube-nocookie|youtu|vimeo)\.(com|be)\/(watch\?v=([\w-]+)|([\w-]+))/,
) ||
$link.data('force') === 'youtube' ||
$link.data('force') === 'vimeo'
) {
const video = href.match(
/(youtube|youtube-nocookie|youtu|vimeo)\.(com|be)\/(watch\?v=([\w-]+)|([\w-]+))/,
);
let classTerm = 'meta-lightbox-video';
let src;
if (video[1] == 'youtube') {
src = `https://www.youtube.com/embed/${video[4]}`;
classTerm = `${classTerm} meta-lightbox-youtube`;
}
if (video[1] == 'youtu') {
src = `https://www.youtube.com/embed/${video[3]}`;
classTerm = `${classTerm} meta-lightbox-youtube`;
}
if (video[1] == 'youtube-nocookie') {
src = `https://www.youtube-nocookie.com/embed/${video[4]}`;
classTerm = `${classTerm} meta-lightbox-youtube`;
}
if (video[1] == 'vimeo') {
src = `https://player.vimeo.com/video/${video[3]}`;
classTerm = `${classTerm} meta-lightbox-vimeo`;
}
if (!src) {
console.warn(`${NAME}: Video loading bad URL`);
return false;
}
const $iframe = ui.loadIframe(src, classTerm);
if (!$iframe) {
$link.addClass('meta-offline');
return false;
}
$link.removeClass('meta-offline');
// Set the title
const title = $link.data('title')
? $link.data('title')
: $link.attr('title');
ui.setTitle(title);
// google analytics
if (typeof ga === 'function') {
ga('send', 'event', 'meta', 'Video Click', video);
}
}
// Inline HTML
else if (
href.substring(0, 1) == '#' ||
$link.data('force') === 'inline'
) {
if ($(href).length) {
wrap = $('<div class="meta-lightbox-inline" />');
wrap.append($(href).clone().show());
// Vertically center html
if (wrap.outerHeight() < ui.$content.height()) {
wrap.css({
position: 'relative',
top: '50%',
'margin-top': `${-(wrap.outerHeight() / 2)}px`,
});
}
$W.resize(() => {
if (wrap.outerHeight() < ui.$content.height()) {
wrap.css({
position: 'relative',
top: '50%',
'margin-top': `${-(wrap.outerHeight() / 2)}px`,
});
}
});
ui.$content.html(wrap);
ui.contentLoaded();
} else {
wrap = $(NETWORK_ERROR);
ui.$content.html(wrap);
ui.contentLoaded();
}
$('.meta-lightbox-title-wrap').html('');
// google analytics
if (typeof ga === 'function') {
ga('send', 'event', 'meta', 'inline HTML click', href);
}
}
// AJAX/iFrame (default)
else {
if ($link.data('force-iframe') || $link.data('force') === 'iframe') {
console.log(`${NAME}: IFrame forced`);
const $iframe = ui.loadIframe(href, 'meta-lightbox-iframe-content');
if (!$iframe) {
$link.addClass('meta-offline');
return false;
}
$link.removeClass('meta-offline');
return true;
}
console.log(`${NAME}: loading AJAX`);
$.ajax({
sync: false,
async: true,
url: href,
dataType: 'html',
method: 'GET',
cache: false,
statusCode: {
404: function () {
console.log(`${NAME}: page not found`);
W.location.href = url;
},
302: function () {
console.log(`${NAME}: redirect 302`);
W.location.href = url;
},
},
error: function (jqXHR, status) {
console.log(`${NAME}: AJAX request failure.${jqXHR.statusText}`);
var wrap = $(NETWORK_ERROR);
ui.$content.html(wrap);
ui.contentLoaded();
// google analytics
if (typeof ga === 'function') {
ga('send', 'event', 'error', 'AJAX ERROR', jqXHR.statusText);
}
},
success: function (data, status, jqXHR) {
console.log(`${NAME}: AJAX success`);
try {
const dataJson = $.parseJSON(data);
if (typeof dataJson === 'object') {
console.log(`${NAME}: AJAX JSON`);
// Replace regions
if (
typeof dataJson['regions'] === 'object' &&
typeof dataJson['regions']['LayoutAjax'] !== 'undefinded'
) {
var wrap = $('<div class="meta-lightbox-ajax" />');
wrap.html(dataJson['regions']['LayoutAjax']);
ui.$content.html(wrap);
ui.contentLoaded();
}
// trigger events
/*if (typeof (data['events']) === 'object') {
for (var eventName in data.events) {
$(D).trigger(eventName, [data['events'][eventName]]);
}
}*/
var title = jqXHR.getResponseHeader('X-Title'),
link = jqXHR.getResponseHeader('X-Link');
if (
title &&
title.length &&
link &&
link.length &&
link !== W.location.href &&
link.substring(0, link.indexOf('#')) !==
W.location.href.replace($('base').attr('href'), '/')
) {
$('.meta-lightbox-ajax').data('curr-title', D.title);
$('.meta-lightbox-ajax').data('curr-link', W.location.href);
if (typeof W.localStorage !== 'undefined' && link !== '/') {
W.localStorage.setItem('current-page', link);
}
if (
D.URL !== link &&
D.URL !== $('base').attr('href') + link &&
D.URL !== `${$('base').attr('href')}/${link}`
) {
W.history.pushState(
{
title,
page: link,
ajax: 'true',
},
title,
link,
);
}
$('.meta-lightbox-title-wrap').html('');
// google analytics
if (typeof ga === 'function') {
ga('set', {
page: link.replace($('base').attr('href'), ''),
title,
});
ga('send', 'pageview');
}
}
}
} catch (e) {
console.log(`${NAME}: AJAX HTML`);
const $wrap = $('<div class="meta-lightbox-ajax" />');
$wrap.append(data);
ui.$content.html($wrap);
ui.contentLoaded();
}
// Vertically center html
/*if (wrap.outerHeight() < ui.$content.height()) {
wrap.css({
position: 'relative',
top: '50%',
'margin-top': `${-(wrap.outerHeight() / 2)}px`,
});
}
$W.resize(() => {
if (wrap.outerHeight() < ui.$content.height()) {
wrap.css({
position: 'relative',
top: '50%',
'margin-top': `${-(wrap.outerHeight() / 2)}px`,
});
}
});*/
/*setTimeout(() => {
$W.resize();
if (typeof W.imagesLoaded === 'function') {
W.imagesLoaded().then(() => {
$W.resize();
});
}
}, 500);*/
ui.contentLoaded();
},
});
}
}
static loadIframe(href, classTerm) {
const ui = this;
const $iframe = $('<iframe>', {
src: href,
class: classTerm,
frameborder: 0,
vspace: 0,
hspace: 0,
scrolling: 'auto',
allowtransparency: 'true',
});
console.log(`${NAME}: loading iframe`);
$Body.append(
'<div id="MetaIFramePreload" class="hidden d-none iframe-preload" style="display:none"></div>',
);
const $preload = $('#MetaIFramePreload');
$preload.html($iframe);
$iframe.on('load', () => {
// don't load on offline
if ($Body.hasClass('is-offline')) {
console.warn(`${NAME}: Unable to load iframe offline`);
return false;
}
ui.finishIFrameLoading();
});
return $iframe;
}
static finishIFrameLoading() {
const ui = this;
const $preload = $('#MetaIFramePreload');
if (!$preload.length) {
console.warn(`${NAME}: iframe preload not found`);
return false;
}
const $iframe = $preload.find('iframe');
if (!$iframe.length) {
console.warn(`${NAME}: iframe preload > iframe not found`);
return false;
}
console.log(`${NAME}: the iframe was loaded`);
$preload.html('');
$preload.remove();
ui.$content.addClass('iframe-delay');
ui.$content.html($iframe);
ui.contentLoaded();
setTimeout(() => {
ui.$content.removeClass('iframe-delay');
}, 1000);
}
static contentLoaded() {
const ui = this;
ui.$content.removeClass('meta-lightbox-loading');
$(
`.meta-lightbox-content .js${NAME},.meta-lightbox-content [data-toggle="lightbox"],.meta-lightbox-content [data-lightbox-gallery]`,
).on('click', (e) => {
e.preventDefault();
e.stopPropagation();
const $link = $(e.currentTarget);
ui.show($link);
});
$(`.js${NAME}-close`).on('click', (e) => {
e.preventDefault();
ui.hide();
});
setTimeout(() => {
$W.trigger('meta-lightbox-loaded');
}, 1); // For CSS transitions
setTimeout(() => {
$Body.addClass('meta-lightbox-body-effect-fade');
}, 600);
}
static hide(callback) {
const ui = this;
const $overlay = ui.$overlay;
var title = $('.meta-lightbox-ajax').data('curr-title'),
link = $('.meta-lightbox-ajax').data('curr-link');
if (title && link) {
if (typeof W.localStorage !== 'undefined' && link !== '/') {
W.localStorage.setItem('current-page', link);
}
if (
D.URL !== link &&
D.URL !== $('base').attr('href') + link &&
D.URL !== `${$('base').attr('href')}/${link}`
) {
W.history.replaceState(
{
title,
page: link,
ajax: 'true',
},
title,
link,
);
}
}
$overlay.removeClass('meta-lightbox-open');
$Body.removeClass('meta-lightbox-body-effect-fade');
$('.meta-lightbox-content .meta-lightbox-zoom-wrapper').trigger(
'zoom.destroy',
);
// For IE
if (ui.isMSIE) {
$overlay.find('iframe').attr('src', ' ');
$overlay.find('iframe').remove();
}
$('.meta-lightbox-prev').off('click');
// Remove click handlers
$('.meta-lightbox-next').off('click');
// Empty content (for videos)
$('.meta-lightbox-content').empty();
$Body.removeClass('meta-lightbox-body-effect-fade');
}
}
$W.on(`MetaLightboxUI.init ${Events.AJAX} ${Events.LOADED}`, () => {
MetaLightboxUI.init();
});
$W.on(`${Events.BACKONLINE}`, () => {
$('.meta-offline').removeClass('meta-offline');
console.log(`${NAME}: reloading iframe`);
MetaLightboxUI.finishIFrameLoading();
const $iframe = $('.meta-lightbox-content iframe');
if ($iframe.length) {
$iframe.attr('src', $iframe.attr('src'));
}
});
W.MetaLightboxUI = MetaLightboxUI;
return MetaLightboxUI;
})($);
export default MetaLightboxUI;