@tomasvn/glightbox 0.0.0-stage → 3.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +16 -0
- package/.eslintignore +3 -0
- package/.eslintrc.json +94 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- package/.github/stale.yml +21 -0
- package/.github/workflows/greetings.yml +13 -0
- package/.husky/pre-commit +3 -0
- package/.lando.yml +10 -0
- package/.prettierignore +3 -0
- package/.prettierrc.json +30 -0
- package/CHANGELOG.md +259 -0
- package/CONTRIBUTING.md +29 -0
- package/LICENSE.md +21 -0
- package/README.md +714 -2
- package/bower.json +29 -0
- package/development/build.js +44 -0
- package/development/jscompiler.js +90 -0
- package/development/notifications.js +15 -0
- package/development/package.js +116 -0
- package/development/postcss.js +63 -0
- package/development/watcher.js +105 -0
- package/dist/css/glightbox.css +939 -0
- package/dist/css/glightbox.min.css +1 -0
- package/dist/js/glightbox.js +3109 -0
- package/dist/js/glightbox.min.js +1 -0
- package/index.d.ts +586 -0
- package/package.json +60 -4
- package/src/js/.jshintrc +6 -0
- package/src/js/core/drag.js +203 -0
- package/src/js/core/keyboard-navigation.js +101 -0
- package/src/js/core/slide-parser.js +236 -0
- package/src/js/core/slide.js +251 -0
- package/src/js/core/touch-events.js +378 -0
- package/src/js/core/touch-navigation.js +291 -0
- package/src/js/core/zoom.js +156 -0
- package/src/js/glightbox.js +1351 -0
- package/src/js/slides/iframe.js +24 -0
- package/src/js/slides/image.js +56 -0
- package/src/js/slides/inline.js +71 -0
- package/src/js/slides/video.js +108 -0
- package/src/js/utils/helpers.js +541 -0
- package/src/postcss/glightbox.css +725 -0
- package/tests/slide.test.mjs +130 -0
- package/tests/touch-navigation.test.mjs +13 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set slide iframe content
|
|
3
|
+
*
|
|
4
|
+
* @param {node} slide
|
|
5
|
+
* @param {object} data
|
|
6
|
+
* @param {int} index
|
|
7
|
+
* @param {function} callback
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createIframe } from '../utils/helpers.js';
|
|
11
|
+
|
|
12
|
+
export default function slideIframe(slide, data, index, callback) {
|
|
13
|
+
const slideMedia = slide.querySelector('.gslide-media');
|
|
14
|
+
const iframe = createIframe({
|
|
15
|
+
url: data.href,
|
|
16
|
+
callback: callback
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
slideMedia.parentNode.style.maxWidth = data.width;
|
|
20
|
+
slideMedia.parentNode.style.height = data.height;
|
|
21
|
+
slideMedia.appendChild(iframe);
|
|
22
|
+
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set slide inline content
|
|
3
|
+
* we'll extend this to make http
|
|
4
|
+
* requests using the fetch api
|
|
5
|
+
* but for now we keep it simple
|
|
6
|
+
*
|
|
7
|
+
* @param {node} slide
|
|
8
|
+
* @param {object} data
|
|
9
|
+
* @param {int} index
|
|
10
|
+
* @param {function} callback
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { isNil, isFunction } from '../utils/helpers.js';
|
|
14
|
+
|
|
15
|
+
export default function slideImage(slide, data, index, callback) {
|
|
16
|
+
const slideMedia = slide.querySelector('.gslide-media');
|
|
17
|
+
|
|
18
|
+
let img = new Image();
|
|
19
|
+
let titleID = 'gSlideTitle_' + index;
|
|
20
|
+
let textID = 'gSlideDesc_' + index;
|
|
21
|
+
|
|
22
|
+
// prettier-ignore
|
|
23
|
+
img.addEventListener('load', () => {
|
|
24
|
+
if (isFunction(callback)) {
|
|
25
|
+
callback();
|
|
26
|
+
}
|
|
27
|
+
}, false);
|
|
28
|
+
|
|
29
|
+
img.src = data.href;
|
|
30
|
+
if (data.sizes != '' && data.srcset != '') {
|
|
31
|
+
img.sizes = data.sizes;
|
|
32
|
+
img.srcset = data.srcset;
|
|
33
|
+
}
|
|
34
|
+
img.alt = ''; // https://davidwalsh.name/accessibility-tip-empty-alt-attributes
|
|
35
|
+
if (!isNil(data.alt) && data.alt !== '') {
|
|
36
|
+
img.alt = data.alt;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (data.title !== '') {
|
|
40
|
+
img.setAttribute('aria-labelledby', titleID);
|
|
41
|
+
}
|
|
42
|
+
if (data.description !== '') {
|
|
43
|
+
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-describedby_attribute#Example_2_A_Close_Button
|
|
44
|
+
img.setAttribute('aria-describedby', textID);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (data.hasOwnProperty('_hasCustomWidth') && data._hasCustomWidth) {
|
|
48
|
+
img.style.width = data.width;
|
|
49
|
+
}
|
|
50
|
+
if (data.hasOwnProperty('_hasCustomHeight') && data._hasCustomHeight) {
|
|
51
|
+
img.style.height = data.height;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
slideMedia.insertBefore(img, slideMedia.firstChild);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set slide inline content
|
|
3
|
+
* we'll extend this to make http
|
|
4
|
+
* requests using the fetch api
|
|
5
|
+
* but for now we keep it simple
|
|
6
|
+
*
|
|
7
|
+
* @param {node} slide
|
|
8
|
+
* @param {object} data
|
|
9
|
+
* @param {int} index
|
|
10
|
+
* @param {function} callback
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { has, addClass, addEvent, createHTML, isString, isNode, isFunction } from '../utils/helpers.js';
|
|
14
|
+
|
|
15
|
+
export default function slideInline(slide, data, index, callback) {
|
|
16
|
+
const slideMedia = slide.querySelector('.gslide-media');
|
|
17
|
+
const hash = has(data, 'href') && data.href ? data.href.split('#').pop().trim() : false;
|
|
18
|
+
const content = has(data, 'content') && data.content ? data.content : false;
|
|
19
|
+
let innerContent;
|
|
20
|
+
|
|
21
|
+
if (content) {
|
|
22
|
+
if (isString(content)) {
|
|
23
|
+
innerContent = createHTML(`<div class="ginlined-content">${content}</div>`);
|
|
24
|
+
}
|
|
25
|
+
if (isNode(content)) {
|
|
26
|
+
if (content.style.display == 'none') {
|
|
27
|
+
content.style.display = 'block';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const container = document.createElement('div');
|
|
31
|
+
container.className = 'ginlined-content';
|
|
32
|
+
container.appendChild(content);
|
|
33
|
+
innerContent = container;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (hash) {
|
|
38
|
+
let div = document.getElementById(hash);
|
|
39
|
+
if (!div) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const cloned = div.cloneNode(true);
|
|
43
|
+
|
|
44
|
+
cloned.style.height = data.height;
|
|
45
|
+
cloned.style.maxWidth = data.width;
|
|
46
|
+
addClass(cloned, 'ginlined-content');
|
|
47
|
+
innerContent = cloned;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!innerContent) {
|
|
51
|
+
console.error('Unable to append inline slide content', data);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
slideMedia.style.height = data.height;
|
|
56
|
+
slideMedia.style.width = data.width;
|
|
57
|
+
slideMedia.appendChild(innerContent);
|
|
58
|
+
|
|
59
|
+
this.events['inlineclose' + hash] = addEvent('click', {
|
|
60
|
+
onElement: slideMedia.querySelectorAll('.gtrigger-close'),
|
|
61
|
+
withCallback: (e) => {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
this.close();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (isFunction(callback)) {
|
|
68
|
+
callback();
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set slide video
|
|
3
|
+
*
|
|
4
|
+
* @param {node} slide
|
|
5
|
+
* @param {object} data
|
|
6
|
+
* @param {int} index
|
|
7
|
+
* @param {function} callback
|
|
8
|
+
*/
|
|
9
|
+
import { has, closest, injectAssets, addClass, removeClass, createHTML, isFunction, waitUntil } from '../utils/helpers.js';
|
|
10
|
+
|
|
11
|
+
export default function slideVideo(slide, data, index, callback) {
|
|
12
|
+
const slideContainer = slide.querySelector('.ginner-container');
|
|
13
|
+
const videoID = 'gvideo' + index;
|
|
14
|
+
const slideMedia = slide.querySelector('.gslide-media');
|
|
15
|
+
const videoPlayers = this.getAllPlayers();
|
|
16
|
+
|
|
17
|
+
addClass(slideContainer, 'gvideo-container');
|
|
18
|
+
|
|
19
|
+
slideMedia.insertBefore(createHTML('<div class="gvideo-wrapper"></div>'), slideMedia.firstChild);
|
|
20
|
+
|
|
21
|
+
const videoWrapper = slide.querySelector('.gvideo-wrapper');
|
|
22
|
+
|
|
23
|
+
injectAssets(this.settings.plyr.css, 'Plyr');
|
|
24
|
+
|
|
25
|
+
let url = data.href;
|
|
26
|
+
let provider = data?.videoProvider;
|
|
27
|
+
let customPlaceholder = false;
|
|
28
|
+
|
|
29
|
+
slideMedia.style.maxWidth = data.width;
|
|
30
|
+
|
|
31
|
+
injectAssets(this.settings.plyr.js, 'Plyr', () => {
|
|
32
|
+
// Set vimeo videos
|
|
33
|
+
if (!provider && url.match(/vimeo\.com\/([0-9]*)/)) {
|
|
34
|
+
provider = 'vimeo';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Set youtube videos
|
|
38
|
+
if (
|
|
39
|
+
!provider &&
|
|
40
|
+
(url.match(/(youtube\.com|youtube-nocookie\.com)\/watch\?v=([a-zA-Z0-9\-_]+)/) ||
|
|
41
|
+
url.match(/youtu\.be\/([a-zA-Z0-9\-_]+)/) ||
|
|
42
|
+
url.match(/(youtube\.com|youtube-nocookie\.com)\/embed\/([a-zA-Z0-9\-_]+)/) ||
|
|
43
|
+
url.match(/(youtube\.com|youtube-nocookie\.com)\/shorts\/([a-zA-Z0-9\-_]+)/))
|
|
44
|
+
) {
|
|
45
|
+
provider = 'youtube';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Set local videos
|
|
49
|
+
// if no provider, default to local
|
|
50
|
+
if (provider === 'local' || !provider) {
|
|
51
|
+
provider = 'local';
|
|
52
|
+
let html = '<video id="' + videoID + '" ';
|
|
53
|
+
html += `style="background:#000; max-width: ${data.width};" `;
|
|
54
|
+
html += 'preload="metadata" ';
|
|
55
|
+
html += 'x-webkit-airplay="allow" ';
|
|
56
|
+
html += 'playsinline ';
|
|
57
|
+
html += 'controls ';
|
|
58
|
+
html += 'class="gvideo-local">';
|
|
59
|
+
html += `<source src="${url}">`;
|
|
60
|
+
html += '</video>';
|
|
61
|
+
customPlaceholder = createHTML(html);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// prettier-ignore
|
|
65
|
+
const placeholder = customPlaceholder ? customPlaceholder : createHTML(`<div id="${videoID}" data-plyr-provider="${provider}" data-plyr-embed-id="${url}"></div>`);
|
|
66
|
+
|
|
67
|
+
addClass(videoWrapper, `${provider}-video gvideo`);
|
|
68
|
+
videoWrapper.appendChild(placeholder);
|
|
69
|
+
videoWrapper.setAttribute('data-id', videoID);
|
|
70
|
+
videoWrapper.setAttribute('data-index', index);
|
|
71
|
+
|
|
72
|
+
const playerConfig = has(this.settings.plyr, 'config') ? this.settings.plyr.config : {};
|
|
73
|
+
const player = new Plyr('#' + videoID, playerConfig);
|
|
74
|
+
|
|
75
|
+
player.on('ready', (event) => {
|
|
76
|
+
videoPlayers[videoID] = event.detail.plyr;
|
|
77
|
+
if (isFunction(callback)) {
|
|
78
|
+
callback();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
waitUntil(
|
|
82
|
+
() => {
|
|
83
|
+
return slide.querySelector('iframe') && slide.querySelector('iframe').dataset.ready == 'true';
|
|
84
|
+
},
|
|
85
|
+
() => {
|
|
86
|
+
this.resize(slide);
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
player.on('enterfullscreen', handleMediaFullScreen);
|
|
90
|
+
player.on('exitfullscreen', handleMediaFullScreen);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Handle fullscreen
|
|
96
|
+
*
|
|
97
|
+
* @param {object} event
|
|
98
|
+
*/
|
|
99
|
+
function handleMediaFullScreen(event) {
|
|
100
|
+
const media = closest(event.target, '.gslide-media');
|
|
101
|
+
|
|
102
|
+
if (event.type === 'enterfullscreen') {
|
|
103
|
+
addClass(media, 'fullscreen');
|
|
104
|
+
}
|
|
105
|
+
if (event.type === 'exitfullscreen') {
|
|
106
|
+
removeClass(media, 'fullscreen');
|
|
107
|
+
}
|
|
108
|
+
}
|