Difference between revisions of "Widget:DCTList"

From LINKS Community Center
Jump to: navigation, search
 
(33 intermediate revisions by the same user not shown)
Line 1: Line 1:
<noinclude>Current version 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="/resources/assets/tabulator.min.css" rel="stylesheet">
+
     <link href="/resources/assets/tabulator/dist/css/tabulator.min.css" rel="stylesheet">
     <script type="text/javascript" src="/resources/assets/tabulator.min.js"></script>
+
     <script type="text/javascript" src="/resources/assets/tabulator/dist/js/tabulator.min.js"></script>
  
 
     <style>
 
     <style>
Line 261: Line 261:
 
             font-weight: 300;
 
             font-weight: 300;
 
         }
 
         }
 
 
     </style>
 
     </style>
  
Line 283: Line 282:
 
         * @property {FuncData} functions
 
         * @property {FuncData} functions
 
         * @property {string} usedByDmo
 
         * @property {string} usedByDmo
 +
        * @property {string} archived
 
         * @property {string} hasUC
 
         * @property {string} hasUC
 
         * @property {string} logo
 
         * @property {string} logo
Line 367: Line 367:
 
             const DMO_PROP = 'Used by Practitioners';
 
             const DMO_PROP = 'Used by Practitioners';
 
             const UC_PROP = 'Use Cases available';
 
             const UC_PROP = 'Use Cases available';
 +
            const ARCHIVED = 'Is Archived';
 
             const dctQuery = '[[Category:Disaster Community Technology]]'
 
             const dctQuery = '[[Category:Disaster Community Technology]]'
                 + '[[Is Archived::No]]'
+
                 // + '[[Is Archived::No]]'
 
                 + '|limit=500'
 
                 + '|limit=500'
 +
                + '|?' + ARCHIVED
 
                 + '|?' + IMG_PROP
 
                 + '|?' + IMG_PROP
 
                 + '|?' + DATASRC_PROP
 
                 + '|?' + DATASRC_PROP
Line 391: Line 393:
 
                 dct.usedByDmo = dctResult.printouts[DMO_PROP][0] === 't' ? 'yes' : 'no';    // not quite, but we only care about yes
 
                 dct.usedByDmo = dctResult.printouts[DMO_PROP][0] === 't' ? 'yes' : 'no';    // not quite, but we only care about yes
 
                 dct.hasUC = dctResult.printouts[UC_PROP][0] === 't' ? 'yes' : 'no';    // not quite, but we only care about yes
 
                 dct.hasUC = dctResult.printouts[UC_PROP][0] === 't' ? 'yes' : 'no';    // not quite, but we only care about yes
 +
                dct.archived = dctResult.printouts[ARCHIVED][0] === 't' ? 'yes' : 'no';    // not quite, but we only care about yes
  
 
                 dct.functions = new Map();
 
                 dct.functions = new Map();
Line 414: Line 417:
 
             // If filtering property is empty, don't apply the filter (set the check to true).
 
             // If filtering property is empty, don't apply the filter (set the check to true).
 
             // Passing an empty object (as with applyFilters(true)) should result in an unfiltered table.
 
             // Passing an empty object (as with applyFilters(true)) should result in an unfiltered table.
 
            console.log('FILT', filterState)
 
  
 
             let functionsCheck = true;  // automatically pass functions check if the filter missing
 
             let functionsCheck = true;  // automatically pass functions check if the filter missing
Line 425: Line 426:
 
                 });
 
                 });
  
                 // Empty categories should only be checked by their name, nonempty - ONLY by subfunctions.
+
                 // Empty categories should only be checked by their name
                 const checkEmpty = emptyCategories.some(cat => dct.functions.has(cat));
+
                 const checkEmpty = emptyCategories.every(cat => dct.functions.has(cat));
                 const checkNonempty = nonemptyCategories.some(cat => {
+
 
 +
                // Nonempty categories should only be checked for presence of their subfunctions. Category itself is irrelevant.
 +
                 const checkNonempty = nonemptyCategories.every(cat => {
 
                     const selectedSubs = filterState.functions.get(cat);
 
                     const selectedSubs = filterState.functions.get(cat);
                     const dctCat = dct.functions.get(cat);
+
                     const dctSubs = dct.functions.get(cat);
                     return dctCat && dctCat[FUNC_KEY] && dctCat[FUNC_KEY].some(sub => selectedSubs.includes(sub));
+
                     return dctSubs && dctSubs[FUNC_KEY] && selectedSubs.every(sub => dctSubs[FUNC_KEY].includes(sub));
 
                 });
 
                 });
  
                 functionsCheck = checkEmpty || checkNonempty;
