| @@ -1,6 +1,12 @@ | ||
| 1 | 1 | "use strict"; |
| 2 | 2 | |
| 3 | +function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } | |
| 4 | +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } | |
| 5 | +function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } | |
| 6 | +function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } | |
| 7 | +function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } | |
| 8 | +function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } | |
| 3 | 9 | function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } |
| 4 | 10 | ; |
| 5 | 11 | (function ($, window, document, undefined) { |
| 6 | 12 | 'use strict'; |
| @@ -16,9 +22,18 @@ | ||
| 16 | 22 | $('.merchant-module-page-content').on('change keypress change.merchant', function (e) { |
| 17 | 23 | if ($(e.target).hasClass('merchant-backup-file') || $(e.target).hasClass('merchant-search-field')) { |
| 18 | 24 | return; |
| 19 | 25 | } |
| 20 | - if (!$(this).is('.merchant-module-question-answer-textarea, .merchant-license-code-input')) { | |
| 26 | + | |
| 27 | + // Nothing in the preview is a setting. Its controls are there to be played | |
| 28 | + // with, so a module whose mock-up has working fields cannot dirty the form. | |
| 29 | + if ($(e.target).closest('.merchant-module-page-preview').length) { | |
| 30 | + return; | |
| 31 | + } | |
| 32 | + | |
| 33 | + // The licence key and the module feedback textarea save through their | |
| 34 | + // own handlers, so editing them leaves the save bar alone. | |
| 35 | + if (!$(e.target).is('.merchant-module-question-answer-textarea, .merchant-license-code-input')) { | |
| 21 | 36 | if (!merchant.show_save) { |
| 22 | 37 | $ajaxHeader.addClass('merchant-show'); |
| 23 | 38 | $ajaxHeader.removeClass('merchant-saving'); |
| 24 | 39 | merchant.show_save = true; |
| @@ -483,9 +498,25 @@ | ||
| 483 | 498 | init: function init() { |
| 484 | 499 | this.initiate_datepicker(); |
| 485 | 500 | this.events(); |
| 486 | 501 | }, |
| 502 | + // Date() cannot parse the bare 'H:i' a time-only picker stores, so pin it to today. | |
| 503 | + parseInitialDate: function parseInitialDate(value, fieldOptions) { | |
| 504 | + if (!value) { | |
| 505 | + return []; | |
| 506 | + } | |
| 507 | + if (fieldOptions.onlyTimepicker && /^\d{1,2}:\d{2}$/.test(value)) { | |
| 508 | + var _value$split = value.split(':'), | |
| 509 | + _value$split2 = _slicedToArray(_value$split, 2), | |
| 510 | + hours = _value$split2[0], | |
| 511 | + minutes = _value$split2[1]; | |
| 512 | + return [new Date(new Date().setHours(Number(hours), Number(minutes), 0, 0))]; | |
| 513 | + } | |
| 514 | + var date = new Date(value); | |
| 515 | + return isNaN(date) ? [] : [date]; | |
| 516 | + }, | |
| 487 | 517 | initiate_datepicker: function initiate_datepicker() { |
| 518 | + var self = this; | |
| 488 | 519 | var elements = $('.merchant-module-page-setting-field .merchant-datetime-field'); |
| 489 | 520 | if (elements.length === 0) { |
| 490 | 521 | return; |
| 491 | 522 | } |
| @@ -490,11 +521,12 @@ | ||
| 490 | 521 | return; |
| 491 | 522 | } |
| 492 | 523 | elements.each(function (index) { |
| 493 | 524 | var input = $(this).find('input'), |
| 525 | + fieldOptions = $(this).data('options') || {}, | |
| 494 | 526 | options = { |
| 495 | 527 | locale: JSON.parse(merchant_datepicker_locale), |
| 496 | - selectedDates: input.val() ? [new Date(input.val())] : [], | |
| 528 | + selectedDates: self.parseInitialDate(input.val(), fieldOptions), | |
| 497 | 529 | onSelect: function onSelect(_ref) { |
| 498 | 530 | var date = _ref.date, |
| 499 | 531 | formattedDate = _ref.formattedDate, |
| 500 | 532 | datepicker = _ref.datepicker; |
| @@ -505,23 +537,20 @@ | ||
| 505 | 537 | } |
| 506 | 538 | input.trigger('change.merchant'); |
| 507 | 539 | input.trigger('change.merchant-datepicker', [formattedDate, input, options, index]); |
| 508 | 540 | } |
| 509 | - }, | |
| 510 | - fieldOptions = $(this).data('options'); | |
| 541 | + }; | |
| 511 | 542 | // add buttons to fieldOptions |
| 512 | 543 | fieldOptions.buttons = ['clear']; |
| 513 | - if (fieldOptions) { | |
| 514 | - if (fieldOptions.minDate !== undefined && fieldOptions.minDate === 'today') { | |
| 515 | - fieldOptions.minDate = new Date(); | |
| 516 | - if (fieldOptions.timeZone !== undefined && fieldOptions.timeZone !== '') { | |
| 517 | - fieldOptions.minDate = new Date(fieldOptions.minDate.toLocaleString('en-US', { | |
| 518 | - timeZone: fieldOptions.timeZone | |
| 519 | - })); | |
| 520 | - } | |
| 544 | + if (fieldOptions.minDate !== undefined && fieldOptions.minDate === 'today') { | |
| 545 | + fieldOptions.minDate = new Date(); | |
| 546 | + if (fieldOptions.timeZone !== undefined && fieldOptions.timeZone !== '') { | |
| 547 | + fieldOptions.minDate = new Date(fieldOptions.minDate.toLocaleString('en-US', { | |
| 548 | + timeZone: fieldOptions.timeZone | |
| 549 | + })); | |
| 521 | 550 | } |
| 522 | - options = Object.assign(options, fieldOptions); | |
| 523 | 551 | } |
| 552 | + options = Object.assign(options, fieldOptions); | |
| 524 | 553 | var datepickerObj = new AirDatepicker(input.getPath(), options); |
| 525 | 554 | input.attr('readonly', true); |
| 526 | 555 | $(document).trigger('initiated.merchant-datepicker', [datepickerObj, input, options, index]); |
| 527 | 556 | }); |
| @@ -703,8 +732,230 @@ | ||
| 703 | 732 | }; |
| 704 | 733 | |
| 705 | 734 | // Initialize Sortable Repeater. |
| 706 | 735 | SortableRepeaterField.init(); |
| 736 | + | |
| 737 | + // Sortable Repeater Icons. | |
| 738 | + var SortableRepeaterIconsField = { | |
| 739 | + CONTROL: '.merchant-sortable-repeater-icons-control', | |
| 740 | + init: function init() { | |
| 741 | + var self = this; | |
| 742 | + $(self.CONTROL).each(function () { | |
| 743 | + self.populate($(this)); | |
| 744 | + }); | |
| 745 | + this.events(); | |
| 746 | + }, | |
| 747 | + /** | |
| 748 | + * Populate rows from the hidden JSON input. | |
| 749 | + */ | |
| 750 | + populate: function populate($control) { | |
| 751 | + var self = this; | |
| 752 | + var items = []; | |
| 753 | + try { | |
| 754 | + items = JSON.parse($control.find('.merchant-sortable-repeater-input').val()); | |
| 755 | + } catch (e) { | |
| 756 | + items = []; | |
| 757 | + } | |
| 758 | + if (!Array.isArray(items) || items.length === 0) { | |
| 759 | + return; | |
| 760 | + } | |
| 761 | + var $firstRow = $control.find('.repeater').first(); | |
| 762 | + | |
| 763 | + // First item populates the existing row. | |
| 764 | + var firstItem = self.normalizeItem(items[0]); | |
| 765 | + $firstRow.find('.repeater-input').val(firstItem.text); | |
| 766 | + self.setRowIcon($firstRow, firstItem.icon); | |
| 767 | + | |
| 768 | + // Remaining items get new rows (silent = true to avoid triggering save bar). | |
| 769 | + for (var i = 1; i < items.length; i++) { | |
| 770 | + var item = self.normalizeItem(items[i]); | |
| 771 | + self.appendRow($control, item.text, item.icon, true); | |
| 772 | + } | |
| 773 | + }, | |
| 774 | + events: function events() { | |
| 775 | + var self = this; | |
| 776 | + | |
| 777 | + // Toggle icon picker dropdown. | |
| 778 | + $(document).on('click', self.CONTROL + ' .merchant-icon-picker-toggle', function (e) { | |
| 779 | + e.preventDefault(); | |
| 780 | + e.stopPropagation(); | |
| 781 | + var $dropdown = $(this).siblings('.merchant-icon-picker-dropdown'); | |
| 782 | + | |
| 783 | + // Close all other dropdowns first. | |
| 784 | + $(self.CONTROL + ' .merchant-icon-picker-dropdown').not($dropdown).hide(); | |
| 785 | + $dropdown.toggle(); | |
| 786 | + }); | |
| 787 | + | |
| 788 | + // Select icon from dropdown. | |
| 789 | + $(document).on('click', self.CONTROL + ' .merchant-icon-option', function (e) { | |
| 790 | + e.preventDefault(); | |
| 791 | + e.stopPropagation(); | |
| 792 | + var $repeater = $(this).closest('.repeater'); | |
| 793 | + var iconKey = $(this).data('icon') || ''; | |
| 794 | + self.setRowIcon($repeater, iconKey); | |
| 795 | + $(this).closest('.merchant-icon-picker-dropdown').hide(); | |
| 796 | + self.syncHiddenInput($(this).closest(self.CONTROL)); | |
| 797 | + }); | |
| 798 | + | |
| 799 | + // Close dropdown on outside click. | |
| 800 | + $(document).on('click', function () { | |
| 801 | + $(SortableRepeaterIconsField.CONTROL + ' .merchant-icon-picker-dropdown').hide(); | |
| 802 | + }); | |
| 803 | + | |
| 804 | + // Prevent dropdown clicks from closing. | |
| 805 | + $(document).on('click', self.CONTROL + ' .merchant-icon-picker-dropdown', function (e) { | |
| 806 | + e.stopPropagation(); | |
| 807 | + }); | |
| 808 | + | |
| 809 | + // Delete row. | |
| 810 | + $(document).on('click', self.CONTROL + ' .merchant-sortable-repeater-icons.sortable .customize-control-sortable-repeater-delete', function (e) { | |
| 811 | + e.preventDefault(); | |
| 812 | + var $control = $(this).closest(self.CONTROL); | |
| 813 | + $(this).parent().slideUp('fast', function () { | |
| 814 | + $(this).remove(); | |
| 815 | + self.syncHiddenInput($control); | |
| 816 | + }); | |
| 817 | + $(document).trigger('merchant-sortable-repeater-item-deleted'); | |
| 818 | + }); | |
| 819 | + | |
| 820 | + // Add new row. | |
| 821 | + $(document).on('click', self.CONTROL + ' .customize-control-sortable-repeater-icons-add', function (e) { | |
| 822 | + e.preventDefault(); | |
| 823 | + var $control = $(this).closest(self.CONTROL); | |
| 824 | + self.appendRow($control, '', ''); | |
| 825 | + self.syncHiddenInput($control); | |
| 826 | + }); | |
| 827 | + | |
| 828 | + // Text change → sync. | |
| 829 | + $(document).on('focusout', self.CONTROL + ' .merchant-sortable-repeater-icons.sortable .repeater-input', function () { | |
| 830 | + self.syncHiddenInput($(this).closest(self.CONTROL)); | |
| 831 | + }); | |
| 832 | + | |
| 833 | + // Sort change → sync. | |
| 834 | + $(document).on('change', self.CONTROL + ' .merchant-sortable-repeater-icons.sortable', function () { | |
| 835 | + self.syncHiddenInput($(this).closest(self.CONTROL)); | |
| 836 | + }); | |
| 837 | + | |
| 838 | + // Re-init on flexible content add. | |
| 839 | + $(document).on('merchant-flexible-content-added', function (e, $layout) { | |
| 840 | + var $control = $layout.find(self.CONTROL); | |
| 841 | + if ($control.length) { | |
| 842 | + self.populate($control); | |
| 843 | + self.makeFieldsSortable($control.find('.sortable')); | |
| 844 | + } | |
| 845 | + }); | |
| 846 | + }, | |
| 847 | + /** | |
| 848 | + * Append a new repeater row. | |
| 849 | + */ | |
| 850 | + appendRow: function appendRow($control, text, icon, silent) { | |
| 851 | + var self = this; | |
| 852 | + var iconLibrary = self.getIconLibrary($control); | |
| 853 | + var dropdownHtml = '<div class="merchant-icon-picker-dropdown" style="display:none;">'; | |
| 854 | + dropdownHtml += '<button type="button" class="merchant-icon-option" data-icon="" title="Use campaign icon"><span class="dashicons dashicons-no-alt"></span></button>'; | |
| 855 | + Object.keys(iconLibrary).forEach(function (key) { | |
| 856 | + dropdownHtml += '<button type="button" class="merchant-icon-option" data-icon="' + key + '" title="' + key + '">' + iconLibrary[key] + '</button>'; | |
| 857 | + }); | |
| 858 | + dropdownHtml += '</div>'; | |
| 859 | + var escapedText = $('<div>').text(text).html(); | |
| 860 | + var newRow = $('<div class="repeater" style="display:none">' + '<button type="button" class="merchant-icon-picker-toggle" data-icon="" title="Select icon"><span class="dashicons dashicons-plus-alt2"></span></button>' + dropdownHtml + '<input type="text" value="' + escapedText + '" 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>'); | |
| 861 | + $control.find('.sortable').append(newRow); | |
| 862 | + if (silent) { | |
| 863 | + newRow.show(); | |
| 864 | + } else { | |
| 865 | + newRow.slideDown('slow', function () { | |
| 866 | + $(this).find('input').focus(); | |
| 867 | + }); | |
| 868 | + } | |
| 869 | + if (icon) { | |
| 870 | + self.setRowIcon(newRow, icon); | |
| 871 | + } | |
| 872 | + self.makeFieldsSortable($control.find('.sortable')); | |
| 873 | + $(document).trigger('merchant-sortable-repeater-item-added', [newRow, $control.find('.sortable')]); | |
| 874 | + }, | |
| 875 | + /** | |
| 876 | + * Set the icon on a repeater row. | |
| 877 | + */ | |
| 878 | + setRowIcon: function setRowIcon($row, iconKey) { | |
| 879 | + var $toggle = $row.find('.merchant-icon-picker-toggle'); | |
| 880 | + $toggle.attr('data-icon', iconKey); | |
| 881 | + if (iconKey) { | |
| 882 | + var $control = $row.closest(SortableRepeaterIconsField.CONTROL); | |
| 883 | + var iconLibrary = this.getIconLibrary($control); | |
| 884 | + var svg = iconLibrary[iconKey] || ''; | |
| 885 | + if (svg) { | |
| 886 | + $toggle.html(svg).addClass('has-icon'); | |
| 887 | + } else { | |
| 888 | + $toggle.html('<span class="dashicons dashicons-plus-alt2"></span>').removeClass('has-icon'); | |
| 889 | + } | |
| 890 | + } else { | |
| 891 | + $toggle.html('<span class="dashicons dashicons-plus-alt2"></span>').removeClass('has-icon'); | |
| 892 | + } | |
| 893 | + | |
| 894 | + // Mark selected option in dropdown. | |
| 895 | + $row.find('.merchant-icon-option').removeClass('selected'); | |
| 896 | + $row.find('.merchant-icon-option[data-icon="' + iconKey + '"]').addClass('selected'); | |
| 897 | + }, | |
| 898 | + /** | |
| 899 | + * Sync all rows back to the hidden JSON input. | |
| 900 | + */ | |
| 901 | + syncHiddenInput: function syncHiddenInput($control) { | |
| 902 | + var items = []; | |
| 903 | + $control.find('.merchant-sortable-repeater-icons .repeater').each(function () { | |
| 904 | + var text = $(this).find('.repeater-input').val(); | |
| 905 | + var icon = $(this).find('.merchant-icon-picker-toggle').attr('data-icon') || ''; | |
| 906 | + items.push({ | |
| 907 | + text: text, | |
| 908 | + icon: icon | |
| 909 | + }); | |
| 910 | + }); | |
| 911 | + if (!items.length) { | |
| 912 | + items.push({ | |
| 913 | + text: '', | |
| 914 | + icon: '' | |
| 915 | + }); | |
| 916 | + } | |
| 917 | + $control.find('.merchant-sortable-repeater-input').val(JSON.stringify(items)); | |
| 918 | + $control.find('.merchant-sortable-repeater-input').trigger('change'); | |
| 919 | + $control.find('.merchant-sortable-repeater-input').trigger('sortable.repeater.change'); | |
| 920 | + }, | |
| 921 | + makeFieldsSortable: function makeFieldsSortable($sortable) { | |
| 922 | + var self = this; | |
| 923 | + if (!$sortable.hasClass('disable-sorting')) { | |
| 924 | + $sortable.sortable({ | |
| 925 | + handle: '.dashicons-menu', | |
| 926 | + update: function update() { | |
| 927 | + self.syncHiddenInput($sortable.closest(self.CONTROL)); | |
| 928 | + } | |
| 929 | + }); | |
| 930 | + } | |
| 931 | + }, | |
| 932 | + getIconLibrary: function getIconLibrary($control) { | |
| 933 | + if (!$control.data('_iconLibrary')) { | |
| 934 | + try { | |
| 935 | + $control.data('_iconLibrary', JSON.parse($control.attr('data-icons')) || {}); | |
| 936 | + } catch (e) { | |
| 937 | + $control.data('_iconLibrary', {}); | |
| 938 | + } | |
| 939 | + } | |
| 940 | + return $control.data('_iconLibrary'); | |
| 941 | + }, | |
| 942 | + normalizeItem: function normalizeItem(item) { | |
| 943 | + if (typeof item === 'string') { | |
| 944 | + return { | |
| 945 | + text: item, | |
| 946 | + icon: '' | |
| 947 | + }; | |
| 948 | + } | |
| 949 | + return { | |
| 950 | + text: item.text || '', | |
| 951 | + icon: item.icon || '' | |
| 952 | + }; | |
| 953 | + } | |
| 954 | + }; | |
| 955 | + | |
| 956 | + // Initialize Sortable Repeater Icons. | |
| 957 | + SortableRepeaterIconsField.init(); | |
| 707 | 958 | var GroubField = { |
| 708 | 959 | init: function init() { |
| 709 | 960 | var self = this; |
| 710 | 961 | self.initAccordion(); |
| @@ -1698,17 +1949,16 @@ | ||
| 1698 | 1949 | var val = values[fieldKey]; |
| 1699 | 1950 | if (val === undefined || val === null) { |
| 1700 | 1951 | return; |
| 1701 | 1952 | } |
| 1702 | - if ($el.is(':checkbox') || $el.is(':radio')) { | |
| 1703 | - // For checkboxes/radios, check if this input's value matches. | |
| 1704 | - if ($el.val() === String(val) || val === '1' && $el.is(':checkbox')) { | |
| 1705 | - $el.prop('checked', true); | |
| 1706 | - } | |
| 1953 | + if ($el.is(':checkbox') && !$el.is(':radio')) { | |
| 1954 | + $el.prop('checked', !!parseInt(val, 10)); | |
| 1955 | + } else if ($el.is(':radio')) { | |
| 1956 | + $el.prop('checked', $el.val() === String(val)); | |
| 1707 | 1957 | } else if ($el.is('select')) { |
| 1708 | 1958 | $el.val(val); |
| 1709 | 1959 | } else { |
| 1710 | - $el.val(val); | |
| 1960 | + $el.val(_typeof(val) === 'object' && val !== null ? JSON.stringify(val) : val); | |
| 1711 | 1961 | } |
| 1712 | 1962 | }); |
| 1713 | 1963 | |
| 1714 | 1964 | // Populate select_ajax pre-selected options. |
| @@ -1798,17 +2048,18 @@ | ||
| 1798 | 2048 | } |
| 1799 | 2049 | }); |
| 1800 | 2050 | } else { |
| 1801 | 2051 | var $field = $body.find('[name="' + namePrefix + '[' + key + ']"]'); |
| 1802 | - if ($field.length) { | |
| 1803 | - if ($field.is(':checkbox') || $field.is(':radio')) { | |
| 1804 | - if ($field.val() === String(val) || val === '1' && $field.is(':checkbox')) { | |
| 1805 | - $field.prop('checked', true); | |
| 1806 | - } | |
| 1807 | - } else { | |
| 1808 | - $field.val(val); | |
| 1809 | - } | |
| 2052 | + if (!$field.length) { | |
| 2053 | + return; | |
| 1810 | 2054 | } |
| 2055 | + if ($field.is(':checkbox') && !$field.is(':radio')) { | |
| 2056 | + $field.prop('checked', !!parseInt(val, 10)); | |
| 2057 | + } else if ($field.is(':radio')) { | |
| 2058 | + $field.prop('checked', $field.val() === String(val)); | |
| 2059 | + } else { | |
| 2060 | + $field.val(val); | |
| 2061 | + } | |
| 1811 | 2062 | } |
| 1812 | 2063 | }); |
| 1813 | 2064 | }; |
| 1814 | 2065 | $.each(values, function (key, val) { |
| @@ -1917,9 +2168,9 @@ | ||
| 1917 | 2168 | parent.find('.merchant-selected-products-preview ul').append($(this)); |
| 1918 | 2169 | parent.find('.merchant-selections-products-preview').html('').hide(); |
| 1919 | 2170 | parent.find('.merchant-search-field').val('').change(); |
| 1920 | 2171 | if (oldValue === '') { |
| 1921 | - valueField.val($(this).data('id')); | |
| 2172 | + valueField.val($(this).data('id')).change(); | |
| 1922 | 2173 | } else { |
| 1923 | 2174 | if (!multiple) { |
| 1924 | 2175 | valueField.val($(this).data('id')).change(); |
| 1925 | 2176 | } else { |
| @@ -2278,9 +2529,17 @@ | ||
| 2278 | 2529 | }); |
| 2279 | 2530 | $(document).on('dragenter', '.merchant-upload-button-drag-drop', function (e) { |
| 2280 | 2531 | $(this).closest('.merchant-module-page-setting-field-upload').find('.merchant-upload-button').click(); |
| 2281 | 2532 | }); |
| 2282 | - var initSelectAjax = function initSelectAjax($selectAjax) { | |
| 2533 | + | |
| 2534 | + // Callers pass a collection, and reading the source off a collection would give | |
| 2535 | + // every select the first field's source, so each field is set up on its own. | |
| 2536 | + var initSelectAjax = function initSelectAjax($selectAjaxFields) { | |
| 2537 | + $selectAjaxFields.each(function () { | |
| 2538 | + initSelectAjaxField($(this)); | |
| 2539 | + }); | |
| 2540 | + }; | |
| 2541 | + var initSelectAjaxField = function initSelectAjaxField($selectAjax) { | |
| 2283 | 2542 | var $select = $selectAjax.find('select'); |
| 2284 | 2543 | var $source = $select.data('source'); |
| 2285 | 2544 | var $config = window.merchant_admin_options; |
| 2286 | 2545 | var $object = { |
| @@ -2454,8 +2713,92 @@ | ||
| 2454 | 2713 | $moduleAlert.find('.merchant-module-alert-close').on('click', function (e) { |
| 2455 | 2714 | e.preventDefault(); |
| 2456 | 2715 | $moduleAlert.removeClass('merchant-show'); |
| 2457 | 2716 | $(document).off('click.merchant-alert-close'); |
| 2717 | + }); | |
| 2718 | + } | |
| 2719 | + | |
| 2720 | + // AI Prompt Examples Modal | |
| 2721 | + var $aiPromptsModal = $('#merchant-ai-prompts-modal'); | |
| 2722 | + if ($aiPromptsModal.length) { | |
| 2723 | + var $aiPromptsList = $aiPromptsModal.find('.merchant-ai-prompts-modal-list'); | |
| 2724 | + var copyHintText = window.merchant.ai_prompt_copy_hint || 'Click to copy'; | |
| 2725 | + var copiedLabelText = window.merchant.ai_prompt_copied_label || 'Copied!'; | |
| 2726 | + var copyIconSvg = '<svg width="14" height="14" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="5" y="5" width="8" height="8" rx="1.5" stroke="currentColor" stroke-width="1.3"/><path d="M3 10V3.5C3 2.67157 3.67157 2 4.5 2H10.5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>'; | |
| 2727 | + var checkIconSvg = '<svg width="14" height="14" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.5 4.5L6 12L2.5 8.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>'; | |
| 2728 | + var copyTextToClipboard = function copyTextToClipboard(text, onCopied) { | |
| 2729 | + if (navigator.clipboard && navigator.clipboard.writeText) { | |
| 2730 | + navigator.clipboard.writeText(text).then(onCopied); | |
| 2731 | + return; | |
| 2732 | + } | |
| 2733 | + var $temp = $('<textarea readonly></textarea>').val(text).css({ | |
| 2734 | + position: 'fixed', | |
| 2735 | + top: '-1000px' | |
| 2736 | + }); | |
| 2737 | + $('body').append($temp); | |
| 2738 | + $temp[0].select(); | |
| 2739 | + document.execCommand('copy'); | |
| 2740 | + $temp.remove(); | |
| 2741 | + onCopied(); | |
| 2742 | + }; | |
| 2743 | + $(document).on('click', '.merchant-ai-badge', function (e) { | |
| 2744 | + e.preventDefault(); | |
| 2745 | + e.stopPropagation(); | |
| 2746 | + var prompts = $(this).data('aiPrompts'); | |
| 2747 | + $aiPromptsModal.find('.merchant-ai-prompts-modal-title-text').text($(this).data('aiTitle') || ''); | |
| 2748 | + $aiPromptsModal.find('.merchant-ai-prompts-modal-blurb').text($(this).data('aiBlurb') || ''); | |
| 2749 | + $aiPromptsList.empty(); | |
| 2750 | + if (Array.isArray(prompts)) { | |
| 2751 | + prompts.forEach(function (prompt) { | |
| 2752 | + var $row = $('<button type="button" class="merchant-ai-prompt-row"></button>').attr('data-prompt', prompt); | |
| 2753 | + $row.append($('<span class="merchant-ai-prompt-text"></span>').text(prompt)); | |
| 2754 | + $row.append($('<span class="merchant-ai-prompt-icon"></span>').html(copyIconSvg)); | |
| 2755 | + $row.attr('aria-label', copyHintText); | |
| 2756 | + $aiPromptsList.append($row); | |
| 2757 | + }); | |
| 2758 | + } | |
| 2759 | + $aiPromptsModal.addClass('merchant-show'); | |
| 2760 | + var $badgeIcon = $aiPromptsModal.find('.merchant-ai-prompts-modal-badge svg'); | |
| 2761 | + $badgeIcon.removeClass('merchant-ai-badge-spin'); | |
| 2762 | + void $badgeIcon[0].offsetWidth; | |
| 2763 | + $badgeIcon.addClass('merchant-ai-badge-spin'); | |
| 2764 | + }); | |
| 2765 | + $(document).on('keydown', '.merchant-ai-badge', function (e) { | |
| 2766 | + if (e.key === 'Enter' || e.key === ' ') { | |
| 2767 | + e.preventDefault(); | |
| 2768 | + $(this).trigger('click'); | |
| 2769 | + } | |
| 2770 | + }); | |
| 2771 | + $aiPromptsList.on('click', '.merchant-ai-prompt-row', function () { | |
| 2772 | + var $row = $(this); | |
| 2773 | + if ($row.hasClass('is-copied')) { | |
| 2774 | + return; | |
| 2775 | + } | |
| 2776 | + copyTextToClipboard($row.attr('data-prompt'), function () { | |
| 2777 | + $row.addClass('is-copied').attr('aria-label', copiedLabelText); | |
| 2778 | + $row.find('.merchant-ai-prompt-icon').html(checkIconSvg); | |
| 2779 | + setTimeout(function () { | |
| 2780 | + $row.removeClass('is-copied').attr('aria-label', copyHintText); | |
| 2781 | + $row.find('.merchant-ai-prompt-icon').html(copyIconSvg); | |
| 2782 | + }, 1600); | |
| 2783 | + }); | |
| 2784 | + }); | |
| 2785 | + var closeAiPromptsModal = function closeAiPromptsModal() { | |
| 2786 | + $aiPromptsModal.removeClass('merchant-show'); | |
| 2787 | + $aiPromptsModal.find('.merchant-ai-prompts-modal-badge svg').removeClass('merchant-ai-badge-spin'); | |
| 2788 | + }; | |
| 2789 | + $(document).on('click', '.merchant-ai-prompts-modal-close', function () { | |
| 2790 | + closeAiPromptsModal(); | |
| 2791 | + }); | |
| 2792 | + $aiPromptsModal.on('click', function (e) { | |
| 2793 | + if ($(e.target).is($aiPromptsModal)) { | |
| 2794 | + closeAiPromptsModal(); | |
| 2795 | + } | |
| 2796 | + }); | |
| 2797 | + $(document).on('keydown', function (e) { | |
| 2798 | + if (e.key === 'Escape' && $aiPromptsModal.hasClass('merchant-show')) { | |
| 2799 | + closeAiPromptsModal(); | |
| 2800 | + } | |
| 2458 | 2801 | }); |
| 2459 | 2802 | } |
| 2460 | 2803 | }); |
| 2461 | 2804 | |