Skip to content
Snippets Groups Projects
eclipsefdn.weighted-working-groups.js 4.78 KiB
Newer Older
import template from '../templates/weighted-working-groups/working-group-block.mustache'

const defaultOptions = {
    count: 1,
    wrapperClass: ''
}

// Working groups with a weight of -1 will not be displayed.
const weights = {
    default: -1,
    'jakarta-ee': 1,
    sdv: 20,
    'cloud-development-tools': 30,
    adoptium: 38,
    oniro: 38,
    'eclipse-ide': 44,
    'internet-things-iot': 44,
    aice: 50,
    asciidoc: 50,
    'edge-native': 50,
    microprofile: 50,
    openmobility: 50,
    osgi: 50,
    sparkplug: 50,
};

const fallbackLogos = {
    sdv: '/images/collaborations/logos/software-defined-vehicle-fallback.png'
}

const removeDuplicates = (value, index, self) => self.indexOf(value) === index;

const getWeightedRandomIndex = (weightBuckets, categorizedArrayByWeight) => {
    const largestWeight = Object.values(weights).sort().at(-1);
    const randomNumber = Math.floor(Math.random() * largestWeight);

    // Returns whatever number is the closest to a weight bucket
    const closest = Object.values(weights).reduce((prev, curr) => {
        return (Math.abs(curr - randomNumber) < Math.abs(prev - randomNumber) ? curr : prev);
    })

    const weightBucketSelectionIndex = weightBuckets.indexOf(closest);
    const weightBucketSelection = weightBuckets[weightBucketSelectionIndex];
    const selectionIndex = Math.floor(Math.random() * categorizedArrayByWeight[weightBucketSelection].length);
    
    return categorizedArrayByWeight[weightBucketSelection][selectionIndex];
}

function getUniqueRandomWorkingGroups(workingGroupsCategorizedByWeight, weightBuckets, count) {
    // Creates a set of selected working groups. This will omit duplicates.
    let selectionSet = new Set();

    while (selectionSet.size < count) {
        const randomWorkingGroup = getWeightedRandomIndex(weightBuckets, workingGroupsCategorizedByWeight);

        if (selectionSet.has(randomWorkingGroup)) continue;
        selectionSet.add(randomWorkingGroup);
    }

    return Array.from(selectionSet);
}

async function getWeightedRandomWorkingGroups(count) {
    const cachedWorkingGroups = JSON.parse(sessionStorage.getItem('weighted-working-groups'));
    const isCached = cachedWorkingGroups != null;

    // Only return the cached working groups if the count hasn't changed since last time run
    if (isCached && cachedWorkingGroups.length === count) return cachedWorkingGroups;

    const response = await fetch('https://membership.eclipse.org/api/working_groups');
    const workingGroups = await response.json();

    const weightBuckets = Object
        .values(weights)
        .filter(removeDuplicates);

    // Create an object where the key is a bucket (or weight), and the value an array of working groups tied to that bucket
    const weightBucketObject = weightBuckets.reduce((acc, bucket) => ({...acc, [bucket]: [] }), {})

    const workingGroupsCategorizedByWeight = workingGroups.reduce((acc, wg) => {
        const weight = weights[wg.alias] || weights.default;
        acc[weight].push(wg);

        return acc;
    }, { ...weightBucketObject });

    // Retrieves weighted random working groups and stores it in session storage cache
    const randomWorkingGroups = getUniqueRandomWorkingGroups(workingGroupsCategorizedByWeight, weightBuckets, count);
    sessionStorage.setItem('weighted-working-groups', JSON.stringify(randomWorkingGroups));

    return randomWorkingGroups;
};

const matchHeightForLogos = (baseElement) => {
    const imgElements = baseElement.querySelectorAll('.weighted-working-group-logo');

    imgElements.forEach(el => { 
        el.addEventListener('load', () => {
            $('.weighted-working-group-block-wrapper').matchHeight();
        });
    });
}

const getWorkingGroupLogo = ({ alias, logo } = workingGroup) => {
    const fallbackLogo = fallbackLogos[alias];
    if (logo === '') return fallbackLogo || '';

    return logo;
}

(async function renderWeightedWorkingGroups() {
    const element = document.querySelector('.eclipsefdn-weighted-working-groups');
    if (!element) return;

    const options = { 
        ...defaultOptions, 
        ...element.dataset,
        count: +element.dataset.count
    };

    element.innerHTML = template({ isFetching: true, items: new Array(options.count) , wrapperClass: options.wrapperClass })

    const workingGroups = await getWeightedRandomWorkingGroups(options.count);
    
    const data = {
        isFetching: false,
        wrapperClass: options.wrapperClass,
        items: workingGroups.map(wg => ({
            title: wg.title,
            logo: getWorkingGroupLogo(wg),
            websiteUrl: wg.resources.website,
        }))
    };

    element.innerHTML = template(data); 
    matchHeightForLogos(element);
})();