Widget: DCTList: Difference between revisions

From LINKS Community Center
Jump to: navigation, search
Eschmidt (talk | contribs)
No edit summary
Marterer (talk | contribs)
No edit summary
(530 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<noinclude>Development verstion of the DCT List.<br><span style="color: red; font-weight: bold;">Not ready for production!</span></noinclude>
<noinclude>DCT list widget.<br><span style="color: red; font-weight: bold;">Currently in use &ndash; do not modify!</span></noinclude>
 
<includeonly>
<includeonly>
     <link href="https://unpkg.com/tabulator-tables@5.2.7/dist/css/tabulator.min.css" rel="stylesheet">
     <link href="/resources/assets/tabulator/dist/css/tabulator.min.css" rel="stylesheet">
     <script type="text/javascript" src="https://unpkg.com/tabulator-tables@5.2.7/dist/js/tabulator.min.js"></script>
     <script type="text/javascript" src="/resources/assets/tabulator/dist/js/tabulator.min.js"></script>


     <style>
     <!-- STYLES BEGIN -->
        #dct-list-wrapper { font-family: 'Open Sans'; }
<link rel="stylesheet" href="https://www.safetyinnovation.center/lcc/dct_list/styles.css">
        #dct-list-wrapper h1, #dct-list-wrapper h2, #dct-list-wrapper h3 {
<!-- STYLES END -->
            font-family: 'Raleway';
            font-weight: 300;
            letter-spacing: .06em;
        }
        #dct-list-wrapper h1 {
            margin-bottom: 2em;
            color: var(--links-blue);
        }
        #dct-list-wrapper h2 {
            margin-bottom: 1em;
        }
        #data-source-filter-wrapper button {
            border: 0 none;
            color: var(--links-blue);
            font-variant: small-caps;
            font-size: 1.2em;
            margin: 0 1em;
        }
        #data-source-filter {
            font-size: 1.2em;
            margin-bottom: 4em;
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(14em, 1fr));
            gap: 1em 1em;
        }
        #data-source-filter img { width: 2em; height: 2em; margin: 0 .5em; }
        #dct-tabulator.tabulator { border: 0 none; background-color: transparent; font-size: 1.2em; }
        #dct-tabulator.tabulator .tabulator-header { border-bottom: 4px double var(--links-blue); background-color: transparent; }
        #dct-tabulator.tabulator .tabulator-header .tabulator-col { border-right: 0 none; background: transparent; }
        #dct-tabulator.tabulator .tabulator-header .tabulator-col-content { padding: .5em 0; }
        #dct-tabulator.tabulator .tabulator-header .tabulator-col-sorter { right: 1em; }
        #dct-tabulator.tabulator .tabulator-row { background-color: transparent; }
        #dct-tabulator.tabulator .tabulator-cell { border-right: 0 none; border-bottom: 1px solid var(--links-blue); padding: .5em 0; }
        .data-source-img { width: 2em; height: 2em; }
    </style>


     <script>
    <!-- SCRIPT BEGIN -->
     'use strict';
     <script type="text/javascript" src="https://www.safetyinnovation.center/lcc/dct_list/script.js"></script>
     <!-- SCRIPT END -->


     /**
     <!-- Icon definitons -->
    * @typedef {Object} DCT
    <img src="https://www.safetyinnovation.center/lcc/dct_list/img/unknown.svg">
    * @property {string} name
    * @property {string} url
    * @property {string[]} dataSources
    * @property {string} logo
    */


     let table;
     <div id="dct-list-wrapper">
        <h1>
            <img src="https://www.safetyinnovation.center/lcc/dct_list/img/1-dct.svg">
            <div>
                <div>Technologies</div>
                <div style="font-size:small; letter-spacing:.03em; margin-left: .6em;">Social Media and Crowdsourcing Library</div>
            </div>
        </h1>
        <div id="dct-intro">
            <p>The overall goal of the Social Media and Crowdsourcing (SMCS) Technologies Library is to face the growing
                heterogeneous use of technologies in disasters and the overwhelming number of technologies on the
                market. It gathers and structures information about existing technologies to provide an up-to-date overview and
                thus support the selection of suitable technologies.
            </p>
            <p>
                You can use the filters to identify relevant technologies according to your needs and then click on the
                name of the technology to get further information.
            </p>
        </div>


    /** @param {string} title */
        <div id="filter-bar">
    function getUrl(title) {
            <div style="display: flex; justify-content: space-between;">
        return title ? '/index.php/Special:FilePath/' + title : title;
                <div style="flex: 1 1;">
    }
                    <h2 style="margin-bottom: 1rem;">Selected Filters</h2>
                    <div id="filter-summary">No filter. Showing all results.</div>
                </div>
                <div>
                    <button class="large-button open-filters" type="button" onclick="toggleFilter()">Open Filters</button>
                </div>
            </div>


    /** @param {string} text */  
            <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 2.5rem;">
    function escapeAttr(text) {
                <h2 style="margin-bottom: 0;">Results: <span id="result-count"></span></h2>
        return text ? text.replace(/\s/g, '-') : text;
                <div><a href="/index.php/Form:Disaster_Community_Technology" style="color: var(--links-blue); font-size: 1.5em; font-variant:small-caps">Add new technology</a></div>
    }
            </div>


    async function getSources() {
            <div id="dct-filters">
        const sourceQuery = '/api.php?action=ask&format=json&query=' + encodeURIComponent('[[Category:Social media platform]]|?IMAGE');
                <h2 style="display: flex; justify-content: space-between;">
        const sourceResponse = await fetch(sourceQuery).then(response => response.json());
                    <div>
 
                        <img src="filters.svg">
        const results = sourceResponse.query.results;
                        <span>Filters</span>
        const sources = Object.getOwnPropertyNames(results).map(platformName => ({
                    </div>
            name: platformName,
                    <a onclick="toggleFilter()" id="close-filter-button">&times;</a>
            image: getUrl(results[platformName].printouts['IMAGE'][0].fulltext.replace('PAGENAME:', ''))
                </h2>
        }));
                <div style="text-align: center;">
 
                    <button class="large-button" type="button" onclick="clearFilters()">Clear Filters</button>
        return sources;
                </div>
    }
                <div class="filter-wrapper">
 
                    <h4 class="filter-toggle">Functions <div class="plus icon"></div>
    async function getDcts() {
                    </h4>
        const dctQuery = '[[Category:Disaster Community Technology]]' +
                    <div class="filter-container">
                        '|?Image' +
                        <div class="filter-button-wrapper">
                        '|?Data Sources';
                            <button type="button" onclick="selectAll('#functions-filter')">Select all</button> |
        const dctQueryUrl = '/api.php?action=ask&format=json&query=' + encodeURIComponent(dctQuery);
                            <button type="button" onclick="deselectAll('#functions-filter')">Clear all</button>
        const dctResponse = await fetch(dctQueryUrl).then(response => response.json());
                        </div>
 
                        <div class="filter-content loose" id="functions-filter"></div>
        const results = dctResponse.query.results;
                    </div>
        const dctList = Object.getOwnPropertyNames(results).map(dctKey => {
                </div>
            /** @type {DCT} */
                <div class="filter-wrapper">
            const dct = {};
                    <h4 class="filter-toggle">Supported Platforms <div class="plus icon"></div>
            dct.name = dctKey;
                    </h4>
            dct.url = results[dctKey].fullurl;
                    <div class="filter-container">
            dct.dataSources = results[dctKey].printouts['Data Sources'].map(source => source.fulltext).sort();
                        <div class="filter-button-wrapper">
            dct.logo = results[dctKey].printouts['Image'][0] ? getUrl(results[dctKey].printouts['Image'][0].fulltext) : void 0;
                            <button type="button" onclick="selectAll('#data-source-filter')">Select all</button> |
            return dct;
                            <button type="button" onclick="deselectAll('#data-source-filter')">Clear all</button>
        })
                        </div>
 
                        <div class="filter-content loose" id="data-source-filter"></div>
        return dctList;
                    </div>
    }
                 </div>
 
                <div class="filter-wrapper">
    /**
                    <h4 class="filter-toggle">Pricing <div class="plus icon"></div>
    * @param {DCT} dct
                    </h4>
    * @param {Partial<DCT>} filterState
                    <div class="filter-container">
    */
                        <div class="filter-button-wrapper">
    function dctFilter(dct, filterState) {
                            <button type="button" onclick="selectAll('#business-model-filter')">Select all</button> |
        // if the property is empty, don't apply the filter (return true)
                            <button type="button" onclick="deselectAll('#business-model-filter')">Clear all</button>
        const sourcesCheck = filterState.dataSources
                         </div>
            ? dct.dataSources.some(source => filterState.dataSources.includes(source))
                         <div class="filter-content" id="business-model-filter"></div>
            : true;
                     </div>
        return sourcesCheck;
                 </div>
    }
                 <!-- <div class="filter-wrapper">
 
                     <h4 class="filter-toggle">Used by Practitioners <div class="plus icon"></div>
    function applyFilters() {
                     </h4>
        if (!table) return;
                     <div class="filter-container">
 
                         <div class="filter-button-wrapper">
        /** @type {Partial<DCT>} */
                             <button type="button" onclick="selectAll('#dm-use-filter')">Select all</button> |
        const filterState = {};
                             <button type="button" onclick="deselectAll('#dm-use-filter')">Clear all</button>
 
                         </div>
        // Build filter from the current filter form state
                         <div class="filter-content" id="dm-use-filter"></div>
        // Alternative: keep a copy and update
                     </div>
 
                 </div> -->
        const selectedSources = Array.from(document.querySelectorAll('#data-source-filter input[type="checkbox"]:checked')).map(checkbox => checkbox.value);
                <div id="bool-filters"
        filterState.dataSources = selectedSources;
                    style="border-top: 1px solid var(--links-blue); margin-top: 1em; padding-top: 1em;">
 
                    <div>
        table.setFilter(dctFilter, filterState);
                        <input type="checkbox" id="used-by-practitioners" value="yes">
    }
                        <label for="used-by-practitioners">Used by practitioners</label>
 
                    </div>
    // Load data and build page.
                    <div>
    Promise.all([getSources(), getDcts()]).then(data => {
                        <input type="checkbox" id="has-use-case" value="yes">
        const dataSources = data[0];
                        <label for="has-use-case">Use case available</label>
        const dcts = data[1];
                    </div>
 
                    <div>
        // Set up filters.
                        <input type="checkbox" id="show-archived" value="yes">
        const filterHtml = dataSources.reduce((prev, curr) => {
                        <label for="show-archived">Show archived</label>
            const identifier = escapeAttr(curr.name);
                    </div>
            return prev +
                </div>
                 '<div><input type="checkbox" id="filter-' + identifier + '" value="' + curr.name + '" checked>' +
            </div>
                '<label for="filter-' + identifier + '"><img src="' + curr.image + '"> ' + curr.name + '</label></div>'
        }, '');
        document.getElementById('data-source-filter').innerHTML = filterHtml;
 
        // Set up table.
        const tabulator = new Tabulator("#dct-tabulator", {
            layout: 'fitColumns',
            columns: [
                {
                    title: 'Name',
                    field: 'name',
                    formatter: function (cell) {
                         /** @type {DCT} */
                         const dct = cell.getData();
                        return '<a href="' + dct.url + '">' + dct.name + '</a>';
                     }
                 },
                 {
                     title: 'Data Sources',
                     field: 'dataSources',
                     formatter: function (cell) {
                         const output = cell.getValue().reduce((prev, curr) => {
                             const src = dataSources.find(src => src.name === curr);
                            const url = src ? src.image : '';
                             return url ? prev + '<img class="data-source-img" src="' + url + '">' : prev + ' ' + curr;
                         }, '');
                         return output;
                     }
                 }
            ]
        });
        tabulator.on('tableBuilt', () => {
            tabulator.setData(dcts);
            table = tabulator;
        });
 
        tabulator.on('dataFiltered', (filters, rows) => {
            console.log(filters)
        });
 
        document.getElementById('data-source-filter').addEventListener('change', event => {
            applyFilters();
        }, { passive: true });
 
    });
 
    function selectAllSources() {
        document.querySelectorAll('#data-source-filter input[type="checkbox"]').forEach(checkbox => checkbox.checked = true);
        applyFilters();
    }
 
    function deselectAllSources() {
        document.querySelectorAll('#data-source-filter input[type="checkbox"]').forEach(checkbox => checkbox.checked = false);
        applyFilters();
    }
    </script>
 
    <div id="dct-list-wrapper">
        <h1>Social Media and Crowdsourcing Technologies</h1>
        <h2>Filters</h2>
        <div id="data-source-filter-wrapper">
            <h3>Data Sources</h3>
            <button type="button" onclick="selectAllSources()">Select all</button>
            <button type="button" onclick="deselectAllSources()">Deselect all</button>
            <div id="data-source-filter"></div>
         </div>
         </div>
         <div id="dct-tabulator"></div>
         <div id="dct-tabulator"></div>
     </div>
     </div>
</includeonly>
</includeonly>

Revision as of 22:22, 10 May 2024

DCT list widget.
Currently in use – do not modify!