| 1 |
(function ($) { |
| 2 |
'use strict'; |
| 3 |
|
| 4 |
function readJSON(value, fallback) { |
| 5 |
try { return JSON.parse(value); } catch (e) { return fallback; } |
| 6 |
} |
| 7 |
|
| 8 |
function enhanceIcon(input) { |
| 9 |
input.addClass('wpvr-sticker-icon-value'); |
| 10 |
var control = input.parent().find('> .wpvr-sticker-icon-control'); |
| 11 |
if (!control.length) { |
| 12 |
control = $('<div class="wpvr-sticker-icon-control"><button type="button" class="wpvr-sticker-icon-trigger" aria-expanded="false"><i></i><span></span></button><div class="wpvr-sticker-icon-menu" hidden><input type="search" class="wpvr-sticker-icon-search" placeholder="Search icons" aria-label="Search icons"><div class="wpvr-sticker-icon-grid"></div></div></div>'); |
| 13 |
input.after(control); |
| 14 |
} |
| 15 |
var icon = input.val() || 'none'; |
| 16 |
control.find('.wpvr-sticker-icon-trigger i').attr('class', icon === 'none' ? '' : icon); |
| 17 |
control.find('.wpvr-sticker-icon-trigger span').text(icon === 'none' ? 'No icon' : icon.split(' ').pop().replace(/^fa-/, '').replace(/-/g, ' ')); |
| 18 |
} |
| 19 |
|
| 20 |
function enhanceField(field) { |
| 21 |
var input = field.find('.wpvr-sticker-value'); |
| 22 |
var name = input.attr('name') || ''; |
| 23 |
var kind = field.attr('data-kind'); |
| 24 |
if (/-color\]?$/i.test(name)) { |
| 25 |
if (!field.find('.wpvr-sticker-color-control').length) { |
| 26 |
input.wrap('<div class="wpvr-sticker-color-control"></div>'); |
| 27 |
$('<input type="color" class="wpvr-sticker-color-swatch" aria-label="Choose color">').insertBefore(input); |
| 28 |
} |
| 29 |
var color = /^#[0-9a-f]{6}$/i.test(input.val()) ? input.val() : '#ffffff'; |
| 30 |
field.find('.wpvr-sticker-color-swatch').val(color); |
| 31 |
} |
| 32 |
var numberInput = field.find('.wpvr-sticker-number'); |
| 33 |
if (kind === 'number') numberInput.val(input.val()); |
| 34 |
if (kind === 'number' && /(?:rating|bg-opacity|blur|brightness)\]?$/.test(name)) { |
| 35 |
if (!field.find('.wpvr-sticker-range-control').length) { |
| 36 |
numberInput.wrap('<div class="wpvr-sticker-range-control"></div>'); |
| 37 |
$('<input type="range" class="wpvr-sticker-range" aria-label="Adjust value">') |
| 38 |
.attr('min', numberInput.attr('min')).attr('max', numberInput.attr('max')).attr('step', numberInput.attr('step')).insertBefore(numberInput); |
| 39 |
} |
| 40 |
field.find('.wpvr-sticker-range').val(input.val()); |
| 41 |
} |
| 42 |
if (kind === 'toggle') { |
| 43 |
input.addClass('wpvr-sticker-toggle-value'); |
| 44 |
if (!field.find('.wpvr-sticker-switch').length) { |
| 45 |
$('<button type="button" role="switch" class="wpvr-sticker-switch"></button><span class="wpvr-sticker-switch-state"></span>').insertAfter(input); |
| 46 |
} |
| 47 |
var on = input.val() === 'on'; |
| 48 |
field.find('.wpvr-sticker-switch').attr('aria-checked', String(on)).attr('aria-label', field.find('.wpvr-sticker-field-label').text()); |
| 49 |
field.find('.wpvr-sticker-switch-state').text(on ? 'On' : 'Off'); |
| 50 |
} |
| 51 |
if (kind === 'media') { |
| 52 |
if (!field.find('.wpvr-sticker-avatar-preview').length) $('<img class="wpvr-sticker-avatar-preview" alt="Client avatar">').insertBefore(field.find('.wpvr-sticker-avatar-select')); |
| 53 |
field.find('.wpvr-sticker-avatar-preview').attr('src', input.val() || '').toggle(!!input.val()); |
| 54 |
} |
| 55 |
if (/btn-icon\]?$/.test(name)) enhanceIcon(input); |
| 56 |
} |
| 57 |
|
| 58 |
$(document).on('input change', '.wpvr-sticker-color-swatch, .wpvr-sticker-range, .wpvr-sticker-number', function () { |
| 59 |
$(this).closest('.wpvr-sticker-field').find('.wpvr-sticker-value').val($(this).val()).trigger('change'); |
| 60 |
}); |
| 61 |
$(document).on('change input', '.wpvr-sticker-value', function () { enhanceField($(this).closest('.wpvr-sticker-field')); }); |
| 62 |
$(document).on('click', '.wpvr-sticker-switch', function () { |
| 63 |
var input = $(this).closest('.wpvr-sticker-field').find('.wpvr-sticker-value'); |
| 64 |
input.val(input.val() === 'on' ? 'off' : 'on').trigger('change'); |
| 65 |
}); |
| 66 |
function iconChoices() { |
| 67 |
var icons = ['none', 'fas fa-tag', 'fas fa-shopping-cart', 'fas fa-arrow-right', 'fas fa-link', 'fas fa-star', 'fas fa-heart', 'fas fa-info-circle', 'fas fa-play', 'fas fa-phone', 'fas fa-envelope', 'fas fa-map-marker-alt', 'fas fa-gift', 'fas fa-ticket-alt', 'fas fa-share-alt', 'fab fa-facebook-f', 'fab fa-instagram', 'fab fa-linkedin-in', 'fab fa-twitter', 'fab fa-dribbble', 'fab fa-youtube', 'fab fa-whatsapp']; |
| 68 |
$('.hotspot-customclass-pro-select').first().find('option').each(function () { |
| 69 |
if (this.value && icons.indexOf(this.value) === -1) icons.push(this.value); |
| 70 |
}); |
| 71 |
return icons; |
| 72 |
} |
| 73 |
function filterIcons(control) { |
| 74 |
var term = control.find('.wpvr-sticker-icon-search').val().toLowerCase(); |
| 75 |
var input = control.prev('input'); |
| 76 |
var grid = control.find('.wpvr-sticker-icon-grid').empty(); |
| 77 |
iconChoices().filter(function (icon) { return icon.indexOf(term) !== -1; }).forEach(function (icon) { |
| 78 |
var button = $('<button type="button" class="wpvr-sticker-icon-option"></button>').attr('data-icon', icon).attr('title', icon).attr('aria-label', icon).attr('aria-pressed', String(input.val() === icon)); |
| 79 |
if (icon === 'none') button.text('×'); else $('<i></i>').attr('class', icon).appendTo(button); |
| 80 |
grid.append(button); |
| 81 |
}); |
| 82 |
} |
| 83 |
$(document).on('click', '.wpvr-sticker-icon-trigger', function () { |
| 84 |
var control = $(this).closest('.wpvr-sticker-icon-control'); |
| 85 |
var open = $(this).attr('aria-expanded') !== 'true'; |
| 86 |
$(this).attr('aria-expanded', String(open)); |
| 87 |
control.find('.wpvr-sticker-icon-menu').prop('hidden', !open); |
| 88 |
if (open) { filterIcons(control); control.find('.wpvr-sticker-icon-search').focus(); } |
| 89 |
}); |
| 90 |
$(document).on('input', '.wpvr-sticker-icon-search', function () { filterIcons($(this).closest('.wpvr-sticker-icon-control')); }); |
| 91 |
$(document).on('click', '.wpvr-sticker-icon-option', function () { |
| 92 |
var control = $(this).closest('.wpvr-sticker-icon-control'); |
| 93 |
var input = control.prev('input'); |
| 94 |
input.val($(this).attr('data-icon')).trigger('input').trigger('change'); |
| 95 |
enhanceIcon(input); |
| 96 |
control.find('.wpvr-sticker-icon-menu').prop('hidden', true); |
| 97 |
control.find('.wpvr-sticker-icon-trigger').attr('aria-expanded', 'false').focus(); |
| 98 |
}); |
| 99 |
$(document).on('keydown', '.wpvr-sticker-icon-control', function (event) { |
| 100 |
if (event.key === 'Escape') { |
| 101 |
$(this).find('.wpvr-sticker-icon-menu').prop('hidden', true); |
| 102 |
$(this).find('.wpvr-sticker-icon-trigger').attr('aria-expanded', 'false').focus(); |
| 103 |
} |
| 104 |
}); |
| 105 |
|
| 106 |
function renderLinks(field) { |
| 107 |
var links = readJSON(field.find('.wpvr-sticker-value').val(), []); |
| 108 |
var list = field.find('.wpvr-sticker-links').empty(); |
| 109 |
links.forEach(function (link) { |
| 110 |
var row = $('<div class="wpvr-sticker-link" style="margin:10px 0"></div>').appendTo(list); |
| 111 |
[['icon', 'Icon class'], ['customSvg', 'Custom SVG'], ['url', 'URL']].forEach(function (item) { |
| 112 |
$('<input type="text" style="width:100%;margin-bottom:5px">') |
| 113 |
.attr('data-link-key', item[0]).attr('aria-label', item[1]).attr('placeholder', item[1]) |
| 114 |
.val(link[item[0]] || '').appendTo(row); |
| 115 |
}); |
| 116 |
$('<select data-link-key="openNewTab" aria-label="Open in new tab"><option value="on">New tab</option><option value="off">Same tab</option></select>') |
| 117 |
.val(link.openNewTab || 'on').appendTo(row); |
| 118 |
$('<button type="button" class="button wpvr-sticker-link-remove" aria-label="Remove social link">×</button>').appendTo(row); |
| 119 |
row.data('link-id', link.id); |
| 120 |
enhanceIcon(row.find('[data-link-key=icon]')); |
| 121 |
}); |
| 122 |
} |
| 123 |
|
| 124 |
function syncCompound(field) { |
| 125 |
var kind = field.attr('data-kind'); |
| 126 |
var value = readJSON(field.find('.wpvr-sticker-value').val(), {}); |
| 127 |
if (kind === 'corners' || kind === 'sides') { |
| 128 |
field.find('[data-part]').each(function () { |
| 129 |
$(this).val(value[$(this).attr('data-part')] || 0); |
| 130 |
}); |
| 131 |
} else if (kind === 'links') { |
| 132 |
renderLinks(field); |
| 133 |
} |
| 134 |
} |
| 135 |
|
| 136 |
function updateSettings(hotspot, changeTemplate) { |
| 137 |
var panel = hotspot.find('.wpvr-legacy-sticker-settings'); |
| 138 |
var type = hotspot.find('select[name*="hotspot-type"]').val(); |
| 139 |
var select = panel.find('.wpvr-sticker-template'); |
| 140 |
var template = select.val() || 'social_proof'; |
| 141 |
var previous = panel.data('active-template') || 'social_proof'; |
| 142 |
var fresh = !select.val(); |
| 143 |
select.val(template); |
| 144 |
panel.toggle(type === 'sticker'); |
| 145 |
if (type === 'sticker') { |
| 146 |
hotspot.find('.hotspot-scene, .hotspot-url, .s_tab, .hotspot-content, .hotspot-products, .hotspot-fluent-forms, .hotspot-hover').hide(); |
| 147 |
} else { |
| 148 |
hotspot.find('.hotspot-hover').show(); |
| 149 |
} |
| 150 |
panel.find('.wpvr-sticker-field').each(function () { |
| 151 |
var field = $(this); |
| 152 |
var defaults = readJSON(field.attr('data-defaults'), {}); |
| 153 |
var input = field.find('.wpvr-sticker-value'); |
| 154 |
var oldDefault = typeof defaults[previous] === 'object' ? JSON.stringify(defaults[previous]) : String(defaults[previous]); |
| 155 |
var newDefault = typeof defaults[template] === 'object' ? JSON.stringify(defaults[template]) : defaults[template]; |
| 156 |
if (fresh || (changeTemplate && String(input.val()) === oldDefault)) input.val(newDefault); |
| 157 |
var applies = field.attr('data-templates'); |
| 158 |
field.toggle(!applies || applies.split(' ').indexOf(template) !== -1); |
| 159 |
syncCompound(field); |
| 160 |
enhanceField(field); |
| 161 |
}); |
| 162 |
panel.find('.wpvr-sticker-section').each(function () { |
| 163 |
var applies = $(this).attr('data-templates'); |
| 164 |
$(this).toggle(!applies || applies.split(' ').indexOf(template) !== -1); |
| 165 |
}); |
| 166 |
panel.data('active-template', template); |
| 167 |
} |
| 168 |
|
| 169 |
// Runs after either Free or Pro's legacy handler, which handles the other types. |
| 170 |
$(document).on('change', 'select[name*="hotspot-type"], .wpvr-sticker-template', function () { |
| 171 |
updateSettings($(this).closest('.single-hotspot'), $(this).hasClass('wpvr-sticker-template')); |
| 172 |
}); |
| 173 |
$(document).on('input change', '.wpvr-sticker-field [data-part]', function () { |
| 174 |
var field = $(this).closest('.wpvr-sticker-field'); |
| 175 |
var value = {}; |
| 176 |
field.find('[data-part]').each(function () { value[$(this).attr('data-part')] = Math.max(0, Number($(this).val()) || 0); }); |
| 177 |
field.find('.wpvr-sticker-value').val(JSON.stringify(value)); |
| 178 |
}); |
| 179 |
function saveLinks(field) { |
| 180 |
var links = []; |
| 181 |
field.find('.wpvr-sticker-link').each(function () { |
| 182 |
var row = $(this); |
| 183 |
var link = { id: row.data('link-id') || String(Date.now()) + '-' + links.length }; |
| 184 |
row.find('[data-link-key]').each(function () { link[$(this).attr('data-link-key')] = $(this).val(); }); |
| 185 |
links.push(link); |
| 186 |
}); |
| 187 |
field.find('.wpvr-sticker-value').val(JSON.stringify(links)); |
| 188 |
} |
| 189 |
$(document).on('input change', '.wpvr-sticker-field [data-link-key]', function () { |
| 190 |
saveLinks($(this).closest('.wpvr-sticker-field')); |
| 191 |
}); |
| 192 |
$(document).on('click', '.wpvr-sticker-link-add, .wpvr-sticker-link-remove', function () { |
| 193 |
var field = $(this).closest('.wpvr-sticker-field'); |
| 194 |
if ($(this).hasClass('wpvr-sticker-link-remove')) { |
| 195 |
$(this).closest('.wpvr-sticker-link').remove(); |
| 196 |
saveLinks(field); |
| 197 |
} else { |
| 198 |
var input = field.find('.wpvr-sticker-value'); |
| 199 |
var links = readJSON(input.val(), []); |
| 200 |
links.push({ id: String(Date.now()), icon: 'fab fa-facebook-f', customSvg: '', url: '', openNewTab: 'on' }); |
| 201 |
input.val(JSON.stringify(links)); |
| 202 |
renderLinks(field); |
| 203 |
} |
| 204 |
}); |
| 205 |
$(document).on('click', '.wpvr-sticker-avatar-select, .wpvr-sticker-avatar-remove', function () { |
| 206 |
var input = $(this).closest('.wpvr-sticker-field').find('.wpvr-sticker-value'); |
| 207 |
if ($(this).hasClass('wpvr-sticker-avatar-remove')) { input.val('').trigger('change'); return; } |
| 208 |
var frame = wp.media({ library: { type: 'image' }, multiple: false }); |
| 209 |
frame.on('select', function () { input.val(frame.state().get('selection').first().toJSON().url).trigger('change'); }); |
| 210 |
frame.open(); |
| 211 |
}); |
| 212 |
$(function () { |
| 213 |
$('.single-hotspot').each(function () { updateSettings($(this), false); }); |
| 214 |
var root = document.querySelector('.scene-setup'); |
| 215 |
if (!root) return; |
| 216 |
// Repeaters clear cloned fields; initialize each new hotspot after that reset. |
| 217 |
new MutationObserver(function (mutations) { |
| 218 |
mutations.forEach(function (mutation) { |
| 219 |
mutation.addedNodes.forEach(function (node) { |
| 220 |
if (node.nodeType !== 1) return; |
| 221 |
$(node).find('.single-hotspot').addBack('.single-hotspot').each(function () { |
| 222 |
updateSettings($(this), false); |
| 223 |
}); |
| 224 |
}); |
| 225 |
}); |
| 226 |
}).observe(root, { childList: true, subtree: true }); |
| 227 |
}); |
| 228 |
})(jQuery); |
| 229 |
|