PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.7
VikBooking Hotel Booking Engine & PMS v1.6.7
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / site / resources / vik-dots-slider.js

vik-dots-slider.js in VikBooking Hotel Booking Engine & PMS 1.6.7, at site/resources/vik-dots-slider.js

554 lines 16.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * @package VikBooking
3 * @subpackage vikDotsSlider
4 * @version 1.2.0
5 * @author Alessio Gaggii - E4J srl
6 * @copyright Copyright (C) 2021 E4J srl. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://e4j.com - https://vikwp.com
9 */
10
11 (function($) {
12
13 var VikDotsSlider = function(elem, options) {
14
15 this.sliderElement = elem;
16 this.sliderDataName = 'vik-dots-slider-id';
17 this.sliderIdPrefix = 'vik-dots-slider-id-';
18 this.xDown = null;
19 this.yDown = null;
20 this.preloadedImages = [];
21 this.currentSlide = 0;
22 this.previousSlide = 0;
23 this.sliderContainer = null;
24
25 this.defaultSettings = {
26 images: [],
27 captions: [],
28 containerClass: 'vik-dots-slider-container',
29 containerHeight: '200px',
30 innerClass: 'vik-dots-slider-inner',
31 slidesClass: 'vik-dots-slider-slides',
32 slideClass: 'vik-dots-slider-slide',
33 captionClass: 'vik-dots-slider-slide-caption',
34 slideStartClass: 'vik-dots-slider-slide-start',
35 slideLeftCurrClass: 'vik-dots-slider-slide-leftcurr',
36 slideLeftNextClass: 'vik-dots-slider-slide-leftnext',
37 slideRightNextClass: 'vik-dots-slider-slide-rightnext',
38 slideRightCurrClass: 'vik-dots-slider-slide-rightcurr',
39 dotsContainerClass: 'vik-dots-slider-dots',
40 dotClass: 'vik-dots-slider-dot',
41 activeDotClass: 'vik-dots-slider-dot-active',
42 hasmoreDotClass: 'vik-dots-slider-dot-hasmore',
43 maxDots: 5,
44 navButContainerClass: 'vik-dots-slider-navbuttons',
45 navButClass: 'vik-dots-slider-navbutton',
46 navButPrevClass: 'vik-dots-slider-navbutton-prev',
47 navButNextClass: 'vik-dots-slider-navbutton-next',
48 navButPrevContent: '<',
49 navButNextContent: '>',
50 enableGestures: true,
51 onDisplaySlide: function() {},
52 };
53
54 this.settings = $.extend(true, {}, this.defaultSettings, options);
55
56 this.options = function(options) {
57 return options ? $.extend(true, this.settings, options) : this.settings;
58 };
59
60 this.countSlides = function() {
61 return this.settings.images.length;
62 };
63
64 this.generateSliderId = function() {
65 return ((parseInt(Math.random() * 1000)) + '');
66 };
67
68 this.goToSlide = function(e) {
69 if (e) {
70 e.preventDefault();
71 }
72 // retrieve dot from data passed to event handler
73 var dot = jQuery(e.data.dot);
74 var gotopos = dot.data('pos');
75 if (gotopos == null || gotopos == this.currentSlide) {
76 return false;
77 }
78 if (gotopos > this.currentSlide) {
79 // show requested slide navigating left
80 this.showSlide((gotopos + 1));
81 } else {
82 // show requested slide navigating right
83 this.showSlide((gotopos + 1), true);
84 }
85 };
86
87 this.prevSlide = function(e) {
88 if (e) {
89 e.preventDefault();
90 }
91 var gotopos = this.currentSlide - 1;
92 if (gotopos < 0) {
93 gotopos = (this.countSlides() - 1);
94 } else if (gotopos >= this.countSlides()) {
95 gotopos = 0;
96 }
97 if (gotopos == this.currentSlide) {
98 return false;
99 }
100 if (gotopos > this.currentSlide) {
101 // show requested slide navigating left
102 this.showSlide((gotopos + 1));
103 } else {
104 // show requested slide navigating right
105 this.showSlide((gotopos + 1), true);
106 }
107 };
108
109 this.nextSlide = function(e) {
110 if (e) {
111 e.preventDefault();
112 }
113 var gotopos = this.currentSlide + 1;
114 if (gotopos < 0) {
115 gotopos = (this.countSlides() - 1);
116 } else if (gotopos >= this.countSlides()) {
117 gotopos = 0;
118 }
119 if (gotopos == this.currentSlide) {
120 return false;
121 }
122 if (gotopos > this.currentSlide) {
123 // show requested slide navigating left
124 this.showSlide((gotopos + 1));
125 } else {
126 // show requested slide navigating right
127 this.showSlide((gotopos + 1), true);
128 }
129 };
130
131 this.getSlide = function(i) {
132 if (this.sliderContainer == null) {
133 return [];
134 }
135
136 return this.sliderContainer.find('.' + this.settings.slideClass + '[data-pos="' + i + '"]');
137 };
138
139 this.getDot = function(i) {
140 if (this.sliderContainer == null) {
141 return [];
142 }
143
144 return this.sliderContainer.find('.' + this.settings.dotClass + '[data-pos="' + i + '"]');
145 };
146
147 this.getDotByIndex = function(i) {
148 if (this.sliderContainer == null) {
149 return [];
150 }
151
152 return this.sliderContainer.find('.' + this.settings.dotClass).eq(i);
153 };
154
155 this.showSlide = function(pos, right) {
156 if (this.sliderContainer == null) {
157 return false;
158 }
159
160 var animatingClasses = [
161 this.settings.slideLeftCurrClass,
162 this.settings.slideLeftNextClass,
163 this.settings.slideRightNextClass,
164 this.settings.slideRightCurrClass,
165 ];
166 var removeClasses = animatingClasses.join(' ');
167
168 if (!pos) {
169 pos = ((this.currentSlide + 1) < this.countSlides() ? (this.currentSlide + 2) : 1);
170 }
171
172 --pos;
173 // update previous slide
174 this.getSlide(this.previousSlide).removeClass(removeClasses);
175
176 if (!right) {
177 this.getSlide(pos).removeClass(removeClasses).addClass(this.settings.slideLeftNextClass);
178 this.getSlide(this.currentSlide).removeClass(removeClasses).addClass(this.settings.slideLeftCurrClass);
179 } else {
180 this.getSlide(pos).removeClass(removeClasses).addClass(this.settings.slideRightNextClass);
181 this.getSlide(this.currentSlide).removeClass(removeClasses).addClass(this.settings.slideRightCurrClass);
182 }
183
184 this.previousSlide = this.currentSlide;
185 this.currentSlide = pos;
186
187 var currentDot = this.getDot(this.currentSlide);
188 if (currentDot.length) {
189 currentDot.addClass(this.settings.activeDotClass);
190 }
191 var prevDot = this.getDot(this.previousSlide);
192 if (prevDot.length) {
193 prevDot.removeClass(this.settings.activeDotClass);
194 }
195
196 // update dots pos attributes in case max dots was reached
197 if (this.countSlides() > this.settings.maxDots && this.settings.maxDots > 1) {
198 // dots cannot represent all slides
199 var isFirstSlide = (this.currentSlide === 0);
200 var isLastSlide = ((this.currentSlide + 1) == this.countSlides());
201
202 if (isFirstSlide) {
203 // renumber dots from the beginning
204 for (var d = 0; d < this.settings.maxDots; d++) {
205 var dot = this.getDotByIndex(d);
206 if (dot.length) {
207 dot.data('pos', d).attr('data-pos', d);
208 if (d === 0) {
209 dot.addClass(this.settings.activeDotClass).removeClass(this.settings.hasmoreDotClass);
210 } else {
211 dot.removeClass(this.settings.activeDotClass);
212 if (d === (this.settings.maxDots - 1)) {
213 dot.addClass(this.settings.hasmoreDotClass);
214 }
215 }
216 }
217 }
218 } else if (isLastSlide) {
219 // renumber dots from the end
220 var missingdots = (this.countSlides() - this.settings.maxDots);
221 for (var d = 0; d < this.settings.maxDots; d++) {
222 var dot = this.getDotByIndex(d);
223 if (dot.length) {
224 var newpos = d + missingdots;
225 dot.data('pos', newpos).attr('data-pos', newpos);
226 if (d === (this.settings.maxDots - 1)) {
227 dot.addClass(this.settings.activeDotClass).removeClass(this.settings.hasmoreDotClass);
228 } else {
229 dot.removeClass(this.settings.activeDotClass);
230 if (d === 0) {
231 dot.addClass(this.settings.hasmoreDotClass);
232 }
233 }
234 }
235 }
236 } else {
237 // we are in the middle, renumber dots
238 var dotselindex = (this.currentSlide + 1) < this.settings.maxDots ? this.currentSlide : (this.settings.maxDots - 2);
239 var dotaddpos = (this.currentSlide + 1) < this.settings.maxDots ? 0 : (this.currentSlide - this.settings.maxDots + 2);
240 var dothasmoreindex = (this.currentSlide + 1) >= this.settings.maxDots ? [0, dotselindex + 1] : [-1, this.settings.maxDots - 1];
241 for (var d = 0; d < this.settings.maxDots; d++) {
242 var dot = this.getDotByIndex(d);
243 if (dot.length) {
244 var newpos = d + dotaddpos;
245 dot.data('pos', newpos).attr('data-pos', newpos);
246 if (d == dotselindex) {
247 dot.addClass(this.settings.activeDotClass);
248 } else {
249 dot.removeClass(this.settings.activeDotClass);
250 }
251 if (d === dothasmoreindex[0] || d === dothasmoreindex[1]) {
252 dot.addClass(this.settings.hasmoreDotClass);
253 } else {
254 dot.removeClass(this.settings.hasmoreDotClass);
255 }
256 }
257 }
258 }
259 }
260 };
261
262 this.generateNavButtons = function() {
263 var navbuttons = $('<div></div>').addClass(this.settings.navButContainerClass);
264 if (this.countSlides() < 2) {
265 return navbuttons;
266 }
267 var navprev = $('<span></span>').addClass(this.settings.navButClass + ' ' + this.settings.navButPrevClass).append(this.settings.navButPrevContent).on('click', this.prevSlide.bind(this));
268 var navnext = $('<span></span>').addClass(this.settings.navButClass + ' ' + this.settings.navButNextClass).append(this.settings.navButNextContent).on('click', this.nextSlide.bind(this));
269 navbuttons.append(navprev).append(navnext);
270
271 return navbuttons;
272 };
273
274 this.generateDots = function() {
275 var dots = $('<div></div>').addClass(this.settings.dotsContainerClass);
276 var tot_slides = this.countSlides();
277 if (this.settings.maxDots < 1 || tot_slides < 2) {
278 return dots;
279 }
280 var canfitall = (this.settings.maxDots >= tot_slides);
281 for (var i = 0; i < tot_slides; i++) {
282 // generate dot, set pos attribute
283 var dot = $('<span></span>').addClass(this.settings.dotClass).data('pos', i).attr('data-pos', i);
284 // define click handler by passing the collection and by binding thisArg to the class instance
285 dot.on('click', {dot: dot}, this.goToSlide.bind(this))
286 if (i == this.currentSlide) {
287 dot.addClass(this.settings.activeDotClass);
288 }
289 if (!canfitall && i == (this.settings.maxDots - 1)) {
290 dot.addClass(this.settings.hasmoreDotClass);
291 }
292 dots.append(dot);
293 if ((i + 1) == this.settings.maxDots) {
294 break;
295 }
296 }
297
298 return dots;
299 };
300
301 this.generateSlides = function() {
302 var slides = $('<div></div>').addClass(this.settings.slidesClass);
303 for (var i = 0; i < this.countSlides(); i++) {
304 var slide = $('<div></div>').data('pos', i).attr('data-pos', i).addClass(this.settings.slideClass);
305 if (i == this.currentSlide) {
306 slide.addClass(this.settings.slideStartClass);
307 }
308 if (this.settings.captions.hasOwnProperty(i) && this.settings.captions[i].length) {
309 var caption = $('<span></span>').addClass(this.settings.captionClass).text(this.settings.captions[i]);
310 slide.append(caption);
311 }
312 var photo = $('<img src="' + this.settings.images[i] + '" />');
313 slide.append(photo);
314
315 // fire onDisplaySlide callback by passing the whole slide content
316 this.settings.onDisplaySlide.call(slide);
317
318 // append slide
319 slides.append(slide);
320 }
321
322 return slides;
323 };
324
325 this.sliderTouches = function(e) {
326 if (!this.settings.enableGestures) {
327 return false;
328 }
329 if (e.touches) {
330 // JS
331 return e.touches;
332 }
333 if (e.originalEvent.touches) {
334 // jQuery
335 return e.originalEvent.touches;
336 }
337 return false;
338 };
339
340 this.sliderTouchStart = function(e) {
341 var firstTouch = this.sliderTouches(e)[0];
342 if (firstTouch === false) {
343 return;
344 }
345 this.xDown = firstTouch.clientX;
346 this.yDown = firstTouch.clientY;
347 };
348
349 this.sliderTouchMove = function(e) {
350 if (!this.xDown || !this.yDown || this.countSlides() < 2) {
351 return;
352 }
353 // register touch positions
354 var xUp = e.touches[0].clientX;
355 var yUp = e.touches[0].clientY;
356 var xDiff = this.xDown - xUp;
357 var yDiff = this.yDown - yUp;
358
359 // detect gesture type
360 if (Math.abs(xDiff) > Math.abs(yDiff)) {
361 if (xDiff > 0) {
362 // left swipe, navigate forward
363 this.nextSlide(e);
364 } else {
365 // right swipe, navigate backward
366 this.prevSlide(e);
367 }
368 } else {
369 if (yDiff > 0) {
370 // up swipe is ignored
371 } else {
372 // down swipe is ignored
373 }
374 }
375
376 // reset vars to handle the next touch gesture
377 this.xDown = null;
378 this.yDown = null;
379 };
380
381 this.registerGestures = function(elem) {
382 if (!elem) {
383 return;
384 }
385 elem.addEventListener('touchstart', this.sliderTouchStart.bind(this), false);
386 elem.addEventListener('touchmove', this.sliderTouchMove.bind(this), false);
387 };
388
389 this.preloadURLs = function(urls) {
390 if (urls == null || !urls.length) {
391 return;
392 }
393 for (var i = 0; i < urls.length; i++) {
394 var photoslide = (new Image()).src = urls[i];
395 this.preloadedImages.push(photoslide);
396 }
397 };
398
399 this.display = function() {
400 // update global vars
401 this.currentSlide = 0;
402 this.previousSlide = (this.countSlides() - 1);
403
404 // if an instance is already present in the current element, remove it
405 if (this.sliderElement.find('.' + this.settings.containerClass).length) {
406 this.sliderElement.find('.' + this.settings.containerClass).remove();
407 }
408
409 // generate slider random ID
410 var sliderId = this.generateSliderId();
411
412 // generate slider container by updating global var
413 this.sliderContainer = $('<div></div>').addClass(this.settings.containerClass).data(this.sliderDataName, sliderId).attr('id', this.sliderIdPrefix + sliderId);
414
415 // register gesture events for mobiles
416 this.registerGestures(this.sliderContainer[0]);
417
418 // builder slider inner
419 var inner = $('<div></div>').addClass(this.settings.innerClass).css('height', this.settings.containerHeight);
420
421 // build slider container
422 this.sliderContainer.append(
423 inner.append(
424 this.generateSlides().append(
425 this.generateNavButtons()
426 )
427 ).append(
428 this.generateDots()
429 )
430 );
431
432 // append slider to current selector
433 this.sliderElement.append(this.sliderContainer);
434 };
435
436 this.update = function() {
437 this.destroy();
438 this.display();
439 };
440
441 this.destroy = function() {
442 this.sliderContainer.remove();
443 };
444
445 this.preloadImages = function(gallery) {
446 gallery = gallery[0];
447 if (gallery == null) {
448 return false;
449 }
450
451 var preloadQueue = {};
452
453 for (var gallery_id in gallery) {
454 if (!gallery.hasOwnProperty(gallery_id)) {
455 continue;
456 }
457 if (typeof gallery[gallery_id] == 'string' && gallery[gallery_id].indexOf('http') >= 0) {
458 // we have an array of photo URLs
459 var photoslide = (new Image()).src = gallery[gallery_id];
460 this.preloadedImages.push(photoslide);
461 continue;
462 }
463 if (typeof gallery[gallery_id] == 'object' && gallery[gallery_id].length) {
464 // we have a gallery object with the photos of each room so we queue the preloading
465 for (var i = 0; i < gallery[gallery_id].length; i++) {
466 if (!preloadQueue.hasOwnProperty(i)) {
467 preloadQueue[i] = [];
468 }
469 // push the photo url for later loading
470 preloadQueue[i].push(gallery[gallery_id][i]);
471 }
472 }
473 }
474
475 // if some preloading was queued, define the loading intervals
476 var queue_timer = 0;
477 for (var i in preloadQueue) {
478 if (!preloadQueue.hasOwnProperty(i)) {
479 continue;
480 }
481 // schedule preloading with timeout
482 setTimeout(this.preloadURLs.bind(this, preloadQueue[i]), queue_timer);
483 // increase timer for next scheduling (1 second per photo)
484 queue_timer += (1000 * preloadQueue[i].length);
485 }
486
487 return this.preloadedImages;
488 };
489
490 };
491
492 $.fn.vikDotsSlider = function(methodOrOptions) {
493
494 var method = typeof methodOrOptions === 'string' ? methodOrOptions : null;
495
496 if (method) {
497 var sliderInstances = [];
498
499 function getVikDotsSliderInstance() {
500 var vikDotsSlider = $(this).data('vikDotsSlider');
501 sliderInstances.push(vikDotsSlider);
502 }
503
504 this.each(getVikDotsSliderInstance);
505
506 var args = (arguments.length > 1) ? Array.prototype.slice.call(arguments, 1) : null;
507 var results = [];
508
509 function applyMethod(index) {
510 var vikDotsSlider = sliderInstances[index];
511
512 if (!vikDotsSlider) {
513 if (method == 'preloadImages') {
514 // preloadImages is the only method that can be called before instantiating vikDotsSlider
515 vikDotsSlider = new VikDotsSlider($(this), {});
516 var result = vikDotsSlider[method].call(vikDotsSlider, $(this));
517 results.push(result);
518 return;
519 } else {
520 console.error('$.vikDotsSlider not instantiated yet');
521 results.push(null);
522 return;
523 }
524 }
525
526 if (typeof vikDotsSlider[method] === 'function') {
527 var result = vikDotsSlider[method].apply(vikDotsSlider, args);
528 results.push(result);
529 } else {
530 console.error('Method \'' + method + '\' is undefined in $.vikDotsSlider');
531 }
532 }
533
534 this.each(applyMethod);
535
536 return (results.length > 1) ? results : results[0];
537 } else {
538 var options = (typeof methodOrOptions === 'object') ? methodOrOptions : null;
539
540 function init() {
541 var vikDotsSlider = new VikDotsSlider($(this), options);
542
543 vikDotsSlider.display();
544
545 $(this).data('vikDotsSlider', vikDotsSlider);
546 }
547
548 return this.each(init);
549 }
550
551 };
552
553 })(jQuery);
554