@tomasvn/glightbox 0.0.0-stage → 3.3.3

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.
Files changed (41) hide show
  1. package/.editorconfig +16 -0
  2. package/.eslintrc.json +94 -0
  3. package/.github/FUNDING.yml +3 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  6. package/.github/stale.yml +21 -0
  7. package/.github/workflows/greetings.yml +13 -0
  8. package/.lando.yml +10 -0
  9. package/.prettierignore +1 -0
  10. package/.prettierrc.json +31 -0
  11. package/CHANGELOG.md +247 -0
  12. package/CONTRIBUTING.md +29 -0
  13. package/LICENSE.md +21 -0
  14. package/README.md +710 -2
  15. package/bower.json +29 -0
  16. package/development/jscompiler.js +84 -0
  17. package/development/notifications.js +15 -0
  18. package/development/package.js +116 -0
  19. package/development/postcss.js +63 -0
  20. package/development/watcher.js +105 -0
  21. package/dist/css/glightbox.css +939 -0
  22. package/dist/css/glightbox.min.css +1 -0
  23. package/dist/js/glightbox.js +3087 -0
  24. package/dist/js/glightbox.min.js +1 -0
  25. package/index.d.ts +570 -0
  26. package/package.json +55 -4
  27. package/src/js/.jshintrc +6 -0
  28. package/src/js/core/drag.js +219 -0
  29. package/src/js/core/keyboard-navigation.js +98 -0
  30. package/src/js/core/slide-parser.js +231 -0
  31. package/src/js/core/slide.js +245 -0
  32. package/src/js/core/touch-events.js +378 -0
  33. package/src/js/core/touch-navigation.js +287 -0
  34. package/src/js/core/zoom.js +156 -0
  35. package/src/js/glightbox.js +1341 -0
  36. package/src/js/slides/iframe.js +24 -0
  37. package/src/js/slides/image.js +56 -0
  38. package/src/js/slides/inline.js +71 -0
  39. package/src/js/slides/video.js +105 -0
  40. package/src/js/utils/helpers.js +541 -0
  41. package/src/postcss/glightbox.css +723 -0
