PluginProbe
Orderable – Restaurant & Food Ordering System / 1.14.0
Orderable – Restaurant & Food Ordering System v1.14.0
0.1.4 0.1.5 0.2.0 1.0.0 1.1.0 1.1.1 1.10.0 1.10.1 1.11.0 1.12.0 1.12.1 1.12.2 1.13.0 1.14.0 1.15.0 1.16.0 1.17.0 1.17.1 1.18.0 1.19.0 1.19.1 1.19.2 1.2.0 1.20.0 1.20.1 All 44 releases
orderable / assets / frontend / js / main.js

main.js in Orderable – Restaurant & Food Ordering System 1.14.0, at assets/frontend/js/main.js

1,512 lines 53.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1
2 (function ($, document) {
3 'use strict';
4
5 var orderable_accordion = {
6 /**
7 * On doc ready.
8 */
9 on_ready() {
10 orderable_accordion.cache();
11 orderable_accordion.watch();
12 },
13 /**
14 * Cache.
15 */
16 cache() {
17 orderable_accordion.vars = {
18 classes: {
19 parent: 'orderable-accordion',
20 link: 'orderable-accordion__item-link',
21 content: 'orderable-accordion__item-content',
22 link_active: 'orderable-accordion__item-link--active',
23 content_active: 'orderable-accordion__item-content--active'
24 }
25 };
26 },
27 /**
28 * Watch.
29 */
30 watch() {
31 /**
32 * When click accordion link.
33 */
34 $(document.body).on('click', '.' + orderable_accordion.vars.classes.link, function (e) {
35 e.preventDefault();
36 const $link = $(this),
37 $parent = $link.closest('.' + orderable_accordion.vars.classes.parent),
38 content_id = $link.attr('href'),
39 $content = $(content_id),
40 is_active = $link.hasClass(orderable_accordion.vars.classes.link_active);
41 $parent.find('.' + orderable_accordion.vars.classes.link).removeClass(orderable_accordion.vars.classes.link_active);
42 $parent.find('.' + orderable_accordion.vars.classes.content).removeClass(orderable_accordion.vars.classes.content_active);
43 if (!is_active) {
44 $link.addClass(orderable_accordion.vars.classes.link_active);
45 $content.addClass(orderable_accordion.vars.classes.content_active);
46 }
47 $(document.body).trigger('orderable-accordion.toggled', {
48 link: $link,
49 content: $content
50 });
51 });
52
53 /**
54 * When drawer is opened.
55 */
56 $(document.body).on('orderable-scrollbar.created', function (e, args) {
57 const $active_accordion = $('.orderable-drawer .' + orderable_accordion.vars.classes.link_active);
58 if ($active_accordion.length <= 0) {
59 return;
60 }
61 const $scroll_content = args.content,
62 scroll_position = $scroll_content.scrollTop() - $scroll_content.offset().top + $active_accordion.offset().top;
63 $scroll_content.scrollTop(scroll_position);
64 });
65 }
66 };
67 $(document).ready(orderable_accordion.on_ready);
68 })(jQuery, document);
69 (function ($, document) {
70 'use strict';
71
72 var orderable_drawer = {
73 /**
74 * Delays invoking function
75 *
76 * @param {Function} func The function to debounce.
77 * @param {number} timeout The number of milliseconds to delay.
78 * @return {Function} Returns the new debounced function.
79 */
80 debounce(func, timeout = 700) {
81 let timer;
82 return (...args) => {
83 clearTimeout(timer);
84 timer = setTimeout(() => {
85 func.apply(this, args);
86 }, timeout);
87 };
88 },
89 /**
90 * Allow only number for events like keypress
91 *
92 * @param {Event} event
93 */
94 allow_only_numbers(event) {
95 const value = String.fromCharCode(event.which);
96 if (!/^\d+$/.test(value)) {
97 event.preventDefault();
98 }
99 },
100 /**
101 * Send a request to change the quantity.
102 *
103 * @param {Event} event
104 */
105 on_change_quantity(event) {
106 const quantityElement = $(event.currentTarget);
107 const product_id = quantityElement.data('orderable-product-id');
108 const cart_item_key = quantityElement.data('orderable-cart-item-key');
109 const quantity = parseInt(quantityElement.text());
110 const data = {
111 action: 'orderable_cart_quantity',
112 cart_item_key,
113 product_id,
114 quantity
115 };
116 jQuery.post(orderable_vars.ajax_url, data, function (response) {
117 if (!response) {
118 return;
119 }
120 $(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, quantityElement]);
121 $(document.body).trigger('orderable-drawer.quantity-updated');
122 });
123 },
124 /**
125 * On doc ready.
126 */
127 on_ready() {
128 orderable_drawer.cache();
129 orderable_drawer.watch();
130
131 /**
132 * Handle manually changing the quantity of a product.
133 */
134 $(document.body).on('keypress', '.orderable-quantity-roller__quantity', orderable_drawer.allow_only_numbers);
135 $('.orderable-drawer__cart, .orderable-product--add-to-cart, .orderable-products-list').on('input', '.orderable-quantity-roller__quantity', orderable_drawer.debounce(orderable_drawer.on_change_quantity));
136 $(document.body).on('click', '.orderable-quantity-roller__quantity', function (event) {
137 event.stopPropagation();
138 });
139
140 /**
141 * We turn off the click event for .add_to_cart_button elements
142 * to keep the AJAX behaviour only on Mini cart when the option
143 * "Enable AJAX add to cart buttons on archives" is disabled.
144 */
145 if (orderable_vars && !orderable_vars.woocommerce_enable_ajax_add_to_cart) {
146 $(document.body).off('click', '.add_to_cart_button');
147 }
148 },
149 /**
150 * Cache.
151 */
152 cache() {
153 orderable_drawer.vars = {
154 classes: {
155 overlay: 'orderable-drawer-overlay',
156 drawer: 'orderable-drawer',
157 drawer_cart: 'orderable-drawer__cart',
158 drawer_html: 'orderable-drawer__html',
159 overlay_open: 'orderable-drawer-overlay--open',
160 drawer_open: 'orderable-drawer--open',
161 drawer_open_body: 'orderable-drawer-open'
162 }
163 };
164 orderable_drawer.elements = {
165 body: $('body'),
166 overlay: $('.' + orderable_drawer.vars.classes.overlay),
167 drawer: $('.' + orderable_drawer.vars.classes.drawer),
168 drawer_cart: $('.' + orderable_drawer.vars.classes.drawer_cart),
169 drawer_html: $('.' + orderable_drawer.vars.classes.drawer_html),
170 floating_cart_button_class: '.orderable-floating-cart__button'
171 };
172 },
173 /**
174 * Watch for trigger events.
175 */
176 watch() {
177 if (typeof orderable_drawer.elements.drawer === 'undefined') {
178 return;
179 }
180 $(document.body).on('orderable-drawer.open', orderable_drawer.open);
181 $(document.body).on('orderable-drawer.close', orderable_drawer.close);
182 $(document.body).on('click', orderable_drawer.elements.floating_cart_button_class, function () {
183 $(document.body).trigger('orderable-drawer.open', {
184 show_cart: true
185 });
186 });
187 $(document.body).on('orderable-increase-quantity', orderable_drawer.cart.handle_quantity_change_by_button);
188 $(document.body).on('orderable-decrease-quantity', orderable_drawer.cart.handle_quantity_change_by_button);
189 const updateQuantityRequest = orderable_drawer.debounce(orderable_drawer.cart.click_increase_decrease_quantity);
190 $(document.body).on('orderable-increase-quantity', updateQuantityRequest);
191 $(document.body).on('orderable-decrease-quantity', updateQuantityRequest);
192 const drawer = document.querySelector('body:not( .rtl ) .orderable-drawer');
193 const drawer_rtl = document.querySelector('body.rtl .orderable-drawer');
194 if (drawer) {
195 drawer.addEventListener('swiped-right', function (e) {
196 orderable_drawer.close();
197 });
198 }
199 if (drawer_rtl) {
200 drawer_rtl.addEventListener('swiped-left', function (e) {
201 orderable_drawer.close();
202 });
203 }
204 },
205 /**
206 * Open the drawer.
207 * @param event
208 * @param args
209 */
210 open(event, args) {
211 args.html = args.html || false;
212 args.show_cart = args.show_cart || false;
213 orderable_drawer.elements.drawer_html.hide();
214 orderable_drawer.elements.drawer_cart.hide();
215 if (args.html) {
216 orderable_drawer.elements.drawer_html.html(args.html);
217 orderable_drawer.elements.drawer_html.show();
218 }
219 if (args.show_cart) {
220 // Empty drawer HTML before showing cart. Prevents options
221 // interfering with subsequent cart additions.
222 orderable_drawer.elements.drawer_html.html('');
223 orderable_drawer.elements.drawer_cart.show();
224 }
225 orderable_drawer.elements.overlay.addClass(orderable_drawer.vars.classes.overlay_open);
226 orderable_drawer.elements.drawer.addClass(orderable_drawer.vars.classes.drawer_open);
227 orderable_drawer.elements.body.addClass(orderable_drawer.vars.classes.drawer_open_body);
228 $(document.body).trigger('orderable-drawer.opened', args);
229 },
230 /**
231 * Close the drawer.
232 */
233 close() {
234 orderable_drawer.elements.overlay.removeClass(orderable_drawer.vars.classes.overlay_open);
235 orderable_drawer.elements.drawer.removeClass(orderable_drawer.vars.classes.drawer_open);
236 orderable_drawer.elements.body.removeClass(orderable_drawer.vars.classes.drawer_open_body);
237 orderable_drawer.elements.drawer_html.html('');
238 $(document.body).trigger('orderable-drawer.closed');
239 },
240 /**
241 * Mini cart related functions.
242 */
243 cart: {
244 /**
245 * When increase qty is clicked.
246 *
247 * @param e
248 * @param $button
249 */
250 click_increase_decrease_quantity(e, $button) {
251 const direction = $button.data('orderable-trigger');
252 const product_id = $button.attr('data-orderable-product-id'),
253 cart_item_key = $button.attr('data-orderable-cart-item-key'),
254 quantity = $button.attr('data-orderable-quantity');
255 const siblingButtonName = 'increase-quantity' === direction ? 'decrease' : 'increase';
256 const $siblingButton = $button.siblings(`.orderable-quantity-roller__button--${siblingButtonName}`);
257 const $quantityElement = $button.siblings('.orderable-quantity-roller__quantity');
258 const data = {
259 action: 'orderable_cart_quantity',
260 cart_item_key,
261 product_id,
262 quantity
263 };
264 if (this.currentRequest) {
265 this.currentRequest.abort();
266 this.currentRequest = undefined;
267 }
268 $button.addClass('orderable-button--loading');
269 $button.attr('disabled', true);
270 $siblingButton.attr('disabled', true);
271 $quantityElement.attr('contenteditable', false);
272 this.currentRequest = jQuery.post(orderable_vars.ajax_url, data, function (response) {
273 if (!response) {
274 return;
275 }
276 const $quantityElement = $button.siblings('.orderable-quantity-roller__quantity');
277 if (response && response.fragments && response.fragments['.orderable-mini-cart__notices']) {
278 $(document.body).trigger('orderable-drawer.open', {
279 show_cart: true
280 });
281 }
282 switch (data.quantity) {
283 case '0':
284 $(document.body).trigger('removed_from_cart', [response.fragments, response.cart_hash, $button]);
285 break;
286 case $quantityElement.attr('data-orderable-updating-quantity'):
287 $(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $button]);
288 $(document.body).trigger('orderable-drawer.quantity-updated');
289 break;
290 default:
291 break;
292 }
293 }.bind(this)).always(function () {
294 this.currentRequest = undefined;
295 $button.removeClass('orderable-button--loading');
296 $button.attr('disabled', false);
297 $siblingButton.attr('disabled', false);
298 $quantityElement.attr('contenteditable', true);
299 }.bind(this));
300 },
301 handle_quantity_change_by_button(e, $button) {
302 const direction = $button.data('orderable-trigger');
303 const quantity = parseInt($button.attr('data-orderable-quantity'));
304 const siblingButtonName = 'increase-quantity' === direction ? 'decrease' : 'increase';
305 const $siblingButton = $button.siblings(`.orderable-quantity-roller__button--${siblingButtonName}`);
306 const $quantityElement = $button.siblings('.orderable-quantity-roller__quantity');
307 const newQuantity = 'increase-quantity' === direction ? quantity + 1 : Math.max(0, quantity - 1);
308 const $parent = $button.parents('.orderable-product__actions-button');
309 if (0 === newQuantity && $parent.length) {
310 const $addToCartButton = $parent.find('button.orderable-button[data-orderable-trigger]');
311 const $quantityRoller = $parent.find('.orderable-quantity-roller');
312 if ($quantityRoller.length) {
313 $addToCartButton.removeClass('orderable-button--product-in-the-cart');
314 $quantityRoller.removeClass('orderable-quantity-roller--is-active');
315 }
316 }
317 $button.attr('data-orderable-quantity', newQuantity);
318 $siblingButton.attr('data-orderable-quantity', newQuantity);
319 $quantityElement.attr('data-orderable-updating-quantity', newQuantity);
320 $quantityElement.text(newQuantity);
321 $quantityElement.attr('contenteditable', false);
322 }
323 }
324 };
325 $(document).ready(orderable_drawer.on_ready);
326 })(jQuery, document);
327 (function ($, document) {
328 'use strict';
329
330 var orderable_products = {
331 /**
332 * On doc ready.
333 */
334 on_ready() {
335 orderable_products.cache();
336 orderable_products.watch();
337 },
338 /**
339 * Cache.
340 */
341 cache() {
342 orderable_products.vars = {
343 classes: {
344 clickable_product: 'orderable-product--add-to-cart ',
345 add_to_order_button: 'orderable-product__add-to-order',
346 product_messages: 'orderable-product__messages',
347 product_price: 'orderable-product__actions-price',
348 invalid_field: 'orderable-field--invalid',
349 option_select_td: 'orderable-product__option-select',
350 button_loading: 'orderable-button--loading',
351 out_of_stock: 'orderable-button--out-of-stock'
352 },
353 parent_price: null,
354 variable_product_types: ['variable', 'variable-subscription']
355 };
356 orderable_products.elements = {};
357 },
358 /**
359 * Watch for trigger events.
360 */
361 watch() {
362 $(document.body).on('orderable-drawer.opened', orderable_products.init_product_options);
363 $(document.body).on('orderable-add-to-cart', orderable_products.click_add_to_order);
364 $(document.body).on('orderable-product-options', orderable_products.click_add_to_order);
365 $(document.body).on('orderable-view-product', orderable_products.view_product);
366 $(document.body).on('mouseenter mouseleave', '.' + orderable_products.vars.classes.clickable_product, orderable_products.simulate_add_to_order_hover);
367 $(document.body).on('orderable-edit-cart-item', orderable_products.edit_cart_item);
368 $(document.body).on('orderable-update-cart-item', orderable_products.update_cart_item);
369 $(document.body).on('orderable-show-cart', orderable_products.show_cart);
370 $(document.body).on('orderable-add-to-cart-without-side-drawer', orderable_products.click_add_to_order);
371 $(document.body).on('added_to_cart', orderable_products.remove_fragments);
372 $(document.body).on('added_to_cart', orderable_products.remove_animation);
373 $(document.body).on('added_to_cart', orderable_products.shake_floating_cart);
374 $(document.body).on('removed_from_cart', orderable_products.hide_quantity_roller);
375 $(document.body).on('wc_cart_button_updated', orderable_products.remove_view_cart_link);
376 },
377 /**
378 * Simulate hover on add to order button.
379 *
380 * @param event
381 */
382 simulate_add_to_order_hover(event) {
383 const $element = $(this),
384 $button = $element.find('.' + orderable_products.vars.classes.add_to_order_button);
385 $button.toggleClass('orderable-button--hover', 'mouseenter' === event.type);
386 },
387 /**
388 * Add to order click event.
389 *
390 * This event accounts for button clicks or card clicks.
391 * @param event
392 * @param $element
393 */
394 click_add_to_order(event, $element) {
395 // If undefined, it means it was triggered by a click
396 // event and not the `orderable-add-to-cart` trigger.
397 $element = typeof $element !== 'undefined' ? $element : $(this);
398
399 // The button is either the clicked element, or the
400 // add to order button within the clicked element.
401 const $button = $element.is('button') ? $element : $element.find('.' + orderable_products.vars.classes.add_to_order_button),
402 action = $button.data('orderable-trigger'),
403 product_id = $button.data('orderable-product-id'),
404 variation_id = $button.data('orderable-variation-id'),
405 attributes = $button.data('orderable-variation-attributes'),
406 args = {
407 action
408 };
409 if ($button.hasClass(orderable_products.vars.classes.button_loading) || $button.hasClass(orderable_products.vars.classes.out_of_stock)) {
410 return;
411 }
412 $button.addClass(orderable_products.vars.classes.button_loading);
413 switch (action) {
414 case 'add-to-cart':
415 orderable_products.add_to_cart({
416 product_id,
417 variation_id,
418 attributes,
419 thisbutton: $element
420 }, function (response) {
421 args.show_cart = true;
422 args.response = response;
423 $(document.body).trigger('orderable-drawer.open', args);
424 $button.removeClass(orderable_products.vars.classes.button_loading);
425 const $addToCartButtonOutsideDrawer = $('.orderable-product .orderable-product__actions-button button.orderable-product__add-to-order[data-orderable-product-id=' + product_id + ']');
426 if ($addToCartButtonOutsideDrawer.siblings('.orderable-quantity-roller').length) {
427 $addToCartButtonOutsideDrawer.addClass('orderable-button--product-in-the-cart');
428 }
429 });
430 break;
431 case 'add-to-cart-without-side-drawer':
432 orderable_products.add_to_cart({
433 product_id,
434 variation_id,
435 attributes
436 }, function (response) {
437 args.response = response;
438 $button.addClass('orderable-button--product-in-the-cart');
439 $button.removeClass(orderable_products.vars.classes.button_loading);
440 });
441 break;
442 case 'product-options':
443 orderable_products.get_product_options({
444 product_id,
445 focus: $button.data('orderable-focus')
446 }, function (response) {
447 args.html = response.html;
448 $(document.body).trigger('orderable-drawer.open', args);
449 $button.removeClass(orderable_products.vars.classes.button_loading);
450 });
451 break;
452 default:
453 break;
454 }
455 },
456 /**
457 * Show the cart.
458 */
459 show_cart() {
460 $(document.body).trigger('orderable-drawer.open', {
461 show_cart: true
462 });
463 },
464 /**
465 * View product.
466 *
467 * @param event
468 * @param $element
469 */
470 view_product(event, $element) {
471 const product_id = $element.data('orderable-product-id'),
472 args = {
473 action: 'product-options'
474 };
475 orderable_products.get_product_options({
476 product_id,
477 focus: $element.data('orderable-focus')
478 }, function (response) {
479 args.html = response.html;
480 $(document.body).trigger('orderable-drawer.open', args);
481 });
482 },
483 /**
484 * Ajax add to cart.
485 * @param args
486 * @param callback
487 */
488 add_to_cart(args, callback) {
489 if (typeof args.product_id === 'undefined') {
490 return;
491 }
492 let data = {
493 action: 'orderable_add_to_cart',
494 product_id: args.product_id,
495 variation_id: args.variation_id || false,
496 attributes: args.attributes || false
497 };
498
499 // Prepare addons data.
500 if ($('.orderable-product-fields-group').length) {
501 let inputs = jQuery('.orderable-product-fields-group :input').serializeArray();
502 inputs = orderable_products.add_unchecked_checkbox_fields(inputs);
503 const addons_data = orderable_products.convert_to_flat_object(inputs);
504 if (!jQuery.isEmptyObject(addons_data)) {
505 data = Object.assign(data, addons_data); // Merge objects.
506 }
507 }
508 jQuery.post(orderable_vars.ajax_url, data, function (response) {
509 if (!response) {
510 return;
511 }
512
513 // Trigger event so themes can refresh other areas.
514 $(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, args.thisbutton]);
515 if (typeof callback === 'function') {
516 callback(response);
517 }
518 });
519 },
520 /**
521 * Edit cart item.
522 *
523 * @param event
524 * @param $element
525 */
526 edit_cart_item(event, $element) {
527 const cart_item_key = $element.data('orderable-cart-item-key');
528 $element.addClass(orderable_products.vars.classes.button_loading);
529 orderable_products.get_cart_item_options({
530 cart_item_key
531 }, function (response) {
532 const args = {
533 html: response.html,
534 action: 'update-cart-item'
535 };
536 $(document.body).trigger('orderable-drawer.open', args);
537 $element.removeClass(orderable_products.vars.classes.button_loading);
538 });
539 },
540 /**
541 * Update cart item.
542 *
543 * @param event
544 * @param $element
545 */
546 update_cart_item(event, $element) {
547 const cart_item_key = $element.data('orderable-cart-item-key');
548 const product_id = $element.data('orderable-product-id');
549 const variation_id = $element.data('orderable-variation-id');
550 const attributes = $element.data('orderable-variation-attributes');
551 $element.addClass(orderable_products.vars.classes.button_loading);
552 orderable_products.update_cart_item_options({
553 cart_item_key,
554 product_id,
555 variation_id,
556 attributes
557 }, function (response) {
558 const args = {
559 show_cart: true,
560 response
561 };
562 $(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash]);
563 $(document.body).trigger('orderable-drawer.open', args);
564 $element.removeClass(orderable_products.vars.classes.button_loading);
565 });
566 },
567 /**
568 * Convert [{name:x, value:y }] to {x:y} format.
569 * @param inputs
570 */
571 convert_to_flat_object(inputs) {
572 const data = {};
573 inputs.forEach(function (input) {
574 const is_array = '[]' === input.name.substr(-2) || Array.isArray(input.name);
575 // If last 2 chars are '[]', remove them.
576 const key = is_array ? input.name.substr(0, input.name.length - 2) : input.name;
577 if (is_array) {
578 data[key] = typeof data[key] === 'undefined' ? [] : data[key];
579 data[key].push(input.value);
580 } else {
581 data[key] = input.value;
582 }
583 });
584 return data;
585 },
586 /**
587 * Get variable product options.
588 *
589 * @param args
590 * @param callback
591 */
592 get_product_options(args, callback) {
593 if (typeof args.product_id === 'undefined') {
594 return;
595 }
596 args.action = 'orderable_get_product_options';
597 jQuery.post(orderable_vars.ajax_url, args, function (response) {
598 if (!response.success) {
599 return;
600 }
601 if (typeof callback === 'function') {
602 callback(response.data);
603 }
604 });
605 },
606 /**
607 * Get variable product options.
608 *
609 * @param args
610 * @param callback
611 */
612 get_cart_item_options(args, callback) {
613 if (typeof args.cart_item_key === 'undefined') {
614 return;
615 }
616 args.action = 'orderable_get_cart_item_options';
617 jQuery.post(orderable_vars.ajax_url, args, function (response) {
618 if (!response.success) {
619 return;
620 }
621 if (typeof callback === 'function') {
622 callback(response.data);
623 }
624 });
625 },
626 /**
627 * Update variable product options.
628 *
629 * @param args
630 * @param callback
631 */
632 update_cart_item_options(args, callback) {
633 if (typeof args.cart_item_key === 'undefined') {
634 return;
635 }
636 args.action = 'orderable_update_cart_item_options';
637
638 // Prepare addons data.
639 if ($('.orderable-product-fields-group').length) {
640 let inputs = jQuery('.orderable-product-fields-group :input').serializeArray();
641 inputs = orderable_products.add_unchecked_checkbox_fields(inputs);
642 const addons_data = orderable_products.convert_to_flat_object(inputs);
643 if (!jQuery.isEmptyObject(addons_data)) {
644 args = Object.assign(args, addons_data); // Merge objects.
645 }
646 }
647 jQuery.post(orderable_vars.ajax_url, args, function (response) {
648 if (!response) {
649 return;
650 }
651 if (typeof callback === 'function') {
652 callback(response);
653 }
654 });
655 },
656 /**
657 * Init drawer product options.
658 *
659 * @param event
660 * @param args
661 */
662 init_product_options(event, args) {
663 if (typeof args.action === 'undefined' || 'product-options' !== args.action && 'update-cart-item' !== args.action) {
664 return;
665 }
666 const selectors = '.orderable-drawer .orderable-product__options input, .orderable-drawer .orderable-product__options select, .orderable-product__options textarea';
667 const $options = $(selectors);
668 orderable_products.vars.parent_price = $('.orderable-drawer .orderable-product__actions-price').html();
669 orderable_products.product_options_change($options);
670 orderable_products.update_button_state();
671 const debounced_update_button_state = orderable_products.debounce(orderable_products.update_button_state, 500);
672 const debounced_product_options_change = orderable_products.debounce(orderable_products.product_options_change, 500);
673 $(document).on('change keyup', selectors, function () {
674 debounced_product_options_change($options);
675 debounced_update_button_state();
676 });
677 },
678 /**
679 * On product options change.
680 *
681 * @param $options
682 */
683 product_options_change($options) {
684 const $add_to_order_button = $('.orderable-drawer .orderable-product__add-to-order, .orderable-drawer .orderable-product__update-cart-item'),
685 options_set = orderable_products.check_options($options),
686 product_type = $add_to_order_button.data('orderable-product-type');
687 if ('product-options' === $add_to_order_button.attr('data-orderable-trigger')) {
688 $add_to_order_button.attr('data-orderable-trigger', 'add-to-cart');
689 }
690 $('.' + orderable_products.vars.classes.product_messages).html('');
691 if (!orderable_products.vars.variable_product_types.includes(product_type)) {
692 return;
693 }
694 if (!options_set) {
695 orderable_products.clear_variation($add_to_order_button);
696 return;
697 }
698 const variation = orderable_products.check_variation($options);
699 orderable_products.set_variation($add_to_order_button, variation);
700 },
701 /**
702 * Check if all product options are set.
703 *
704 * @param $options
705 * @return {boolean}
706 */
707 check_options($options) {
708 if ($options.length <= 0) {
709 return false;
710 }
711 let all_set = true;
712 $options.each(function (index, option) {
713 // Only check attribute fields.
714 if (!$(option).hasClass('orderable-input--validate')) {
715 return;
716 }
717 if ('' === $(option).val()) {
718 $(option).addClass(orderable_products.vars.classes.invalid_field);
719 all_set = false;
720 } else {
721 $(option).removeClass(orderable_products.vars.classes.invalid_field);
722 }
723 });
724 return all_set;
725 },
726 /**
727 * Check if variation has been selected.
728 * @param $options
729 */
730 check_variation($options) {
731 const $product = $options.closest('.orderable-drawer');
732 let variations = $product.find('.orderable-product__variations').text();
733 variations = variations ? JSON.parse(variations) : '';
734 const selected_options = orderable_products.serialize_object($options),
735 matching_variations = orderable_products.find_matching_variations(variations, selected_options);
736 if (orderable_products.is_empty(matching_variations)) {
737 return false;
738 }
739 const variation = matching_variations.shift();
740 variation.attributes = selected_options;
741 variation.attributes_json = JSON.stringify(selected_options);
742 return typeof variation !== 'undefined' ? variation : false;
743 },
744 /**
745 * Set variation for add to cart button.
746 * @param $button
747 * @param variation
748 */
749 set_variation($button, variation) {
750 let variation_id = variation.variation_id || '',
751 attributes = variation.attributes_json || '',
752 price = variation.price_html || orderable_products.vars.parent_price,
753 message = '';
754 if (variation && '' !== variation.availability_html) {
755 message = variation.availability_html;
756 }
757 if (variation && !variation.is_in_stock) {
758 message = '<p>' + orderable_vars.i18n.out_of_stock + '</p>';
759 }
760 if (variation && !variation.is_purchasable) {
761 message = '<p>' + orderable_vars.i18n.unavailable + '</p>';
762 }
763 if (false === variation) {
764 message = '<p>' + orderable_vars.i18n.no_exist + '</p>';
765 }
766 if (variation && (!variation.is_purchasable || !variation.is_in_stock)) {
767 variation_id = '';
768 attributes = '';
769 }
770 if ('' !== message) {
771 $('.' + orderable_products.vars.classes.product_messages).html(message);
772 }
773 $button.data('orderable-variation-id', variation_id);
774 $button.data('orderable-variation-attributes', attributes);
775 $('.orderable-drawer .orderable-product__actions-price').html(price);
776 $button.trigger('orderable_variation_set', {
777 variation,
778 variation_id,
779 attributes,
780 price
781 });
782 },
783 /**
784 * Clear variation and disable add to order.
785 *
786 * @param $button
787 */
788 clear_variation($button) {
789 orderable_products.set_variation($button, '');
790 if (orderable_products.vars.parent_price) {
791 $('.orderable-drawer .orderable-product__actions-price').html(orderable_products.vars.parent_price);
792 }
793 },
794 /**
795 * Find matching variations for attributes.
796 * @param variations
797 * @param attributes
798 */
799 find_matching_variations(variations, attributes) {
800 const matching = [];
801 for (let i = 0; i < variations.length; i++) {
802 const variation = variations[i];
803 if (orderable_products.is_matching_variation(variation.attributes, attributes)) {
804 matching.push(variation);
805 }
806 }
807 return matching;
808 },
809 /**
810 * See if attributes match.
811 * @param variation_attributes
812 * @param attributes
813 * @return {boolean}
814 */
815 is_matching_variation(variation_attributes, attributes) {
816 let match = true;
817 for (const attr_name in variation_attributes) {
818 if (variation_attributes.hasOwnProperty(attr_name)) {
819 const val1 = variation_attributes[attr_name];
820 const val2 = attributes[attr_name];
821 if (val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2) {
822 match = false;
823 }
824 }
825 }
826 return match;
827 },
828 /**
829 * Is value empty?
830 *
831 * @param value
832 * @return {boolean}
833 */
834 is_empty(value) {
835 return typeof value === 'undefined' || false === value || value.length <= 0 || !value;
836 },
837 /**
838 * Serialize into a key/value object.
839 *
840 * @param $elements
841 * @return {{}}
842 */
843 serialize_object: function objectifyForm($elements) {
844 const serialized = $elements.serializeArray(),
845 return_object = {};
846 for (let i = 0; i < serialized.length; i++) {
847 return_object[serialized[i].name] = serialized[i].value;
848 }
849 return return_object;
850 },
851 /**
852 * Disable/Enable the 'Add to cart' button based on the presence of orderable-field--invalid class.
853 */
854 update_button_state() {
855 // Add delay to ensure invalid class has been assigned to inputs.
856 setTimeout(function () {
857 let $button = $('.orderable-drawer .orderable-product__add-to-order, .orderable-drawer .orderable-product__update-cart-item'),
858 invalid_fields_count = $('.orderable-drawer__html .' + orderable_products.vars.classes.invalid_field).length,
859 product_type = $button.data('orderable-product-type'),
860 has_variation_id = true;
861 if ('variable' === product_type) {
862 has_variation_id = '' !== $button.data('orderable-variation-id');
863 }
864 $button.prop('disabled', invalid_fields_count || !has_variation_id);
865 }, 50);
866 },
867 /**
868 * Debounce function.
869 *
870 * @param func Function to debounce.
871 * @param wait Time to wait in milliseconds.
872 * @param immediate Trigger the function on the leading edge, instead of the trailing.
873 *
874 * @return
875 */
876 debounce(func, wait, immediate) {
877 let timeout;
878 return function () {
879 const context = this,
880 args = arguments;
881 const later = function () {
882 timeout = null;
883 if (!immediate) {
884 func.apply(context, args);
885 }
886 };
887 const callNow = immediate && !timeout;
888 clearTimeout(timeout);
889 timeout = setTimeout(later, wait);
890 if (callNow) {
891 func.apply(context, args);
892 }
893 };
894 },
895 /**
896 * Remove the quantity roller fragments
897 *
898 * @param {Event} e
899 * @param {Object} fragments
900 * @return void
901 */
902 remove_fragments(e, fragments) {
903 if (!fragments || 'undefined' === typeof wc_cart_fragments_params || !wc_cart_fragments_params.fragment_name) {
904 return;
905 }
906 const regex_quantity_roller = /\.orderable-product\[data-orderable-product-id='[1-9][0-9]*'\] \.orderable-product__actions-button \.orderable-quantity-roller/;
907 const regex_product_in_the_cart_counter = /\.orderable-product\[data-orderable-product-id='[1-9][0-9]*'\] \.orderable-product__actions-button \.orderable-product__actions-counter/;
908 for (const key in fragments) {
909 if (!regex_quantity_roller.test(key) && !regex_product_in_the_cart_counter.test(key)) {
910 continue;
911 }
912 fragments[key] = undefined;
913 }
914 sessionStorage.setItem(wc_cart_fragments_params.fragment_name, JSON.stringify(fragments));
915 },
916 /**
917 * Remove animation.
918 */
919 remove_animation() {
920 setTimeout(function () {
921 $('.orderable-product__actions-counter').css('animation', '');
922 }, 1000);
923 },
924 /**
925 * Hide quantity roller element and show the Add to Cart button.
926 *
927 * @param {Event} e
928 * @param {Object} fragments
929 * @param {string} cart_hash
930 * @param {Element} $button
931 * @return
932 */
933 hide_quantity_roller(e, fragments, cart_hash, $button) {
934 const product_id = $button.attr('data-product_id') || $button.attr('data-orderable-product-id');
935 if (!product_id) {
936 return;
937 }
938 const $actions_button = $('.orderable-product[data-orderable-product-id=' + product_id + '] .orderable-product__actions-button');
939 if (!$actions_button.length) {
940 return;
941 }
942 const $quantity_roller = $actions_button.find('.orderable-quantity-roller');
943 if ($quantity_roller.length) {
944 $actions_button.find('button.orderable-product__add-to-order[data-orderable-trigger]').removeClass('orderable-button--product-in-the-cart');
945 $quantity_roller.addClass('orderable-button--hide');
946 }
947 },
948 /**
949 * Add unchecked checkboxs to the list of inputs
950 * sent to the request to add/update an item
951 *
952 * @param {Object} inputs
953 * @return {Object}
954 */
955 add_unchecked_checkbox_fields(inputs) {
956 jQuery('.orderable-product-fields-group :input[type="checkbox"]:not(:checked)').each(function (index, element) {
957 inputs.push({
958 name: element.getAttribute('name'),
959 value: ''
960 });
961 });
962 return inputs;
963 },
964 /**
965 * Shake the floating cart button.
966 *
967 * @return void
968 */
969 shake_floating_cart() {
970 $('.orderable-floating-cart__button').css('animation', 'wobble-hor-bottom .8s both');
971 },
972 /**
973 * Remove the view cart link.
974 *
975 * @param event
976 * @param $button
977 */
978 remove_view_cart_link(event, $button) {
979 if (!$button?.hasClass('orderable-product__add-to-order')) {
980 return;
981 }
982 $button?.siblings('.added_to_cart.wc-forward').remove();
983 }
984 };
985 $(document).ready(orderable_products.on_ready);
986 })(jQuery, document);
987 (function ($, document) {
988 'use strict';
989
990 var orderable_scrollbar = {
991 /**
992 * On doc ready.
993 */
994 on_ready() {
995 orderable_scrollbar.cache();
996 orderable_scrollbar.watch();
997 },
998 /**
999 * Cache.
1000 */
1001 cache() {
1002 orderable_scrollbar.vars = {
1003 top: {}
1004 };
1005 orderable_scrollbar.elements = {};
1006 },
1007 /**
1008 * Watch.
1009 */
1010 watch() {
1011 $(document.body).on('orderable-drawer.opened', orderable_scrollbar.trigger);
1012 $(document.body).on('orderable-tabs.changed', orderable_scrollbar.trigger);
1013 $(document.body).on('orderable-accordion.toggled', orderable_scrollbar.trigger);
1014 $(document.body).on('wc_fragments_loaded', orderable_scrollbar.trigger);
1015 },
1016 /**
1017 * Init or retrigger scrollbars.
1018 */
1019 trigger() {
1020 $('.orderable-sb-container').each(function (index, element) {
1021 const $element = $(element),
1022 scroll_id = $element.data('orderable-scroll-id');
1023 if (!orderable_scrollbar.has_scrollbar($element)) {
1024 $element.scrollBox({
1025 containerClass: 'orderable-sb-container',
1026 containerNoScrollClass: 'orderable-sb-container-noscroll',
1027 contentClass: 'orderable-sb-content',
1028 scrollbarContainerClass: 'orderable-sb-scrollbar-container',
1029 scrollBarClass: 'orderable-sb-scrollbar'
1030 });
1031 const $content = $element.find('.orderable-sb-content');
1032 if ($content.length > 0) {
1033 $content.on('scroll.scrollBox', orderable_scrollbar.log_top_position);
1034
1035 // Set scroll position.
1036 if (typeof orderable_scrollbar.vars.top[scroll_id] !== 'undefined') {
1037 $content.scrollTop(orderable_scrollbar.vars.top[scroll_id]);
1038 }
1039 }
1040 $(document.body).trigger('orderable-scrollbar.created', {
1041 element: $element,
1042 content: $content
1043 });
1044 }
1045 });
1046 $(window).trigger('resize.scrollBox');
1047 },
1048 /**
1049 * Has scrollbar already?
1050 *
1051 * @param $element
1052 * @return {boolean}
1053 */
1054 has_scrollbar($element) {
1055 return $element.find('.orderable-sb-content').length > 0;
1056 },
1057 /**
1058 * Set scrolltop position.
1059 *
1060 * @param e
1061 */
1062 log_top_position(e) {
1063 const $element = $(e.currentTarget),
1064 $container = $element.closest('.orderable-sb-container'),
1065 scroll_id = $container.data('orderable-scroll-id');
1066 orderable_scrollbar.vars.top[scroll_id] = $(e.currentTarget).scrollTop();
1067 }
1068 };
1069 $(document).ready(orderable_scrollbar.on_ready);
1070 })(jQuery, document);
1071 (function ($, document) {
1072 'use strict';
1073
1074 var orderable_tabs = {
1075 /**
1076 * On doc ready.
1077 */
1078 on_ready() {
1079 orderable_tabs.cache();
1080 orderable_tabs.watch();
1081 orderable_tabs.toggle_scroll();
1082 },
1083 /**
1084 * On resize.
1085 */
1086 on_resize() {
1087 orderable_tabs.toggle_scroll();
1088 },
1089 /**
1090 * Cache.
1091 */
1092 cache() {
1093 orderable_tabs.vars = {
1094 classes: {
1095 tabs: 'orderable-tabs',
1096 tabs_list: 'orderable-tabs__list',
1097 tab_items: 'orderable-tabs__item',
1098 tab_item_active: 'orderable-tabs__item--active',
1099 tab_links: 'orderable-tabs__link',
1100 tab_arrow_right: 'orderable-tabs__arrow-right',
1101 tab_arrow_left: 'orderable-tabs__arrow-left'
1102 },
1103 dragging: false
1104 };
1105 orderable_tabs.elements = {};
1106 },
1107 /**
1108 * Watch.
1109 */
1110 watch() {
1111 $('body').on('touchstart', function () {
1112 orderable_tabs.vars.dragging = false;
1113 }).on('touchmove', function () {
1114 orderable_tabs.vars.dragging = true;
1115 });
1116 $(document.body).on('click mouseup touchend', '.' + orderable_tabs.vars.classes.tab_links, function (e) {
1117 if (orderable_tabs.vars.dragging) {
1118 return;
1119 }
1120 e.preventDefault();
1121 const $link = $(this),
1122 section_id = $link.attr('href'),
1123 $tab = $link.closest('.' + orderable_tabs.vars.classes.tab_items),
1124 $tabs = $link.closest('.' + orderable_tabs.vars.classes.tabs),
1125 $tabs_list = $tabs.find('.' + orderable_tabs.vars.classes.tabs_list),
1126 $tab_items = $tabs.find('.' + orderable_tabs.vars.classes.tab_items),
1127 tabs_args = $tabs.data('orderable-tabs'),
1128 $wrapper = $link.closest(tabs_args.wrapper),
1129 $sections = $wrapper.find(tabs_args.sections),
1130 $section = $wrapper.find(section_id);
1131 $sections.hide();
1132 $section.show();
1133 $tab_items.removeClass(orderable_tabs.vars.classes.tab_item_active);
1134 $tab.addClass(orderable_tabs.vars.classes.tab_item_active);
1135 $tabs_list.animate({
1136 scrollLeft: $tabs_list.scrollLeft() + $tab.position().left
1137 });
1138 $(document.body).trigger('orderable-tabs.changed', {
1139 tab: $tab
1140 });
1141 });
1142
1143 /**
1144 * Watch scroll position of tabs.
1145 */
1146 $('.' + orderable_tabs.vars.classes.tabs_list).on('scroll', function (e) {
1147 const $list = $(this),
1148 $wrapper = $list.parent('.' + orderable_tabs.vars.classes.tabs),
1149 $arrow_right = $list.siblings('.' + orderable_tabs.vars.classes.tab_arrow_right),
1150 $arrow_left = $list.siblings('.' + orderable_tabs.vars.classes.tab_arrow_left);
1151 if ($list[0].scrollWidth <= $wrapper.width() + $list.scrollLeft()) {
1152 $arrow_right.fadeOut();
1153 } else {
1154 $arrow_right.fadeIn();
1155 }
1156 if (0 >= $list.scrollLeft() - $arrow_left.width()) {
1157 $arrow_left.fadeOut();
1158 } else {
1159 $arrow_left.fadeIn();
1160 }
1161 });
1162
1163 /**
1164 * Stop animated scroll if user manually scrolls.
1165 */
1166 $('.' + orderable_tabs.vars.classes.tabs_list).on('wheel DOMMouseScroll mousewheel touchmove', function () {
1167 $(this).stop();
1168 });
1169
1170 /**
1171 * Click tab arrow right.
1172 */
1173 $(document).on('click', '.' + orderable_tabs.vars.classes.tab_arrow_right, function (e) {
1174 e.preventDefault();
1175 const $arrow = $(this),
1176 $wrapper = $arrow.parent(),
1177 $list = $wrapper.find('.' + orderable_tabs.vars.classes.tabs_list);
1178 $list.animate({
1179 scrollLeft: $list.scrollLeft() + $wrapper.width() * 0.5
1180 });
1181 });
1182
1183 /**
1184 * Click tab arrow left.
1185 */
1186 $(document).on('click', '.' + orderable_tabs.vars.classes.tab_arrow_left, function (e) {
1187 e.preventDefault();
1188 const $arrow = $(this),
1189 $wrapper = $arrow.parent(),
1190 $list = $wrapper.find('.' + orderable_tabs.vars.classes.tabs_list);
1191 $list.animate({
1192 scrollLeft: $list.scrollLeft() - $wrapper.width() * 0.5
1193 });
1194 });
1195 },
1196 /**
1197 * Toggle scroll arrow.
1198 */
1199 toggle_scroll() {
1200 $('.' + orderable_tabs.vars.classes.tabs).each(function (index, wrapper) {
1201 const $tabs = $(this),
1202 tabs_args = $tabs.data('orderable-tabs'),
1203 $wrapper = $tabs.closest(tabs_args.wrapper),
1204 $list = $wrapper.find('.' + orderable_tabs.vars.classes.tabs_list),
1205 $arrow_right = $wrapper.find('.' + orderable_tabs.vars.classes.tab_arrow_right),
1206 wrapper_width = $wrapper.outerWidth(),
1207 list_width = $list[0].scrollWidth;
1208 if (list_width > wrapper_width) {
1209 $arrow_right.show();
1210 } else {
1211 $arrow_right.hide();
1212 }
1213 });
1214 }
1215 };
1216 $(document).ready(orderable_tabs.on_ready);
1217 $(window).on('resize', orderable_tabs.on_resize);
1218 })(jQuery, document);
1219 let orderable_timings = {}; // Make this global so pro modules can access it.
1220
1221 (function ($, document) {
1222 'use strict';
1223
1224 orderable_timings = {
1225 /**
1226 * On doc ready.
1227 */
1228 on_ready() {
1229 orderable_timings.watch();
1230 },
1231 /**
1232 * Restore current timings.
1233 */
1234 restore() {
1235 const timings = orderable_timings.get_timings();
1236 if (!timings || !timings.date) {
1237 return;
1238 }
1239 const dateSelect = $('.orderable-order-timings__date');
1240 if (dateSelect.find('option[value="' + timings.date + '"]').length > 0) {
1241 dateSelect.val(timings.date);
1242 dateSelect.change();
1243 }
1244 if (!timings.time) {
1245 return;
1246 }
1247 const timeSelect = $('.orderable-order-timings__time');
1248 if (timeSelect.find('option[value="' + timings.time + '"]').length > 0) {
1249 timeSelect.val(timings.time);
1250 timeSelect.change();
1251 }
1252 },
1253 /**
1254 * Watch for trigger events.
1255 */
1256 watch() {
1257 $(document.body).on('wc_fragments_refreshed', function () {
1258 orderable_timings.restore();
1259 });
1260 $(document.body).on('updated_checkout', function () {
1261 orderable_timings.restore();
1262 });
1263 $(document.body).on('change', '.orderable-order-timings__date', function (event) {
1264 const $date_field = $(this),
1265 $selected = $date_field.find('option:selected'),
1266 slots = $selected.data('orderable-slots'),
1267 $time_field_wrap = $('.orderable-order-timings--time'),
1268 $time_field = $('.orderable-order-timings__time'),
1269 $first_option = $time_field.find('option').first(),
1270 $asap_option = $time_field.find('option[value="asap"]').first();
1271 const timings = orderable_timings.get_timings();
1272 timings.date = $('.orderable-order-timings__date').val();
1273 window.localStorage.setItem('orderable_timings', JSON.stringify(timings));
1274 $time_field.html($first_option);
1275 if ($asap_option) {
1276 $time_field.append($asap_option);
1277 }
1278 if (!slots) {
1279 $time_field.prop('disabled', true);
1280 $time_field_wrap.hide();
1281 return;
1282 }
1283 if ('all-day' === slots[0].value) {
1284 $time_field_wrap.hide();
1285 $time_field.prop('disabled', true);
1286 } else {
1287 $time_field.prop('disabled', false);
1288 $time_field_wrap.show();
1289 $.each(slots, function (index, slot) {
1290 $time_field.append($('<option />').attr('value', slot.value).text(slot.formatted));
1291 });
1292 }
1293 });
1294 $(document.body).on('change', '.orderable-order-timings__time', function (event) {
1295 const timings = orderable_timings.get_timings();
1296 timings.time = $('.orderable-order-timings__time').val();
1297 window.localStorage.setItem('orderable_timings', JSON.stringify(timings));
1298 });
1299 },
1300 get_timings() {
1301 return JSON.parse(window.localStorage.getItem('orderable_timings')) || {};
1302 }
1303 };
1304 $(document).ready(orderable_timings.on_ready);
1305 })(jQuery, document);
1306 (function ($, document) {
1307 'use strict';
1308
1309 var orderable_triggers = {
1310 /**
1311 * On doc ready.
1312 */
1313 on_ready() {
1314 orderable_triggers.watch();
1315 },
1316 /**
1317 * Watch for trigger events.
1318 */
1319 watch() {
1320 $(document.body).on('click', '[data-orderable-trigger]', orderable_triggers.trigger);
1321 },
1322 /**
1323 * Fire trigger.
1324 * @param e
1325 */
1326 trigger(e) {
1327 // Prevent even bubbling up.
1328 e.stopImmediatePropagation();
1329 const $trigger_element = $(this),
1330 trigger = $trigger_element.data('orderable-trigger');
1331 $(document.body).trigger('orderable-' + trigger, [$trigger_element]);
1332 }
1333 };
1334 $(document).ready(orderable_triggers.on_ready);
1335 })(jQuery, document);
1336 /**
1337 * jQiery scrollBar Plugin
1338 * @author Falk Müller (www-falk-m.de)
1339 * Thankts to https://codepen.io/IliaSky/pen/obowmv
1340 */
1341 ;
1342 (function ($, window, document) {
1343 "use strict";
1344
1345 var pluginName = "scrollBox",
1346 defaults = {
1347 containerClass: "sb-container",
1348 containerNoScrollClass: "sb-container-noscroll",
1349 contentClass: "sb-content",
1350 scrollbarContainerClass: "sb-scrollbar-container",
1351 scrollBarClass: "sb-scrollbar"
1352 };
1353
1354 // plugin constructor
1355 function Plugin(element, options) {
1356 this.element = element;
1357 this.settings = $.extend({}, defaults, options);
1358 this._defaults = defaults;
1359 this._name = pluginName;
1360 this.init();
1361 }
1362
1363 // Avoid Plugin.prototype conflicts
1364 $.extend(Plugin.prototype, {
1365 init: function () {
1366 this.addScrollbar();
1367 this.addEvents();
1368 this.onResize();
1369 },
1370 addScrollbar: function () {
1371 $(this.element).addClass(this.settings.containerClass);
1372 this.wrapper = $("<div class='" + this.settings.contentClass + "' />");
1373 this.wrapper.append($(this.element).contents());
1374 $(this.element).append(this.wrapper);
1375 this.scollbarContainer = $("<div class='" + this.settings.scrollbarContainerClass + "' />");
1376 this.scrollBar = $("<div class='" + this.settings.scrollBarClass + "' />");
1377 this.scollbarContainer.append(this.scrollBar);
1378 $(this.element).prepend(this.scollbarContainer);
1379 },
1380 addEvents: function () {
1381 this.wrapper.on("scroll." + pluginName, $.proxy(this.onScroll, this));
1382 $(window).on("resize." + pluginName, $.proxy(this.onResize, this));
1383 this.scrollBar.on('mousedown.' + pluginName, $.proxy(this.onMousedown, this));
1384 this.scrollBar.on('touchstart.' + pluginName, $.proxy(this.onTouchstart, this));
1385 },
1386 onTouchstart: function (ev) {
1387 var me = this;
1388 ev.preventDefault();
1389 var y = me.scrollBar[0].offsetTop;
1390 var onMove = function (end) {
1391 var delta = end.touches[0].pageY - ev.touches[0].pageY;
1392 me.scrollBar[0].style.top = Math.min(me.scollbarContainer[0].clientHeight - me.scrollBar[0].clientHeight, Math.max(0, y + delta)) + 'px';
1393 me.wrapper[0].scrollTop = me.wrapper[0].scrollHeight * me.scrollBar[0].offsetTop / me.scollbarContainer[0].clientHeight;
1394 };
1395 $(document).on("touchmove." + pluginName, onMove);
1396 $(document).on("touchend." + pluginName, function () {
1397 $(document).off("touchmove." + pluginName);
1398 $(document).off("touchend." + pluginName);
1399 });
1400 },
1401 onMousedown: function (ev) {
1402 var me = this;
1403 ev.preventDefault();
1404 var y = me.scrollBar[0].offsetTop;
1405 var onMove = function (end) {
1406 var delta = end.pageY - ev.pageY;
1407 me.scrollBar[0].style.top = Math.min(me.scollbarContainer[0].clientHeight - me.scrollBar[0].clientHeight, Math.max(0, y + delta)) + 'px';
1408 me.wrapper[0].scrollTop = me.wrapper[0].scrollHeight * me.scrollBar[0].offsetTop / me.scollbarContainer[0].clientHeight;
1409 };
1410 $(document).on("mousemove." + pluginName, onMove);
1411 $(document).on("mouseup." + pluginName, function () {
1412 $(document).off("mousemove." + pluginName);
1413 $(document).off("mouseup." + pluginName);
1414 });
1415 },
1416 onResize: function () {
1417 this.wrapper.css("max-height", $(this.element).height());
1418 var wrapper_client_height = this.wrapper[0].clientHeight;
1419 this.scrollBar.css("height", this.scollbarContainer[0].clientHeight * wrapper_client_height / this.wrapper[0].scrollHeight + "px");
1420 if (this.scollbarContainer[0].clientHeight <= this.scrollBar[0].clientHeight) {
1421 $(this.element).addClass(this.settings.containerNoScrollClass);
1422 } else {
1423 $(this.element).removeClass(this.settings.containerNoScrollClass);
1424 }
1425 this.onScroll();
1426 },
1427 onScroll: function () {
1428 this.scrollBar.css("top", Math.min(this.scollbarContainer[0].clientHeight - this.scrollBar[0].clientHeight, this.scollbarContainer[0].clientHeight * this.wrapper[0].scrollTop / this.wrapper[0].scrollHeight) + "px");
1429 }
1430 });
1431
1432 // A really lightweight plugin wrapper around the constructor,
1433 // preventing against multiple instantiations
1434 $.fn[pluginName] = function (options) {
1435 return this.each(function () {
1436 if (!$.data(this, "plugin_" + pluginName)) {
1437 $.data(this, "plugin_" + pluginName, new Plugin(this, options));
1438 }
1439 });
1440 };
1441 })(jQuery, window, document);
1442 /*!
1443 * swiped-events.js - v1.1.6
1444 * Pure JavaScript swipe events
1445 * https://github.com/john-doherty/swiped-events
1446 * @inspiration https://stackoverflow.com/questions/16348031/disable-scrolling-when-touch-moving-certain-element
1447 * @author John Doherty <www.johndoherty.info>
1448 * @license MIT
1449 */
1450 !function (t, e) {
1451 "use strict";
1452
1453 "function" != typeof t.CustomEvent && (t.CustomEvent = function (t, n) {
1454 n = n || {
1455 bubbles: !1,
1456 cancelable: !1,
1457 detail: void 0
1458 };
1459 var a = e.createEvent("CustomEvent");
1460 return a.initCustomEvent(t, n.bubbles, n.cancelable, n.detail), a;
1461 }, t.CustomEvent.prototype = t.Event.prototype), e.addEventListener("touchstart", function (t) {
1462 if ("true" === t.target.getAttribute("data-swipe-ignore")) return;
1463 s = t.target, r = Date.now(), n = t.touches[0].clientX, a = t.touches[0].clientY, u = 0, i = 0;
1464 }, !1), e.addEventListener("touchmove", function (t) {
1465 if (!n || !a) return;
1466 var e = t.touches[0].clientX,
1467 r = t.touches[0].clientY;
1468 u = n - e, i = a - r;
1469 }, !1), e.addEventListener("touchend", function (t) {
1470 if (s !== t.target) return;
1471 var e = parseInt(l(s, "data-swipe-threshold", "20"), 10),
1472 o = parseInt(l(s, "data-swipe-timeout", "500"), 10),
1473 c = Date.now() - r,
1474 d = "",
1475 p = t.changedTouches || t.touches || [];
1476 Math.abs(u) > Math.abs(i) ? Math.abs(u) > e && c < o && (d = u > 0 ? "swiped-left" : "swiped-right") : Math.abs(i) > e && c < o && (d = i > 0 ? "swiped-up" : "swiped-down");
1477 if ("" !== d) {
1478 var b = {
1479 dir: d.replace(/swiped-/, ""),
1480 touchType: (p[0] || {}).touchType || "direct",
1481 xStart: parseInt(n, 10),
1482 xEnd: parseInt((p[0] || {}).clientX || -1, 10),
1483 yStart: parseInt(a, 10),
1484 yEnd: parseInt((p[0] || {}).clientY || -1, 10)
1485 };
1486 s.dispatchEvent(new CustomEvent("swiped", {
1487 bubbles: !0,
1488 cancelable: !0,
1489 detail: b
1490 })), s.dispatchEvent(new CustomEvent(d, {
1491 bubbles: !0,
1492 cancelable: !0,
1493 detail: b
1494 }));
1495 }
1496 n = null, a = null, r = null;
1497 }, !1);
1498 var n = null,
1499 a = null,
1500 u = null,
1501 i = null,
1502 r = null,
1503 s = null;
1504 function l(t, n, a) {
1505 for (; t && t !== e.documentElement;) {
1506 var u = t.getAttribute(n);
1507 if (u) return u;
1508 t = t.parentNode;
1509 }
1510 return a;
1511 }
1512 }(window, document);