+
                 functionsCheck = checkEmpty && checkNonempty;
 +
                // TODO: Empty should no longer exist, once every category is fully listed in the filter.
 +
                // TODO: The filtering of functions therefore should be reduced to nonempty only.
 
             }
 
             }
  
 
             const sourcesCheck = filterState.dataSources
 
             const sourcesCheck = filterState.dataSources
                 ? dct.dataSources.some(source => filterState.dataSources.includes(source))
+
                 ? filterState.dataSources.every(source => dct.dataSources.includes(source))
 
                 : true;
 
                 : true;
 
             const businessModelCheck = filterState.businessModel
 
             const businessModelCheck = filterState.businessModel
Line 448: Line 453:
 
                 ? filterState.hasUC === dct.hasUC
 
                 ? filterState.hasUC === dct.hasUC
 
                 : true;
 
                 : true;
             return sourcesCheck && functionsCheck && businessModelCheck && dmUseCheck && ucCheck;
+
            const archivedCheck = filterState.showArchived
 +
                ? true
 +
                : dct.archived !== 'yes';
 +
 
 +
             return sourcesCheck && functionsCheck && businessModelCheck && dmUseCheck && ucCheck && archivedCheck;
 
         }
 
         }
  
Line 460: Line 469:
 
             }
 
             }
  
            /** @type {Partial<Omit<DCT, 'usedByDmo'> & { usedByDmo: string[]>}} */
 
 
             const filterState = {};
 
             const filterState = {};
  
Line 489: Line 497:
 
             if (document.getElementById('used-by-practitioners').checked) filterState.usedByDmo = 'yes';
 
             if (document.getElementById('used-by-practitioners').checked) filterState.usedByDmo = 'yes';
 
             if (document.getElementById('has-use-case').checked) filterState.hasUC = 'yes';
 
             if (document.getElementById('has-use-case').checked) filterState.hasUC = 'yes';
 +
            if (document.getElementById('show-archived').checked) filterState.showArchived = 'yes';
  
 
             table.setFilter(dctFilter, filterState);
 
             table.setFilter(dctFilter, filterState);
Line 501: Line 510:
 
             Array.from(functionsData).forEach(([fnCat, fnInfo], index) => {
 
             Array.from(functionsData).forEach(([fnCat, fnInfo], index) => {
 
                 const identifier = 'func-filter-' + escapeAttr(fnCat);
 
                 const identifier = 'func-filter-' + escapeAttr(fnCat);
                 funcFilterHtml +=
+
                 funcFilterHtml +=  
 
                     `<div class="func-filter-block">
 
                     `<div class="func-filter-block">
 
                         <div>
 
                         <div>
Line 509: Line 518:
  
 
                 // add subfunctions  
 
                 // add subfunctions  
                 if (index < 4) {
+
                 funcFilterHtml += '<div class="subfunc-filter-block">';
                    funcFilterHtml += '<div class="subfunc-filter-block">';
+
                for (const func of fnInfo.functions) {
                    for (const func of fnInfo.functions) {
+
                    const subfuncId = 'subfunc-filter-' + escapeAttr(func);
                        const subfuncId = 'subfunc-filter-' + escapeAttr(func);
+
                    funcFilterHtml +=
                        funcFilterHtml +=
+
                        `<div>
                            `<div>
+
                            <input type="checkbox" id="${subfuncId}" value="${func}">
                                <input type="checkbox" id="${subfuncId}" value="${func}">
+
                            <label for="${subfuncId}">${func}</label>
                                <label for="${subfuncId}">${func}</label>
+
                        </div>`;
                            </div>`;
 
                    }
 
                    funcFilterHtml += '</div>';
 
 
                 }
 
                 }
 +
                funcFilterHtml += '</div>';
 +
 
                 funcFilterHtml += '</div>';
 
                 funcFilterHtml += '</div>';
 
             });
 
             });