@@ -0,0 +1,219 @@
1
+ /**
2
+ * DragSlides
3
+ * Allow imaes to be dragged for prev and next
4
+ * in desktops
5
+ *
6
+ * @param { object } config
7
+ */
8
+
9
+ import { closest } from '../utils/helpers.js';
10
+
11
+ export default class DragSlides {
12
+ constructor(config = {}) {
13
+ let { dragEl, toleranceX = 40, toleranceY = 65, slide = null, instance = null } = config;
14
+
15
+ this.el = dragEl;
16
+ this.active = false;
17
+ this.dragging = false;
18
+ this.currentX = null;
19
+ this.currentY = null;
20
+ this.initialX = null;
21
+ this.initialY = null;
22
+ this.xOffset = 0;
23
+ this.yOffset = 0;
24
+ this.direction = null;
25
+ this.lastDirection = null;
26
+ this.toleranceX = toleranceX;
27
+ this.toleranceY = toleranceY;
28
+ this.toleranceReached = false;
29
+ this.dragContainer = this.el;
30
+ this.slide = slide;
31
+ this.instance = instance;
32
+
33
+ this.el.addEventListener('mousedown', (e) => this.dragStart(e), false);
34
+ this.el.addEventListener('mouseup', (e) => this.dragEnd(e), false);
35
+ this.el.addEventListener('mousemove', (e) => this.drag(e), false);
36
+ }
37
+ dragStart(e) {
38
+ if (this.slide.classList.contains('zoomed')) {
39
+ this.active = false;
40
+ return;
41
+ }
42
+
43
+ if (e.type === 'touchstart') {
44
+ this.initialX = e.touches[0].clientX - this.xOffset;
45
+ this.initialY = e.touches[0].clientY - this.yOffset;
46
+ } else {
47
+ this.initialX = e.clientX - this.xOffset;
48
+ this.initialY = e.clientY - this.yOffset;
49
+ }
50
+
51
+ let clicked = e.target.nodeName.toLowerCase();
52
+ let exludeClicks = ['input', 'select', 'textarea', 'button', 'a'];
53
+ if (
54
+ e.target.classList.contains('nodrag') ||
55
+ closest(e.target, '.nodrag') ||
56
+ exludeClicks.indexOf(clicked) !== -1
57
+ ) {
58
+ this.active = false;
59
+ return;
60
+ }
61
+
62
+ e.preventDefault();
63
+
64
+ if (e.target === this.el || (clicked !== 'img' && closest(e.target, '.gslide-inline'))) {
65
+ this.active = true;
66
+ this.el.classList.add('dragging');
67
+ this.dragContainer = closest(e.target, '.ginner-container');
68
+ }
69
+ }
70
+ dragEnd(e) {
71
+ e && e.preventDefault();
72
+ this.initialX = 0;
73
+ this.initialY = 0;
74
+ this.currentX = null;
75
+ this.currentY = null;
76
+ this.initialX = null;
77
+ this.initialY = null;
78
+ this.xOffset = 0;
79
+ this.yOffset = 0;
80
+ this.active = false;
81
+
82
+ if (this.doSlideChange) {
83
+ this.instance.preventOutsideClick = true;
84
+ this.doSlideChange == 'right' && this.instance.prevSlide();
85
+ this.doSlideChange == 'left' && this.instance.nextSlide();
86
+ }
87
+
88
+ if (this.doSlideClose) {
89
+ this.instance.close();
90
+ }
91
+
92
+ if (!this.toleranceReached) {
93
+ this.setTranslate(this.dragContainer, 0, 0, true);
94
+ }
95
+
96
+ setTimeout(() => {
97
+ this.instance.preventOutsideClick = false;
98
+ this.toleranceReached = false;
99
+ this.lastDirection = null;
100
+ this.dragging = false;
101
+ this.el.isDragging = false;
102
+ this.el.classList.remove('dragging');
103
+ this.slide.classList.remove('dragging-nav');
104
+ this.dragContainer.style.transform = '';
105
+ this.dragContainer.style.transition = '';
106
+ }, 100);
107
+ }
108
+ drag(e) {
109
+ if (this.active) {
110
+ e.preventDefault();
111
+
112
+ this.slide.classList.add('dragging-nav');
113
+
114
+ if (e.type === 'touchmove') {
115
+ this.currentX = e.touches[0].clientX - this.initialX;
116
+ this.currentY = e.touches[0].clientY - this.initialY;
117
+ } else {
118
+ this.currentX = e.clientX - this.initialX;
119
+ this.currentY = e.clientY - this.initialY;
120
+ }
121
+
122
+ this.xOffset = this.currentX;
123
+ this.yOffset = this.currentY;
124
+
125
+ this.el.isDragging = true;
126
+ this.dragging = true;
127
+ this.doSlideChange = false;
128
+ this.doSlideClose = false;
129
+
130
+ let currentXInt = Math.abs(this.currentX);
131
+ let currentYInt = Math.abs(this.currentY);
132
+
133
+ // Horizontal drag
134
+ if (
135
+ currentXInt > 0 &&
136
+ currentXInt >= Math.abs(this.currentY) &&
137
+ (!this.lastDirection || this.lastDirection == 'x')
138
+ ) {
139
+ this.yOffset = 0;
140
+ this.lastDirection = 'x';
141
+ this.setTranslate(this.dragContainer, this.currentX, 0);
142
+
143
+ let doChange = this.shouldChange();
144
+ if (!this.instance.settings.dragAutoSnap && doChange) {
145
+ this.doSlideChange = doChange;
146
+ }
147
+
148
+ if (this.instance.settings.dragAutoSnap && doChange) {
149
+ this.instance.preventOutsideClick = true;
150
+ this.toleranceReached = true;
151
+ this.active = false;
152
+ this.instance.preventOutsideClick = true;
153
+ this.dragEnd(null);
154
+ doChange == 'right' && this.instance.prevSlide();
155
+ doChange == 'left' && this.instance.nextSlide();
156
+ return;
157
+ }
158
+ }
159
+
160
+ // Vertical drag
161
+ if (
162
+ this.toleranceY > 0 &&
163
+ currentYInt > 0 &&
164
+ currentYInt >= currentXInt &&
165
+ (!this.lastDirection || this.lastDirection == 'y')
166
+ ) {
167
+ this.xOffset = 0;
168
+ this.lastDirection = 'y';
169
+ this.setTranslate(this.dragContainer, 0, this.currentY);
170
+
171
+ let doClose = this.shouldClose();
172
+
173
+ if (!this.instance.settings.dragAutoSnap && doClose) {
174
+ this.doSlideClose = true;
175
+ }
176
+ if (this.instance.settings.dragAutoSnap && doClose) {
177
+ this.instance.close();
178
+ }
179
+ return;
180
+ }
181
+ }
182
+ }
183
+
184
+ shouldChange() {
185
+ let doChange = false;
186
+ let currentXInt = Math.abs(this.currentX);
187
+
188
+ if (currentXInt >= this.toleranceX) {
189
+ let dragDir = this.currentX > 0 ? 'right' : 'left';
190
+
191
+ if (
192
+ (dragDir == 'left' && this.slide !== this.slide.parentNode.lastChild) ||
193
+ (dragDir == 'right' && this.slide !== this.slide.parentNode.firstChild)
194
+ ) {
195
+ doChange = dragDir;
196
+ }
197
+ }
198
+ return doChange;
199
+ }
200
+
201
+ shouldClose() {
202
+ let doClose = false;
203
+ let currentYInt = Math.abs(this.currentY);
204
+
205
+ if (currentYInt >= this.toleranceY) {
206
+ doClose = true;
207
+ }
208
+ return doClose;
209
+ }
210
+
211
+ setTranslate(node, xPos, yPos, animated = false) {
212
+ if (animated) {
213
+ node.style.transition = 'all .2s ease';
214
+ } else {
215
+ node.style.transition = '';
216
+ }
217
+ node.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`;
218
+ }
219
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Keyboard Navigation
3
+ * Allow navigation using the keyboard
4
+ *
5
+ * @param {object} instance
6
+ */
7
+
8
+ import { addEvent, addClass, removeClass, each } from '../utils/helpers.js';
9
+
10
+ function getNextFocusElement(current = -1) {
11
+ const btns = document.querySelectorAll('.gbtn[data-taborder]:not(.disabled)');
12
+ if (!btns.length) {
13
+ return false;
14
+ }
15
+
16
+ if (btns.length == 1) {
17
+ return btns[0];
18
+ }
19
+
20
+ if (typeof current == 'string') {
21
+ current = parseInt(current);
22
+ }
23
+
24
+ const orders = [];
25
+ each(btns, (btn) => {
26
+ orders.push(btn.getAttribute('data-taborder'));
27
+ });
28
+ const highestOrder = Math.max.apply(Math, orders.map((order) => parseInt(order)));
29
+
30
+ let newIndex = current < 0 ? 1 : current + 1;
31
+ if (newIndex > highestOrder) {
32
+ newIndex = '1';
33
+ }
34
+
35
+ const nextOrders = orders.filter((el) => el >= parseInt(newIndex));
36
+ const nextFocus = nextOrders.sort()[0];
37
+
38
+ return document.querySelector(`.gbtn[data-taborder="${nextFocus}"]`);
39
+ }
40
+
41
+ export default function keyboardNavigation(instance) {
42
+ if (instance.events.hasOwnProperty('keyboard')) {
43
+ return false;
44
+ }
45
+
46
+ instance.events['keyboard'] = addEvent('keydown', {
47
+ onElement: window,
48
+ withCallback: (event, target) => {
49
+ event = event || window.event;
50
+ const key = event.keyCode;
51
+ if (key == 9) {
52
+ //prettier-ignore
53
+ const focusedButton = document.querySelector('.gbtn.focused');
54
+
55
+ if (!focusedButton) {
56
+ const activeElement = document.activeElement && document.activeElement.nodeName ? document.activeElement.nodeName.toLocaleLowerCase() : false;
57
+ if (activeElement == 'input' || activeElement == 'textarea' || activeElement == 'button') {
58
+ return;
59
+ }
60
+ }
61
+
62
+ event.preventDefault();
63
+ const btns = document.querySelectorAll('.gbtn[data-taborder]');
64
+ if (!btns || btns.length <= 0) {
65
+ return;
66
+ }
67
+
68
+ if (!focusedButton) {
69
+ const first = getNextFocusElement();
70
+ if (first) {
71
+ first.focus();
72
+ addClass(first, 'focused');
73
+ }
74
+ return;
75
+ }
76
+
77
+ let currentFocusOrder = focusedButton.getAttribute('data-taborder');
78
+ let nextFocus = getNextFocusElement(currentFocusOrder);
79
+
80
+ removeClass(focusedButton, 'focused');
81
+
82
+ if (nextFocus) {
83
+ nextFocus.focus();
84
+ addClass(nextFocus, 'focused');
85
+ }
86
+ }
87
+ if (key == 39) {
88
+ instance.nextSlide();
89
+ }
90
+ if (key == 37) {
91
+ instance.prevSlide();
92
+ }
93
+ if (key == 27) {
94
+ instance.close();
95
+ }
96
+ }
97
+ });
98
+ }
@@ -0,0 +1,231 @@
1
+ import { extend, has, each, isNil, isNode, isObject, isNumber } from '../utils/helpers.js';
2
+
3
+ export default class SlideConfigParser {
4
+ constructor(slideParamas = {}) {
5
+ this.defaults = {
6
+ href: '',
7
+ sizes: '',
8
+ srcset: '',
9
+ title: '',
10
+ type: '',
11
+ videoProvider: '',
12
+ description: '',
13
+ alt: '',
14
+ descPosition: 'bottom',
15
+ effect: '',
16
+ width: '',
17
+ height: '',
18
+ content: false,
19
+ zoomable: true,
20
+ draggable: true
21
+ };
22
+
23
+ if (isObject(slideParamas)) {
24
+ this.defaults = extend(this.defaults, slideParamas);
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Get source type
30
+ * gte the source type of a url
31
+ *
32
+ * @param {string} url
33
+ */
34
+ sourceType(url) {
35
+ let origin = url;
36
+ url = url.toLowerCase();
37
+
38
+ if (url.match(/\.(jpeg|jpg|jpe|gif|png|apn|webp|avif|svg)/) !== null) {
39
+ return 'image';
40
+ }
41
+ if (url.match(/(youtube\.com|youtube-nocookie\.com)\/watch\?v=([a-zA-Z0-9\-_]+)/) || url.match(/youtu\.be\/([a-zA-Z0-9\-_]+)/) || url.match(/(youtube\.com|youtube-nocookie\.com)\/embed\/([a-zA-Z0-9\-_]+)/) || url.match(/(youtube\.com|youtube-nocookie\.com)\/shorts\/([a-zA-Z0-9\-_]+)/)) {
42
+ return 'video';
43
+ }
44
+ if (url.match(/vimeo\.com\/([0-9]*)/)) {
45
+ return 'video';
46
+ }
47
+ if (url.match(/\.(mp4|ogg|webm|mov)/) !== null) {
48
+ return 'video';
49
+ }
50
+ if (url.match(/\.(mp3|wav|wma|aac|ogg)/) !== null) {
51
+ return 'audio';
52
+ }
53
+
54
+ // Check if inline content
55
+ if (url.indexOf('#') > -1) {
56
+ let hash = origin.split('#').pop();
57
+ if (hash.trim() !== '') {
58
+ return 'inline';
59
+ }
60
+ }
61
+ // Ajax
62
+ if (url.indexOf('goajax=true') > -1) {
63
+ return 'ajax';
64
+ }
65
+
66
+ return 'external';
67
+ }
68
+
69
+ parseConfig(element, settings) {
70
+ let data = extend({ descPosition: settings.descPosition }, this.defaults);
71
+
72
+ if (isObject(element) && !isNode(element)) {
73
+ if (!has(element, 'type')) {
74
+ if (has(element, 'content') && element.content) {
75
+ element.type = 'inline';
76
+ } else if (has(element, 'href')) {
77
+ element.type = this.sourceType(element.href);
78
+ }
79
+ }
80
+ let objectData = extend(data, element);
81
+ this.setSize(objectData, settings);
82
+
83
+ return objectData;
84
+ }
85
+
86
+ let url = '';
87
+ let config = element.getAttribute('data-glightbox');
88
+ let nodeType = element.nodeName.toLowerCase();
89
+
90
+ if (nodeType === 'a') {
91
+ url = element.href;
92
+ }
93
+ if (nodeType === 'img') {
94
+ url = element.src;
95
+ //alt attribute propagation
96
+ data.alt = element.alt;
97
+ }
98
+
99
+ data.href = url;
100
+
101
+ each(data, (val, key) => {
102
+ if (has(settings, key) && key !== 'width') {
103
+ data[key] = settings[key];
104
+ }
105
+ const nodeData = element.dataset[key];
106
+ if (!isNil(nodeData)) {
107
+ data[key] = this.sanitizeValue(nodeData);
108
+ }
109
+ });
110
+
111
+ if (data.content) {
112
+ data.type = 'inline';
113
+ }
114
+
115
+ if (!data.type && url) {
116
+ data.type = this.sourceType(url);
117
+ }
118
+
119
+ if (!isNil(config)) {
120
+ let cleanKeys = [];
121
+ each(data, (v, k) => {
122
+ cleanKeys.push(';\\s?' + k);
123
+ });
124
+ cleanKeys = cleanKeys.join('\\s?:|');
125
+ if (config.trim() !== '') {
126
+ each(data, (val, key) => {
127
+ const str = config;
128
+ const match = 's?' + key + 's?:s?(.*?)(' + cleanKeys + 's?:|$)';
129
+ const regex = new RegExp(match);
130
+ const matches = str.match(regex);
131
+
132
+ if (matches && matches.length && matches[1]) {
133
+ const value = matches[1].trim().replace(/;\s*$/, '');
134
+ data[key] = this.sanitizeValue(value);
135
+ }
136
+ });
137
+ }
138
+ } else {
139
+ if (!data.title && nodeType == 'a') {
140
+ let title = element.title;
141
+ if (!isNil(title) && title !== '') {
142
+ data.title = title;
143
+ }
144
+ }
145
+ if (!data.title && nodeType == 'img') {
146
+ let alt = element.alt;
147
+ if (!isNil(alt) && alt !== '') {
148
+ data.title = alt;
149
+ }
150
+ }
151
+ }
152
+
153
+ // Try to get the description from a referenced element
154
+ if (data.description && data.description.substring(0, 1) === '.') {
155
+ let description;
156
+
157
+ try {
158
+ description = document.querySelector(data.description).innerHTML;
159
+ } catch (error) {
160
+ if (!(error instanceof DOMException)) {
161
+ throw error;
162
+ }
163
+ }
164
+
165
+ if (description) {
166
+ data.description = description;
167
+ }
168
+ }
169
+
170
+ // Try to get the description from a .glightbox-desc element
171
+ if (!data.description) {
172
+ let nodeDesc = element.querySelector('.glightbox-desc');
173
+ if (nodeDesc) {
174
+ data.description = nodeDesc.innerHTML;
175
+ }
176
+ }
177
+
178
+ this.setSize(data, settings, element);
179
+ this.slideConfig = data;
180
+
181
+ return data;
182
+ }
183
+
184
+ /**
185
+ * Set slide data size
186
+ * set the correct size dependin
187
+ * on the slide type
188
+ *
189
+ * @param { object } data
190
+ * @param { object } settings
191
+ * @return { object }
192
+ */
193
+ setSize(data, settings, element = null) {
194
+ const defaultWith = data.type == 'video' ? this.checkSize(settings.videosWidth) : this.checkSize(settings.width);
195
+ const defaultHeight = this.checkSize(settings.height);
196
+
197
+ data.width = has(data, 'width') && data.width !== '' ? this.checkSize(data.width) : defaultWith;
198
+ data.height = has(data, 'height') && data.height !== '' ? this.checkSize(data.height) : defaultHeight;
199
+
200
+ if (element && data.type == 'image') {
201
+ data._hasCustomWidth = element.dataset.width ? true : false;
202
+ data._hasCustomHeight = element.dataset.height ? true : false;
203
+ }
204
+
205
+ return data;
206
+ }
207
+
208
+ /**
209
+ * [checkSize size
210
+ * check if the passed size has a correct unit
211
+ *
212
+ * @param {string} size
213
+ * @return {string}
214
+ */
215
+ checkSize(size) {
216
+ return isNumber(size) ? `${size}px` : size;
217
+ }
218
+
219
+ /**
220
+ * Sanitize data attributes value
221
+ *
222
+ * @param string val
223
+ * @return mixed
224
+ */
225
+ sanitizeValue(val) {
226
+ if (val !== 'true' && val !== 'false') {
227
+ return val;
228
+ }
229
+ return val === 'true';
230
+ }
231
+ }