Wednesday, January 21, 2026

Alternative aéPiot Working Scripts Guide: Innovative Implementation Methods - PART 3

 

🖱️ Hover-to-Preview System

Shows a preview card when user hovers over content, with option to generate link.

html
<script>
(function() {
  'use strict';
  
  // Configuration
  const CONFIG = {
    hoverDelay: 800, // ms before showing preview
    targetSelector: 'h1, h2.entry-title, .post-title',
    previewPosition: 'below' // 'below', 'above', 'side'
  };
  
  let hoverTimeout = null;
  let previewCard = null;
  let currentTarget = null;
  
  // Preview card builder
  const PreviewCard = {
    create(metadata, backlinkURL) {
      const card = document.createElement('div');
      card.className = 'aepiot-hover-preview';
      card.setAttribute('role', 'tooltip');
      
      Object.assign(card.style, {
        position: 'absolute',
        zIndex: '10000',
        width: '320px',
        padding: '20px',
        background: 'white',
        border: '2px solid #e5e7eb',
        borderRadius: '12px',
        boxShadow: '0 10px 40px rgba(0,0,0,0.15)',
        fontSize: '14px',
        lineHeight: '1.6',
        animation: 'fadeIn 0.3s ease-out'
      });
      
      card.innerHTML = `
        <style>
          @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-10px); }
            to { opacity: 1; transform: translateY(0); }
          }
          .aepiot-hover-preview-btn {
            transition: all 0.2s ease;
          }
          .aepiot-hover-preview-btn:hover {
            transform: translateY(-2px);
          }
        </style>
        <div style="margin-bottom: 12px;">
          <div style="font-weight: 700; color: #111827; margin-bottom: 4px; font-size: 16px;">
            📎 aéPiot Backlink
          </div>
          <div style="color: #6b7280; font-size: 13px;">
            Share this content with a semantic backlink
          </div>
        </div>
        
        <div style="margin-bottom: 16px; padding: 12px; background: #f9fafb; border-radius: 8px;">
          <div style="font-size: 13px; color: #374151; margin-bottom: 6px;">
            <strong>Title:</strong> ${this.truncate(metadata.title, 50)}
          </div>
          <div style="font-size: 12px; color: #6b7280;">
            ${this.truncate(metadata.description, 80)}
          </div>
        </div>
        
        <div style="display: flex; gap: 8px;">
          <a href="${backlinkURL}" 
             target="_blank" 
             rel="noopener noreferrer"
             class="aepiot-hover-preview-btn"
             style="flex: 1; padding: 10px 16px; background: #6366f1; color: white; 
                    text-align: center; text-decoration: none; border-radius: 8px; 
                    font-weight: 600; font-size: 13px;">
            Open Link
          </a>
          <button onclick="navigator.clipboard.writeText('${backlinkURL.replace(/'/g, "\\'")}'); 
                          this.textContent='✅ Copied'; 
                          setTimeout(() => this.textContent='📋 Copy', 2000);"
                  class="aepiot-hover-preview-btn"
                  style="padding: 10px 16px; background: #f3f4f6; color: #374151; 
                         border: 1px solid #d1d5db; border-radius: 8px; 
                         font-weight: 600; font-size: 13px; cursor: pointer;">
            📋 Copy
          </button>
        </div>
        
        <div style="margin-top: 12px; text-align: center;">
          <button onclick="this.closest('.aepiot-hover-preview').remove();"
                  style="background: none; border: none; color: #9ca3af; 
                         font-size: 12px; cursor: pointer; text-decoration: underline;">
            Close
          </button>
        </div>
      `;
      
      return card;
    },
    
    truncate(text, length) {
      if (!text) return '';
      if (text.length <= length) return text;
      return text.substring(0, length - 3) + '...';
    },
    
    position(card, target) {
      const rect = target.getBoundingClientRect();
      const cardHeight = 280; // approximate
      
      if (CONFIG.previewPosition === 'above') {
        card.style.top = (rect.top + window.scrollY - cardHeight - 10) + 'px';
        card.style.left = (rect.left + window.scrollX) + 'px';
      } else if (CONFIG.previewPosition === 'side') {
        card.style.top = (rect.top + window.scrollY) + 'px';
        card.style.left = (rect.right + window.scrollX + 15) + 'px';
      } else {
        // Default: below
        card.style.top = (rect.bottom + window.scrollY + 10) + 'px';
        card.style.left = (rect.left + window.scrollX) + 'px';
      }
    }
  };
  
  // Metadata extraction
  function extractMetadata() {
    return {
      title: document.title || 'Untitled',
      description: document.querySelector('meta[name="description"]')?.content || 
                   document.querySelector('p')?.textContent?.substring(0, 160) || 
                   'Content',
      url: window.location.href
    };
  }
  
  // Generate backlink URL
  function generateBacklinkURL(metadata) {
    const params = new URLSearchParams({
      title: metadata.title,
      description: metadata.description,
      link: metadata.url
    });
    
    return `https://aepiot.com/backlink.html?${params.toString()}`;
  }
  
  // Show preview
  function showPreview(target) {
    // Remove existing preview
    if (previewCard) {
      previewCard.remove();
    }
    
    const metadata = extractMetadata();
    const backlinkURL = generateBacklinkURL(metadata);
    
    previewCard = PreviewCard.create(metadata, backlinkURL);
    PreviewCard.position(previewCard, target);
    
    document.body.appendChild(previewCard);
    currentTarget = target;
    
    // Auto-hide when clicking outside
    setTimeout(() => {
      document.addEventListener('click', hidePreview);
    }, 100);
  }
  
  // Hide preview
  function hidePreview(event) {
    if (previewCard && 
        !previewCard.contains(event?.target) && 
        currentTarget !== event?.target) {
      previewCard.remove();
      previewCard = null;
      document.removeEventListener('click', hidePreview);
    }
  }
  
  // Initialize hover listeners
  function initialize() {
    const targets = document.querySelectorAll(CONFIG.targetSelector);
    
    targets.forEach(target => {
      target.style.cursor = 'help';
      target.title = 'Hover to generate aéPiot backlink';
      
      target.addEventListener('mouseenter', () => {
        hoverTimeout = setTimeout(() => {
          showPreview(target);
        }, CONFIG.hoverDelay);
      });
      
      target.addEventListener('mouseleave', () => {
        clearTimeout(hoverTimeout);
      });
    });
    
    console.log(`[aéPiot] Hover preview enabled on ${targets.length} elements`);
  }
  
  // Start when ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initialize);
  } else {
    initialize();
  }
})();
</script>

