javascript

examples

examples.js
/**
 * Advanced DOM Traversal - Examples
 * Powerful techniques for navigating the DOM
 *
 * Note: These examples are designed for browser environments.
 * In Node.js, DOM APIs are not available natively.
 */

// =============================================================================
// 1. TREEWALKER BASICS
// =============================================================================

console.log('--- TreeWalker Basics ---');

// Simulating DOM structure for demonstration
const mockDOM = {
  description: `
    <div id="root">
        <header>
            <nav>
                <a href="/">Home</a>
                <a href="/about">About</a>
            </nav>
        </header>
        <main>
            <article>
                <h1>Title</h1>
                <p>Paragraph 1</p>
                <p>Paragraph 2</p>
            </article>
        </main>
        <footer>Copyright 2024</footer>
    </div>
    `,
};

console.log('DOM Structure:', mockDOM.description);

// TreeWalker usage (browser code):
const treeWalkerExample = `
// Create TreeWalker for elements only
const walker = document.createTreeWalker(
    document.body,
    NodeFilter.SHOW_ELEMENT,
    null  // No custom filter
);

// Traverse all elements
const elements = [];
while (walker.nextNode()) {
    elements.push(walker.currentNode.tagName);
}
console.log(elements);
`;

console.log('TreeWalker Example Code:');
console.log(treeWalkerExample);

// =============================================================================
// 2. CUSTOM NODE FILTERS
// =============================================================================

console.log('\n--- Custom Node Filters ---');

// NodeFilter result constants
const NodeFilterResults = {
  FILTER_ACCEPT: 1, // Accept node
  FILTER_REJECT: 2, // Reject node and its children
  FILTER_SKIP: 3, // Skip node but process children
};

// Custom filter function
function createFilter(options = {}) {
  return {
    acceptNode(node) {
      // Filter by tag name
      if (options.tagNames && !options.tagNames.includes(node.tagName)) {
        return NodeFilterResults.FILTER_SKIP;
      }

      // Filter by class
      if (options.className && !node.classList?.contains(options.className)) {
        return NodeFilterResults.FILTER_SKIP;
      }

      // Filter by attribute
      if (options.attribute && !node.hasAttribute?.(options.attribute)) {
        return NodeFilterResults.FILTER_SKIP;
      }

      return NodeFilterResults.FILTER_ACCEPT;
    },
  };
}

console.log('Custom filter example:');
console.log(`
const filter = createFilter({
    tagNames: ['DIV', 'SPAN'],
    className: 'interactive'
});

const walker = document.createTreeWalker(
    document.body,
    NodeFilter.SHOW_ELEMENT,
    filter
);
`);

// =============================================================================
// 3. NODE ITERATOR
// =============================================================================

console.log('\n--- NodeIterator ---');

// NodeIterator is similar to TreeWalker but simpler
const nodeIteratorExample = `
// NodeIterator for text nodes
const iterator = document.createNodeIterator(
    document.body,
    NodeFilter.SHOW_TEXT,
    {
        acceptNode(node) {
            // Only accept non-empty text
            return node.textContent.trim() 
                ? NodeFilter.FILTER_ACCEPT 
                : NodeFilter.FILTER_REJECT;
        }
    }
);

// Collect all text content
const textNodes = [];
let node;
while ((node = iterator.nextNode())) {
    textNodes.push(node.textContent.trim());
}
`;

console.log('NodeIterator Example:', nodeIteratorExample);

// =============================================================================
// 4. RANGE API
// =============================================================================

console.log('\n--- Range API ---');

// Range represents a fragment of a document
const rangeExample = `
// Create a range
const range = document.createRange();

// Select entire contents of an element
range.selectNodeContents(element);

// Select specific portion
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);

// Range properties
console.log({
    startContainer: range.startContainer,
    startOffset: range.startOffset,
    endContainer: range.endContainer,
    endOffset: range.endOffset,
    collapsed: range.collapsed,
    commonAncestorContainer: range.commonAncestorContainer
});

// Range manipulation
const contents = range.extractContents();  // Remove and return
const clone = range.cloneContents();       // Clone without removing
range.deleteContents();                     // Just delete
range.insertNode(newNode);                  // Insert at start
range.surroundContents(wrapper);            // Wrap contents
`;

console.log('Range API Example:', rangeExample);

// =============================================================================
// 5. SELECTION API
// =============================================================================

