PluginProbe ʕ •ᴥ•ʔ
Event Tickets with Ticket Scanner / 3.1.2
Event Tickets with Ticket Scanner v3.1.2
3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.4 trunk 2.6.0 2.7.0 2.7.1 2.7.10 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.10 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 2.9.8 2.9.9 3.0.0 3.0.1 3.0.2 3.0.3
event-tickets-with-ticket-scanner / wc_frontend.js
event-tickets-with-ticket-scanner Last commit date
3rd 1 week ago css 1 week ago img 1 week ago includes 1 week ago js 1 week ago languages 1 week ago ticket 1 week ago vendors 1 week ago SASO_EVENTTICKETS.php 1 week ago backend.js 1 week ago changelog-features.json 1 week ago changelog.txt 1 week ago db.php 1 week ago index.php 1 week ago init_file.php 1 week ago order_details.js 1 week ago pwa-sw.js 1 week ago readme.txt 1 week ago saso-eventtickets-validator.js 1 week ago sasoEventtickets_AdminSettings.php 1 week ago sasoEventtickets_Authtoken.php 1 week ago sasoEventtickets_Base.php 1 week ago sasoEventtickets_Core.php 1 week ago sasoEventtickets_Frontend.php 1 week ago sasoEventtickets_Messenger.php 1 week ago sasoEventtickets_Options.php 1 week ago sasoEventtickets_PDF.php 1 week ago sasoEventtickets_Seating.php 1 week ago sasoEventtickets_Ticket.php 1 week ago sasoEventtickets_TicketBadge.php 1 week ago sasoEventtickets_TicketDesigner.php 1 week ago sasoEventtickets_TicketQR.php 1 week ago ticket_events.js 1 week ago ticket_scanner.js 1 week ago validator.js 1 week ago version-notices.json 1 week ago vollstart-cross-promo.php 1 week ago wc_backend.js 1 week ago wc_frontend.js 1 week ago woocommerce-hooks.php 1 week ago
wc_frontend.js
533 lines
1 function SasoEventticketsValidator_WC_frontend($, phpObject) {
2 const { __, _x, _n, sprintf } = wp.i18n;
3 let _self = this;
4 let inputTypes = [phpObject.inputType, "text", "value"];
5
6 function init() {
7 _addHandlerToTheCodeFields();
8 _addHandlerToAddToCartButtons(); // for shop and product pages
9 }
10
11 function addStyleCode(content) {
12 let c = document.createElement('style');
13 c.innerHTML = content;
14 document.getElementsByTagName("head")[0].appendChild(c);
15 }
16
17 function getPidFromAddToCartButton(btn){
18 return btn.data('product_id') || btn.attr('data-product_id') || btn.val() || null;
19 }
20
21 function _addHandlerToAddToCartButtons() {
22 if (!phpObject.fieldKey) return;
23 if (!phpObject.has_daychooser) return; // only if at least one product has a date picker
24
25 function findDateForPid(pid, $btn){
26 let input_id = phpObject.fieldKey+'_'+pid;
27
28 return $(document.body)
29 .find('input[data-input-type="daychooser"][data-plugin="event"][data-is-shop-page="1"][data-cart-item-id="'+input_id+'"]')
30 .first();
31 }
32
33 function checkDate(btn, e) {
34 var pid = getPidFromAddToCartButton(btn);
35 if (!pid) return true; // manche Themes weichen ab; dann greift serverseitige Prüfung
36
37 var input = findDateForPid(pid, btn);
38 if (!input || !input.length) return true; // kein Feld gefunden, dann greift serverseitige Prüfung
39
40 var val = (input && input.val ? (input.val()||'').trim() : '');
41
42 if (!val) {
43 if (e) {
44 e.preventDefault();
45 e.stopPropagation();
46 e.stopImmediatePropagation();
47 }
48 // Kurzes Feedback (ersetze gern durch eigenes Notice-System)
49 alert(phpObject.daychooser_warning ? phpObject.daychooser_warning : __('Please choose a valid date.', 'event-tickets-with-ticket-scanner'));
50 return false;
51 }
52 return true;
53 }
54
55 // product page
56 $(document).on('click', '.single_add_to_cart_button', function(e){
57 var btn = $(this);
58
59 if (!checkDate(btn, e)) {
60 return false;
61 }
62 });
63
64 // product page with AJAX add to cart
65 var form = document.querySelector('form.cart');
66 if (form) {
67 form.addEventListener('submit', function(e){
68 var btn = $(form).find('.single_add_to_cart_button').first();
69 if (!btn || btn.length == 0) return; // no button found, then server side check
70 if (!checkDate(btn, e)) {
71 return false;
72 }
73 var pid = getPidFromAddToCartButton(btn);
74 if (!pid) return; // manche Themes weichen ab; dann greift serverseitige Prüfung
75 var $input = findDateForPid(pid, btn);
76 if ($input && $input.length > 0) {
77 var val = ($input && $input.val ? ($input.val()||'').trim() : '');
78 if (val == "") return false;
79 // add hidden input field to the form if not already present
80 var hiddenInput = form.querySelector('input[name="'+phpObject.fieldKey+'"]');
81 if (!hiddenInput) {
82 hiddenInput = document.createElement('input');
83 hiddenInput.type = 'hidden';
84 hiddenInput.name = phpObject.fieldKey;
85 form.appendChild(hiddenInput);
86 }
87 hiddenInput.value = val ? val : '';
88 // indicate that a day chooser was used
89 var hiddenInputIndicator = form.querySelector('input[name="'+phpObject.fieldDayChooserIndicator+'"]');
90 if (!hiddenInputIndicator) {
91 hiddenInputIndicator = document.createElement('input');
92 hiddenInputIndicator.type = 'hidden';
93 hiddenInputIndicator.name = phpObject.fieldDayChooserIndicator;
94 form.appendChild(hiddenInputIndicator);
95 }
96 hiddenInputIndicator.value = 1;
97 }
98 });
99 }
100
101 // shop/archive page: intercept ANY add-to-cart link with data-product_id
102 // Works with both WC Classic (ajax_add_to_cart) and WC Blocks (plain <a> link)
103 $(document.body).on('click', 'a[data-product_id]', function(e){
104 var btn = $(this);
105 var pid = getPidFromAddToCartButton(btn);
106 if (!pid) return;
107
108 var $input = findDateForPid(pid, btn);
109 if (!$input || !$input.length) return; // not a daychooser product — let WC handle normally
110
111 var val = ($input.val() || '').trim();
112 if (!val) {
113 e.preventDefault();
114 e.stopImmediatePropagation();
115 alert(phpObject.daychooser_warning ? phpObject.daychooser_warning : __('Please choose a valid date.', 'event-tickets-with-ticket-scanner'));
116 return false;
117 }
118
119 // For AJAX buttons (classic WC): let the adding_to_cart handler below add data
120 if (btn.hasClass('ajax_add_to_cart')) return;
121
122 // For non-AJAX buttons (WC Blocks / plain links): append date to URL
123 e.preventDefault();
124 e.stopImmediatePropagation();
125 var url = btn.attr('href');
126 if (!url) return;
127 url += (url.indexOf('?') > -1 ? '&' : '?');
128 url += encodeURIComponent(phpObject.fieldKey) + '=' + encodeURIComponent(val);
129 url += '&' + encodeURIComponent(phpObject.fieldDayChooserIndicator) + '=1';
130 var nonce = document.querySelector('input[name="'+phpObject.nonceKey+'"]');
131 if (nonce) url += '&' + encodeURIComponent(phpObject.nonceKey) + '=' + encodeURIComponent(nonce.value);
132 window.location.href = url;
133 });
134
135 // shop page with AJAX add to cart (classic WC)
136 $(document.body).on('adding_to_cart', function(e, $button, data){
137 var pid = getPidFromAddToCartButton($button);
138 if (!pid) return;
139
140 var $input = findDateForPid(pid, $button);
141 if ($input && $input.length > 0) {
142 var val = ($input && $input.val ? ($input.val()||'').trim() : '');
143 if (val == "") return false;
144 data[phpObject.fieldKey] = val ? val : '';
145 data[phpObject.fieldDayChooserIndicator] = 1;
146 }
147
148 var nonce = document.querySelector('input[name="'+phpObject.nonceKey+'"]');
149 data[phpObject.nonceKey] = nonce ? nonce.value : '';
150 });
151
152 }
153
154 function _addHandlerToTheCodeFields() {
155 let isStoring = false;
156 let waitingTimeout = null;
157 let isChanged = false;
158
159 function sendCode(elem, code, type) {
160 //clearWaitingTimeout();
161 if (!isStoring) {
162 $('div[class="woocommerce"]').block({
163 //message: '...loading...',
164 message: null,
165 overlayCSS: {
166 background: '#fff',
167 opacity: 0.6
168 }
169 });
170 isStoring = true;
171 let cart_item_id = elem.attr('data-cart-item-id');
172 let cart_item_count = elem.attr('data-cart-item-count');
173 let nonce = phpObject.nonce;
174 $.ajax(
175 {
176 type: 'POST',
177 url: phpObject.ajaxurl,
178 data: {
179 action: phpObject.action,
180 a: 'updateSerialCodeToCartItem',
181 security: nonce,
182 cart_item_id: cart_item_id,
183 cart_item_count: cart_item_count,
184 type: type,
185 code: code
186 },
187 success: function( response ) {
188 $('div[class="woocommerce"]').unblock();
189 $('.cart_totals').unblock();
190 if (response.success) {
191 elem.val(response.code);
192 } else {
193 if (response.msg) alert(response.msg);
194 }
195 isStoring = false;
196 //window.location.reload();
197 }
198 }
199 )
200 }
201 }
202
203 function clearWaitingTimeout() {
204 clearTimeout(waitingTimeout);
205 }
206 function setWaitingTimeout(elem, code) {
207 clearWaitingTimeout();
208 waitingTimeout = setTimeout(()=>{
209 if (isChanged) {
210 isChanged = false;
211 sendCode(elem, code);
212 }
213 }, 2500);
214 }
215
216 // finde die code text inputs
217 // eventcoderrestriction is no longer used, but still in the code
218 $('body').find('input[data-input-type="eventcoderestriction"][data-plugin="event"]')
219 .on('keydown',function(e){
220 if (e.which === 13) {
221 e.preventDefault();
222 let elem = $(this);
223 isChanged = true;
224 sendCode(elem, elem.val().trim(), "saso_eventtickets_request_name_per_ticket");
225 }
226 })
227 .on('paste', event=>{
228 isStoring = false;
229 let elem = $(event.srcElement);
230 let code = (event.clipboardData || window.clipboardData).getData('text');
231 if (typeof code == "string") {
232 code = code.trim();
233 isChanged = true;
234 sendCode(elem, code, "saso_eventtickets_request_name_per_ticket");
235 } else { alert("no text"); }
236 })
237 .on('change',function(){
238 let elem = $(this);
239 let code = elem.val().trim();
240 //let cart_item_id = elem.data('cart-item-id');
241 //let d = document.querySelector('input[data-cart-item-id="'+cart_item_id+'"]').value
242 isChanged = true;
243 sendCode(elem, code, "saso_eventtickets_request_name_per_ticket");
244 })
245 /*
246 .on('blur',function(){
247 let elem = $(this);
248 let code = elem.val().trim();
249 if (code != "" && isChanged) {
250 let cart_item_id = elem.data('cart-item-id');
251 //let d = document.querySelector('input[data-cart-item-id="'+cart_item_id+'"]').value
252 sendCode(elem, code, "saso_eventtickets_request_name_per_ticket");
253 }
254 })
255 */
256 .removeAttr('disabled');
257
258 $('body').find('input[data-input-type="text"][data-plugin="event"]')
259 .on('keydown',function(e){
260 if (e.which === 13) {
261 e.preventDefault();
262 let elem = $(this);
263 isChanged = true;
264 sendCode(elem, elem.val().trim(), "saso_eventtickets_request_name_per_ticket");
265 }
266 })
267 .on('paste', event=>{
268 isStoring = false;
269 let elem = $(event.srcElement);
270 let code = (event.clipboardData || window.clipboardData).getData('text');
271 if (typeof code == "string") {
272 code = code.trim();
273 isChanged = true;
274 sendCode(elem, code, "saso_eventtickets_request_name_per_ticket");
275 } else { alert("no text"); }
276 })
277 .on('change',function(){
278 let elem = $(this);
279 let code = elem.val().trim();
280 isChanged = true;
281 sendCode(elem, code, "saso_eventtickets_request_name_per_ticket");
282 })
283 .removeAttr('disabled');
284
285 $('body').find('select[data-input-type="value"][data-plugin="event"]')
286 .on('change',function(){
287 let elem = $(this);
288 let code = elem.val().trim();
289 isChanged = true;
290 sendCode(elem, code, "saso_eventtickets_request_value_per_ticket");
291 })
292 .removeAttr('disabled');
293
294 // Resolve a min/max value (number-of-days, YYYY-MM-DD, or empty) → JS Date or null.
295 function _sasoResolveLimitDate(opt) {
296 if (opt == null || opt === '') return null;
297 if (typeof opt === 'number' && !isNaN(opt)) {
298 let d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() + opt);
299 return d;
300 }
301 let s = String(opt).trim();
302 let m = s.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
303 if (m) return new Date(parseInt(m[1], 10), parseInt(m[2], 10) - 1, parseInt(m[3], 10));
304 let n = parseInt(s, 10);
305 if (!isNaN(n)) {
306 let d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() + n);
307 return d;
308 }
309 return null;
310 }
311
312 // Selectability rules — kept in sync with beforeShowDay below intentionally.
313 function _sasoIsDateSelectable(date, attrs) {
314 if (attrs.excludeWdays) {
315 let excludedDays = attrs.excludeWdays.split(',');
316 if (excludedDays.indexOf(date.getDay().toString()) !== -1) return false;
317 }
318 let today = new Date(); today.setHours(0, 0, 0, 0);
319 let chk = new Date(date.getFullYear(), date.getMonth(), date.getDate());
320 if (chk < today) return false;
321 if (attrs.excludeDates) {
322 let excludedDates = attrs.excludeDates.split(',');
323 let m = date.getMonth() + 1;
324 let d = date.getDate();
325 let dateStr = date.getFullYear() + '-' + (m < 10 ? '0' : '') + m + '-' + (d < 10 ? '0' : '') + d;
326 if (excludedDates.indexOf(dateStr) !== -1) return false;
327 }
328 return true;
329 }
330
331 // Scan up to 24 months forward from `from` for the first selectable day.
332 // Used as datepicker.defaultDate so the picker opens on the first month
333 // that actually has free slots — instead of an all-grey current month.
334 function _sasoFindFirstSelectableDate(attrs, from, until) {
335 let cap = 24;
336 let start = from ? new Date(from.getFullYear(), from.getMonth(), from.getDate())
337 : (function () { let t = new Date(); t.setHours(0, 0, 0, 0); return t; })();
338 let scanFrom = new Date(start);
339 for (let i = 0; i < cap; i++) {
340 let monthEnd = new Date(scanFrom.getFullYear(), scanFrom.getMonth() + 1, 0);
341 let lastDay = (until && monthEnd > until) ? until : monthEnd;
342 for (let d = new Date(scanFrom); d <= lastDay; d.setDate(d.getDate() + 1)) {
343 if (_sasoIsDateSelectable(d, attrs)) return new Date(d);
344 }
345 scanFrom = new Date(scanFrom.getFullYear(), scanFrom.getMonth() + 1, 1);
346 if (until && scanFrom > until) return null;
347 }
348 return null;
349 }
350
351 $('body').find('input[data-input-type="daychooser"][data-plugin="event"]')
352 .on('keydown', function(e) { e.preventDefault(); })
353 .on('paste', function(e) { e.preventDefault(); })
354 .each((idx, input) => {
355 let elem_intern = $(input);
356 let dateFormat = elem_intern.attr('placeholder');
357 dateFormat = dateFormat != null ? dateFormat.trim() : '';
358 dateFormat = dateFormat ? dateFormat : 'YYYY-MM-DD';
359 dateFormat = 'YYYY-MM-DD';
360 elem_intern.attr('placeholder', __(dateFormat));
361 let data_offset_start = 0;
362 let data_offset_end = 0;
363 try {
364 data_offset_start = parseInt(elem_intern.attr('data-offset-start'));
365 } catch (error) {
366 //console.log(error);
367 }
368 if (elem_intern.attr('min') && elem_intern.attr('min').length > 0) {
369 data_offset_start = elem_intern.attr('min');
370 }
371 // Same-day cutoff: runs after min-attribute override so absolute start dates
372 // (ticket_start_date) cannot silently undo the cutoff effect.
373 // If current time >= cutoff and the resolved minDate still includes today, shift to tomorrow.
374 let _saso_cutoff = elem_intern.attr('data-cutoff-time');
375 if (_saso_cutoff) {
376 let _cp = _saso_cutoff.split(':');
377 let _cutoffDate = new Date();
378 _cutoffDate.setHours(parseInt(_cp[0], 10), parseInt(_cp[1], 10), 0, 0);
379 if (new Date() >= _cutoffDate) {
380 let _todayMidnight = new Date(); _todayMidnight.setHours(0, 0, 0, 0);
381 let _resolvedMin = _sasoResolveLimitDate(data_offset_start);
382 if (_resolvedMin === null || _resolvedMin <= _todayMidnight) {
383 data_offset_start = 1;
384 }
385 }
386 }
387 try {
388 data_offset_end = parseInt(elem_intern.attr('data-offset-end'));
389 } catch (error) {
390 //console.log(error);
391 }
392 if (elem_intern.attr('max') && elem_intern.attr('max').length > 0) {
393 data_offset_end = elem_intern.attr('max');
394 }
395 //let today = new Date();
396 //let start = new Date(today.getFullYear(), today.getMonth(), today.getDate() + data_offset_start);
397 //let end = new Date(today.getFullYear(), today.getMonth(), today.getDate() + data_offset_end);
398
399 let _saso_attrs = {
400 excludeWdays: elem_intern.attr('data-exclude-wdays') || '',
401 excludeDates: elem_intern.attr('data-exclude-dates') || ''
402 };
403 let _saso_minAbs = _sasoResolveLimitDate(data_offset_start);
404 let _saso_maxAbs = _sasoResolveLimitDate(data_offset_end);
405 let _saso_default = _sasoFindFirstSelectableDate(_saso_attrs, _saso_minAbs, _saso_maxAbs);
406
407 elem_intern.datepicker({
408 dateFormat: 'yy-mm-dd',
409 //dateFormat: dateFormat,
410 showWeek: true,
411 firstDay: 1,
412 hideIfNoPrevNext : true,
413 minDate: data_offset_start,
414 maxDate: data_offset_end,
415 defaultDate: _saso_default,
416 beforeShow: function(input, options) {
417 this._sasoevent_input_field = $(input);
418 },
419 beforeShowDay: function(date) { // https://api.jqueryui.com/datepicker/#option-beforeShow
420 let day = date.getDay();
421 let data_exclude_wdays = this._sasoevent_input_field.attr('data-exclude-wdays');
422 let selectable = true;
423 let cssClass = '';
424 let toolTipp = '';
425 if (data_exclude_wdays && data_exclude_wdays.length > 0) {
426 let excludedDays = data_exclude_wdays.split(',');
427 selectable = excludedDays.indexOf(day.toString()) == -1;
428
429 cssClass = selectable ? '' : 'ui-datepicker-unselectable';
430 toolTipp = selectable ? '' : __('This day is not selectable');
431 }
432 if (selectable) {
433 // check if the date is in the past
434 let today = new Date();
435 let y = date.getFullYear();
436 let m = date.getMonth() + 1;
437 let d = date.getDate();
438 let dateStr = y + '-' + (m < 10 ? '0' : '') + m + '-' + (d < 10 ? '0' : '') + d;
439 let todayStr = today.getFullYear() + '-' + (today.getMonth() + 1 < 10 ? '0' : '') + (today.getMonth() + 1) + '-' + (today.getDate() < 10 ? '0' : '') + today.getDate();
440 if (dateStr < todayStr) {
441 selectable = false;
442 cssClass = 'ui-datepicker-unselectable';
443 toolTipp = __('This day is not selectable');
444 }
445 }
446 if (selectable) {
447 let data_exclude_dates = this._sasoevent_input_field.attr('data-exclude-dates');
448 if (data_exclude_dates && data_exclude_dates.length > 0) {
449 let excludedDates = data_exclude_dates.split(',');
450 let y = date.getFullYear();
451 let m = date.getMonth() + 1;
452 let d = date.getDate();
453 let dateStr = y + '-' + (m < 10 ? '0' : '') + m + '-' + (d < 10 ? '0' : '') + d;
454 selectable = excludedDates.indexOf(dateStr) == -1;
455
456 cssClass = selectable ? '' : 'ui-datepicker-unselectable';
457 toolTipp = selectable ? '' : __('This day is not selectable');
458 }
459 }
460 return [selectable, cssClass, toolTipp];
461 //return [true, ''];
462 }
463 });
464 })
465 .on('change',event=>{
466 let elem_intern = $(event.target);
467
468 if (elem_intern.attr('data-is-shop-page') == "1") return; // only on cart and checkout page
469
470 //console.log('change datepicker', elem_intern.attr('id'));
471 let date_value = elem_intern.val().trim();
472 if (elem_intern.attr('data-previous-value') == date_value) return; // no change
473 elem_intern.attr('data-previous-value', date_value);
474 if (date_value) {
475 sendCode(elem_intern, date_value, "saso_eventtickets_request_daychooser");
476 isChanged = true;
477 let to_be_changed = [];
478 // update the other date pickers if no value is set to use this date
479 let data_cart_item_id = elem_intern.attr('data-cart-item-id');
480 $('body').find('input[data-input-type="daychooser"][data-plugin="event"][id^="saso_eventtickets_request_daychooser['+data_cart_item_id+']"]').each((idx, input_to_update) => {
481 //console.log('update datepicker', input_to_update);
482 let input_elem = $(input_to_update);
483 let v = input_elem.val().trim();
484 if (!v) {
485 //console.log(input_elem.attr("id")+' set value to: '+date_value);
486 input_elem.val(date_value); // is not working somehow, so skip this step for now. The value is shown and send to the server, but on the checkout the other fields are empty
487 to_be_changed.push(input_elem);
488 }
489 });
490
491 // remove the related error message on the cart
492 //let data_cart_item_count = elem.attr('data-cart-item-count');
493 //$('li[data-cart-item-id="'+data_cart_item_id+'"][data-cart-item-count="'+data_cart_item_count+'"]').remove();
494 // send data to the server
495
496 let counter = 0;
497 let wait = 0;
498 to_be_changed.forEach(input => {
499 //console.log(input.attr("id")+'send code: '+date_value);
500 //console.log(input);
501 window.setTimeout(()=>{
502 sendCode(input, date_value, "saso_eventtickets_request_daychooser");
503 }, wait);
504 counter++;
505 if (wait == 0) wait = 250;
506 if (counter == to_be_changed.length) {
507 $(document.body).trigger('update_checkout');
508 }
509 });
510 } // end date_value
511 })
512 .each(function() {
513 // Only remove disabled if not in a locked container (seats selected)
514 if (!$(this).closest('.saso-datepicker-locked').length) {
515 $(this).removeAttr('disabled');
516 }
517 });
518
519 //addStyleCode('#ui-datepicker-div > table {background-color: white;}');
520 }
521
522 init();
523
524 return {
525 _addHandlerToTheCodeFields: _addHandlerToTheCodeFields,
526 };
527 }
528
529 (function($){
530 $(document).ready(function(){
531 window.SasoEventticketsValidator_WC_frontend = SasoEventticketsValidator_WC_frontend($, SasoEventticketsValidator_phpObject);
532 });
533 })(jQuery);