-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodal-engine.js
More file actions
152 lines (128 loc) · 6.4 KB
/
Copy pathmodal-engine.js
File metadata and controls
152 lines (128 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
(function() {
const LOG_PREFIX = "[Faceify Modal]";
// Added 'triggerClass' to the arguments
function createModal(targetId, carrdTargetId, instanceConfig, triggerClass) {
if (carrdTargetId) {
const originalNode = document.getElementById(carrdTargetId);
if (originalNode) {
// 1. SELECT THE WRAPPER & SCRAPE WIDTH
const wrapper = originalNode.querySelector('.wrapper') || originalNode;
const computedStyle = window.getComputedStyle(wrapper);
let cssWidth = computedStyle.maxWidth !== 'none' ? computedStyle.maxWidth : computedStyle.width;
let finalPixelWidth = 0;
if (cssWidth && cssWidth.includes('px')) {
finalPixelWidth = parseFloat(cssWidth);
} else if (cssWidth && cssWidth.includes('rem')) {
finalPixelWidth = parseFloat(cssWidth) * 16;
}
if (instanceConfig.preferredWidth) {
finalPixelWidth = instanceConfig.preferredWidth;
} else if (finalPixelWidth < 50) {
finalPixelWidth = 684;
}
const totalModalWidth = Math.ceil(finalPixelWidth) + 40;
instanceConfig.dynamicMaxWidth = totalModalWidth + 'px';
// 2. CLONE AND SANITIZE
const clonedNode = originalNode.cloneNode(true);
const bgLayers = clonedNode.querySelectorAll('.bg, .container-bg, .wrapper-bg, [class*="-bg"]');
bgLayers.forEach(bg => bg.remove());
const layoutNodes = [clonedNode, ...clonedNode.querySelectorAll('div, ul')];
layoutNodes.forEach(node => {
node.classList.remove('hidden', 'deferred', 'is-deferred', 'onvisible');
if (node.style) {
node.style.setProperty('opacity', '1', 'important');
node.style.setProperty('visibility', 'visible', 'important');
node.style.setProperty('transform', 'none', 'important');
node.style.setProperty('background', 'transparent', 'important');
node.style.setProperty('box-shadow', 'none', 'important');
node.style.setProperty('padding', '0', 'important');
node.style.setProperty('margin', '0', 'important');
node.style.setProperty('width', '100%', 'important');
}
});
const allClonedLinks = clonedNode.querySelectorAll('a');
allClonedLinks.forEach(link => {
const href = link.getAttribute('href') || '';
// 1. Social & External Links -> Force New Tab
if (href.includes('facebook.com') || href.includes('instagram.com')) {
link.setAttribute('target', '_blank');
link.setAttribute('rel', 'noopener noreferrer'); // Security best practice
}
// 2. Mailto Links -> Force Native Mail App Handoff
if (href.includes('mailto:')) {
// Using _top prevents the browser from opening a useless blank tab
link.setAttribute('target', '_top');
// Strip any dead Carrd anti-spam scripts that failed to clone
link.removeAttribute('onclick');
}
});
// 3. TARGET THE BUTTON LIST (UL)
const ul = clonedNode.tagName.toLowerCase() === 'ul' ? clonedNode : clonedNode.querySelector('ul');
if (ul) {
ul.style.setProperty('display', 'flex', 'important');
ul.style.setProperty('flex-direction', 'column', 'important');
ul.style.setProperty('align-items', 'stretch', 'important');
ul.style.setProperty('width', '100%', 'important');
const listItems = ul.querySelectorAll('li');
if (listItems.length > 0) {
const links = ul.querySelectorAll('a');
links.forEach(link => {
if (link.style) {
link.style.setProperty('width', '100%', 'important');
link.style.setProperty('box-sizing', 'border-box', 'important');
}
});
// Extract the Trigger Button
const triggerUl = ul.cloneNode(false);
const triggerLi = listItems[0].cloneNode(true);
const triggerA = triggerLi.querySelector('a');
// Neutralize the cloned link so our onclick wrapper handles the event
if (triggerA) triggerA.setAttribute('href', 'javascript:void(0);');
triggerUl.appendChild(triggerLi);
instanceConfig.triggerHtml = triggerUl.outerHTML;
// Remove trigger from modal content
listItems[0].remove();
instanceConfig.modalHtml = clonedNode.outerHTML;
}
}
}
}
// ==========================================
// 4. INJECT BUTTON INTO ALL REMOTE CONTROLS
// ==========================================
if (triggerClass && instanceConfig.triggerHtml) {
// Find every element on the page with this class
const triggerDivs = document.querySelectorAll('.' + triggerClass);
triggerDivs.forEach(div => {
div.innerHTML = instanceConfig.triggerHtml;
});
}
// Safety check: Make sure the Central Hub actually exists on the page
if (!document.getElementById(targetId)) return;
// ==========================================
// 5. INITIALIZE CENTRAL VUE MODAL
// ==========================================
const vm = new Vue({
el: "#" + targetId,
data: { config: instanceConfig, isOpen: false },
computed: {
cssVariables() {
return {
'--modal-bg': this.config.modalBackgroundColor || '#F4E6C8',
'--modal-max-width': this.config.dynamicMaxWidth
}
}
}
});
// ==========================================
// 6. EXPOSE VUE TO WINDOW FOR REMOTE CONTROLS
// ==========================================
window.FaceifyModals = window.FaceifyModals || {};
window.FaceifyModals[targetId] = vm;
}
// QUEUE HANDLING
var queue = window.FaceifyModalQueue || [];
// Notice we added item.triggerClass to the mapping below
queue.forEach(item => createModal(item.targetId, item.carrdButtonsId || item.carrdContainerId, item.config, item.triggerClass));
window.FaceifyModalQueue = { push: item => createModal(item.targetId, item.carrdButtonsId || item.carrdContainerId, item.config, item.triggerClass) };
})();