// Attach event listeners
attachEventListeners() {
const generateBtn = this.shadowRoot.getElementById('generate-btn');
const copyBtn = this.shadowRoot.getElementById('copy-btn');
const regenerateBtn = this.shadowRoot.getElementById('regenerate-btn');
if (generateBtn) {
generateBtn.addEventListener('click', () => this.generateBacklink());
}
if (copyBtn) {
copyBtn.addEventListener('click', () => this.copyToClipboard());
}
if (regenerateBtn) {
regenerateBtn.addEventListener('click', () => {
this._backlinkURL = null;
this.generateBacklink();
});
}
}
// Copy to clipboard
async copyToClipboard() {
try {
await navigator.clipboard.writeText(this._backlinkURL);
const copyBtn = this.shadowRoot.getElementById('copy-btn');
if (copyBtn) {
copyBtn.textContent = '✅ Copied!';
setTimeout(() => {
copyBtn.textContent = '📋 Copy to Clipboard';
}, 2000);
}
} catch (err) {
console.error('Failed to copy:', err);
alert('Failed to copy to clipboard');
}
}
// Truncate text
truncate(text, length) {
if (text.length <= length) return text;
return text.substring(0, length - 3) + '...';
}
// Get styles based on variant
getStyles(variant) {
const variants = {
default: {
container: `
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
text-align: center;
`,
button: `
padding: 12px 24px;
background: white;
color: #667eea;
border: none;
border-radius: 8px;
font-weight: 600;
font-size: 16px;
cursor: pointer;
`,
buttonHover: `
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
`,
link: `
display: inline-block;
color: white;
text-decoration: underline;
word-break: break-all;
`,
generated: `
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
color: white;
`
},
minimal: {
container: `
padding: 16px;
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 8px;
`,
button: `
padding: 10px 20px;
background: #6366f1;
color: white;
border: none;
border-radius: 6px;
font-weight: 600;
font-size: 14px;
cursor: pointer;
`,
buttonHover: `
background: #4f46e5;
`,
link: `
display: inline-block;
color: #2563eb;
text-decoration: underline;
word-break: break-all;
`,
generated: `
background: #f0fdf4;
border-color: #86efac;
color: #166534;
`
},
dark: {
container: `
padding: 20px;
background: #1f2937;
border-radius: 12px;
color: white;
`,
button: `
padding: 12px 24px;
background: #6366f1;
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
font-size: 16px;
cursor: pointer;
`,
buttonHover: `
background: #4f46e5;
transform: translateY(-2px);
`,
link: `
display: inline-block;
color: #93c5fd;
text-decoration: underline;
word-break: break-all;
`,
generated: `
background: #064e3b;
color: #d1fae5;
`
}
};
return variants[variant] || variants.default;
}
}
// Register custom element
if (!customElements.get('aepiot-link')) {
customElements.define('aepiot-link', AePiotLinkElement);
console.log('[aéPiot] Custom element <aepiot-link> registered');
}
})();
</script>
<!-- Usage Examples -->
<!-- Basic usage - auto-generate -->
<aepiot-link auto-generate="true"></aepiot-link>
<!-- With custom data -->
<aepiot-link
title="My Custom Title"
description="Custom description for this link"
url="https://example.com/page"
style-variant="minimal">
</aepiot-link>
<!-- Dark theme -->
<aepiot-link style-variant="dark"></aepiot-link>
<!-- Listen to events -->
<script>
document.addEventListener('backlink-generated', (e) => {
console.log('Backlink created:', e.detail.url);
// Send to analytics, etc.
});
</script>
Features:
- 🧩 Reusable Web Component
- 🎨 Multiple style variants
- 🔄 Reactive to attribute changes
- 📢 Custom events for integration
- 🌓 Light/Dark theme support
- 📱 Responsive design
- ♿ Shadow DOM encapsulation
👀 Mutation Observer for Dynamic Content
Automatically generates backlinks when new content is added to the page (SPA compatibility).
html
<script>
(function() {
'use strict';
const CONFIG = {
targetSelector: 'article, .post, .entry',
observeSubtree: true,
debounceDelay: 1000,
maxBacklinks: 5
};
let processedElements = new WeakSet();
let debounceTimer = null;
let backlinkCount = 0;
// Backlink generator
const BacklinkGenerator = {
create(element) {
const metadata = this.extractFromElement(element);
const url = this.buildURL(metadata);
return this.createUI(url, metadata);
},
extractFromElement(element) {
return {
title: this.getElementTitle(element),
description: this.getElementDescription(element),
url: this.getElementURL(element)
};
},
getElementTitle(element) {
// Try various selectors
const titleElement = element.querySelector('h1, h2, h3, .title, .post-title, .entry-title');
if (titleElement) {
return titleElement.textContent.trim();
}
// Fallback to first text
const walker = document.createTreeWalker(
element,
NodeFilter.SHOW_TEXT,
null,
false
);
let node;
while (node = walker.nextNode()) {
const text = node.textContent.trim();
if (text.length > 10) {
return text.substring(0, 100);
}
}
return document.title || 'Content';
},
getElementDescription(element) {
const paragraph = element.querySelector('p, .excerpt, .summary');
if (paragraph) {
return paragraph.textContent.trim().substring(0, 160);
}
return element.textContent.trim().substring(0, 160);
},
getElementURL(element) {
// Try to find a link within the element
const link = element.querySelector('a[href^="http"]');
if (link) {
return link.href;
}
// Check for data attributes
const urlAttr = element.getAttribute('data-url') ||
element.getAttribute('data-permalink');
if (urlAttr) {
return urlAttr;
}
return window.location.href;
},
buildURL(metadata) {
const params = new URLSearchParams({
title: metadata.title,
description: metadata.description,
link: metadata.url
});
return `https://aepiot.com/backlink.html?${params.toString()}`;
},
createUI(url, metadata) {
const container = document.createElement('div');
container.className = 'aepiot-dynamic-link';
container.setAttribute('data-aepiot-generated', 'true');
Object.assign(container.style, {
margin: '16px 0',
padding: '12px 16px',
background: '#f0f9ff',
border: '1px solid #bae6fd',
borderLeft: '4px solid #0284c7',
borderRadius: '6px',
fontSize: '14px',
display: 'flex',
alignItems: 'center',
gap: '12px'
});
container.innerHTML = ` <div style="flex-shrink: 0; font-size: 20px;">🔗</div>
<div style="flex-grow: 1;">
<div style="font-weight: 600; color: #0c4a6e; margin-bottom: 4px;">
aéPiot Backlink
</div>
<a href="${url}"
target="_blank"
rel="noopener noreferrer"
style="color: #0284c7; text-decoration: none; font-size: 13px;">
View semantic backlink →
</a>
</div>
`;
return container;
}
};
// Process new elements
function processNewElements(elements) {
if (backlinkCount >= CONFIG.maxBacklinks) {
console.log('[aéPiot] Max backlinks reached, stopping observer');
observer.disconnect();
return;
}
elements.forEach(element => {
// Skip if already processed
if (processedElements.has(element)) {
return;
}
// Skip if already has backlink
if (element.querySelector('[data-aepiot-generated]')) {
return;
}
// Skip if too small (likely not main content)
const textContent = element.textContent.trim();
if (textContent.length < 100) {
return;
}
// Mark as processed
processedElements.add(element);
// Generate and insert backlink
try {
const backlinkElement = BacklinkGenerator.create(element);
element.appendChild(backlinkElement);
backlinkCount++;
console.log(`[aéPiot] Generated dynamic backlink ${backlinkCount}/${CONFIG.maxBacklinks}`);
// Analytics
if (typeof gtag !== 'undefined') {
gtag('event', 'aepiot_dynamic_generated', {
'event_category': 'automation',
'value': backlinkCount
});
}
} catch (error) {
console.error('[aéPiot] Failed to generate backlink:', error);
}
});
}
// Debounced mutation handler
function handleMutations(mutations) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
const newElements = [];
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
// Check if node matches target
if (node.matches(CONFIG.targetSelector)) {
newElements.push(node);
}
// Check children
const children = node.querySelectorAll(CONFIG.targetSelector);
newElements.push(...Array.from(children));
}
});
});
if (newElements.length > 0) {
processNewElements(newElements);
}
}, CONFIG.debounceDelay);
}
// Initialize observer
const observer = new MutationObserver(handleMutations);
function initialize() {
// Process existing elements
const existingElements = document.querySelectorAll(CONFIG.targetSelector);
processNewElements(Array.from(existingElements));
// Start observing
observer.observe(document.body, {
childList: true,
subtree: CONFIG.observeSubtree
});
console.log('[aéPiot] Mutation observer started for:', CONFIG.targetSelector);
}
// Start when ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialize);
} else {
initialize();
}
// Cleanup on page unload
window.addEventListener('beforeunload', () => {
observer.disconnect();
});
})();
</script>Features:
- 👁️ Monitors DOM changes automatically
- 🔄 Perfect for SPAs (Single Page Apps)
- ⚡ Debounced for performance
- 🎯 Smart content detection
- 📊 Backlink limit protection
- 🧹 Memory-efficient with WeakSet
🎬 Intersection Observer for Viewport Tracking
Generates backlinks only when content enters viewport (optimal performance).
html
<script>
(function() {
'use strict';
const CONFIG = {
contentSelector: '.post-content, article, main',
threshold: 0.3, // 30% visible
rootMargin: '50px',
generateOnce: true
};
const processedElements = new Set();
// Backlink builder
function buildBacklink() {
const metadata = {
title: document.title || 'Page',
description: document.querySelector('meta[name="description"]')?.content ||
document.querySelector('p')?.textContent?.substring(0, 160) ||
'Content',
url: window.location.href
};
const params = new URLSearchParams(metadata);
return `https://aepiot.com/backlink.html?${params.toString()}`;
}
// Create backlink widget
function createWidget(url) {
const widget = document.createElement('aside');
widget.className = 'aepiot-viewport-widget';
widget.setAttribute('role', 'complementary');
widget.setAttribute('aria-label', 'Page backlink');
Object.assign(widget.style, {
position: 'sticky',
top: '20px',
margin: '30px 0',
padding: '20px',
background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
borderRadius: '16px',
boxShadow: '0 8px 32px rgba(245, 87, 108, 0.3)',
textAlign: 'center',
animation: 'slideInRight 0.6s ease-out'
});
widget.innerHTML = ` <style>
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.aepiot-widget-link {
transition: all 0.3s ease;
}
.aepiot-widget-link:hover {
transform: scale(1.05);
}
</style>
<div style="color: white;">
<div style="font-size: 28px; margin-bottom: 8px;">✨</div>
<div style="font-weight: 700; font-size: 18px; margin-bottom: 8px;">
Share This Content
</div>
<div style="font-size: 14px; opacity: 0.95; margin-bottom: 16px;">
Get your aéPiot backlink now
</div>
<a href="${url}"
class="aepiot-widget-link"
target="_blank"
rel="noopener noreferrer"
style="display: inline-block; padding: 12px 28px; background: white;
color: #f5576c; text-decoration: none; border-radius: 10px;
font-weight: 700; font-size: 15px;">
Get Backlink
</a>
</div>
`;
return widget;
}
// Intersection callback
function handleIntersection(entries, observer) {
entries.forEach(entry => {
if (entry.isIntersecting && !processedElements.has(entry.target)) {
// Mark as processed
if (CONFIG.generateOnce) {
processedElements.add(entry.target);
observer.unobserve(entry.target);
}
// Generate backlink
const url = buildBacklink();
const widget = createWidget(url);
// Insert at the end of content
entry.target.appendChild(widget);
console.log('[aéPiot] Viewport-triggered backlink generated');
// Analytics
if (typeof gtag !== 'undefined') {
gtag('event', 'aepiot_viewport_generated', {
'event_category': 'engagement',
'viewport_percent': Math.round(entry.intersectionRatio * 100)
});
}
}
});
}
// Initialize
function initialize() {
const targets = document.querySelectorAll(CONFIG.contentSelector);
if (targets.length === 0) {
console.warn('[aéPiot] No content elements found');
return;
}
const observerOptions = {
threshold: CONFIG.threshold,
rootMargin: CONFIG.rootMargin
};
const observer = new IntersectionObserver(handleIntersection, observerOptions);
targets.forEach(target => {
observer.observe(target);
});
console.log(`[aéPiot] Observing ${targets.length} content elements`);
}
// Start
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialize);
} else {
initialize();
}
})();
</script>Features:
- 👁️ Viewport-based generation
- ⚡ Excellent performance (no scroll events)
- 🎨 Animated entrance
- 📌 Sticky positioning
- 🎯 Configurable thresholds
- 📊 Analytics integration
Continue to Part 4: Production & Optimization →
Alternative aéPiot Working Scripts Guide - Part 4: Production & Optimization
Performance, Monitoring, and Deployment Best Practices
🚀 Performance-Optimized Async Script
Loads and executes without blocking page rendering.
html
<script>
(async function() {
'use strict';
// Configuration
const CONFIG = {
apiEndpoint: 'https://aepiot.com/backlink.html',
cacheKey: 'aepiot_backlink_cache',
cacheDuration: 3600000, // 1 hour in milliseconds
retryAttempts: 3,
retryDelay: 1000
};
// Performance monitoring
const Performance = {
marks: {},
start(label) {
this.marks[label] = performance.now();
},
end(label) {
if (this.marks[label]) {
const duration = performance.now() - this.marks[label];
console.log(`[aéPiot Performance] ${label}: ${duration.toFixed(2)}ms`);
delete this.marks[label];
return duration;
}
},
measure(label, fn) {
this.start(label);
const result = fn();
this.end(label);
return result;
}
};
// Cache manager
const Cache = {
get(key) {
try {
const item = localStorage.getItem(key);
if (!item) return null;
const data = JSON.parse(item);
// Check expiration
if (Date.now() > data.expiry) {
this.remove(key);
return null;
}
return data.value;
} catch (error) {
console.error('[aéPiot Cache] Read error:', error);
return null;
}
},
set(key, value, duration = CONFIG.cacheDuration) {
try {
const data = {
value: value,
expiry: Date.now() + duration
};
localStorage.setItem(key, JSON.stringify(data));
} catch (error) {
console.error('[aéPiot Cache] Write error:', error);
}
},
remove(key) {
try {
localStorage.removeItem(key);
} catch (error) {
console.error('[aéPiot Cache] Remove error:', error);
}
}
};
// Metadata extractor with caching
const MetadataExtractor = {
async extract() {
Performance.start('metadata_extraction');
// Try cache first
const cacheKey = `${CONFIG.cacheKey}_${window.location.pathname}`;
const cached = Cache.get(cacheKey);
if (cached) {
Performance.end('metadata_extraction');
console.log('[aéPiot] Using cached metadata');
return cached;
}
// Extract fresh metadata
const metadata = {
title: await this.extractTitle(),
description: await this.extractDescription(),
url: this.extractURL(),
timestamp: Date.now()
};
// Cache for future use
Cache.set(cacheKey, metadata);
Performance.end('metadata_extraction');
return metadata;
},
async extractTitle() {
// Check various sources in priority order
const sources = [
() => document.querySelector('meta[property="og:title"]')?.content,
() => document.querySelector('meta[name="twitter:title"]')?.content,
() => document.title,
() => document.querySelector('h1')?.textContent?.trim(),
() => 'Untitled Page'
];