Line 563: Line 571:
 
             }, '');
 
             }, '');
 
             document.getElementById('business-model-filter').innerHTML = pricingFilterHtml;
 
             document.getElementById('business-model-filter').innerHTML = pricingFilterHtml;
 
            // const dmUse = ['Yes', 'Use Case', 'Unknown'];
 
            // let dmUseFilterHtml = dmUse.reduce((acc, curr) => {
 
            //    const identifier = escapeAttr(curr);
 
            //    return acc
 
            //        + '<div><input type="checkbox" id="dm-use-filter-' + identifier
 
            //        + '" value="' + curr + '">'
 
            //        + '<label for="dm-use-filter-' + identifier + '">' + curr + '</label></div>'
 
            // }, '');
 
            // document.getElementById('dm-use-filter').innerHTML = dmUseFilterHtml;
 
  
 
             // Set up table.
 
             // Set up table.
Line 583: Line 581:
 
                         field: 'name',
 
                         field: 'name',
 
                         minWidth: 300, // required for responsiveness when using fitColumns
 
                         minWidth: 300, // required for responsiveness when using fitColumns
 +
                        widthGrow: 2,
 
                         formatter: function (cell) {
 
                         formatter: function (cell) {
 
                             /** @type {DCT} */
 
                             /** @type {DCT} */
 
                             const dct = cell.getData();
 
                             const dct = cell.getData();
                             let out = '<a href="' + dct.url + '">' + dct.name + '</a><br>';
+
                             let out = '<a href="' + dct.url + '" translate="no">' + dct.name + '</a><br>';
 +
                            if (dct.archived.toLowerCase() === 'yes') {
 +
                                out += '<small><span class="badge lcc-badge-grey">Archived</span></small> ';
 +
                            }
 
                             if (dct.businessModel.includes(FREE_KEY)) {
 
                             if (dct.businessModel.includes(FREE_KEY)) {
                                 out += '<small><span class="badge badge-success">' + FREE_KEY + '</span></small> ';
+
                                 out += '<small><span class="badge lcc-badge-green">' + FREE_KEY + '</span></small> ';
 
                             }
 
                             }
 
                             if (dct.businessModel.includes(FREE_PLAN_KEY)) {
 
                             if (dct.businessModel.includes(FREE_PLAN_KEY)) {
                                 out += '<small><span class="badge badge-success">' + FREE_PLAN_KEY + '</span></small> ';
+
                                 out += '<small><span class="badge lcc-badge-green">' + FREE_PLAN_KEY + '</span></small> ';
 
                             }
 
                             }
 
                             if (dct.usedByDmo.toLowerCase() === 'yes') {
 
                             if (dct.usedByDmo.toLowerCase() === 'yes') {
                                 out += '<small><span class="badge badge-danger">Used by practitioners</span></small> ';
+
                                 out += '<small><span class="badge lcc-badge-red">Used by practitioners</span></small> ';
 
                             }
 
                             }
 
                             if (dct.hasUC.toLowerCase() === 'yes') {
 
                             if (dct.hasUC.toLowerCase() === 'yes') {
                                 out += '<small><span class="badge badge-warning">Use case available</span></small> ';
+
                                 out += '<small><span class="badge lcc-badge-purple">Use case available</span></small> ';
 
                             }
 
                             }
  
Line 606: Line 608:
 
                         title: 'Functions',
 
                         title: 'Functions',
 
                         field: 'functions',
 
                         field: 'functions',
                         minWidth: 300, // required for responsiveness when using fitColumns
+
                         minWidth: 200, // required for responsiveness when using fitColumns
 
                         cssClass: 'functions-cell',
 
                         cssClass: 'functions-cell',
 
                         formatter: function (cell) {
 
                         formatter: function (cell) {
Line 615: Line 617:
 
                                     alt="${fn}"  
 
                                     alt="${fn}"  
 
                                     title="${fn}\n\n${functionsData.get(fn)[DESC_KEY]}">`
 
                                     title="${fn}\n\n${functionsData.get(fn)[DESC_KEY]}">`
                                    )
+
                                )
 
                                 .join('');
 
                                 .join('');
 
                         }
 
                         }