console.log('\n--- Selection API ---');

const selectionExample = `
// Get the selection object
const selection = window.getSelection();

// Selection properties
console.log({
    anchorNode: selection.anchorNode,     // Where selection started
    anchorOffset: selection.anchorOffset,
    focusNode: selection.focusNode,        // Where selection ended
    focusOffset: selection.focusOffset,
    isCollapsed: selection.isCollapsed,    // Is it a cursor?
    rangeCount: selection.rangeCount,
    type: selection.type                   // 'Caret', 'Range', 'None'
});

// Get selected text
const selectedText = selection.toString();

// Work with ranges
if (selection.rangeCount > 0) {
    const range = selection.getRangeAt(0);
    // Manipulate range...
}

// Modify selection
selection.removeAllRanges();  // Clear selection
selection.addRange(range);    // Set new selection

// Collapse selection
selection.collapse(node, offset);

// Select all in element
selection.selectAllChildren(element);
`;

console.log('Selection API Example:', selectionExample);

// =============================================================================
// 6. FINDING TEXT IN DOM
// =============================================================================

console.log('\n--- Finding Text in DOM ---');

function findTextExample() {
  return `
// Find all text nodes containing a string
function findTextContaining(searchText, rootElement = document.body) {
    const matches = [];
    
    const walker = document.createTreeWalker(
        rootElement,
        NodeFilter.SHOW_TEXT,
        {
            acceptNode(node) {
                return node.textContent.toLowerCase()
                    .includes(searchText.toLowerCase())
                    ? NodeFilter.FILTER_ACCEPT
                    : NodeFilter.FILTER_REJECT;
            }
        }
    );
    
    while (walker.nextNode()) {
        matches.push({
            node: walker.currentNode,
            parent: walker.currentNode.parentElement,
            text: walker.currentNode.textContent
        });
    }
    
    return matches;
}

// Usage
const results = findTextContaining('search term');
results.forEach(result => {
    result.parent.classList.add('highlight');
});
`;
}

console.log(findTextExample());

// =============================================================================
// 7. HIGHLIGHT TEXT
// =============================================================================

console.log('\n--- Text Highlighting ---');

const highlightExample = `
// Highlight all occurrences of text
function highlightText(searchText, className = 'highlight') {
    const textNodes = findTextContaining(searchText);
    
    textNodes.forEach(({ node }) => {
        const text = node.textContent;
        const regex = new RegExp('(' + escapeRegex(searchText) + ')', 'gi');
        
        const wrapper = document.createElement('span');
        wrapper.innerHTML = text.replace(regex, '<mark class="' + className + '">$1</mark>');
        
        node.parentNode.replaceChild(wrapper, node);
    });
}

function escapeRegex(string) {
    return string.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
}

// Remove highlights
function removeHighlights(className = 'highlight') {
    document.querySelectorAll('mark.' + className).forEach(mark => {
        const parent = mark.parentNode;
        parent.replaceChild(document.createTextNode(mark.textContent), mark);
        parent.normalize(); // Merge adjacent text nodes
    });
}
`;

console.log('Text Highlighting:', highlightExample);

// =============================================================================
// 8. CUSTOM ELEMENT QUERIES
// =============================================================================

console.log('\n--- Custom Element Queries ---');

// Collection of custom query utilities
const customQueries = {
  // Find elements by computed style
  findByComputedStyle: `
function findByComputedStyle(property, value, root = document) {
    const elements = root.querySelectorAll('*');
    const matches = [];
    
    elements.forEach(el => {
        const computed = getComputedStyle(el);
        if (computed[property] === value) {
            matches.push(el);
        }
    });
    
    return matches;
}

// Find all visible elements
const visibleElements = findByComputedStyle('display', 'block');

// Find all fixed elements
const fixedElements = findByComputedStyle('position', 'fixed');
`,

  // Find by bounding rect
  findInViewport: `
function findInViewport(root = document.body) {
    const elements = root.querySelectorAll('*');
    const viewport = {
        top: 0,
        left: 0,
        bottom: window.innerHeight,
        right: window.innerWidth
    };
    
    return Array.from(elements).filter(el => {
        const rect = el.getBoundingClientRect();
        return (
            rect.top < viewport.bottom &&
            rect.bottom > viewport.top &&
            rect.left < viewport.right &&
            rect.right > viewport.left
        );
    });
}
`,

  // Find by data attribute pattern
  findByDataPattern: `
function findByDataPattern(pattern, root = document) {
    const elements = root.querySelectorAll('*');
    const regex = new RegExp(pattern);
    
    return Array.from(elements).filter(el => {
        return Array.from(el.attributes).some(attr => 
            attr.name.startsWith('data-') && regex.test(attr.value)
        );
    });
}
`,
};

