Difference between revisions of "Widget:UseCaseList"
From LINKS Community Center
(27 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | <noinclude>Current version of the List of Use Cases.<br><strong style="color:red;"> | + | <noinclude>Current version of the List of Use Cases.<br><strong style="color:red;">Currently in use – do not modify!</strong> |
</noinclude> | </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> | ||
#usecase-list-wrapper { | #usecase-list-wrapper { | ||
Line 234: | Line 234: | ||
#usecase-tabulator.tabulator .tabulator-row .tabulator-responsive-collapse td>strong { | #usecase-tabulator.tabulator .tabulator-row .tabulator-responsive-collapse td>strong { | ||
font-weight: 300; | font-weight: 300; | ||
+ | } | ||
+ | |||
+ | #usecase-tabulator.tabulator .usecase-title { | ||
+ | white-space: normal !important; | ||
} | } | ||
Line 239: | Line 243: | ||
#usecase-tabulator.tabulator .tabulator-responsive-collapse table a { | #usecase-tabulator.tabulator .tabulator-responsive-collapse table a { | ||
color: var(--links-cyan); | color: var(--links-cyan); | ||
+ | } | ||
+ | |||
+ | .uc-summary { | ||
+ | font-size: smaller; | ||
+ | padding-bottom: 1em; | ||
} | } | ||
</style> | </style> | ||
Line 268: | Line 277: | ||
const SCALE_PROP = 'Scale'; | const SCALE_PROP = 'Scale'; | ||
const CAT_PROP = 'Use Cases Category'; | const CAT_PROP = 'Use Cases Category'; | ||
− | const EVENT_PROP = 'Event type' | + | const EVENT_PROP = 'Event type'; |
+ | const SUMMARY_PROP = 'Description'; | ||
+ | const IMAGES_PROP = 'Other images'; | ||
+ | const PUB_PROP = 'Publishing Organisation'; | ||
+ | const INVOLVED_PROP = 'Involved Organisations'; | ||
const useCaseQuery = '[[Category:Use Cases]]' | const useCaseQuery = '[[Category:Use Cases]]' | ||
Line 277: | Line 290: | ||
+ '|?' + EVENT_PROP | + '|?' + EVENT_PROP | ||
+ '|?' + CAT_PROP | + '|?' + CAT_PROP | ||
+ | + '|?' + SUMMARY_PROP | ||
+ | + '|?' + IMAGES_PROP | ||
+ | + '|?' + PUB_PROP | ||
+ | + '|?' + INVOLVED_PROP | ||
+ '|?' + YEAR_PROP; | + '|?' + YEAR_PROP; | ||
async function getUseCases() { | async function getUseCases() { | ||
const useCasesResponse = await fetch(getQueryUrl(useCaseQuery)).then(response => response.json()); | const useCasesResponse = await fetch(getQueryUrl(useCaseQuery)).then(response => response.json()); | ||
+ | |||
+ | console.log(useCasesResponse) | ||
return Object.keys(useCasesResponse.query.results).map(title => { | return Object.keys(useCasesResponse.query.results).map(title => { | ||
Line 295: | Line 314: | ||
useCase[SCALE_PROP] = useCaseResult.printouts[SCALE_PROP].map(value => value.fulltext); | useCase[SCALE_PROP] = useCaseResult.printouts[SCALE_PROP].map(value => value.fulltext); | ||
useCase[EVENT_PROP] = useCaseResult.printouts[EVENT_PROP].map(value => value.fulltext); | useCase[EVENT_PROP] = useCaseResult.printouts[EVENT_PROP].map(value => value.fulltext); | ||
+ | useCase[PUB_PROP] = useCaseResult.printouts[PUB_PROP].map(value => value.fulltext); | ||
+ | useCase[INVOLVED_PROP] = useCaseResult.printouts[INVOLVED_PROP].map(value => value.fulltext); | ||
+ | useCase[SUMMARY_PROP] = useCaseResult.printouts[SUMMARY_PROP][0]; | ||
useCase[YEAR_PROP] = useCaseResult.printouts[YEAR_PROP][0] && useCaseResult.printouts[YEAR_PROP][0].raw.slice(-4); | useCase[YEAR_PROP] = useCaseResult.printouts[YEAR_PROP][0] && useCaseResult.printouts[YEAR_PROP][0].raw.slice(-4); | ||
return useCase; | return useCase; | ||
Line 314: | Line 336: | ||
const filterState = {}; | const filterState = {}; | ||
− | const | + | const selectedTypes = Array.from(document.querySelectorAll('#type-filter input[type="checkbox"]:checked')) |
− | + | .map(checkbox => checkbox.value); | |
− | filterState.type = | + | if (selectedTypes.length > 0) filterState.type = selectedTypes; |
− | const | + | const selectedEvents = Array.from(document.querySelectorAll('#event-type-filter input[type="checkbox"]:checked')) |
− | + | .map(checkbox => checkbox.value); | |
− | filterState.eventType = | + | if (selectedEvents.length > 0) filterState.eventType = selectedEvents; |
− | const | + | const selectedCats = Array.from(document.querySelectorAll('#category-filter input[type="checkbox"]:checked')) |
− | + | .map(checkbox => checkbox.value); | |
− | filterState.category = | + | if (selectedCats.length > 0) filterState.category = selectedCats; |
− | const | + | const selectedScales = Array.from(document.querySelectorAll('#scale-filter input[type="checkbox"]:checked')) |
− | + | .map(checkbox => checkbox.value); | |
− | filterState.scale = | + | if (selectedScales.length > 0) filterState.scale = selectedScales; |
− | const | + | const selectedThematics = Array.from(document.querySelectorAll('#thematic-filter input[type="checkbox"]:checked')) |
− | + | .map(checkbox => checkbox.value); | |
− | filterState.thematics = | + | if (selectedThematics.length > 0) filterState.thematics = selectedThematics; |
− | const | + | const selectedPhases = Array.from(document.querySelectorAll('#phases-filter input[type="checkbox"]:checked')) |
− | + | .map(checkbox => checkbox.value); | |
− | filterState.phases = | + | if (selectedPhases.length > 0) filterState.phases = selectedPhases; |
table.setFilter(useCaseFilter, filterState); | table.setFilter(useCaseFilter, filterState); | ||
Line 351: | Line 373: | ||
const typeCheck = filterState.type | const typeCheck = filterState.type | ||
− | ? | + | ? filterState.type.every(type => useCase[TYPE_PROP].includes(type)) |
: true; | : true; | ||
const eventTypeCheck = filterState.eventType | const eventTypeCheck = filterState.eventType | ||
− | ? | + | ? filterState.eventType.every(event => useCase[EVENT_PROP].includes(event)) |
: true; | : true; | ||
const categoryCheck = filterState.category | const categoryCheck = filterState.category | ||
− | ? useCase[CAT_PROP] | + | ? filterState.category.every(cat => useCase[CAT_PROP].includes(cat)) |
: true; | : true; | ||
const scaleCheck = filterState.scale | const scaleCheck = filterState.scale | ||
− | ? useCase[SCALE_PROP]. | + | ? filterState.scale.every(scale => useCase[SCALE_PROP].includes(scale)) |
: true; | : true; | ||
const thematicCheck = filterState.thematics | const thematicCheck = filterState.thematics | ||
− | ? useCase[THEME_PROP] | + | ? filterState.thematics.every(thematic => useCase[THEME_PROP].includes(thematic)) |
: true; | : true; | ||
const phaseCheck = filterState.phases | const phaseCheck = filterState.phases | ||
− | ? | + | ? filterState.phases.every(phase => useCase[PHASE_PROP].includes(phase)) |
: true; | : true; | ||
return typeCheck && eventTypeCheck && categoryCheck && scaleCheck && thematicCheck && phaseCheck; | return typeCheck && eventTypeCheck && categoryCheck && scaleCheck && thematicCheck && phaseCheck; | ||
Line 373: | Line 395: | ||
Promise.all([getUseCases()]).then(data => { | Promise.all([getUseCases()]).then(data => { | ||
const useCases = data[0]; | const useCases = data[0]; | ||
+ | console.log(useCases) | ||
let THEME_VALUES = [] | let THEME_VALUES = [] | ||
Line 413: | Line 436: | ||
const identifier = escapeAttr(curr); | const identifier = escapeAttr(curr); | ||
return acc | return acc | ||
− | + '<div><input type="checkbox" | + | + '<div><input type="checkbox" id="type-filter-' + identifier |
+ '" value="' + curr + '">' | + '" value="' + curr + '">' | ||
+ '<label for="type-filter-' + identifier + '">' + curr + '</label></div>' | + '<label for="type-filter-' + identifier + '">' + curr + '</label></div>' | ||
Line 422: | Line 445: | ||
const identifier = escapeAttr(curr); | const identifier = escapeAttr(curr); | ||
return acc | return acc | ||
− | + '<div><input type="checkbox" | + | + '<div><input type="checkbox" id="event-type-filter-' + identifier |
+ '" value="' + curr + '">' | + '" value="' + curr + '">' | ||
+ '<label for="event-type-filter-' + identifier + '">' + curr + '</label></div>' | + '<label for="event-type-filter-' + identifier + '">' + curr + '</label></div>' | ||
Line 431: | Line 454: | ||
const identifier = escapeAttr(curr); | const identifier = escapeAttr(curr); | ||
return acc | return acc | ||
− | + '<div><input type="checkbox" | + | + '<div><input type="checkbox" id="category-filter-' + identifier |
+ '" value="' + curr + '">' | + '" value="' + curr + '">' | ||
+ '<label for="category-filter-' + identifier + '">' + curr + '</label></div>' | + '<label for="category-filter-' + identifier + '">' + curr + '</label></div>' | ||
Line 440: | Line 463: | ||
const identifier = escapeAttr(curr); | const identifier = escapeAttr(curr); | ||
return acc | return acc | ||
− | + '<div><input type="checkbox" | + | + '<div><input type="checkbox" id="scale-filter-' + identifier |
+ '" value="' + curr + '">' | + '" value="' + curr + '">' | ||
+ '<label for="scale-filter-' + identifier + '">' + curr + '</label></div>' | + '<label for="scale-filter-' + identifier + '">' + curr + '</label></div>' | ||
Line 449: | Line 472: | ||
const identifier = escapeAttr(curr); | const identifier = escapeAttr(curr); | ||
return acc | return acc | ||
− | + '<div><input type="checkbox" | + | + '<div><input type="checkbox" id="phases-filter-' + identifier |
+ '" value="' + curr + '">' | + '" value="' + curr + '">' | ||
+ '<label for="phases-filter-' + identifier + '">' + curr + '</label></div>' | + '<label for="phases-filter-' + identifier + '">' + curr + '</label></div>' | ||
Line 458: | Line 481: | ||
const identifier = escapeAttr(curr); | const identifier = escapeAttr(curr); | ||
return acc | return acc | ||
− | + '<div><input type="checkbox" | + | + '<div><input type="checkbox" id="thematic-filter-' + identifier |
+ '" value="' + curr + '">' | + '" value="' + curr + '">' | ||
+ '<label for="thematic-filter-' + identifier + '">' + curr + '</label></div>' | + '<label for="thematic-filter-' + identifier + '">' + curr + '</label></div>' | ||
Line 474: | Line 497: | ||
field: 'title', | field: 'title', | ||
cssClass: 'usecase-title', | cssClass: 'usecase-title', | ||
− | formatter: cell = | + | formatter: function (cell) { |
− | + | let out = '<a href="' + cell.getData().url + '">' + cell.getValue() + '</a>'; | |
+ | out += '<div class="uc-summary">' + cell.getData()[SUMMARY_PROP] + '</div>'; | ||
+ | return out; | ||
+ | }, | ||
+ | maxWidth: '850px' | ||
}, | }, | ||
{ | { | ||
Line 483: | Line 510: | ||
}, | }, | ||
{ | { | ||
− | title: ' | + | title: 'Publisher', |
+ | field: PUB_PROP, | ||
+ | formatter: cell => cell.getValue().join(', ') | ||
+ | }, | ||
+ | { | ||
+ | title: 'Theme', | ||
field: TYPE_PROP, | field: TYPE_PROP, | ||
formatter: cell => cell.getValue().join(', ') | formatter: cell => cell.getValue().join(', ') | ||
}, | }, | ||
{ | { | ||
− | title: ' | + | title: 'Hazard', |
field: EVENT_PROP, | field: EVENT_PROP, | ||
− | formatter: cell => cell.getValue().join(', ') | + | formatter: cell => cell.getValue().join(', ') || '—' |
}, | }, | ||
{ | { | ||
Line 517: | Line 549: | ||
title: 'Disaster Management Phase', | title: 'Disaster Management Phase', | ||
field: PHASE_PROP, | field: PHASE_PROP, | ||
+ | formatter: cell => cell.getValue().join(', ') | ||
+ | }, | ||
+ | { | ||
+ | title: 'Involved Organisations', | ||
+ | field: INVOLVED_PROP, | ||
formatter: cell => cell.getValue().join(', ') | formatter: cell => cell.getValue().join(', ') | ||
} | } | ||
Line 528: | Line 565: | ||
tabulator.on('tableBuilt', () => { | tabulator.on('tableBuilt', () => { | ||
tabulator.redraw(true); | tabulator.redraw(true); | ||
− | |||
table = tabulator; | table = tabulator; | ||
+ | |||
+ | // Set up the table if parameter was passed. | ||
+ | const params = new URLSearchParams(window.location.search); | ||
+ | const encoded = params.get('do'); | ||
+ | |||
+ | if (encoded) { | ||
+ | const actions = JSON.parse(decodeURIComponent(atob(encoded))); | ||
+ | const filter = actions.filter; | ||
+ | |||
+ | if (filter) { | ||
+ | const thematic = filter[THEME_PROP]; | ||
+ | if (thematic) { | ||
+ | Object.keys(thematic).forEach(theme => { | ||
+ | const box = document.getElementById('thematic-filter-' + escapeAttr(theme)); | ||
+ | box.checked = !!thematic[theme]; | ||
+ | box.dispatchEvent(new Event('change', { bubbles: true })); | ||
+ | }); | ||
+ | |||
+ | document.getElementById('thematic-filter').closest('.filter-wrapper').classList.toggle('open'); | ||
+ | } | ||
+ | |||
+ | const type = filter[TYPE_PROP]; | ||
+ | if (type) { | ||
+ | Object.keys(type).forEach(tp => { | ||
+ | const box = document.getElementById('type-filter-' + escapeAttr(tp)); | ||
+ | box.checked = !!type[tp]; | ||
+ | box.dispatchEvent(new Event('change', { bubbles: true })); | ||
+ | }); | ||
+ | |||
+ | document.getElementById('type-filter').closest('.filter-wrapper').classList.toggle('open'); | ||
+ | } | ||
+ | |||
+ | applyFilters(); | ||
+ | toggleFilter(); | ||
+ | } | ||
+ | |||
+ | // Further actions (e.g. open filter panel, etc.) | ||
+ | // ... | ||
+ | } | ||
}); | }); | ||
Line 541: | Line 616: | ||
// Exit if filter object/type doesn't exist (happens after Tabulator's own filter reset). | // Exit if filter object/type doesn't exist (happens after Tabulator's own filter reset). | ||
if (!(filter && filter.type)) { summary.textContent = 'No filter. Showing all results.'; return; } | if (!(filter && filter.type)) { summary.textContent = 'No filter. Showing all results.'; return; } | ||
− | |||
− | |||
− | |||
// Update filter text. | // Update filter text. | ||
Line 557: | Line 629: | ||
let summaryHtml = '<table>'; | let summaryHtml = '<table>'; | ||
if (filter.type.type) { | if (filter.type.type) { | ||
− | summaryHtml += '<tr><td><strong> | + | summaryHtml += '<tr><td><strong>Theme</strong></td><td>' |
+ (filter.type.type.length > 0 ? filter.type.type.join(', ') : 'none') | + (filter.type.type.length > 0 ? filter.type.type.join(', ') : 'none') | ||
+ '</td></tr>'; | + '</td></tr>'; | ||
} | } | ||
if (filter.type.eventType) { | if (filter.type.eventType) { | ||
− | summaryHtml += '<tr><td><strong> | + | summaryHtml += '<tr><td><strong>Hazard</strong></td><td>' |
+ (filter.type.eventType.length > 0 ? filter.type.eventType.join(', ') : 'none') | + (filter.type.eventType.length > 0 ? filter.type.eventType.join(', ') : 'none') | ||
+ '</td></tr>'; | + '</td></tr>'; | ||
Line 633: | Line 705: | ||
tabulator.on('renderComplete', function () { | tabulator.on('renderComplete', function () { | ||
// TODO: Check the bugfix for a possible infinite event loop. | // TODO: Check the bugfix for a possible infinite event loop. | ||
− | |||
− | |||
try { | try { | ||
Line 704: | Line 774: | ||
<div id="filter-summary">No filter. Showing all results.</div> | <div id="filter-summary">No filter. Showing all results.</div> | ||
</div> | </div> | ||
− | <div | + | <div> |
− | <button class="large-button" type="button" onclick="toggleFilter()">Filters</button> | + | <button class="large-button" type="button" onclick="toggleFilter()">Open Filters</button> |
</div> | </div> | ||
</div> | </div> | ||
− | < | + | <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:Use_Cases" style="font-size: 1.5em; font-variant:small-caps; color: var(--links-cyan)">Add new use case</a></div> | ||
+ | </div> | ||
<div id="uc-filters"> | <div id="uc-filters"> | ||
Line 731: | Line 804: | ||
</h2> | </h2> | ||
<div style="text-align: center;"> | <div style="text-align: center;"> | ||
− | <button class="large-button" type="button" onclick="clearFilters()"> | + | <button class="large-button" type="button" onclick="clearFilters()">Clear Filters</button> |
</div> | </div> | ||
<div class="filter-wrapper"> | <div class="filter-wrapper"> | ||
− | <h4 class="filter-toggle"> | + | <h4 class="filter-toggle">Theme <div class="plus icon"></div></h4> |
− | |||
<div class="filter-container"> | <div class="filter-container"> | ||
<div class="filter-button-wrapper"> | <div class="filter-button-wrapper"> | ||
Line 745: | Line 817: | ||
</div> | </div> | ||
<div class="filter-wrapper"> | <div class="filter-wrapper"> | ||
− | <h4 class="filter-toggle"> | + | <h4 class="filter-toggle">Hazard <div class="plus icon"></div></h4> |
− | |||
<div class="filter-container"> | <div class="filter-container"> | ||
<div class="filter-button-wrapper"> | <div class="filter-button-wrapper"> | ||
Line 756: | Line 827: | ||
</div> | </div> | ||
<div class="filter-wrapper"> | <div class="filter-wrapper"> | ||
− | <h4 class="filter-toggle">Category <div class="plus icon"></div> | + | <h4 class="filter-toggle">Category <div class="plus icon"></div></h4> |
− | |||
<div class="filter-container"> | <div class="filter-container"> | ||
<div class="filter-button-wrapper"> | <div class="filter-button-wrapper"> | ||
Line 767: | Line 837: | ||
</div> | </div> | ||
<div class="filter-wrapper"> | <div class="filter-wrapper"> | ||
− | <h4 class="filter-toggle">Scale <div class="plus icon"></div> | + | <h4 class="filter-toggle">Scale <div class="plus icon"></div></h4> |
− | |||
<div class="filter-container"> | <div class="filter-container"> | ||
<div class="filter-button-wrapper"> | <div class="filter-button-wrapper"> | ||
Line 778: | Line 847: | ||
</div> | </div> | ||
<div class="filter-wrapper"> | <div class="filter-wrapper"> | ||
− | <h4 class="filter-toggle">Thematic <div class="plus icon"></div> | + | <h4 class="filter-toggle">Thematic <div class="plus icon"></div></h4> |
− | |||
<div class="filter-container"> | <div class="filter-container"> | ||
<div class="filter-button-wrapper"> | <div class="filter-button-wrapper"> | ||
Line 789: | Line 857: | ||
</div> | </div> | ||
<div class="filter-wrapper"> | <div class="filter-wrapper"> | ||
− | <h4 class="filter-toggle">Disaster Management Phase <div class="plus icon"></div> | + | <h4 class="filter-toggle">Disaster Management Phase <div class="plus icon"></div></h4> |
− | |||
<div class="filter-container"> | <div class="filter-container"> | ||
<div class="filter-button-wrapper"> | <div class="filter-button-wrapper"> |
Latest revision as of 12:29, 13 October 2023
Current version of the List of Use Cases.
Currently in use – do not modify!