Line 663: Line 665:
  
 
                 if (encoded) {
 
                 if (encoded) {
                     const action = JSON.parse(decodeURIComponent(atob(encoded)));
+
                     const actions = JSON.parse(decodeURIComponent(atob(encoded)));
  
                     const filter = action.filter;
+
                     const filter = actions.filter;
 
                     if (filter) {
 
                     if (filter) {
 
                         // Functions filter
 
                         // Functions filter
 
                         const functions = filter.functions;
 
                         const functions = filter.functions;
 
                         if (functions) {
 
                         if (functions) {
                             Object.keys(functions).forEach(fnCat => {
+
                             Object.keys(functions).forEach(subfun => {
                                 document.getElementById('func-filter-' + escapeAttr(fnCat))
+
                                 const subfunEl = document.getElementById('subfunc-filter-' + escapeAttr(subfun));
                                    .closest('.func-filter-block')
+
                                subfunEl.checked = !!functions[subfun];
                                    .querySelectorAll('input[type="checkbox"]').forEach(box => box.checked = !!functions[fnCat]);
+
                                subfunEl.dispatchEvent(new Event('change', { bubbles: true }));
 
                             });
 
                             });
  
Line 689: Line 691:
 
                     // ...
 
                     // ...
 
                 }
 
                 }
 +
 +
                applyFilters();
 
             });
 
             });
  
Line 780: Line 784:
 
                     const checkedSubs = Array.from(subfunctions).filter(sub => sub.checked).length;
 
                     const checkedSubs = Array.from(subfunctions).filter(sub => sub.checked).length;
 
                     category.checked = checkedSubs > 0;
 
                     category.checked = checkedSubs > 0;
                    // if (checkedSubs > 0) { category.checked = true; } else { category.checked = false; }
 
 
                 }
 
                 }
  
Line 891: Line 894:
 
         <div id="dct-intro">
 
         <div id="dct-intro">
 
             <p>The overall goal of the Social Media and Crowdsourcing (SMCS) Technologies Library is to face the growing
 
             <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
+
                 heterogeneous use of technologies in disasters and the overwhelming number of technologies on the
                 gathers and structures information about existing technologies to provide an up-to-date overview and thus
+
                market. It
 +
                 gathers and structures information about existing technologies to provide an up-to-date overview and
 +
                thus
 
                 support the selection of suitable technologies.
 
                 support the selection of suitable technologies.
 
             </p>
 
             </p>
 
             <p>
 
             <p>
                 You can use the filters to identify relevant technologies according to your needs and then click on the name of
+
                 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.
 
                 the technology to get further information.
 
             </p>
 
             </p>
Line 913: Line 919:
 
             </div>
 
             </div>
  
             <h2 style="margin-top: 2.5rem; margin-bottom: 0;">Results: <span id="result-count"></span></h2>
+
             <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 2.5rem;">
 +
                <h2 style="margin-bottom: 0;">Results: <span id="result-count"></span></h2>
 +
                <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>
  
 
             <div id="dct-filters">
 
             <div id="dct-filters">
Line 935: Line 944:
 
                 </h2>
 
                 </h2>
 
                 <div style="text-align: center;">
 
                 <div style="text-align: center;">
                     <button class="large-button" type="button" onclick="clearFilters()">Show All</button>
+
                     <button class="large-button" type="button" onclick="clearFilters()">Clear Filters</button>
 
                 </div>
 
                 </div>
 
                 <div class="filter-wrapper">
 
                 <div class="filter-wrapper">
Line 981: Line 990:
 
                     </div>
 
                     </div>
 
                 </div> -->
 
                 </div> -->
                 <div id="bool-filters" style="border-top: 1px solid var(--links-blue); margin-top: 1em; padding-top: 1em;">
+
                 <div id="bool-filters"
 +
                    style="border-top: 1px solid var(--links-blue); margin-top: 1em; padding-top: 1em;">
 
                     <div>
 
                     <div>
 
                         <input type="checkbox" id="used-by-practitioners" value="yes">
 
                         <input type="checkbox" id="used-by-practitioners" value="yes">
Line 989: Line 999:
 
                         <input type="checkbox" id="has-use-case" value="yes">
 
                         <input type="checkbox" id="has-use-case" value="yes">
 
                         <label for="has-use-case">Use case available</label>
 
                         <label for="has-use-case">Use case available</label>
 +
                    </div>
 +
                    <div>
 +
                        <input type="checkbox" id="show-archived" value="yes">
 +
                        <label for="show-archived">Show archived</label>
 
                     </div>
 
                     </div>
 
                 </div>
 
                 </div>

Latest revision as of 15:30, 19 December 2023

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