Difference between revisions of "Widget:DCTList"
From LINKS Community Center
Tag: Undo |
|||
Line 1: | Line 1: | ||
− | <noinclude>Development verstion of the DCT | + | <noinclude>Development verstion of the DCT List.<br><span style="color: red; font-weight: bold;">Not ready for production!</span></noinclude> |
− | <includeonly><style> | + | <includeonly> |
− | # | + | <link href="https://unpkg.com/tabulator-tables@5.2.7/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> | |
− | + | ||
− | + | <style> | |
− | # | + | #dct-list-wrapper { font-family: 'Open Sans'; margin-top: 4em; } |
+ | #dct-list-wrapper h1, #dct-list-wrapper h2, #dct-list-wrapper h3 { | ||
font-family: 'Raleway'; | font-family: 'Raleway'; | ||
font-weight: 300; | font-weight: 300; | ||
letter-spacing: .06em; | letter-spacing: .06em; | ||
} | } | ||
− | # | + | #dct-list-wrapper h1, #dct-filters h2 { |
− | + | color: var(--links-blue); | |
+ | display: flex; | ||
+ | align-items: center; | ||
+ | } | ||
+ | #dct-intro { | ||
+ | font-size: larger; | ||
margin-bottom: 4em; | margin-bottom: 4em; | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | #dct-list-wrapper h1 svg { | |
− | # | + | height: 2.5em; |
− | # | + | width: 2.5em; |
− | + | fill: var(--links-blue); | |
− | + | margin-right: .5em; | |
− | + | } | |
− | + | #dct-filters h2 svg { | |
− | + | height: 1.5em; | |
+ | width: 1.5em; | ||
+ | fill: var(--links-blue); | ||
+ | margin-right: .5em; | ||
+ | margin-left: -.2em; | ||
+ | } | ||
+ | #clear-filters-button { | ||
+ | border: 1px solid var(--links-blue); | ||
+ | font-size: 1.5em; | ||
+ | font-family: 'Open Sans'; | ||
+ | font-weight: 100; | ||
+ | margin-bottom: 2em; | ||
+ | padding: 0.3em 0.8em; | ||
+ | color: var(--links-blue); | ||
+ | background: transparent; | ||
+ | font-variant: small-caps; | ||
} | } | ||
− | + | #dct-list-wrapper h2 { | |
− | + | margin-bottom: 1em; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | . | + | .filter-button-wrapper { |
− | + | margin: 1.5em 0 1em 0; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | .filter-wrapper button { | |
− | + | border: 0 none; | |
− | |||
− | |||
− | |||
− | |||
− | |||
color: var(--links-blue); | color: var(--links-blue); | ||
− | + | background-color: transparent; | |
− | + | font-variant: small-caps; | |
+ | font-size: 1.2em; | ||
+ | text-decoration: underline; | ||
+ | padding: 0; | ||
} | } | ||
− | . | + | .filter-content { |
− | + | font-size: 1.2em; | |
− | + | margin-bottom: 4em; | |
− | + | display: grid; | |
+ | grid-template-columns: repeat(auto-fit, minmax(14em, 1fr)); | ||
+ | gap: 1em 1em; | ||
+ | align-items: end; | ||
} | } | ||
− | . | + | .filter-group-header { |
− | + | grid-column: 1/-1; | |
− | + | margin-bottom: -.5em; | |
− | + | margin-top: 1em; | |
+ | font-family: 'Raleway'; | ||
+ | font-weight: 200; | ||
+ | letter-spacing: .06em; | ||
} | } | ||
− | . | + | .filter-group-start { grid-column-start: 1; } |
− | + | .filter-content 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, .func-img { width: 2em; height: 2em; margin-right: .4em; margin-bottom: .4em; } | ||
+ | .source-img-placeholder { display:inline-block; width: 2em; height: 2em; } | ||
+ | #dct-tabulator img.unselected { | ||
+ | filter: grayscale(1); | ||
+ | opacity: .25; | ||
} | } | ||
+ | </style> | ||
+ | |||
+ | <script> | ||
+ | 'use strict'; | ||
− | + | /** | |
− | + | * @typedef {Object} DCT | |
+ | * @property {string} name | ||
+ | * @property {string} url | ||
+ | * @property {string[]} dataSources | ||
+ | * @property {string[]} functions | ||
+ | * @property {string} logo | ||
+ | */ | ||
− | + | let table; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | const FN_SEARCH = 'Search & Monitor'; | |
− | + | const FN_POST = 'Post & Schedule'; | |
− | + | const FN_ANALYSIS = 'Analysis'; | |
+ | const FN_METRICS = 'Metrics'; | ||
+ | const FN_REPORT = 'Report'; | ||
+ | const FN_COLLAB = 'Collaboration'; | ||
+ | const FN_INTEROP = 'Interoperability'; | ||
+ | const FN_META = 'Meta'; | ||
+ | |||
+ | const fnImages = {}; | ||
+ | fnImages[FN_SEARCH] = '/index.php/Special:FilePath/File:Func_search.svg'; | ||
+ | fnImages[FN_POST] = '/index.php/Special:FilePath/File:Func_post.svg'; | ||
+ | fnImages[FN_ANALYSIS] = '/index.php/Special:FilePath/File:Func_analysis.svg'; | ||
+ | fnImages[FN_METRICS] = '/index.php/Special:FilePath/File:Func_metrics.svg'; | ||
+ | fnImages[FN_REPORT] = '/index.php/Special:FilePath/File:Func_report.svg'; | ||
+ | fnImages[FN_COLLAB] = '/index.php/Special:FilePath/File:Func_collaboration.svg'; | ||
+ | fnImages[FN_INTEROP] = '/index.php/Special:FilePath/File:Func_interoperability.svg'; | ||
+ | fnImages[FN_META] = '/index.php/Special:FilePath/File:Func_meta.svg'; | ||
+ | |||
+ | const sourcesLayout = [ | ||
+ | { | ||
+ | title: 'General', | ||
+ | sources: ['Crowd', 'Web'] | ||
+ | }, | ||
+ | { | ||
+ | title: 'Platforms', | ||
+ | sources: ['Facebook', 'Twitter', 'Instagram', 'YouTube'] | ||
} | } | ||
− | </ | + | ]; |
+ | |||
+ | const getUrl = title => title ? '/index.php/Special:FilePath/' + title : title; | ||
+ | |||
+ | const escapeAttr = text => text ? text.replace(/\s/g, '-') : text; | ||
+ | |||
+ | const hasFunction = (dctResult, subfunctions) => subfunctions.some(func => { | ||
+ | const printoutResult = dctResult.printouts[func]; | ||
+ | return printoutResult && printoutResult[0] && printoutResult[0].fulltext.toLowerCase() === 'yes' | ||
+ | }); | ||
+ | |||
+ | async function getSources() { | ||
+ | const sourceQuery = '/api.php?action=ask&format=json&query=' + encodeURIComponent('[[Category:Social media platform]]|?IMAGE'); | ||
+ | const sourceResponse = await fetch(sourceQuery).then(response => response.json()); | ||
+ | |||
+ | const results = sourceResponse.query.results; | ||
+ | const sources = Object.getOwnPropertyNames(results).map(platformName => ({ | ||
+ | name: platformName, | ||
+ | image: getUrl(results[platformName].printouts['IMAGE'][0].fulltext.replace('PAGENAME:', '')) | ||
+ | })); | ||
+ | |||
+ | return sources; | ||
+ | } | ||
+ | |||
+ | async function getDcts() { | ||
+ | const searchFunctions = [ | ||
+ | 'Advanced search features', | ||
+ | 'Keyword search', | ||
+ | 'Hashtag search', | ||
+ | 'Keyword monitoring', | ||
+ | 'Hashtag monitoring', | ||
+ | 'Event monitoring', | ||
+ | 'Event notifications' | ||
+ | ]; | ||
+ | const postFunctions = [ | ||
+ | 'Posting content', | ||
+ | 'Scheduling content', | ||
+ | 'Post time optimization', | ||
+ | 'Content library' | ||
+ | ]; | ||
+ | const analysisFunctions = [ | ||
+ | 'Text analysis', | ||
+ | 'Image analysis', | ||
+ | 'Video analysis', | ||
+ | 'Topic analysis', | ||
+ | 'Sentiment analysis', | ||
+ | 'Trend analysis' | ||
+ | ]; | ||
+ | const metricsFunctions = [ | ||
+ | 'Post metrics', | ||
+ | 'Profile or Site metrics', | ||
+ | 'Network metrics', | ||
+ | 'Follower metrics', | ||
+ | 'Audience metrics', | ||
+ | 'Competitor metrics' | ||
+ | ]; | ||
+ | const reportFunctions = [ | ||
+ | 'Filtering sorting searching', | ||
+ | 'Clustering Aggregation', | ||
+ | 'Visualization options', | ||
+ | 'PDF export' | ||
+ | ]; | ||
+ | const collaborationFunctions = [ | ||
+ | 'Multiuser', | ||
+ | 'Permission management', | ||
+ | 'Inbox workflow', | ||
+ | 'Approval workflows' | ||
+ | ]; | ||
+ | const interoperabilityFunctions = [ | ||
+ | 'Data export', | ||
+ | 'Third party tool integration', | ||
+ | 'API support' | ||
+ | ]; | ||
+ | const metaFunctions = [ | ||
+ | 'White Label', | ||
+ | 'GDPR compliant', | ||
+ | 'Historical data access', | ||
+ | 'Multiple accounts per platform' | ||
+ | ]; | ||
+ | |||
+ | const dctQuery = '[[Category:Disaster Community Technology]]' + | ||
+ | '[[Is Archived::No]]' + | ||
+ | '|limit=500' + | ||
+ | '|?Image' + | ||
+ | '|?Data Sources' + | ||
+ | '|?' + searchFunctions.join('|?') + | ||
+ | '|?' + postFunctions.join('|?') + | ||
+ | '|?' + analysisFunctions.join('|?') + | ||
+ | '|?' + metricsFunctions.join('|?') + | ||
+ | '|?' + reportFunctions.join('|?') + | ||
+ | '|?' + collaborationFunctions.join('|?') + | ||
+ | '|?' + interoperabilityFunctions.join('|?') + | ||
+ | '|?' + metaFunctions.join('|?'); | ||
+ | |||
+ | const dctQueryUrl = '/api.php?action=ask&format=json&query=' + encodeURIComponent(dctQuery); | ||
+ | const dctResponse = await fetch(dctQueryUrl).then(response => response.json()); | ||
+ | |||
+ | const results = dctResponse.query.results; | ||
+ | const dctList = Object.getOwnPropertyNames(results).map(dctKey => { | ||
+ | |||
+ | /** @type {DCT} */ | ||
+ | const dct = {}; | ||
+ | const dctResult = results[dctKey]; | ||
+ | dct.name = dctKey; | ||
+ | dct.url = dctResult.fullurl; | ||
+ | dct.dataSources = dctResult.printouts['Data Sources'].map(source => source.fulltext).sort(); | ||
+ | dct.logo = dctResult.printouts['Image'][0] ? getUrl(dctResult.printouts['Image'][0].fulltext) : void 0; | ||
+ | dct.functions = []; | ||
+ | |||
+ | if (hasFunction(dctResult, searchFunctions)) dct.functions.push(FN_SEARCH); | ||
+ | if (hasFunction(dctResult, postFunctions)) dct.functions.push(FN_POST); | ||
+ | if (hasFunction(dctResult, analysisFunctions)) dct.functions.push(FN_ANALYSIS); | ||
+ | if (hasFunction(dctResult, metricsFunctions)) dct.functions.push(FN_METRICS); | ||
+ | if (hasFunction(dctResult, reportFunctions)) dct.functions.push(FN_REPORT); | ||
+ | if (hasFunction(dctResult, collaborationFunctions)) dct.functions.push(FN_COLLAB); | ||
+ | if (hasFunction(dctResult, interoperabilityFunctions)) dct.functions.push(FN_INTEROP); | ||
+ | if (hasFunction(dctResult, metaFunctions)) dct.functions.push(FN_META); | ||
+ | |||
+ | return dct; | ||
+ | }); | ||
+ | |||
+ | return dctList; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @param {DCT} dct | ||
+ | * @param {Partial<DCT>} filterState | ||
+ | */ | ||
+ | function dctFilter(dct, filterState) { | ||
+ | // 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. | ||
+ | const sourcesCheck = filterState.dataSources | ||
+ | ? dct.dataSources.some(source => filterState.dataSources.includes(source)) | ||
+ | : true; | ||
+ | const functionsCheck = filterState.functions | ||
+ | ? dct.functions.some(func => filterState.functions.includes(func)) | ||
+ | : true; | ||
+ | return sourcesCheck && functionsCheck; | ||
+ | } | ||
+ | |||
+ | function applyFilters(clear) { | ||
+ | if (!table) return; | ||
+ | |||
+ | // If clear=true, pass empty object to the filter to disable it. | ||
+ | if (clear) { | ||
+ | table.setFilter(dctFilter, {}); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | /** @type {Partial<DCT>} */ | ||
+ | const filterState = {}; | ||
+ | |||
+ | const selectedFunctions = Array.from(document.querySelectorAll('#functions-filter input[type="checkbox"]:checked')).map(checkbox => checkbox.value); | ||
+ | filterState.functions = selectedFunctions; | ||
+ | |||
+ | const selectedSources = Array.from(document.querySelectorAll('#data-source-filter input[type="checkbox"]:checked')).map(checkbox => checkbox.value); | ||
+ | filterState.dataSources = selectedSources; | ||
+ | |||
+ | table.setFilter(dctFilter, filterState); | ||
+ | } | ||
+ | |||
+ | // Load data and build page. | ||
+ | Promise.all([getSources(), getDcts()]).then(data => { | ||
+ | const dataSources = data[0]; | ||
+ | const dcts = data[1]; | ||
+ | |||
+ | // Set up filters. | ||
+ | const functionFilterHtml = Object.getOwnPropertyNames(fnImages).reduce((acc, funcName) => { | ||
+ | const identifier = escapeAttr(funcName); | ||
+ | return acc + '<div><input type="checkbox" id="func-filter-' + identifier + '" value="' + funcName + '" checked>' + | ||
+ | '<label for="func-filter-' + identifier + '"><img src="' + fnImages[funcName] + '"> ' + funcName + '</label></div>' | ||
+ | }, ''); | ||
+ | document.getElementById('functions-filter').innerHTML = functionFilterHtml; | ||
− | + | const groupedSources = []; | |
− | + | const sourcesCopy = Array.from(dataSources); | |
− | + | for (const layoutGroup of sourcesLayout) { | |
− | const | + | const group = []; |
− | + | for (const source of layoutGroup.sources) { | |
+ | let idx = sourcesCopy.findIndex(src => src.name === source); | ||
+ | if (idx !== -1) { group.push(sourcesCopy.splice(idx, 1)[0]); } | ||
+ | } | ||
+ | if (group.length > 0) { groupedSources.push({ title: layoutGroup.title, sources: group }); } | ||
} | } | ||
− | + | groupedSources.push({ title: 'More platforms', sources: sourcesCopy }); | |
+ | |||
+ | let dataSourceFilterHtml = ''; | ||
+ | groupedSources.forEach(group => { | ||
+ | dataSourceFilterHtml += '<div class="filter-group-header">' + group.title + '</div>'; | ||
+ | dataSourceFilterHtml += group.sources.reduce((acc, curr, idx) => { | ||
+ | const identifier = escapeAttr(curr.name); | ||
+ | return acc + | ||
+ | '<div ' + (idx === 0 ? ' class="filter-group-start">' : '>') + | ||
+ | '<input type="checkbox" id="filter-' + identifier + '" value="' + curr.name + '" checked>' + | ||
+ | '<label for="filter-' + identifier + '"><img src="' + curr.image + '"> ' + curr.name + '</label></div>' | ||
+ | }, ''); | ||
+ | }) | ||
+ | document.getElementById('data-source-filter').innerHTML = dataSourceFilterHtml; | ||
+ | |||
+ | // 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: 'Functions', | ||
+ | field: 'functions', | ||
+ | cssClass: 'functions-cell', | ||
+ | formatter: function (cell) { | ||
+ | const output = cell.getValue() | ||
+ | .map(func => '<img class="func-img" src="' + fnImages[func] + | ||
+ | '" data-value="' + func + | ||
+ | '" alt="' + func + | ||
+ | '" title="' + func + | ||
+ | '">') | ||
+ | .join(''); | ||
+ | return output; | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | title: 'Supported Platforms', | ||
+ | field: 'dataSources', | ||
+ | cssClass: 'data-sources-cell', | ||
+ | formatter: function (cell) { | ||
+ | const val = cell.getValue(); | ||
+ | let out = ''; | ||
+ | groupedSources.forEach((group, gIndex) => { | ||
+ | // out += '<div>'; | ||
+ | out += group.sources.reduce((prev, curr) => { | ||
+ | const idx = val.findIndex(src => src === curr.name); | ||
+ | if (idx === -1) { | ||
+ | return prev // + '<div class="source-img-placeholder"> </div>' | ||
+ | } else { | ||
+ | return curr.image | ||
+ | ? prev + '<img class="data-source-img" data-value="' + curr.name + '" src="' + curr.image + '" alt="' + curr.name +'" title="' + curr.name + '">' | ||
+ | : prev + ' ' + curr; | ||
+ | } | ||
+ | }, ''); | ||
+ | // out += '</div>'; | ||
+ | }); | ||
+ | return out; | ||
+ | } | ||
+ | } | ||
+ | ] | ||
+ | }); | ||
+ | |||
+ | tabulator.on('tableBuilt', () => { | ||
+ | tabulator.setData(dcts); | ||
+ | table = tabulator; | ||
+ | }); | ||
+ | |||
+ | tabulator.on('dataFiltered', (filters, rows) => { | ||
+ | if (!(filters[0] && filters[0].type)) { return; } | ||
+ | |||
+ | const markImages = () => { | ||
+ | const selectedSources = filters[0].type.dataSources; | ||
+ | const selectedFunctions = filters[0].type.functions; | ||
+ | |||
+ | // Mark data source images | ||
+ | document.querySelectorAll('.data-sources-cell .data-source-img').forEach(img => { | ||
+ | if (!selectedSources || selectedSources.includes(img.dataset.value)) { img.classList.remove('unselected'); } | ||
+ | else { img.classList.add('unselected'); } | ||
+ | }); | ||
+ | |||
+ | // Mark functions images | ||
+ | document.querySelectorAll('.functions-cell .func-img').forEach(img => { | ||
+ | if (!selectedFunctions || selectedFunctions.includes(img.dataset.value)) { img.classList.remove('unselected'); } | ||
+ | else { img.classList.add('unselected'); } | ||
+ | }); | ||
− | + | tabulator.off('renderComplete', markImages); | |
− | + | } | |
− | + | tabulator.on('renderComplete', markImages); | |
− | + | }); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | document.getElementById('data-source-filter').addEventListener('change', event => { | |
− | + | applyFilters(); | |
− | + | }, { passive: true }); | |
− | + | document.getElementById('functions-filter').addEventListener('change', event => { | |
+ | applyFilters(); | ||
+ | }, { passive: true }); | ||
+ | }); | ||
− | + | function selectAll(context) { | |
− | + | document.querySelectorAll(context + ' input[type="checkbox"]').forEach(checkbox => checkbox.checked = true); | |
− | + | applyFilters(); | |
− | + | } | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | function deselectAll(context) { | |
− | + | document.querySelectorAll(context + ' input[type="checkbox"]').forEach(checkbox => checkbox.checked = false); | |
− | + | applyFilters(); | |
− | + | } | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | function clearFilters() { | |
− | + | document.querySelectorAll('#dct-filters input[type="checkbox').forEach(checkbox => checkbox.checked = checkbox.defaultChecked); | |
− | + | applyFilters(true); | |
− | + | } | |
− | + | </script> | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | <div id="dct-list-wrapper"> | ||
+ | <h1> | ||
+ | <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" overflow="hidden" viewBox="0 0 96 96"><defs><clipPath id="a"><path d="M65 334h96v96H65z"/></clipPath></defs><g clip-path="url(#a)" transform="translate(-65 -334)"><path d="m142 395.981.004-35.993H84.001v36.01Zm-55.999-33.993h54.003L140 393.981l-53.999.017Z"/><path d="M81.001 358.987a2.002 2.002 0 0 1 2-2h60.003a2.002 2.002 0 0 1 2 2V400h2v-41.013a4.003 4.003 0 0 0-4-4H83.001a4.003 4.003 0 0 0-4 4V400h2ZM118.003 402.981v2h-10.001v-2H67v1.999a5.006 5.006 0 0 0 5 5.001h82.004a5.006 5.006 0 0 0 5.001-5.001v-1.999Zm36.001 5H72a3.004 3.004 0 0 1-3-3h37.002a1.934 1.934 0 0 0 2 2h10.001a1.934 1.934 0 0 0 2-2h37.002a3.005 3.005 0 0 1-3.001 3Z"/><path d="M113 365c-7.18 0-13 5.82-13 13s5.82 13 13 13 13-5.82 13-13c-.008-7.176-5.824-12.992-13-13Zm10.949 12h-3.518a14.167 14.167 0 0 0-4.176-9.508 11.023 11.023 0 0 1 7.694 9.508ZM112 368.226V377h-4.426c.254-3.771 1.929-7.06 4.426-8.774ZM112 379v8.775c-2.494-1.717-4.17-5.017-4.425-8.775Zm2 8.774V379h4.425c-.255 3.754-1.932 7.056-4.425 8.774ZM114 377v-8.773c2.492 1.718 4.17 5.019 4.425 8.773Zm-4.273-9.502a14.124 14.124 0 0 0-4.158 9.502h-3.518a11.02 11.02 0 0 1 7.676-9.502ZM102.051 379h3.518a14.157 14.157 0 0 0 4.173 9.507 11.022 11.022 0 0 1-7.691-9.507Zm14.205 9.508a14.168 14.168 0 0 0 4.175-9.508h3.518a11.023 11.023 0 0 1-7.693 9.508Z"/></g></svg> | ||
+ | <span>Technologies</span> | ||
+ | </h1> | ||
+ | <div id="dct-intro"> | ||
− | < | + | <p>This page provides an overview of various Technologies related to Social Media and Crowdsourcing. You can use the filters to identify |
− | < | + | relevant technologies according to your needs and then click on the name of a tool to get further information.</p> |
− | + | </div> | |
− | + | <div id="dct-filters"> | |
− | + | <h2> | |
− | </ | + | <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" overflow="hidden" viewBox="0 0 96 96"><defs><clipPath id="b"><path d="M592 312h96v96h-96z"/></clipPath></defs><g clip-path="url(#b)" transform="translate(-592 -312)"><path d="M636 356.012v38.011l8-8v-30.011L674 326h-68Zm6.588-1.412-.588.584v30.008l-4 4v-34.008l-.585-.586L610.828 328h58.348Z"/></g></svg> |
− | <div class=" | + | <span>Filters</span> |
− | < | + | </h2> |
− | < | + | <div style="text-align: center;"> |
− | + | <button id="clear-filters-button" type="button" onclick="clearFilters()">Clear Filters</button> | |
− | + | </div> | |
+ | <div class="filter-wrapper"> | ||
+ | <h3>Functions</h3> | ||
+ | <div class="filter-button-wrapper"> | ||
+ | <button type="button" onclick="selectAll('#functions-filter')">Select all</button> | | ||
+ | <button type="button" onclick="deselectAll('#functions-filter')">Deselect all</button> | ||
</div> | </div> | ||
+ | <div class="filter-content" id="functions-filter" ></div> | ||
</div> | </div> | ||
− | + | <div class="filter-wrapper"> | |
− | + | <h3>Supported Platforms</h3> | |
− | + | <div class="filter-button-wrapper"> | |
− | + | <button type="button" onclick="selectAll('#data-source-filter')">Select all</button> | | |
− | + | <button type="button" onclick="deselectAll('#data-source-filter')">Deselect all</button> | |
− | |||
− | |||
− | < | ||
− | |||
− | |||
− | < | ||
− | |||
− | |||
− | |||
</div> | </div> | ||
+ | <div class="filter-content" id="data-source-filter"></div> | ||
</div> | </div> | ||
− | </div></div></includeonly> | + | </div> |
+ | <div id="dct-tabulator"></div> | ||
+ | </div> | ||
+ | </includeonly> |
Revision as of 13:34, 30 June 2022
Development verstion of the DCT List.
Not ready for production!