Wire Ladill domain picker and purchase modal into hosting flows.
Deploy Ladill Hosting / deploy (push) Successful in 51s
Deploy Ladill Hosting / deploy (push) Successful in 51s
Use the Domains API for owned domains across panel, account, and order forms, with an embedded iframe purchase modal instead of redirecting to domains.ladill.com. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
import './bootstrap';
|
||||
|
||||
import { registerLadillConfirmStore, registerLadillModalHelpers } from './ladill-modals';
|
||||
import { registerLadillSearchShortcut } from './ladill-search-shortcut';
|
||||
import { registerLadillDomainPurchase } from './ladill-domain-purchase';
|
||||
|
||||
registerLadillModalHelpers();
|
||||
registerLadillSearchShortcut();
|
||||
registerLadillDomainPurchase();
|
||||
|
||||
|
||||
import Alpine from 'alpinejs';
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import { closeLadillModal, openLadillModal } from './ladill-modals';
|
||||
|
||||
const PURCHASE_MODAL = 'domain-purchase';
|
||||
|
||||
function allowedParentOrigin(origin) {
|
||||
try {
|
||||
const host = new URL(origin).hostname;
|
||||
|
||||
return host === 'ladill.com' || host.endsWith('.ladill.com');
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function loadPurchaseFrame() {
|
||||
const frame = document.getElementById('ladill-domain-purchase-frame');
|
||||
if (!frame || frame.dataset.loaded === '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
const embedUrl = frame.dataset.embedUrl;
|
||||
if (embedUrl) {
|
||||
frame.src = embedUrl;
|
||||
frame.dataset.loaded = '1';
|
||||
}
|
||||
}
|
||||
|
||||
export function registerLadillDomainPurchase() {
|
||||
window.ladillDomainSourceForm = (initial = {}) => ({
|
||||
domainSource: initial.domainSource ?? 'external',
|
||||
selectedOwnedDomain: initial.selectedOwnedDomain ?? '',
|
||||
externalDomain: initial.externalDomain ?? '',
|
||||
ownedDomains: initial.ownedDomains ?? [],
|
||||
ownedUrl: initial.ownedUrl ?? '',
|
||||
onboardingMode: initial.onboardingMode ?? 'ns_auto',
|
||||
|
||||
openPurchaseModal() {
|
||||
loadPurchaseFrame();
|
||||
openLadillModal(PURCHASE_MODAL);
|
||||
},
|
||||
|
||||
async refreshOwnedDomains() {
|
||||
if (!this.ownedUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(this.ownedUrl, {
|
||||
headers: { Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = await res.json();
|
||||
this.ownedDomains = Array.isArray(payload.data) ? payload.data : [];
|
||||
this.domainSource = 'ladill';
|
||||
} catch {
|
||||
// Non-fatal.
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
if (!allowedParentOrigin(event.origin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = event.data;
|
||||
if (!data || data.type !== 'ladill:domains:purchase-complete') {
|
||||
return;
|
||||
}
|
||||
|
||||
closeLadillModal(PURCHASE_MODAL);
|
||||
|
||||
const domains = Array.isArray(data.domains) ? data.domains : (data.domain ? [data.domain] : []);
|
||||
document.querySelectorAll('[x-data*="ladillDomainSourceForm"]').forEach((el) => {
|
||||
const component = el._x_dataStack?.[0];
|
||||
if (!component?.refreshOwnedDomains) {
|
||||
return;
|
||||
}
|
||||
|
||||
component.refreshOwnedDomains().then(() => {
|
||||
const newest = domains.map((d) => String(d).toLowerCase()).find(Boolean);
|
||||
if (newest) {
|
||||
component.selectedOwnedDomain = newest;
|
||||
component.domainSource = 'ladill';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('open-modal', (event) => {
|
||||
if (String(event.detail) === PURCHASE_MODAL) {
|
||||
loadPurchaseFrame();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
function isEditableTarget(element) {
|
||||
if (!(element instanceof HTMLElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const tag = element.tagName;
|
||||
|
||||
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return element.isContentEditable;
|
||||
}
|
||||
|
||||
function isVisibleInput(input) {
|
||||
if (!(input instanceof HTMLElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const style = window.getComputedStyle(input);
|
||||
|
||||
return style.display !== 'none'
|
||||
&& style.visibility !== 'hidden'
|
||||
&& style.opacity !== '0';
|
||||
}
|
||||
|
||||
function findSearchInput() {
|
||||
const marked = [...document.querySelectorAll('[data-ladill-search-input]')];
|
||||
const visibleMarked = marked.find(isVisibleInput);
|
||||
|
||||
if (visibleMarked) {
|
||||
return visibleMarked;
|
||||
}
|
||||
|
||||
if (marked.length > 0) {
|
||||
return marked[0];
|
||||
}
|
||||
|
||||
return document.querySelector('[x-data*="topbarSearch"] input');
|
||||
}
|
||||
|
||||
function focusSearchInput() {
|
||||
const input = findSearchInput();
|
||||
|
||||
if (!input) {
|
||||
const fallbackUrl = document.body?.dataset?.ladillSearchUrl;
|
||||
|
||||
if (fallbackUrl) {
|
||||
window.location.href = fallbackUrl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isVisibleInput(input)) {
|
||||
const fallbackUrl = document.body?.dataset?.ladillSearchUrl;
|
||||
|
||||
if (fallbackUrl) {
|
||||
window.location.href = fallbackUrl;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
input.focus();
|
||||
|
||||
if (input instanceof HTMLInputElement && (input.type === 'text' || input.type === 'search')) {
|
||||
input.select();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function registerLadillSearchShortcut() {
|
||||
if (window.__ladillSearchShortcutRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.__ladillSearchShortcutRegistered = true;
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key !== '/' && event.code !== 'Slash') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.ctrlKey || event.metaKey || event.altKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEditableTarget(document.activeElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
focusSearchInput();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user