PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 1.11.1
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v1.11.1
2.3.2 2.3.1 2.3.0 2.2.8 2.2.7 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.11.1 1.11.2 1.6 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.9.10 1.9.11 All 60 releases
merchant / assets / js / admin / admin.js

admin.js in Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant 1.11.1, at assets/js/admin/admin.js

1,794 lines 73.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 "use strict";
2
3 ;
4 (function ($, window, document, undefined) {
5 'use strict';
6
7 var merchant = merchant || {};
8 var params = new URLSearchParams(window.location.search);
9 var currentModule = params.get('module');
10 $(document).ready(function () {
11 // AjaxSave
12 var $ajaxForm = $('.merchant-module-page-ajax-form');
13 var $ajaxHeader = $('.merchant-module-page-ajax-header');
14 var $ajaxSaveBtn = $('.merchant-module-save-button');
15 $('.merchant-module-page-content').on('change keypress change.merchant', function () {
16 if (!$(this).is('.merchant-module-question-answer-textarea, .merchant-license-code-input')) {
17 if (!merchant.show_save) {
18 $ajaxHeader.addClass('merchant-show');
19 $ajaxHeader.removeClass('merchant-saving');
20 merchant.show_save = true;
21 }
22 }
23 GroubField.initFlag();
24 });
25 $ajaxForm.ajaxForm({
26 beforeSubmit: function beforeSubmit() {
27 $ajaxHeader.addClass('merchant-saving');
28 },
29 success: function success() {
30 $ajaxHeader.removeClass('merchant-show');
31 merchant.show_save = false;
32
33 // Module Alert after Ajax Save
34 if (!$('.merchant-module-action').hasClass('merchant-enabled')) {
35 var $moduleAlert = $('.merchant-module-alert');
36 $moduleAlert.addClass('merchant-show');
37 $(document).off('click.merchant-alert-close');
38 $(document).on('click.merchant-alert-close', function (e) {
39 if (!$(e.target).closest('.merchant-module-alert-wrapper').length) {
40 $moduleAlert.removeClass('merchant-show');
41 $(document).off('click.merchant-alert-close');
42 }
43 });
44 }
45 $(document).trigger('save.merchant', [currentModule]);
46 }
47 });
48 var $disableModuleSubmitBtn = $('.merchant-module-question-answer-button');
49 var $disableModuleTextField = $('.merchant-module-question-answer-textarea');
50 $disableModuleTextField.on('input', function () {
51 $disableModuleSubmitBtn.prop('disabled', $(this).val().trim() === '');
52 });
53 $disableModuleSubmitBtn.on('click', function (e) {
54 e.preventDefault();
55 var message = $disableModuleTextField.val();
56 if (!message.trim()) {
57 alert('Please provide the required information.');
58 return;
59 }
60 var $button = $(this);
61 $('.merchant-module-question-answer-dropdown').removeClass('merchant-show');
62 $('.merchant-module-question-thank-you-dropdown').addClass('merchant-show');
63 window.wp.ajax.post('merchant_module_feedback', {
64 subject: $disableModuleTextField.attr('data-subject'),
65 message: message,
66 module: $button.closest('.merchant-module-action').find('.merchant-module-page-button-action-activate').data('module'),
67 nonce: window.merchant.nonce
68 });
69 });
70 $('.merchant-module-page-button-action-activate').on('click', function (e) {
71 e.preventDefault();
72 if ($(this).hasClass('merchant-module-deactivated-by-bp')) {
73 return false;
74 }
75 $('.merchant-module-question-list-dropdown').removeClass('merchant-show');
76 $('.merchant-module-question-answer-dropdown').removeClass('merchant-show');
77 $('.merchant-module-question-answer-form').removeClass('merchant-show');
78 $('.merchant-module-question-answer-title').removeClass('merchant-show');
79 $('.merchant-module-question-thank-you-dropdown').removeClass('merchant-show');
80 $('.merchant-module-question-answer-textarea').val('');
81 window.wp.ajax.post('merchant_module_activate', {
82 module: $(this).data('module'),
83 nonce: window.merchant.nonce
84 }).done(function () {
85 $('body').removeClass('merchant-module-disabled').addClass('merchant-module-enabled');
86 $('.merchant-module-action').addClass('merchant-enabled');
87 });
88 });
89 $('.merchant-module-page-button-action-deactivate').on('click', function (e) {
90 e.preventDefault();
91 window.wp.ajax.post('merchant_module_deactivate', {
92 module: $(this).data('module'),
93 nonce: window.merchant.nonce
94 }).done(function () {
95 $('body').removeClass('merchant-module-enabled').addClass('merchant-module-disabled');
96 $('.merchant-module-action').removeClass('merchant-enabled');
97 $('.merchant-module-question-list-dropdown').addClass('merchant-show');
98 });
99 });
100 $('.merchant-module-question-list-dropdown li').on('click', function (e) {
101 $disableModuleSubmitBtn.prop('disabled', $disableModuleTextField.val().trim() === '');
102 var $question = $(this);
103 var target = $question.data('answer-target');
104 var $answer = $('[data-answer-title="' + target + '"]');
105 if ($answer.length) {
106 $answer.addClass('merchant-show').siblings().removeClass('merchant-show');
107 $('.merchant-module-question-answer-dropdown').addClass('merchant-show');
108 $('.merchant-module-question-answer-textarea').attr('data-subject', $question.text().trim());
109 } else {
110 $('.merchant-module-question-thank-you-dropdown').addClass('merchant-show');
111 $('.merchant-module-question-answer-dropdown').removeClass('merchant-show');
112 }
113 $('.merchant-module-question-answer-textarea').val('');
114 $('.merchant-module-question-list-dropdown').removeClass('merchant-show');
115 });
116 $('.merchant-module-dropdown-close').on('click', function (e) {
117 e.preventDefault();
118 $(this).closest('.merchant-module-dropdown').removeClass('merchant-show');
119 });
120 $('.merchant-module-page-button-deactivate').on('click', function (e) {
121 e.preventDefault();
122 var $button = $(this);
123 var $dropdown = $('.merchant-module-deactivate-dropdown');
124 $dropdown.toggleClass('merchant-show');
125 $(document).off('click.merchant-close');
126 $(document).on('click.merchant-close', function (e) {
127 if (!$(e.target).closest('.merchant-module-deactivate').length) {
128 $dropdown.removeClass('merchant-show');
129 $(document).off('click.merchant-close');
130 }
131 });
132 });
133 $('.merchant-range').each(function () {
134 var $range = $(this);
135 var $rangeInput = $range.find('.merchant-range-input');
136 var $numberInput = $range.find('.merchant-range-number-input');
137 $rangeInput.on('change input merchant.range merchant-init.range', function (e) {
138 var $range = $(this);
139 var value = (e.type === 'merchant' ? $numberInput.val() : $range.val()) || 0;
140 var min = $range.attr('min') || 0;
141 var max = $range.attr('max') || 1;
142 var percentage = (value - min) / (max - min) * 100;
143 if ($('body').hasClass('rtl')) {
144 $range.css({
145 'background': 'linear-gradient(to left, #3858E9 0%, #3858E9 ' + percentage + '%, #ddd ' + percentage + '%, #ddd 100%)'
146 });
147 } else {
148 $range.css({
149 'background': 'linear-gradient(to right, #3858E9 0%, #3858E9 ' + percentage + '%, #ddd ' + percentage + '%, #ddd 100%)'
150 });
151 }
152 $rangeInput.val(value);
153 $numberInput.val(value);
154 }).trigger('merchant-init.range');
155 $numberInput.on('change input blur', function () {
156 if ($rangeInput.hasClass('merchant-range-input')) {
157 $rangeInput.val($(this).val()).trigger('merchant.range');
158 }
159 });
160 });
161 $(document).on('click', '.merchant-module-page-setting-field-hidden-desc-trigger', function () {
162 var $trigger = $(this);
163 $trigger.toggleClass('expanded');
164 var showText = $trigger.attr('data-show-text');
165 var hiddenText = $trigger.attr('data-hidden-text');
166 $(this).find('span:first').text($trigger.text() === showText ? hiddenText : showText);
167 $(this).closest('.merchant-module-page-setting-field').find('.merchant-module-page-setting-field-hidden-desc').stop(true, true).slideToggle('fast');
168 });
169
170 // Add support for toggle field inside flexible content.
171 var flexibleToggleField = {
172 init: function init(field) {
173 this.events();
174 },
175 events: function events() {
176 $(document).on('click', '.merchant-flexible-content .merchant-toggle-switch .toggle-switch-label span', function () {
177 var checkBox = $(this).closest('.merchant-toggle-switch').find('.toggle-switch-checkbox');
178 checkBox.prop('checked', !checkBox.prop('checked'));
179 }).trigger('merchant.change');
180 }
181 };
182 var dateTimePickerField = {
183 init: function init() {
184 this.initiate_datepicker();
185 this.events();
186 },
187 initiate_datepicker: function initiate_datepicker() {
188 var elements = $('.merchant-module-page-setting-field .merchant-datetime-field');
189 if (elements.length === 0) {
190 return;
191 }
192 elements.each(function (index) {
193 var input = $(this).find('input'),
194 options = {
195 locale: JSON.parse(merchant_datepicker_locale),
196 selectedDates: [input.val() ? new Date(input.val()) : ''],
197 onSelect: function onSelect(_ref) {
198 var date = _ref.date,
199 formattedDate = _ref.formattedDate,
200 datepicker = _ref.datepicker;
201 if (typeof formattedDate === "undefined") {
202 // allow removing date
203 // input.val('');
204 datepicker.$el.value = '';
205 }
206 input.trigger('change.merchant');
207 input.trigger('change.merchant-datepicker', [formattedDate, input, options, index]);
208 }
209 },
210 fieldOptions = $(this).data('options');
211 // add buttons to fieldOptions
212 fieldOptions.buttons = ['clear'];
213 if (fieldOptions) {
214 if (fieldOptions.minDate !== undefined && fieldOptions.minDate === 'today') {
215 fieldOptions.minDate = new Date();
216 if (fieldOptions.timeZone !== undefined && fieldOptions.timeZone !== '') {
217 fieldOptions.minDate = new Date(fieldOptions.minDate.toLocaleString('en-US', {
218 timeZone: fieldOptions.timeZone
219 }));
220 }
221 }
222 options = Object.assign(options, fieldOptions);
223 }
224 var datepickerObj = new AirDatepicker(input.getPath(), options);
225 input.attr('readonly', true);
226 $(document).trigger('initiated.merchant-datepicker', [datepickerObj, input, options, index]);
227 });
228 },
229 events: function events() {
230 var self = this;
231 $(document).on('merchant-flexible-content-added', function () {
232 self.initiate_datepicker();
233 });
234 }
235 };
236 dateTimePickerField.init();
237
238 // Sortable.
239 var SortableField = {
240 init: function init(field) {
241 this.events();
242 },
243 events: function events() {
244 var self = this;
245 $('.merchant-sortable').each(function () {
246 var field = $(this),
247 input = field.find('.merchant-sortable-input');
248
249 // Init sortable.
250 $(field.find('ul.merchant-sortable-list').first()).sortable({
251 // Update value when we stop sorting.
252 update: function update() {
253 input.val(self.sortableGetNewVal(field)).trigger('change.merchant');
254 }
255 }).disableSelection().find('li').each(function () {
256 // Enable/disable options when we click on the eye of Thundera.
257 $(this).find('i.visibility').click(function () {
258 $(this).toggleClass('dashicons-visibility-faint').parents('li:eq(0)').toggleClass('invisible');
259 });
260 }).click(function () {
261 // Update value when click in the eye.
262 if ($(event.target).hasClass('dashicons-visibility')) {
263 input.val(self.sortableGetNewVal(field)).trigger('change.merchant');
264 }
265 });
266 });
267 },
268 sortableGetNewVal: function sortableGetNewVal(field) {
269 var items = $(field.find('li'));
270 var newVal = [];
271 _.each(items, function (item) {
272 if (!$(item).hasClass('invisible')) {
273 newVal.push($(item).data('value'));
274 }
275 });
276 return JSON.stringify(newVal);
277 }
278 };
279
280 // Initialize Sortable.
281 SortableField.init();
282 flexibleToggleField.init();
283
284 // When adding/duplicating new item, refresh sorting
285 $(document).on('merchant-flexible-content-added', function (e, $layout) {
286 var $sortableWrapper = $layout.find('.merchant-sortable-repeater-control');
287 var $sortableElement = $sortableWrapper.find('.merchant-sortable-repeater.sortable');
288 SortableRepeaterField.makeFieldsSortable($sortableElement);
289 });
290
291 // Sortable Repeater.
292 var SortableRepeaterField = {
293 init: function init(field) {
294 var self = this;
295
296 // Update the values for all our input fields and initialise the sortable repeater.
297 $('.merchant-sortable-repeater-control').each(function () {
298 // If there is an existing customizer value, populate our rows
299 var defaultValuesArray = JSON.parse($(this).find('.merchant-sortable-repeater-input').val());
300 var numRepeaterItems = defaultValuesArray.length;
301 if (numRepeaterItems > 0) {
302 // Add the first item to our existing input field
303 $(this).find('.repeater-input').val(defaultValuesArray[0]);
304
305 // Create a new row for each new value
306 if (numRepeaterItems > 1) {
307 // var i;
308 for (var i = 1; i < numRepeaterItems; ++i) {
309 self.appendRow($(this), defaultValuesArray[i]);
310 }
311 }
312 }
313
314 // Todo: remove
315 // Make our Repeater fields sortable. Doesn't work with flexible content
316 // if (!$(this).hasClass('disable-sorting')) {
317 // $(this).find('.merchant-sortable-repeater.sortable').sortable({
318 // update: function (event, ui) {
319 // self.getAllInputs($(this).parent());
320 // }
321 // });
322 // }
323 });
324
325 // Events.
326 this.events();
327 },
328 events: function events() {
329 var self = this;
330
331 // Remove item starting from its parent element
332 $(document).on('click', '.merchant-sortable-repeater.sortable .customize-control-sortable-repeater-delete', function (event) {
333 event.preventDefault();
334 $(this).parent().slideUp('fast', function () {
335 var parentContainer = $(this).parent().parent();
336 $(this).remove();
337 self.getAllInputs(parentContainer);
338 });
339 $(document).trigger('merchant-sortable-repeater-item-deleted');
340 });
341
342 // Add new item
343 $(document).on('click', '.customize-control-sortable-repeater-add', function (event) {
344 event.preventDefault();
345 self.appendRow($(this).parent());
346 self.getAllInputs($(this).parent());
347 });
348
349 // Refresh our hidden field if any fields change
350 $(document).on('change', '.merchant-sortable-repeater.sortable', function () {
351 self.getAllInputs($(this).parent());
352 });
353 $(document).on('focusout', '.merchant-sortable-repeater.sortable .repeater-input', function () {
354 self.getAllInputs($(this).parent());
355 });
356 },
357 /**
358 * Append a new row to our list of elements.
359 *
360 */
361 appendRow: function appendRow($element) {
362 var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
363 var newRow = '<div class="repeater" style="display:none"><input type="text" value="' + defaultValue + '" class="repeater-input" /><span class="dashicons dashicons-menu"></span><a class="customize-control-sortable-repeater-delete" href="#"><span class="dashicons dashicons-no-alt"></span></a></div>';
364 $element.find('.sortable').append(newRow);
365 var $newItem = $element.find('.sortable').find('.repeater:last');
366 $newItem.slideDown('slow', function () {
367 $(this).find('input').focus();
368 });
369
370 // Make Repeater fields sortable; Putting here works better with flexible content
371 this.makeFieldsSortable($element.find('.sortable'));
372 $(document).trigger('merchant-sortable-repeater-item-added', [$newItem, $element.find('.sortable')]);
373 },
374 makeFieldsSortable: function makeFieldsSortable($sortableElement) {
375 if (!$sortableElement.hasClass('disable-sorting')) {
376 $sortableElement.sortable({
377 update: function update(event, ui) {
378 SortableRepeaterField.getAllInputs($sortableElement.parent());
379 }
380 });
381 }
382 },
383 /**
384 * Get the values from the repeater input fields and add to our hidden field.
385 *
386 */
387 getAllInputs: function getAllInputs($element) {
388 var inputValues = $element.find('.repeater-input').map(function () {
389 return $(this).val();
390 }).toArray();
391
392 // Keep one empty item if all deleted.
393 if (!inputValues.length) {
394 inputValues.push('');
395 }
396
397 // Add all the values from our repeater fields to the hidden field (which is the one that actually gets saved)
398 $element.find('.merchant-sortable-repeater-input').val(JSON.stringify(inputValues));
399 // Important! Make sure to trigger change event so Customizer knows it has to save the field
400 $element.find('.merchant-sortable-repeater-input').trigger('change');
401 $element.find('.merchant-sortable-repeater-input').trigger('sortable.repeater.change');
402 }
403 };
404
405 // Initialize Sortable Repeater.
406 SortableRepeaterField.init();
407 var GroubField = {
408 init: function init() {
409 var self = this;
410 self.initAccordion();
411 self.initFlag();
412 },
413 initAccordion: function initAccordion() {
414 var self = this;
415 $('.merchant-group-field.has-accordion').each(function () {
416 var element = $(this);
417 element.accordion({
418 collapsible: true,
419 header: "> .title-area",
420 heightStyle: "content",
421 active: element.hasClass('open') ? 0 : false
422 });
423 });
424 },
425 initFlag: function initFlag() {
426 $('.merchant-group-field.has-flag').each(function () {
427 var element = $(this);
428 var field_id = element.data('id');
429 var status_field = element.find(".merchant-field-".concat(field_id, "_status select"));
430 var selected_value = status_field.val();
431 var selected_label = status_field.find('option:selected').text();
432 var status_element = element.find('.field-status');
433 status_element.removeClass('hidden active inactive').text(selected_label).addClass(selected_value);
434 });
435 }
436 };
437 var ReviewsSelector = {
438 accordion: null,
439 activePopupContainer: null,
440 // Initialize the Reviews Selector
441 init: function init() {
442 var self = this;
443 self.initAccordion();
444 self.events();
445 // Skip the flexible content hidden elements that will be cloned when initialize the sortable reviews functionality
446 self.makeSelectedReviewsSortable($('.merchant-reviews-selector').not('.layouts .merchant-reviews-selector'));
447 },
448 // Set up event listeners
449 events: function events() {
450 var self = this;
451 $(document).on('input', '.merchant-reviews-selector .products-search', self.ajaxSearch.bind(self));
452 $(document).on('change', '.merchant-reviews-selector .product-review input[type="checkbox"]', self.toggleReview.bind(self));
453 $(document).on('click', '.merchant-reviews-selector .review-photo img', self.requestReviewImages.bind(self));
454 $(document).on('click', '.review-photos-popup .overlay', self.dismissImagesGallery.bind(self));
455 $(document).on('click', '.merchant-reviews-selector .product-reviews-load-more button', self.loadMoreReviews.bind(self));
456 $(document).on('click', '.merchant-reviews-selector .popup-trigger', self.initPopUp.bind(self));
457 $(document).on('click', '.merchant-reviews-selector .popup-header .close, .merchant-reviews-selector > .overlay', self.dismissPopUp.bind(self));
458 $(document).on('click', '.merchant-reviews-selector .product-review-delete', self.deleteSelectedReview.bind(self));
459 // Listen to escape key
460 $(document).on('keyup', function (e) {
461 if (e.key === "Escape") {
462 var isGallery = self.dismissImagesGallery();
463 if (isGallery) {
464 return;
465 }
466 self.dismissPopUp(self);
467 }
468 });
469 $(document).on('merchant-flexible-content-added', function (e, layout) {
470 self.makeSelectedReviewsSortable();
471 self.initAccordion();
472 });
473 },
474 // Make selected reviews sortable
475 makeSelectedReviewsSortable: function makeSelectedReviewsSortable() {
476 var container = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : $(document).find('.merchant-reviews-selector').not('.layouts .merchant-reviews-selector');
477 var self = this;
478 var selectedReviews = container.find('.selected-reviews .product-reviews');
479 selectedReviews.sortable({
480 axis: 'y',
481 cursor: 'move',
482 helper: 'original',
483 handle: '.product-review-move',
484 cancel: '',
485 placeholder: 'placeholder',
486 // Add a class for styling
487 update: function update(event, ui) {
488 var container = ui.item.closest('.merchant-reviews-selector');
489 self.saveModifications(container);
490 },
491 start: function start(event, ui) {
492 ui.placeholder.height(ui.item.height()); // Match height
493 }
494 });
495 // $('.product-reviews').sortable('refresh');
496 // console.log('selectedReviews',selectedReviews.sortable('instance'))
497 },
498 // Delete selected review
499 deleteSelectedReview: function deleteSelectedReview(e) {
500 var self = this;
501 var review = $(e.target).closest('.product-review');
502 var container = review.closest('.merchant-reviews-selector');
503 review.remove();
504 self.saveModifications(container);
505 self.updateSelectedReviewsCheckboxState(container);
506 self.countSelectedReviewsInProduct(container);
507 },
508 // Handle AJAX search for reviews
509 ajaxSearch: function ajaxSearch(e) {
510 var self = this;
511 var searchField = $(e.target);
512 var container = searchField.closest('.merchant-reviews-selector');
513 var header = container.find('.popup-header');
514
515 // check value length > 3
516 if (searchField.val().length === 0 || searchField.val().length >= 3) {
517 $.ajax({
518 url: merchant_admin_options.ajaxurl,
519 type: 'POST',
520 data: {
521 action: 'merchant_search_reviews',
522 search: searchField.val(),
523 nonce: merchant_admin_options.ajaxnonce
524 },
525 beforeSend: function beforeSend() {
526 header.addClass('loading');
527 self.destroyAccordion(container);
528 },
529 success: function success(response) {
530 if (response.success) {
531 header.removeClass('popup-error');
532 container.find('.products-search-results').html(response.data);
533 self.initAccordion(container);
534 } else {
535 header.addClass('popup-error');
536 }
537 },
538 complete: function complete() {
539 header.removeClass('loading');
540 },
541 error: function error() {
542 header.addClass('popup-error');
543 }
544 });
545 }
546 },
547 // Load more reviews
548 loadMoreReviews: function loadMoreReviews(e) {
549 var self = this;
550 var product = $(e.target).closest('.product-item');
551 var offset = product.find('.product-review').length;
552 $.ajax({
553 url: merchant_admin_options.ajaxurl,
554 type: 'POST',
555 data: {
556 action: 'merchant_load_more_reviews',
557 product_id: product.attr('data-id'),
558 offset: offset,
559 nonce: merchant_admin_options.ajaxnonce
560 },
561 beforeSend: function beforeSend() {
562 product.addClass('loading');
563 },
564 success: function success(response) {
565 if (response.success) {
566 product.find('.product-reviews .reviews-wrapper').append(response.data.reviews);
567 if (response.data.load_more === '') {
568 self.hideLoadMoreButton(product);
569 }
570 self.updateSelectedReviewsCheckboxState(product.closest('.merchant-reviews-selector'));
571 self.countSelectedReviewsInProduct(product.closest('.merchant-reviews-selector'));
572 }
573 },
574 complete: function complete() {
575 product.removeClass('loading');
576 }
577 });
578 },
579 // Hide load more button
580 hideLoadMoreButton: function hideLoadMoreButton(product) {
581 product.find('.product-reviews-load-more').remove();
582 },
583 // Initialize the popup
584 initPopUp: function initPopUp(e) {
585 var self = this;
586 var container = $(e.target).closest('.merchant-reviews-selector');
587 var popup = container.find('.selector-popup');
588 var overlay = container.find('.overlay');
589 popup.addClass('active');
590 overlay.addClass('active');
591 self.activePopupContainer = container;
592 },
593 // Dismiss the popup
594 dismissPopUp: function dismissPopUp() {
595 var self = this;
596 var container = self.activePopupContainer;
597 if (container === null) {
598 return;
599 }
600 var popup = container.find('.selector-popup');
601 var overlay = container.find('.overlay');
602 popup.removeClass('active');
603 overlay.removeClass('active');
604 self.activePopupContainer = null;
605 },
606 // Initialize the accordion
607 initAccordion: function initAccordion() {
608 var container = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : $(document).find('.merchant-reviews-selector');
609 var self = this;
610 container.each(function () {
611 var elements = $(this).find('.popup-content .product-item.product-item-has-reviews');
612 elements.each(function () {
613 elements.accordion({
614 collapsible: true,
615 heightStyle: "content",
616 icons: false,
617 // Disable icons
618 active: elements.hasClass('opened') ? 0 : false,
619 activate: function activate(event, ui) {
620 // Check if a new panel is being activated
621 if (ui.newPanel.length) {
622 // Add 'opened' class to the parent product item
623 ui.newPanel.parent().addClass('opened');
624 } else {
625 // Remove 'opened' class from all product items
626 elements.removeClass('opened');
627 }
628 }
629 });
630 });
631 elements.find('a').on('click', function (e) {
632 e.stopPropagation(); // Prevent event from bubbling up to the accordion header
633 });
634 self.updateSelectedReviewsCheckboxState($(this));
635 self.countSelectedReviewsInProduct($(this));
636 });
637 },
638 // Destroy the accordion
639 destroyAccordion: function destroyAccordion(container) {
640 var elements = container.find('.selector-popup .product-item.product-item-has-reviews');
641 elements.each(function () {
642 if ($(this).hasClass('ui-accordion')) {
643 // Check if it has the accordion class
644 $(this).accordion('destroy');
645 }
646 });
647 },
648 // Toggle review selection
649 toggleReview: function toggleReview(e) {
650 var self = this;
651 var checked = $(e.target).prop('checked');
652 var reviewsFieldContainer = $(e.target).closest('.merchant-reviews-selector');
653 var review = $(e.target).closest('.product-review');
654 var reviewId = review.attr('data-id');
655 var selectedReviews = reviewsFieldContainer.find('.selected-reviews .product-reviews');
656 var selectedReview = selectedReviews.find(".product-review[data-id=\"".concat(reviewId, "\"]"));
657 if (checked) {
658 if (selectedReview.length === 0) {
659 var newReview = review.clone();
660 selectedReviews.append(newReview);
661 self.makeSelectedReviewsSortable();
662 }
663 } else {
664 selectedReview.remove();
665 }
666 setTimeout(function () {
667 self.saveModifications(reviewsFieldContainer);
668 }, 150);
669 },
670 // Save modifications to the selected reviews
671 saveModifications: function saveModifications(container) {
672 var self = this;
673 var reviewsSavedIdsField = container.find('.review-saved-ids');
674 var selectedReviews = container.find('.selected-reviews .product-reviews');
675 var reviews = selectedReviews.find('.product-review');
676 var reviewsIds = [];
677 reviews.each(function () {
678 var id = $(this).attr('data-id');
679 reviewsIds.push(id);
680 });
681 reviewsSavedIdsField.val(reviewsIds.join(','));
682 reviewsSavedIdsField.trigger('change');
683 // reviewsSavedIds;
684 self.updateSelectedReviewsCheckboxState(container);
685 self.countSelectedReviewsInProduct(container);
686 },
687 // Mark selected reviews checkbox
688 updateSelectedReviewsCheckboxState: function updateSelectedReviewsCheckboxState(container) {
689 var popupContent = container.find('.selector-popup');
690 var reviewsSavedIds = container.find('.review-saved-ids');
691 var reviews = popupContent.find('.product-review');
692 var reviewsIds = reviewsSavedIds.val().split(',');
693 reviews.each(function () {
694 var reviewId = $(this).attr('data-id');
695 var checkbox = container.find(".product-review[data-id=\"".concat(reviewId, "\"] input[type=\"checkbox\"]"));
696 if (reviewsIds.includes(reviewId)) {
697 checkbox.prop('checked', true);
698 } else {
699 checkbox.prop('checked', false);
700 }
701 });
702 },
703 // Count selected reviews in product
704 countSelectedReviewsInProduct: function countSelectedReviewsInProduct(container) {
705 var self = this;
706 var products = container.find('.selector-popup .product-item');
707 var reviewsSavedIds = container.find('.review-saved-ids');
708 var reviewsIds = reviewsSavedIds.val().split(',');
709 products.each(function () {
710 var selectedReviews = 0;
711 var product = $(this);
712 var productReviews = product.find('.product-review');
713 productReviews.each(function () {
714 var review = $(this);
715 var reviewId = review.attr('data-id');
716 if (reviewsIds.includes(reviewId)) {
717 selectedReviews++;
718 }
719 });
720 product.find('.selected-reviews-count .counter').text(selectedReviews);
721 });
722 },
723 // Request review images
724 requestReviewImages: function requestReviewImages(e) {
725 var reviewContainer = $(e.target).closest('.product-review');
726 var image = $(e.target);
727 var reviewId = reviewContainer.attr('data-id');
728 $.ajax({
729 url: merchant_admin_options.ajaxurl,
730 type: 'POST',
731 data: {
732 action: 'merchant_get_review_images',
733 review_id: reviewId,
734 nonce: merchant_admin_options.ajaxnonce
735 },
736 beforeSend: function beforeSend() {
737 // Show loading spinner
738 image.addClass('loading');
739 },
740 success: function success(response) {
741 if (response.success) {
742 $('body').append(response.data);
743 setTimeout(function () {
744 $('body').find('.review-photos-popup').addClass('active');
745 }, 300);
746 }
747 },
748 complete: function complete() {
749 // Hide loading spinner
750 image.removeClass('loading');
751 }
752 });
753 },
754 // Dismiss the images gallery
755 dismissImagesGallery: function dismissImagesGallery() {
756 var gallery = $('body').find('.review-photos-popup');
757 if (gallery.length) {
758 gallery.removeClass('active');
759 setTimeout(function () {
760 gallery.remove();
761 }, 300);
762 return true;
763 }
764 return false;
765 }
766 };
767
768 // Flexible Content.
769 var FlexibleContentField = {
770 init: function init(field) {
771 var self = this;
772
773 // Update the values for all our input fields and initialise the sortable repeater.
774 $('.merchant-flexible-content-control').each(function () {
775 var hasAccordion = $(this).hasClass('has-accordion'),
776 $content = $(this).find('.merchant-flexible-content');
777 if (hasAccordion) {
778 $content.accordion({
779 collapsible: true,
780 //header: "> div > .layout-header",
781 header: function header(elem) {
782 return elem.find('.layout__inner > .layout-header');
783 },
784 heightStyle: "content"
785 }).sortable({
786 axis: 'y',
787 cursor: 'move',
788 helper: 'original',
789 handle: '.customize-control-flexible-content-move',
790 stop: function stop(event, ui) {
791 $content.trigger('merchant.sorted');
792 self.refreshNumbers($content);
793 $content.accordion("refresh");
794 }
795 });
796 } else {
797 $content.sortable({
798 axis: 'y',
799 cursor: 'move',
800 helper: 'original',
801 handle: '.customize-control-flexible-content-move',
802 stop: function stop(event, ui) {
803 $content.trigger('merchant.sorted');
804 self.refreshNumbers($content);
805 $content.accordion("refresh");
806 }
807 });
808 }
809 });
810 this.updateLayoutTitle();
811 this.updateDiscountPercentMaxVal();
812 // Events.
813 this.events();
814 },
815 updateLayoutTitle: function updateLayoutTitle() {
816 // Update the title for all layout header.
817 $('.merchant-flexible-content .layout').each(function () {
818 var title = $(this).find('.layout-title[data-title-field]');
819 if (title.length) {
820 var input = $(this).find('.layout-body .merchant-field-' + title.data('title-field') + ' input');
821 input.on('change keyup', function () {
822 title.text($(this).val());
823 });
824 title.text(input.val());
825 }
826 });
827 },
828 updateDiscountPercentMaxVal: function updateDiscountPercentMaxVal() {
829 $('.merchant-flexible-content .layout').each(function () {
830 var $layout = $(this);
831 var $discountType = $layout.find('.merchant-module-page-setting-field[data-id="discount_type"]');
832 var $discountVal = $layout.find('.merchant-module-page-setting-field[data-id="discount_value"]');
833 $discountVal = $discountVal.length ? $discountVal : $layout.find('.merchant-module-page-setting-field[data-id="discount"]');
834 $discountVal = $discountVal.length ? $discountVal : $layout.find('.merchant-module-page-setting-field[data-id="discount_amount"]');
835 var checkedValue = $discountType.find('input:checked').val();
836
837 // Set/Remove max value based on the discount type.
838 checkedValue === 'percentage_discount' || checkedValue === 'percentage' ? $discountVal.find('input').attr('max', 100) : $discountVal.find('input').removeAttr('max');
839 });
840 $('.merchant-module-page-setting-fields');
841 },
842 events: function events() {
843 var self = this;
844 $(document).on('change', '.merchant-module-page-setting-field[data-id="discount_type"] input', function () {
845 self.updateDiscountPercentMaxVal();
846 });
847
848 // Update "selected" attribute on select. It's Required for duplicating layouts.
849 $(document).on('change', 'select', function () {
850 var selectedValue = $(this).val();
851 var isMultiple = $(this).prop('multiple');
852 $(this).find('option').each(function () {
853 var currentValue = $(this).val();
854 var isSelected = isMultiple ? selectedValue.includes(currentValue) : currentValue === selectedValue;
855 $(this).attr('selected', isSelected);
856 });
857 });
858 $('.customize-control-flexible-content-add-button').click(function (event) {
859 event.preventDefault();
860 event.stopImmediatePropagation();
861 if ($(this).parent().find('.customize-control-flexible-content-add-list a').length === 1) {
862 // If there is only one layout, trigger click on it.
863 $(this).parent().find('.customize-control-flexible-content-add-list a').trigger('click');
864 return;
865 }
866 $(this).parent().find('.customize-control-flexible-content-add-list').toggleClass('active');
867 });
868
869 // Add new item
870 $(document).on('click', '.customize-control-flexible-content-add', function (event) {
871 event.preventDefault();
872 event.stopImmediatePropagation();
873 var $field = $('.merchant-flexible-content-control[data-id=' + $(this).data('id') + ']');
874 var $layouts = $field.find('.layouts');
875 var $selected = $(this).data('layout');
876 var $layout = $layouts.find('.layout[data-type=' + $selected + ']').clone(true);
877 var $content = $field.find('.merchant-flexible-content');
878 var $items = $content.find('.layout');
879 $layout.find('input, select, textarea').each(function () {
880 if ($(this).data('name')) {
881 $(this).attr('name', $(this).data('name').replace('0', $items.length));
882 }
883 if ($(this).is(':checkbox, :radio') && $(this).attr('checked')) {
884 $(this).prop('checked', true);
885 }
886 });
887 $layout.find('.layout-count').text($items.length + 1);
888 $content.append($layout);
889 $content.removeClass('empty');
890 $(this).parent().removeClass('active');
891 if ($layout.find('.merchant-module-page-setting-field-upload').length) {
892 initUploadField($layout.find('.merchant-module-page-setting-field-upload'));
893 }
894 if ($layout.find('.merchant-module-page-setting-field-select_ajax').length) {
895 initSelectAjax($layout.find('.merchant-module-page-setting-field-select_ajax'));
896 }
897 var parentDiv = $(this).closest('.merchant-flexible-content-control'),
898 hasAccordion = parentDiv.hasClass('has-accordion');
899 if (hasAccordion) {
900 parentDiv.find('.merchant-flexible-content').accordion("refresh");
901 // Expand the accordion last added
902 parentDiv.find('.merchant-flexible-content').accordion("option", "active", -1);
903 }
904 GroubField.init();
905 $(document).trigger('merchant-flexible-content-added', [$layout]);
906 self.updateLayoutTitle();
907 self.updateDiscountPercentMaxVal();
908 });
909
910 // Duplicate item
911 $(document).on('click', '.customize-control-flexible-content-duplicate', function (event) {
912 event.preventDefault();
913 event.stopImmediatePropagation();
914 var $duplicateBtn = $(this);
915 var $flexibleContentWrapper = $duplicateBtn.closest('.merchant-flexible-content-control[data-id=' + $duplicateBtn.data('id') + ']');
916 var $flexibleContent = $flexibleContentWrapper === null || $flexibleContentWrapper === void 0 ? void 0 : $flexibleContentWrapper.find('.merchant-flexible-content');
917 if (!$flexibleContentWrapper.length || !$flexibleContent.length) {
918 return;
919 }
920 var $sourceLayout = $duplicateBtn.closest('.layout');
921 if (!$sourceLayout.length) {
922 return;
923 }
924 $sourceLayout.find('.layout-actions__inner').hide();
925
926 // Clone the layout without data & events.
927 var $clonedLayout = $sourceLayout.clone();
928 var $items = $flexibleContent.find('.layout');
929 var index = $sourceLayout.find('.layout-count').text();
930 $clonedLayout.find('input, select, textarea').each(function () {
931 var $input = $(this);
932 var inputName = $input.attr('name');
933 if (inputName) {
934 var prefix = inputName.split('[')[0];
935 var indexPart = inputName.match(/\[(.*?)\]/g);
936 if (indexPart && indexPart.length > 1) {
937 indexPart[1] = '[' + index + ']';
938 var newName = "".concat(prefix).concat(indexPart.join(''));
939 $input.attr('name', newName);
940 }
941 }
942 });
943
944 // Find select2, Remove and Re-init again. select.select2('destroy') doesn't work.
945 $clonedLayout.find('select').each(function () {
946 if ($(this).hasClass('select2-hidden-accessible')) {
947 $(this).removeClass('select2-hidden-accessible').removeAttr('data-live-search').removeAttr('data-select2-id').removeAttr('aria-hidden').removeAttr('tabindex');
948
949 // Remove the existing dropdown
950 $(this).nextAll('.select2-container').remove();
951
952 // Re-init
953 $(this).select2();
954 }
955 });
956
957 // Removing copied style to make the accordion work properly.
958 $clonedLayout.find('.layout-body').removeAttr('style');
959
960 // Append the cloned layout right after the source one with fadeIn effect.
961 $clonedLayout.hide();
962 $clonedLayout.insertAfter($sourceLayout);
963 $clonedLayout.fadeIn();
964 if ($clonedLayout.find('.merchant-module-page-setting-field-upload').length) {
965 initUploadField($clonedLayout.find('.merchant-module-page-setting-field-upload'));
966 }
967 if ($clonedLayout.find('.merchant-module-page-setting-field-select_ajax').length) {
968 initSelectAjax($clonedLayout.find('.merchant-module-page-setting-field-select_ajax'));
969 }
970 self.refreshNumbers($flexibleContent);
971 $(document).trigger('merchant-flexible-content-added', [$clonedLayout]);
972 if ($flexibleContentWrapper.hasClass('has-accordion')) {
973 $flexibleContent.accordion('refresh');
974 }
975 self.updateLayoutTitle();
976 GroubField.init();
977 });
978
979 // Delete item
980 $(document).on('click', '.customize-control-flexible-content-delete', function (event) {
981 event.preventDefault();
982 var $item = $(this).closest('.layout');
983 var $content = $item.parent();
984 $item.remove();
985 if ($content.find('.layout').length === 0) {
986 $content.addClass('empty');
987 }
988 self.refreshNumbers($content);
989 $(document).trigger('merchant-flexible-content-deleted', [$item]);
990 var parentDiv = $(this).closest('.merchant-flexible-content-control'),
991 hasAccordion = parentDiv.hasClass('has-accordion');
992 if (hasAccordion) {
993 parentDiv.find('.merchant-flexible-content').accordion("refresh");
994 }
995 $(document).trigger('change.merchant');
996 });
997
998 // Toggle Actions(delete/duplicate)
999 $(document).on('click', '.layout-actions__toggle', function (e) {
1000 e.preventDefault();
1001
1002 // Hide other opened elements
1003 hideOtherActions($(this).closest('.layout'));
1004
1005 // Toggle the current element
1006 $(this).closest('.layout-actions').find('.layout-actions__inner').stop().slideToggle(300);
1007 });
1008
1009 // Hide Actions when collapse/open
1010 $(document).on('click', '.layout-header', function () {
1011 hideOtherActions($(this).closest('.layout'));
1012 });
1013 $(document).on('merchant-flexible-content-added', function (e, $layout) {
1014 hideOtherActions($layout);
1015 });
1016 function hideOtherActions($layout) {
1017 if ($layout && $layout.length) {
1018 $layout.siblings().find('.layout-actions__inner').slideUp(300);
1019 }
1020 }
1021 },
1022 refreshNumbers: function refreshNumbers($content) {
1023 $content.find('.layout').each(function (index) {
1024 var $count = $(this).find('.layout-count').text();
1025 var $inputIndex = parseInt($count) - 1;
1026 $(this).find('.layout-count').text(index + 1);
1027 $(this).find('input, select, textarea').each(function () {
1028 if ($(this).attr('name')) {
1029 $(this).attr('name', $(this).attr('name').replace('[' + $inputIndex + ']', '[*refreshed*' + index + ']'));
1030 }
1031 });
1032 });
1033 $content.find('.layout').each(function (index) {
1034 $(this).find('input, select, textarea').each(function () {
1035 // We've added *refreshed* to the attribute name in the prior loop as refreshing the numbers in the attribute can cause
1036 // checked boxes to be unchecked due to similar attribute names during the change while sorting, within this loop we remove them
1037 var nameAttr = $(this).attr('name');
1038 if (nameAttr) {
1039 // Check if name attribute exists
1040 $(this).attr('name', nameAttr.replace('*refreshed*', ''));
1041 }
1042 });
1043 });
1044 $content.parent().find('input').trigger('change.merchant');
1045 }
1046 };
1047
1048 // Initialize Flexible Content.
1049 FlexibleContentField.init();
1050 GroubField.init();
1051 ReviewsSelector.init();
1052
1053 // Products selector.
1054 // Handle keyup event for the search input
1055 var debounceTimer;
1056 $(document).on('keyup', '.merchant-module-page-setting-field-products_selector .merchant-search-field', function () {
1057 clearTimeout(debounceTimer);
1058 var categories = [];
1059 var $excluded = $(this).closest('[data-id="excluded_products"]');
1060 if ($excluded.length) {
1061 var $layout = $(this).closest('.layout');
1062 var rules = $layout.find('.merchant-field-rules_to_apply select').val() || $layout.find('.merchant-field-rules_to_display select').val() || $layout.find('.merchant-field-display_rules select').val();
1063 if (rules === 'categories' || rules === 'by_category') {
1064 categories = $layout.find('.merchant-field-category_slugs select').val() || $layout.find('.merchant-field-product_cats select').val();
1065 }
1066 }
1067 var parent = $(this).closest('.merchant-products-search-container');
1068 if ($(this).val() !== '') {
1069 parent.find('.merchant-searching').addClass('active');
1070 var data = {
1071 action: 'merchant_admin_products_search',
1072 nonce: merchant_admin_options.ajaxnonce,
1073 keyword: $(this).val(),
1074 product_types: $(this).data('allowed-types'),
1075 ids: parent.find('.merchant-selected-products').val(),
1076 categories: categories
1077 };
1078 debounceTimer = setTimeout(function () {
1079 $.post(merchant_admin_options.ajaxurl, data, function (response) {
1080 var results = parent.find('.merchant-selections-products-preview');
1081 results.show();
1082 results.html(response);
1083 parent.find('.merchant-searching').removeClass('active');
1084 });
1085 }, 250);
1086 } else {
1087 parent.find('.merchant-selections-products-preview').html('').hide();
1088 }
1089 });
1090
1091 // Products selector.
1092 // Handle click/touch event for the search results
1093 $(document).on('click touch', '.merchant-module-page-setting-field-products_selector .merchant-selections-products-preview li', function () {
1094 var parent = $(this).closest('.merchant-products-search-container'),
1095 valueField = parent.find('.merchant-selected-products'),
1096 oldValue = valueField.val(),
1097 multiple = parent.data('multiple') === 'multiple';
1098 if (parent.find('.merchant-selected-products-preview ul li').length > 0 && !multiple) {
1099 // replace the first item
1100 parent.find('.merchant-selected-products-preview ul li').remove();
1101 valueField.val('').change();
1102 }
1103 $(this).children('.remove').attr('aria-label', 'Remove').html('×');
1104 parent.find('.merchant-selected-products-preview ul').append($(this));
1105 parent.find('.merchant-selections-products-preview').html('').hide();
1106 parent.find('.merchant-search-field').val('').change();
1107 if (oldValue === '') {
1108 valueField.val($(this).data('id'));
1109 } else {
1110 if (!multiple) {
1111 valueField.val($(this).data('id')).change();
1112 } else {
1113 var newValue = oldValue.split(',');
1114 newValue.push($(this).data('id'));
1115 valueField.val(newValue.join(',')).change();
1116 }
1117 }
1118 });
1119
1120 // Products selector.
1121 // Handle click/touch event for the remove button.
1122 $(document).on('click touch', '.merchant-selected-products-preview .remove', function () {
1123 // Store a reference to the remove button
1124 var removeButton = $(this);
1125 // Ask for confirmation before removing the product
1126 if (confirm(merchant_admin_options.product_delete_confirmation_message)) {
1127 var parent = removeButton.closest('.merchant-products-search-container'),
1128 valueField = parent.find('.merchant-selected-products'),
1129 id = removeButton.parent().data('id');
1130 removeButton.parent().remove();
1131 var currentValue = valueField.val().split(',');
1132 if (currentValue.length > 0) {
1133 for (var key in currentValue) {
1134 if (parseInt(currentValue[key]) === parseInt(id)) {
1135 currentValue.splice(key, 1);
1136 }
1137 }
1138 }
1139 valueField.val(currentValue.join(',')).change();
1140 valueField.trigger('change.merchant');
1141 }
1142 });
1143 $(document).on('merchant-admin-check-fields merchant-flexible-content-added', function () {
1144 $('.merchant-module-page-setting-field').each(function () {
1145 var $field = $(this);
1146 if ($field.data('condition') && $field.data('condition').length) {
1147 var condition = $field.data('condition');
1148 var $target = $(this).closest('.layout-body').find('input[name*="' + condition[0] + '"],select[name*="' + condition[0] + '"]');
1149 if (!$target.length) {
1150 $target = $('input[name="merchant[' + condition[0] + ']"],select[name="merchant[' + condition[0] + ']"]');
1151 }
1152 if ($target.length) {
1153 var passed = false;
1154 switch (condition[1]) {
1155 case '==':
1156 if ($target.attr('type') === 'radio' || $target.attr('type') === 'checkbox') {
1157 var checked = $target.parent().find('input:checked');
1158 if (checked.length && checked.val() === condition[2]) {
1159 passed = true;
1160 }
1161 }
1162 if ($target.is('select') && $target.val() == condition[2]) {
1163 passed = true;
1164 }
1165 break;
1166 case 'any':
1167 if ($target.attr('type') === 'radio' || $target.attr('type') === 'checkbox') {
1168 var _checked = $target.parent().find('input:checked');
1169 if (_checked.length && condition[2].split('|').includes(_checked.val())) {
1170 passed = true;
1171 }
1172 }
1173 if ($target.is('select') && condition[2].split('|').includes($target.val())) {
1174 passed = true;
1175 }
1176 break;
1177 }
1178 if (passed) {
1179 $field.removeClass('merchant-hide').addClass('merchant-show');
1180 } else {
1181 $field.removeClass('merchant-show').addClass('merchant-hide');
1182 }
1183 }
1184 }
1185 });
1186 }).trigger('merchant.change');
1187 $(document).on('merchant-admin-check-fields merchant-flexible-content-added change keyup', function () {
1188 $(document).find('.merchant-module-page-setting-field').each(function () {
1189 var $field = $(this);
1190 if ($field.data('conditions')) {
1191 var conditions = $field.data('conditions'),
1192 passed = evaluateConditions(conditions, $field);
1193 if (passed) {
1194 $field.removeClass('merchant-hide').addClass('merchant-show');
1195 } else {
1196 $field.removeClass('merchant-show').addClass('merchant-hide');
1197 }
1198 }
1199 });
1200 }).trigger('merchant.change');
1201 $(document).on('change', '.merchant-module-page-setting-field', function () {
1202 $(document).trigger('merchant-admin-check-fields');
1203 }).trigger('merchant.change');
1204 $(document).trigger('merchant-admin-check-fields');
1205 $(document).on('merchant-admin-check-color-fields merchant-flexible-content-added', function () {
1206 $('.merchant-color').each(function () {
1207 var $color = $(this);
1208 var $picker = $color.find('.merchant-color-picker');
1209 var $input = $color.find('.merchant-color-input');
1210 var inited = false;
1211 var pickr;
1212 $picker.off('click').on('click', function (e) {
1213 e.preventDefault();
1214 e.stopPropagation();
1215 var $bodyHTML = $('body,html');
1216 $bodyHTML.addClass('merchant-height-auto');
1217 if (!inited) {
1218 pickr = new Pickr({
1219 el: $picker.get(0),
1220 container: 'body',
1221 theme: 'merchant',
1222 appClass: 'merchant-pcr-app',
1223 default: $input.val() || $picker.data('default-color') || '#212121',
1224 swatches: ['#000000', '#F44336', '#E91E63', '#673AB7', '#03A9F4', '#8BC34A', '#FFEB3B', '#FFC107', '#FFFFFF'],
1225 sliders: 'h',
1226 useAsButton: true,
1227 components: {
1228 hue: true,
1229 preview: true,
1230 opacity: true,
1231 interaction: {
1232 input: true,
1233 clear: true
1234 }
1235 },
1236 i18n: {
1237 'btn:clear': 'Default'
1238 }
1239 });
1240 pickr.on('change', function (color) {
1241 var colorCode;
1242 if (color.a === 1) {
1243 pickr.setColorRepresentation('HEX');
1244 colorCode = color.toHEXA().toString(0);
1245 } else {
1246 pickr.setColorRepresentation('RGBA');
1247 colorCode = color.toRGBA().toString(0);
1248 }
1249 $picker.css({
1250 'background-color': colorCode
1251 });
1252 if ($input.val() !== colorCode) {
1253 $input.val(colorCode).trigger('change.merchant');
1254 }
1255 $(document).trigger('merchant-color-picker-updated', [colorCode, $input]);
1256 });
1257 pickr.on('clear', function () {
1258 var defaultColor = $picker.data('default-color');
1259 if (defaultColor) {
1260 pickr.setColor(defaultColor);
1261 } else {
1262 $picker.css({
1263 'background-color': 'white'
1264 });
1265 $input.val('');
1266 }
1267 });
1268 pickr.on('hide', function () {
1269 $bodyHTML.removeClass('merchant-height-auto');
1270 });
1271 $picker.data('pickr', pickr);
1272 setTimeout(function () {
1273 pickr.show();
1274 }, 200);
1275 inited = true;
1276 } else {
1277 pickr.setColor($input.val());
1278 }
1279 });
1280 $input.on('change keyup', function () {
1281 var colorCode = $(this).val();
1282 $picker.css({
1283 'background-color': colorCode
1284 });
1285 });
1286 });
1287 });
1288 $(document).trigger('merchant-admin-check-color-fields');
1289
1290 // Create Page Control.
1291 var CreatePageControl = {
1292 init: function init() {
1293 this.events();
1294 },
1295 events: function events() {
1296 var self = this;
1297 $(document).on('click', '.merchant-create-page-control-button', function (e) {
1298 e.preventDefault();
1299 var $this = $(this),
1300 $create_message = $this.parent().find('.merchant-create-page-control-create-message'),
1301 $success_message = $this.parent().find('.merchant-create-page-control-success-message'),
1302 initial_text = $this.text(),
1303 creating_text = $this.data('creating-text'),
1304 created_text = $this.data('created-text'),
1305 page_title = $this.data('page-title'),
1306 page_meta_key = $this.data('page-meta-key'),
1307 page_meta_value = $this.data('page-meta-value'),
1308 option_name = $this.data('option-name'),
1309 nonce = $this.data('nonce');
1310 if (!page_title) {
1311 return false;
1312 }
1313 $(this).text(creating_text);
1314 $(this).attr('disabled', true);
1315 $.ajax({
1316 type: 'post',
1317 url: ajaxurl,
1318 data: {
1319 action: 'merchant_create_page_control',
1320 page_title: page_title,
1321 page_meta_key: page_meta_key,
1322 page_meta_value: page_meta_value,
1323 option_name: option_name,
1324 nonce: nonce
1325 },
1326 success: function success(response) {
1327 self.ajaxResponseHandler(response, $this, $success_message, $create_message);
1328 }
1329 });
1330 });
1331 },
1332 ajaxResponseHandler: function ajaxResponseHandler(response, $this, $success_message, $create_message) {
1333 if ('success' === response.status) {
1334 var href = $success_message.find('a').attr('href'),
1335 newhref = href.replace('?post=&', '?post=' + response.page_id + '&');
1336 $success_message.find('a').attr('href', newhref);
1337 $success_message.css('display', 'block');
1338 $create_message.remove();
1339 $this.remove();
1340 }
1341 }
1342 };
1343
1344 // Initialize Create Page Control.
1345 CreatePageControl.init();
1346 $('.merchant-module-page-setting-field-gallery').each(function () {
1347 var $this = $(this);
1348 var $button = $this.find('.merchant-gallery-button');
1349 var $input = $this.find('.merchant-gallery-input');
1350 var $images = $this.find('.merchant-gallery-images');
1351 var $remove = $this.find('.merchant-gallery-remove');
1352 var wpMediaFrame;
1353 var sortable = $images.sortable({
1354 helper: 'original',
1355 update: function update(event, ui) {
1356 var selectedIds = [];
1357 $images.find('.merchant-gallery-image').each(function () {
1358 selectedIds.push($(this).data('item-id'));
1359 });
1360 $input.val(selectedIds.join(',')).trigger('change');
1361 }
1362 });
1363 $remove.on('click', function (e) {
1364 e.preventDefault();
1365 $(this).parent().remove();
1366 var selectedIds = [];
1367 $images.find('.merchant-gallery-image').each(function () {
1368 selectedIds.push($(this).data('item-id'));
1369 });
1370 $input.val(selectedIds.join(',')).trigger('change');
1371 });
1372 $button.on('click', function (e) {
1373 var $btn = $(this);
1374 var ids = $input.val();
1375 var mode = ids ? 'edit' : 'add';
1376 e.preventDefault();
1377 if (typeof window.wp === 'undefined' || !window.wp.media || !window.wp.media.gallery) {
1378 return;
1379 }
1380 if (mode === 'add') {
1381 wpMediaFrame = window.wp.media({
1382 library: {
1383 type: 'image'
1384 },
1385 frame: 'post',
1386 state: 'gallery',
1387 multiple: true
1388 });
1389 wpMediaFrame.open();
1390 } else {
1391 wpMediaFrame = window.wp.media.gallery.edit('[gallery ids="' + ids + '"]');
1392 }
1393 wpMediaFrame.on('update', function (selection) {
1394 $images.empty();
1395 var selectedIds = selection.models.map(function (attachment) {
1396 var item = attachment.toJSON();
1397 var thumb = item.sizes && item.sizes.thumbnail && item.sizes.thumbnail.url ? item.sizes.thumbnail.url : item.url;
1398 $images.append('<div class="merchant-gallery-image" data-item-id="' + item.id + '"><i class="merchant-gallery-remove dashicons dashicons-no-alt"></i><img src="' + thumb + '" /></div>');
1399 return item.id;
1400 });
1401 $input.val(selectedIds.join(',')).trigger('change');
1402 $this.find('.merchant-gallery-remove').on('click', function (e) {
1403 e.preventDefault();
1404 $(this).parent().remove();
1405 var selectedIds = [];
1406 $images.find('.merchant-gallery-image').each(function () {
1407 selectedIds.push($(this).data('item-id'));
1408 });
1409 $input.val(selectedIds.join(',')).trigger('change');
1410 });
1411 });
1412 });
1413 });
1414 var initUploadField = function initUploadField(element) {
1415 var $this = element;
1416 var $button = $this.find('.merchant-upload-button');
1417 var $input = $this.find('.merchant-upload-input');
1418 var $wrapper = $this.find('.merchant-upload-wrapper');
1419 var $remove = $this.find('.merchant-upload-remove');
1420 var wpMediaFrame;
1421 $remove.on('click', function (e) {
1422 e.preventDefault();
1423 $(this).parent().remove();
1424 $input.val('').trigger('change');
1425 });
1426 $button.on('click', function (e) {
1427 e.preventDefault();
1428 if (typeof window.wp === 'undefined' || !window.wp.media) {
1429 return;
1430 }
1431 if (!wpMediaFrame) {
1432 wpMediaFrame = window.wp.media({
1433 library: {
1434 type: 'image'
1435 }
1436 });
1437 }
1438 wpMediaFrame.open();
1439 wpMediaFrame.on('select', function () {
1440 $wrapper.empty();
1441 var item = wpMediaFrame.state().get('selection').first().attributes;
1442 var thumb = item.sizes && item.sizes.thumbnail && item.sizes.thumbnail.url ? item.sizes.thumbnail.url : item.url;
1443 var sizes = item.sizes ? JSON.stringify(item.sizes) : '';
1444 $wrapper.append('<div class="merchant-upload-image" data-sizes=\'' + sizes + '\'><i class="merchant-upload-remove dashicons dashicons-no-alt"></i><img src="' + thumb + '" /></div>');
1445 $input.val(item.id).trigger('change');
1446 $this.find('.merchant-upload-button-drag-drop').hide();
1447 $this.find('.merchant-upload-remove').on('click', function (e) {
1448 e.preventDefault();
1449 $(this).parent().remove();
1450 $input.val('').trigger('change');
1451 $this.find('.merchant-upload-button-drag-drop').show();
1452 });
1453 });
1454 });
1455 };
1456 $('.merchant-module-page-setting-field-upload:not(.template)').each(function () {
1457 initUploadField($(this));
1458 });
1459
1460 // Drag & Drag
1461 var events = ['dragenter', 'dragover', 'dragleave', 'drop'];
1462 jQuery.each(events, function (index, eventName) {
1463 $(document).on(eventName, '.merchant-upload-button-drag-drop', function (e) {
1464 e.preventDefault();
1465 e.stopPropagation();
1466 });
1467 });
1468 $(document).on('dragenter', '.merchant-upload-button-drag-drop', function (e) {
1469 $(this).closest('.merchant-module-page-setting-field-upload').find('.merchant-upload-button').click();
1470 });
1471 var initSelectAjax = function initSelectAjax($selectAjax) {
1472 var $select = $selectAjax.find('select');
1473 var $source = $select.data('source');
1474 var $config = window.merchant_admin_options;
1475 var $object = {
1476 width: '100%',
1477 templateSelection: function templateSelection(category) {
1478 return category.text.replace(/&nbsp;-*\s*/g, '').trim();
1479 }
1480 };
1481 if ($source === 'post' || $source === 'product' || $source === 'user') {
1482 $object.minimumInputLength = 1;
1483 $object.ajax = {
1484 url: $config.ajaxurl,
1485 dataType: 'json',
1486 delay: 250,
1487 cache: true,
1488 data: function data(params) {
1489 return {
1490 action: 'merchant_admin_options_select_ajax',
1491 nonce: $config.ajaxnonce,
1492 term: params.term,
1493 source: $source
1494 };
1495 },
1496 processResults: function processResults(response, params) {
1497 if (response.success) {
1498 return {
1499 results: response.data
1500 };
1501 }
1502 return {};
1503 }
1504 };
1505 }
1506 $select.select2($object);
1507 $selectAjax.find('.select2-selection--multiple').append('<span class="merchant-select2-clear"></span>');
1508 };
1509 $('.merchant-module-page-setting-field-select_ajax:not(.template)').each(function () {
1510 initSelectAjax($(this));
1511 });
1512 $('.merchant-module-page-settings-responsive').each(function () {
1513 var $this = $(this);
1514 var $button = $this.find('.merchant-module-page-settings-devices button');
1515 var $container = $this.find('.merchant-module-page-settings-device-container');
1516 $button.on('click', function (e) {
1517 e.preventDefault();
1518 var $device = $(this).data('device');
1519 $button.removeClass('active');
1520 $container.removeClass('active');
1521 $(this).addClass('active');
1522 $container.each(function () {
1523 if ($(this).data('device') === $device) {
1524 $(this).addClass('active');
1525 }
1526 });
1527 });
1528 });
1529 $('.merchant-animated-buttons').each(function () {
1530 var $button = $(this).find('label');
1531 var $demo = $('.merchant-animation-demo');
1532 var animation;
1533 var animationHover;
1534 $button.on('click', function () {
1535 $demo.removeClass('merchant-animation-' + animation);
1536 $demo.removeClass('merchant-animation-' + animationHover);
1537 animation = $(this).find('input').attr('value');
1538 setTimeout(function () {
1539 $demo.addClass('merchant-animation-' + animation);
1540 }, 100);
1541 setTimeout(function () {
1542 $demo.removeClass('merchant-animation-' + animation);
1543 }, 1000);
1544 });
1545 $button.mouseover(function () {
1546 $demo.removeClass('merchant-animation-' + animation);
1547 animationHover = $(this).find('input').attr('value');
1548 $demo.addClass('merchant-animation-' + animationHover);
1549 }).mouseout(function () {
1550 $demo.removeClass('merchant-animation-' + animationHover);
1551 });
1552 });
1553
1554 // Notifications Sidebar
1555 var $notificationsSidebar = $('.merchant-notifications-sidebar');
1556 if ($notificationsSidebar.length) {
1557 var $notifications = $('.merchant-notifications');
1558 $notifications.on('click', function (e) {
1559 e.preventDefault();
1560 var $notification = $(this);
1561 var latestNotificationDate = $notificationsSidebar.find('.merchant-notification:first-child .merchant-notification-date').data('raw-date');
1562 $notificationsSidebar.toggleClass('opened');
1563 if (!$notification.hasClass('read')) {
1564 $.post(window.merchant.ajax_url, {
1565 action: 'merchant_notifications_read',
1566 nonce: window.merchant.nonce,
1567 latest_notification_date: latestNotificationDate
1568 }, function (response) {
1569 if (response.success) {
1570 setTimeout(function () {
1571 $notification.addClass('read');
1572 }, 2000);
1573 }
1574 });
1575 }
1576 });
1577 $(window).on('scroll', function () {
1578 if (window.pageYOffset > 60) {
1579 $notificationsSidebar.addClass('closing');
1580 setTimeout(function () {
1581 $notificationsSidebar.removeClass('opened');
1582 $notificationsSidebar.removeClass('closing');
1583 }, 300);
1584 }
1585 });
1586
1587 // Close Sidebar
1588 $('.merchant-notifications-sidebar-close').on('click', function (e) {
1589 e.preventDefault();
1590 $notificationsSidebar.addClass('closing');
1591 setTimeout(function () {
1592 $notificationsSidebar.removeClass('opened');
1593 $notificationsSidebar.removeClass('closing');
1594 }, 300);
1595 });
1596 }
1597
1598 // Tabs Navigation.
1599 var tabs = $('.merchant-tabs-nav');
1600 if (tabs.length) {
1601 tabs.each(function () {
1602 var tabWrapperId = $(this).data('tab-wrapper-id');
1603 $(this).find('.merchant-tabs-nav-link').on('click', function (e) {
1604 e.preventDefault();
1605 var tabsNavLink = $(this).closest('.merchant-tabs-nav').find('.merchant-tabs-nav-link'),
1606 to = $(this).data('tab-to');
1607
1608 // Tab Nav Item
1609 tabsNavLink.each(function () {
1610 $(this).closest('.merchant-tabs-nav-item').removeClass('active');
1611 });
1612 $(this).closest('.merchant-tabs-nav-item').addClass('active');
1613
1614 // Tab Content
1615 var tabContentWrapper = $('.merchant-tab-content-wrapper[data-tab-wrapper-id="' + tabWrapperId + '"]');
1616 tabContentWrapper.find('> .merchant-tab-content').removeClass('active');
1617 tabContentWrapper.find('> .merchant-tab-content[data-tab-content-id="' + to + '"]').addClass('active');
1618 });
1619 });
1620 }
1621
1622 // Module Alert
1623 var $moduleAlert = $('.merchant-module-alert');
1624 if ($moduleAlert.length) {
1625 $moduleAlert.find('.merchant-module-alert-close').on('click', function (e) {
1626 e.preventDefault();
1627 $moduleAlert.removeClass('merchant-show');
1628 $(document).off('click.merchant-alert-close');
1629 });
1630 }
1631 });
1632
1633 /**
1634 * Check if a string is numeric.
1635 *
1636 * @param str the string to check
1637 *
1638 * @returns {boolean} true if numeric, false otherwise
1639 */
1640 function isNumeric(str) {
1641 if (typeof str != "string") return false; // we only process strings!
1642 return !isNaN(str) &&
1643 // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
1644 !isNaN(parseFloat(str)); // ...and ensure strings of whitespace fail
1645 }
1646
1647 /**
1648 * Evaluate conditional fields.
1649 *
1650 * @param conditions the array of conditions
1651 * @param field the field that is being evaluated
1652 *
1653 * @returns {boolean}
1654 */
1655 function evaluateConditions(conditions) {
1656 var field = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1657 var passed = false;
1658 if ('relation' in conditions) {
1659 //loop through terms
1660 var relation = conditions.relation.toUpperCase();
1661 // lowercase relation
1662 if (relation === 'OR') {
1663 for (var i = 0; i < conditions.terms.length; i++) {
1664 var term = conditions.terms[i];
1665 passed = evaluateConditions(term, field);
1666 if (passed) {
1667 return true;
1668 }
1669 }
1670 } else if (relation === 'AND') {
1671 var n = 0;
1672 for (var _i = 0; _i < conditions.terms.length; _i++) {
1673 // check if inner terms are passed
1674 var _term = conditions.terms[_i];
1675 if (evaluateConditions(_term, field)) {
1676 n++;
1677 }
1678 }
1679 if (n === conditions.terms.length) {
1680 passed = true;
1681 }
1682 }
1683 } else {
1684 var condition = '';
1685 if ('terms' in conditions) {
1686 condition = conditions.terms[0];
1687 } else {
1688 condition = conditions;
1689 }
1690 var $target = $('input[name="merchant[' + condition.field + ']"],select[name="merchant[' + condition.field + ']"]');
1691 if (!$target.length) {
1692 // check if inside flexible content
1693 var flexibleContentParent = field.closest('.layout-body');
1694 if (flexibleContentParent.length > 0) {
1695 $target = flexibleContentParent.find('.merchant-field-' + condition.field).find('input, select');
1696 }
1697 }
1698 if (!$target.length) {
1699 // Maybe the field is a multiple field
1700 $target = $('input[name="merchant[' + condition.field + '][]"],select[name="merchant[' + condition.field + '][]"]');
1701 }
1702 if (!$target.length) {
1703 // Maybe the field is inside fields group
1704 $target = $('.merchant-group-fields-container').find('.merchant-field-' + condition.field + ' input[name*="' + condition.field + '"],.merchant-field-' + condition.field + ' select[name*="' + condition.field + '"]');
1705 }
1706 var value = $target.val();
1707 if ($target.attr('type') === 'checkbox') {
1708 value = $target.is(':checked');
1709 }
1710 if ($target.attr('type') === 'radio') {
1711 value = $target.filter(':checked').val();
1712 }
1713
1714 // check if the field is multiple checkbox
1715 if ($target.attr('type') === 'checkbox' && $target.length > 1) {
1716 value = [];
1717 $target.each(function () {
1718 if ($(this).is(':checked')) {
1719 value.push($(this).val());
1720 }
1721 });
1722 }
1723
1724 // cast value as string if numeric
1725 if (isNumeric(value)) {
1726 value = Number(value);
1727 }
1728
1729 // check if is array condition.value
1730 if (Array.isArray(condition.value)) {
1731 condition.value = condition.value.map(function (item) {
1732 if (isNumeric(item)) {
1733 return Number(item);
1734 }
1735 return item;
1736 });
1737 }
1738 if (condition.operator === '===' && value === condition.value) {
1739 passed = true;
1740 } else if (condition.operator === '!==' && value !== condition.value) {
1741 passed = true;
1742 } else if (condition.operator === '>' && value > condition.value) {
1743 passed = true;
1744 } else if (condition.operator === '<' && value < condition.value) {
1745 passed = true;
1746 } else if (condition.operator === '>=' && value >= condition.value) {
1747 passed = true;
1748 } else if (condition.operator === '<=' && value <= condition.value) {
1749 passed = true;
1750 } else if (condition.operator === 'in' && condition.value.includes(value)) {
1751 passed = true;
1752 } else if (condition.operator === '!in' && !condition.value.includes(value)) {
1753 passed = true;
1754 } else if (condition.operator === 'contains' && Array.isArray(value) && value.includes(condition.value)) {
1755 passed = true;
1756 } else if (condition.operator === '!contains' && Array.isArray(value) && !value.includes(condition.value)) {
1757 passed = true;
1758 }
1759 }
1760 return passed;
1761 }
1762 })(jQuery, window, document);
1763
1764 // Extend jQuery to add getPath func to get accurate dynamic selector to an element.
1765 jQuery.fn.extend({
1766 getPath: function getPath() {
1767 var pathes = [];
1768 this.each(function (index, element) {
1769 var path,
1770 $node = jQuery(element);
1771 while ($node.length) {
1772 var realNode = $node.get(0),
1773 name = realNode.localName;
1774 if (!name) {
1775 break;
1776 }
1777 name = name.toLowerCase();
1778 var parent = $node.parent();
1779 var sameTagSiblings = parent.children(name);
1780 if (sameTagSiblings.length > 1) {
1781 var allSiblings = parent.children();
1782 var index = allSiblings.index(realNode) + 1;
1783 if (index > 0) {
1784 name += ':nth-child(' + index + ')';
1785 }
1786 }
1787 path = name + (path ? ' > ' + path : '');
1788 $node = parent;
1789 }
1790 pathes.push(path);
1791 });
1792 return pathes.join(',');
1793 }
1794 });