Features:

  • 🖱️ Hover-triggered preview cards
  • ⏱️ Configurable delay
  • 📋 Quick copy functionality
  • 🎯 Smart positioning
  • 🎨 Modern, clean design
  • ♿ Accessible tooltips

Continue to Part 3: Modular & Advanced Patterns →

Alternative aéPiot Working Scripts Guide - Part 3: Modular & Advanced Patterns

Web Components, Observers, and Dynamic Content Handling


🎨 Custom Web Component Implementation

Create a reusable <aepiot-link> web component for maximum flexibility.

html
<script>
(function() {
  'use strict';
  
  class AePiotLinkElement extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: 'open' });
      this._backlinkURL = null;
    }
    
    // Observed attributes
    static get observedAttributes() {
      return ['title', 'description', 'url', 'style-variant', 'auto-generate'];
    }
    
    // Lifecycle: Connected to DOM
    connectedCallback() {
      this.render();
      
      if (this.getAttribute('auto-generate') === 'true') {
        this.generateBacklink();
      }
    }
    
    // Lifecycle: Attribute changed
    attributeChangedCallback(name, oldValue, newValue) {
      if (oldValue !== newValue) {
        this.render();
      }
    }
    
    // Generate backlink URL
    generateBacklink() {
      const title = this.getAttribute('title') || this.extractTitle();
      const description = this.getAttribute('description') || this.extractDescription();
      const url = this.getAttribute('url') || window.location.href;
      
      const params = new URLSearchParams({
        title: this.sanitize(title, 200),
        description: this.sanitize(description, 500),
        link: url
      });
      
      this._backlinkURL = `https://aepiot.com/backlink.html?${params.toString()}`;
      this.render();
      
      // Dispatch custom event
      this.dispatchEvent(new CustomEvent('backlink-generated', {
        detail: { url: this._backlinkURL },
        bubbles: true,
        composed: true
      }));
    }
    
    // Extract title from page
    extractTitle() {
      return document.title || 
             document.querySelector('h1')?.textContent?.trim() || 
             'Page';
    }
    
    // Extract description from page
    extractDescription() {
      return document.querySelector('meta[name="description"]')?.content ||
             document.querySelector('p')?.textContent?.trim().substring(0, 160) ||
             'Content';
    }
    
    // Sanitize text
    sanitize(text, maxLength) {
      if (!text) return '';
      text = text.replace(/\s+/g, ' ').trim();
      if (text.length > maxLength) {
        text = text.substring(0, maxLength - 3) + '...';
      }
      return text;
    }
    
    // Render component
    render() {
      const variant = this.getAttribute('style-variant') || 'default';
      const styles = this.getStyles(variant);
      
      this.shadowRoot.innerHTML = `
        <style>
          :host {
            display: block;
            margin: 20px 0;
          }
          
          .container {
            ${styles.container}
          }
          
          .button {
            ${styles.button}
            transition: all 0.3s ease;
          }
          
          .button:hover {
            ${styles.buttonHover}
          }
          
          .link {
            ${styles.link}
          }
          
          .generated {
            ${styles.generated}
          }
          
          @media (max-width: 768px) {
            .container {
              padding: 16px;
            }
            .button {
              font-size: 14px;
              padding: 10px 20px;
            }
          }
        </style>
        
        ${this._backlinkURL ? this.renderGenerated() : this.renderButton()}
      `;
      
      this.attachEventListeners();
    }
    
    // Render button state
    renderButton() {
      return `
        <div class="container">
          <button class="button" id="generate-btn">
            🔗 Generate aéPiot Backlink
          </button>
        </div>
      `;
    }
    
    // Render generated state
    renderGenerated() {
      return `
        <div class="container generated">
          <div style="margin-bottom: 12px; font-weight: 600; color: #059669;">
            ✅ Backlink Generated
          </div>
          <a href="${this._backlinkURL}" 
             class="link"
             target="_blank" 
             rel="noopener noreferrer">
            ${this.truncate(this._backlinkURL, 60)}
          </a>
          <div style="margin-top: 12px;">
            <button class="button" id="copy-btn" style="font-size: 14px;">
              📋 Copy to Clipboard
            </button>
            <button class="button" id="regenerate-btn" 
                    style="font-size: 14px; margin-left: 8px; background: #6b7280;">
              🔄 Regenerate
            </button>
          </div>
        </div>
      `;
    }
    
    // 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


Popular Posts