console.log('Custom Query Examples:');
Object.entries(customQueries).forEach(([name, code]) => {
  console.log(`\n${name}:`);
  console.log(code);
});

// =============================================================================
// 9. SHADOW DOM TRAVERSAL
// =============================================================================

console.log('\n--- Shadow DOM ---');

const shadowDOMExample = `
// Creating Shadow DOM
class MyComponent extends HTMLElement {
    constructor() {
        super();
        // Attach shadow root
        this.attachShadow({ mode: 'open' });
        
        // Add content to shadow root
        this.shadowRoot.innerHTML = \`
            <style>
                .internal { color: blue; }
            </style>
            <div class="internal">
                Shadow DOM content
            </div>
        \`;
    }
}

customElements.define('my-component', MyComponent);

// Traversing Shadow DOM
function traverseShadowDOM(root) {
    const walker = document.createTreeWalker(
        root,
        NodeFilter.SHOW_ELEMENT,
        null
    );
    
    const elements = [];
    while (walker.nextNode()) {
        const node = walker.currentNode;
        elements.push(node);
        
        // Check for shadow root
        if (node.shadowRoot) {
            elements.push(...traverseShadowDOM(node.shadowRoot));
        }
    }
    
    return elements;
}

// Find element across shadow boundaries
function deepQuerySelector(selector, root = document) {
    let element = root.querySelector(selector);
    if (element) return element;
    
    // Search in shadow roots
    const walker = document.createTreeWalker(
        root,
        NodeFilter.SHOW_ELEMENT,
        null
    );
    
    while (walker.nextNode()) {
        if (walker.currentNode.shadowRoot) {
            element = deepQuerySelector(selector, walker.currentNode.shadowRoot);
            if (element) return element;
        }
    }
    
    return null;
}
`;

console.log('Shadow DOM Traversal:', shadowDOMExample);

// =============================================================================
// 10. DOM UTILITIES CLASS
// =============================================================================

console.log('\n--- DOM Utilities Class ---');

const domUtilitiesCode = `
class DOMUtils {
    // Find all elements matching multiple selectors
    static findMultiple(...selectors) {
        return selectors.flatMap(selector => 
            Array.from(document.querySelectorAll(selector))
        );
    }
    
    // Get element's path from root
    static getPath(element) {
        const path = [];
        while (element && element !== document.documentElement) {
            let selector = element.tagName.toLowerCase();
            
            if (element.id) {
                selector += '#' + element.id;
            } else if (element.className) {
                selector += '.' + element.className.split(' ').join('.');
            }
            
            path.unshift(selector);
            element = element.parentElement;
        }
        return path.join(' > ');
    }
    
    // Find common ancestor
    static commonAncestor(el1, el2) {
        const ancestors = new Set();
        
        let current = el1;
        while (current) {
            ancestors.add(current);
            current = current.parentElement;
        }
        
        current = el2;
        while (current) {
            if (ancestors.has(current)) {
                return current;
            }
            current = current.parentElement;
        }
        
        return null;
    }
    
    // Get all siblings
    static siblings(element, filter = null) {
        return Array.from(element.parentElement.children)
            .filter(child => child !== element)
            .filter(child => filter ? filter(child) : true);
    }
    
    // Find next/previous matching sibling
    static nextMatching(element, selector) {
        let sibling = element.nextElementSibling;
        while (sibling) {
            if (sibling.matches(selector)) return sibling;
            sibling = sibling.nextElementSibling;
        }
        return null;
    }
    
    // Check if element is ancestor
    static isAncestor(ancestor, descendant) {
        let current = descendant.parentElement;
        while (current) {
            if (current === ancestor) return true;
            current = current.parentElement;
        }
        return false;
    }
}
`;

console.log('DOM Utilities Class:', domUtilitiesCode);

console.log('\n=== Advanced DOM Traversal examples loaded. ===');
console.log('These examples require a browser environment to run.');
Examples - JavaScript Tutorial | DeepML