CSN Odoo Call Hyperlinks (Modified)

Convert phone numbers to clickable links for anonymous calling in CSN Odoo

As of 2024-07-19. See the latest version.

// ==UserScript==
// @name         CSN Odoo Call Hyperlinks (Modified)
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Convert phone numbers to clickable links for anonymous calling in CSN Odoo
// @match        https://csnodoo.shopcsntv.com/*
// @grant        GM_addStyle
// @require      https://kit.fontawesome.com/YOUR_KIT_ID.js
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Add Font Awesome styles
    GM_addStyle(`
        @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css');
    `);

    function formatPhoneNumber(phoneNumberString) {
        return phoneNumberString.replace(/\D/g, '');
    }

    function isValidPhoneNumber(str) {
        const phoneRegex = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4}$/;
        return phoneRegex.test(str);
    }

    function createAnonymousPhoneLink(phoneNumber) {
        const formattedNumber = formatPhoneNumber(phoneNumber);
        const phoneLink = document.createElement('a');
        phoneLink.href = 'tel:*67' + formattedNumber;
        phoneLink.style.textDecoration = 'none';
        phoneLink.innerHTML = '<i class="fas fa-phone-slash"></i>';
        phoneLink.title = 'Call with *67';
        phoneLink.setAttribute('aria-label', 'Anonymous Call');
        phoneLink.style.marginLeft = '10px';
        return phoneLink;
    }

    function createDirectPhoneLink(phoneNumber) {
        const formattedNumber = formatPhoneNumber(phoneNumber);
        const phoneLink = document.createElement('a');
        phoneLink.href = 'tel:' + formattedNumber;
        phoneLink.style.textDecoration = 'none';
        phoneLink.innerHTML = '<i class="fas fa-headphones"></i>';
        phoneLink.title = 'Call with Caller ID';
        phoneLink.setAttribute('aria-label', 'Anonymous Call');
        phoneLink.style.marginLeft = '10px';
        return phoneLink;
    }

    function convertToClickableLink(element) {
        const spanContent = element.textContent.trim();
        if (isValidPhoneNumber(spanContent)) {
            const container = document.createElement('span');
            const phoneText = document.createTextNode(spanContent);
            const directPhoneLink = createDirectPhoneLink(spanContent);
            const anonymousPhoneLink = createAnonymousPhoneLink(spanContent);

            container.appendChild(phoneText);
            container.appendChild(directPhoneLink);
            container.appendChild(anonymousPhoneLink);

            element.parentNode.replaceChild(container, element);
        }
    }

    function observeDOMChanges() {
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            const spans = node.querySelectorAll('span');
                            spans.forEach(convertToClickableLink);
                        }
                    });
                }
            });
        });

        observer.observe(document.body, { childList: true, subtree: true });
    }

    observeDOMChanges();

    function updateButtonClass() {
        const buttons = document.querySelectorAll('button[name="cloudcti_open_outgoing_notification"]');
        buttons.forEach(button => {
            if (button.classList.contains('mb4')) {
                button.classList.remove('mb4');
            }
        });
    }

    // Run the function initially
    updateButtonClass();

    // Add a MutationObserver to handle dynamically added buttons
    const buttonObserver = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.type === 'childList') {
                updateButtonClass();
            }
        });
    });

    buttonObserver.observe(document.body, { childList: true, subtree: true });

})();