/** * Settings → Viator Structure editor. Regions and cities are plain DOM * blocks; cities can only be added from the Viator destination search, and * indexed field names are assigned on submit. */ (function () { 'use strict'; var cfg = window.vcStructure || {}; var i18n = cfg.i18n || {}; var form = document.getElementById('vc-structure-form'); var list = document.getElementById('vc-regions'); if (!form || !list) { return; } function slugify(s) { return String(s).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''); } function fromTemplate(id) { var tpl = document.getElementById(id); return tpl.content.firstElementChild.cloneNode(true); } function usedIds() { var ids = {}; list.querySelectorAll('.vc-city [data-f="id"]').forEach(function (input) { ids[input.value] = true; }); return ids; } function move(el, dir) { if (dir < 0 && el.previousElementSibling) { el.parentNode.insertBefore(el, el.previousElementSibling); } else if (dir > 0 && el.nextElementSibling) { el.parentNode.insertBefore(el.nextElementSibling, el); } } function addCity(region, item) { var row = fromTemplate('vc-tpl-city'); row.querySelector('[data-f="id"]').value = item.id; row.querySelector('[data-f="name"]').value = item.name; row.querySelector('[data-f="slug"]').value = item.slug || slugify(item.name); row.querySelector('.vc-city__name').textContent = item.name; row.querySelector('.vc-city__id').textContent = item.id; region.querySelector('.vc-cities tbody').appendChild(row); } function search(region) { var q = region.querySelector('.vc-city-search input[type="search"]'); var out = region.querySelector('.vc-results'); out.textContent = i18n.searching || '…'; var data = new FormData(); data.append('action', 'vc_search_destinations'); data.append('_ajax_nonce', cfg.nonce); data.append('q', q.value); fetch(cfg.ajaxUrl, { method: 'POST', credentials: 'same-origin', body: data }) .then(function (r) { return r.json(); }) .then(function (res) { if (!res || !res.success) { out.textContent = (res && res.data && res.data.message) || i18n.failed; return; } if (!res.data.results.length) { out.textContent = i18n.noMatches; return; } var used = usedIds(); out.innerHTML = ''; res.data.results.forEach(function (item) { var row = document.createElement('div'); var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'button button-small'; if (used[item.id]) { btn.disabled = true; btn.textContent = i18n.used; } else { btn.textContent = i18n.add; btn.addEventListener('click', function () { addCity(region, item); out.innerHTML = ''; q.value = ''; }); } var label = document.createElement('span'); label.textContent = item.name + ' (ID ' + item.id + ')'; row.appendChild(btn); row.appendChild(label); out.appendChild(row); }); }) .catch(function () { out.textContent = i18n.failed; }); } list.addEventListener('click', function (e) { var btn = e.target.closest('[data-act]'); if (!btn) { return; } var region = btn.closest('.vc-region'); var city = btn.closest('.vc-city'); var target = city || region; switch (btn.getAttribute('data-act')) { case 'up': move(target, -1); break; case 'down': move(target, 1); break; case 'remove-city': city.remove(); break; case 'remove-region': if (window.confirm(i18n.confirm)) { region.remove(); } break; case 'search': search(region); break; } }); list.addEventListener('keydown', function (e) { if (e.key === 'Enter' && e.target.matches('.vc-city-search input[type="search"]')) { e.preventDefault(); search(e.target.closest('.vc-region')); } }); // Suggest a region slug from its name until the slug is edited by hand. list.addEventListener('input', function (e) { var input = e.target; if (input.matches('.vc-region__head [data-f="slug"]')) { input.dataset.touched = '1'; } if (input.matches('.vc-region__head [data-f="name"]')) { var slug = input.closest('.vc-region__head').querySelector('[data-f="slug"]'); if (!slug.dataset.touched && (slug.value === '' || slug.dataset.auto === '1')) { slug.value = slugify(input.value); slug.dataset.auto = '1'; } } }); document.getElementById('vc-add-region').addEventListener('click', function () { var region = fromTemplate('vc-tpl-region'); list.appendChild(region); region.querySelector('[data-f="name"]').focus(); }); function hidden(name) { var input = document.createElement('input'); input.type = 'hidden'; input.name = name; input.value = '1'; form.appendChild(input); } form.addEventListener('submit', function (e) { var regions = list.querySelectorAll('.vc-region'); if (!regions.length) { if (!window.confirm(i18n.confirmEmpty)) { e.preventDefault(); return; } hidden('vc_confirm_empty'); } // Proves the editor ran: the server refuses a save without it, so a // failed script can never submit an empty structure by accident. hidden('vc_structure_present'); regions.forEach(function (region, i) { region.querySelectorAll('.vc-region__head [data-f]').forEach(function (input) { input.name = 'vc_structure[' + i + '][' + input.dataset.f + ']'; }); region.querySelectorAll('.vc-city').forEach(function (city, j) { city.querySelectorAll('[data-f]').forEach(function (input) { input.name = 'vc_structure[' + i + '][cities][' + j + '][' + input.dataset.f + ']'; }); }); }); }); })();