MediaWiki:OrgActionList.js: Difference between revisions
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
ORIGIN = 'http://localhost:8000' | ORIGIN = 'http://localhost:8000' | ||
API_URL = 'https://164-92-142-113.nip.io/api.php' | API_URL = 'https://164-92-142-113.nip.io/api.php' | ||
var actions = []; | var actions = []; |
Revision as of 07:20, 7 January 2023
ORIGIN = 'http://localhost:8000'
API_URL = 'https://164-92-142-113.nip.io/api.php'
var actions = [];
var progressItems = {};
var orgs = {}
var org_name = null
var lang = 'fi'
var highlightedTerm = null
var highlights = null
var hightlightIndex = 0
class_map = {
'Tutkimusjulkaisut': 'field-border-1',
'Toimintakulttuuri': 'field-border-2',
'Oppiminen' : 'field-border-3',
'Data' : 'field-border-4'
}
color_map = {
'Tutkimusjulkaisut': '#007ECA',
'Toimintakulttuuri': '#53BD9D',
'Oppiminen' : '#93A0FF',
'Data' : '#003EAD'
}
const scrollObserver = new IntersectionObserver(
([e]) => e.target.classList.toggle('stuck', e.intersectionRatio < 1),
{threshold: [1]}
);
//observer.observe(document.querySelector('.rowgroup-header'));
function prevMatch() {
var searchword = $("#searchtxt").val();
if(searchword != '') {
$('#overview_actions').addClass('search')
if( hightlightIndex > 0) {
hightlightIndex--
}
replaceText()
}
}
function nextMatch() {
var searchword = $("#searchtxt").val();
if(searchword != '') {
$('#overview_actions').addClass('search')
replaceText()
if(hightlightIndex < highlights.length -1) {
hightlightIndex++
}
}
}
function replaceText() {
var searchword = $("#searchtxt").val();
console.log(hightlightIndex)
if(searchword != highlightedTerm) {
highlightedTerm = searchword
hightlightIndex = 0
$(".card-body").find(".highlight").removeClass("highlight");
var custfilter = new RegExp(searchword, "ig");
var repstr = "<span class='highlight'>" + searchword + "</span>";
if (searchword != "") {
$('.card-body').each(function() {
$(this).html($(this).html().replace(custfilter, repstr));
})
}
highlights = $('.highlight')
if(highlights.length >0) {
highlights[hightlightIndex].scrollIntoView()
$('html, body').animate({scrollTop: '-=70px'}, 0);
}
}
else {
highlights[hightlightIndex].scrollIntoView()
$('html, body').animate({scrollTop: '-=70px'}, 0);
}
$('#numOfMatches').text((hightlightIndex + 1) + '/' + highlights.length)
}
function clearSearch() {
$("#searchtxt").val('');
$('#overview_actions').removeClass('search')
$(".card-body").find(".highlight").removeClass("highlight");
hightlightIndex = 0
$('#numOfMatches').text('')
}
function getSelectedCheckboxes(selector) {
var selected = new Set()
$(selector + ' input:checked').each(function () {
selected.add($(this).val());
});
return selected
}
function getSelectedRadio(selector) {
return $(selector + ' input:checked').val()
}
function getSelectedOptions(selector) {
var selected = new Set();
$(selector + ' option:selected').each(function () {
selected.add($(this).val());
});
return selected
}
function updateActionView() {
$('#org_actions').text('')
var domains = getSelectedOptions('#domains')
var years = getSelectedOptions('#years')
var actors = getSelectedOptions('#actors')
var select_orgs = getSelectedOptions('#orgs')
console.log(domains)
console.log(years)
console.log(select_orgs)
console.log(actors)
if(select_orgs.size > 0) {
$('#intro').hide()
}
else {
$('#intro').show()
}
// filter actions based on selections
filtered_actions = filterActions(domains, years)
console.log(filtered_actions)
// render
var column_grouping = 'org' //getSelectedOptions('#col_grouping').values().next().value
var row_grouping = 'none' // getSelectedOptions('#row_grouping').values().next().value
console.log(row_grouping)
console.log(column_grouping)
// get a set of actors for each selected org
org_actors = []
select_orgs.forEach(businessID => {
businessID = '' + businessID
console.log(orgs)
var org_name = orgs[businessID].name
var actors = orgs[businessID].responsible_actors.map(re => re.id)
console.log(org_name)
console.log(actors)
org_actors.push({
'name': org_name,
'id': businessID,
'actors': actors
})
})
$('#selected-orgs-row').text('')
if(org_actors.length > 0) {
grouped_actions = groupActions(filtered_actions, org_actors)
renderActionHeader(org_actors)
renderActions(grouped_actions, org_actors)
document.querySelectorAll('.rowgroup-header').forEach(function(e) {
scrollObserver.observe(e)
});
}
}
function renderActionHeader(org_actors) {
org_actors.forEach(org_actor => {
var col = $('<div>', {class:'col'}).html('<h1>' + org_actor.name + '</h1>')
$('#selected-orgs-row').append(col)
})
}
function getSortedKeys(dictonary) {
var sorted = [];
for(var key in dictonary) {
sorted[sorted.length] = key;
}
sorted.sort();
return sorted
}
function renderActions(actions, org_actors) {
for(var year = 2020; year < 2026; year++) {
if((''+year in actions)) {
var group = actions[year]
var year_container = $('<div>', {id: 'year' + year, class: 'year-container'})
var year_header_container = $('<div>', {class: 'sticky-top', style:'z-index: 5; background-color: white'})
var year_header = $('<div>', {id: 'year'+ year+'-header', class: 'year-header '}).html('<h1 class="year">'+year+'</h1>')
year_container.append(year_header_container)
year_header_container.append(year_header)
$('#nav-item-year' + year).show()
var colContainer = $('<div>', {class:'container-fluid'})
var colRow = $('<div>', {class: 'row'})
org_actors.forEach(org_actor => {
var colTitle = org_actor.name
var colCol = $('<div>', {class: 'col'})
if(Array.isArray(group[colTitle])) {
//var colgroup_header = $('<div>', {class: 'colgroup-header'}).html('<h2>'+colTitle+'</h2>')
//colCol.append(colgroup_header)
group[colTitle].forEach(obj => {
action_card = renderAction(obj)
colCol.append(action_card)
})
}
colRow.append(colCol)
})
colContainer.append(colRow)
year_container.append(colContainer)
}
else {
$('#year' + year).hide()
}
$('#org_actions').append(year_container)
}
}
function renderAction(obj) {
var policy_page = obj['action_id_raw'].substring(0, obj['action_id_raw'].indexOf('/'))
var policy_doc_link = '/' + policy_page + '#' + obj['section_type_name'] + '_' + obj['section_ordinal'] + ':_' + obj['section_name'].replace(' ', '_')
var action_card = $('<div>', {class: 'card mb-4 ' + class_map[obj.action_field]})
var action_header = $('<div>', {class: 'card-header', style:'color: #ffffff; background-color:' + color_map[obj.action_field]}).html(obj.action_field + ' - ' + obj['section_type_name'] + ' ' + obj.section_ordinal + '<a style="color:white" data-toggle="collapse" href="#collapse' + obj.action_id +'"><i class="bi bi-chevron-down float-right"></i></a>')
var action_body = $('<div>', {class: 'card-body'})
var field_badge = $('<span>', {class: 'badge float-right', style:'background-color:' + color_map[obj.action_field]}).text(obj.action_field)
var action_section = $('<div>', {class:'collapse', id: 'collapse' + obj.action_id }).html(
'<h5 style="margin-top: 1em">'+ obj.section_name + '<a style="color: white" href="' + policy_doc_link + '"><i title="Avaa linjausteksti" style="margin-left: 1em;" class="bi bi-box-arrow-up-right"></i></a></h5><p> ' + obj.section_desc + '</p>'
)
var action_title = $('<h5>', {class: 'card-title'}).text(obj.action_name)
//var action_title = $('<h5>', {class: 'card-title'}).html(obj.action_name+'<i class="bi bi-question-octagon-fill float-right" style="font-size: 2rem; color:'+ color_map[obj.action_field] +'" data-trigger"focus" data-container="body" data-toggle="popover" data-placement="top" data-content="' + obj.section_desc + ' "></i>')
var action_text = $('<p>', {class: 'card-text'}).text(obj.action_description)
var action_footer = $('<div>', {class: 'card-footer', style:'background-color: ' + color_map[obj.action_field]})
var progressCount = 0
if(obj.action_id in progressItems) {
var p_items = progressItems[obj.action_id]
var progressCount = p_items.length
}
if(progressCount > 0) {
console.log(progressCount)
var progress_button = $('<button>', {class: 'btn btn-secondary float-right', type:'button', onclick:'$("#' + obj.action_id + '").modal("show")'}).html('Edistysaskeleita<span style="margin-left: 5px" class="badge badge-dark">' + progressCount +'</span>')
action_body.append(progress_button)
console.log(obj)
}
var progress_add = $('<a>', {class:'new-progress btn btn-outline-primary float-right', style: 'color: white; border-color: white;', href:'https://164-92-142-113.nip.io/index.php/Special:FormEdit/Progress?Progress[Action]='+encodeURIComponent(obj.action_id_raw) }).text('Add new')
action_card.append(action_header)
action_card.append(action_body)
action_header.append(action_section)
action_body.append(action_title)
action_body.append(action_text)
//action_body.append(action_link)
addProgressModal(obj)
return action_card
}
function addProgressModal(action) {
if(action.action_id in progressItems) {
console.log(action)
var _progressItems = progressItems[action.action_id]
var $modalContainer = $('<div>', {class:'modal', tabindex:'-1', role:'dialog', id:action.action_id})
var $modal = $('<div>', {class:'modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable', role:'document'})
var $modalContent = $('<div>', {class:'modal-content'})
var $modalHeader = $('<div>', {class:'modal-header'})
var $title = $('<h5>', {class:'modal-title'}).text(action.section_type_name)
var $titleClose = $('<button>', {type:'button', class:'close', 'data-dismiss':'modal'})
var $close = $('<span>').html('×')
$titleClose.append($close)
var $actionText = $('<p>', {class:'card-text'}).text((action.action_name != '' ? action.action_name + '. ' : '') + action.action_description)
var $actionRole = $('<h6>', {class:'card-subtitle mb-2 text-muted'}).text(action.action_responsible_actor.join(','))
var $objectiveName = $('<h5>', {class:'card-title'}).text(action.section_name)
var $policyLink = $('<a>', {href:'#', class:'card-link'}).text(action.policy_name)
var $modalBody = $('<div>', {class:'modal-body'})
var $sectionType = $('<p>').text(action.section_type_name)
//$modalBody.append($sectionType)
$modalBody.append($objectiveName)
//$modalBody.append($actionRole)
//$modalBody.append($actionText)
_progressItems.forEach(function(progressItem) {
$modalBody.append(createProgressCard(progressItem))
})
$modalHeader.append($title)
$modalHeader.append($titleClose)
$modalContent.append($modalHeader)
$modalContent.append($modalBody)
$modal.append($modalContent)
$modalContainer.append($modal)
$('#modals').append($modalContainer)
}
}
function createProgressCard(data) {
var $card = $('<div>', {class:'card', style: 'margin-bottom: 1em;'})
var $cardBody = $('<div>', {class:'card-body'})
var $cardTitle = $('<h5>', {class: 'card-title'}).text(data.name)
var $cardSubTitle = $('<h6>', {class:'card-subtitle mb-2 text-muted'}).text(data.date)
var $cardSubTitle2 = $('<h6>', {class:'card-subtitle mb-2 text-muted'}).text(data.org)
$cardText = $('<p>', {class: 'card-text'}).text(data.desc)
$cardBody.append($cardTitle)
$cardBody.append($cardSubTitle)
$cardBody.append($cardSubTitle2)
$cardBody.append($cardText)
$card.append($cardBody)
return $card
}
function groupActions(actions, org_actors) {
// group first by year
groups = group_actions_by_year(actions)
// then by org
console.log(groups)
groups = group_by_org(groups, org_actors)
console.log(groups)
return groups
}
function group_actions_by_year(actions) {
return actions.reduce((groups, item) => {
year = getActionYear(item)
const group = (groups[year] || []);
group.push(item);
groups[year] = group;
return groups;
}, {});
}
function group_by_org(groups, org_actors) {
console.log(org_actors)
Object.keys(groups).forEach(function(key) {
var data = groups[key]
const parents = data.reduce((parents, item) => {
org_actors.forEach(org_actor => {
var value = org_actor.name
var candidates = item['action_responsible_actor'].map(ra => ra.fulltext)
console.log(candidates)
var common_values = intersection(new Set(candidates), new Set(org_actor.actors))
console.log(common_values)
console.log(common_values.size)
if(common_values.size > 0) {
const c = parents[value] || []
console.log(c)
if(c.indexOf(item) < 0) {
c.push(item)
console.log(c)
}
console.log(value)
parents[value] = c
}
})
return parents
}, {});
groups[key] = parents
})
return groups
}
function intersection(setA, setB) {
const _intersection = new Set();
for (const elem of setB) {
if (setA.has(elem)) {
_intersection.add(elem);
}
}
return _intersection;
}
function getActionYear(action) {
if(action.action_deadline) {
return ''+action.action_deadline
}
if(action.section_deadline) {
return ''+action.section_deadline
}
return ''+action.policy_endyear
}
function filterActions(domains, years) {
// actors
/*
result = actions.filter(action => {
return intersection(
new Set(action.action_responsible_actor.map(a=>a.fulltext)),
actors).size > 0
})
*/
// years
var result = actions.filter(action => {
return years.has(getActionYear(action))
})
// domains
result = result.filter(action => {
return domains.has(action.action_domain)
})
return result
}
/* shared */
async function updateProgressData(data) {
console.log(data)
items = {}
data.forEach(function (r) {
progressID = Object.keys(r)[0]
obj = r[progressID]
console.log(obj)
date = ''
if (obj.printouts['Date'].length > 0 && obj.printouts['Date'][0].timestamp) {
date = new Date(parseInt(obj.printouts['Date'][0].timestamp) * 1000)
}
actionID = obj.printouts.Action[0].fulltext.replace('#', '').replace(/\s/g, '').replace(':', '').replace('/', '')
progressUrl = obj.printouts.Action[0].fullurl
name = obj.printouts.Name || ''
desc = obj.printouts.Description || ''
orgName = obj.printouts.OrgName || ''
if (!(actionID in items)) {
items[actionID] = []
}
items[actionID].push({
url: obj.fullurl,
fulltext: obj.fulltext,
actionID: actionID,
url: progressUrl,
date: date,
name: name,
desc: desc,
org: orgName
})
})
progressItems = items
}
function updateActions(data) {
console.log(data)
actions = []
data.forEach(function (r) {
progressID = Object.keys(r)[0]
obj = r[progressID]
var section_desc = obj.printouts['sectionDesc'][0] || '' // footnotes!
section_desc = section_desc.replace(/\[\[.*\]\]/g, "");
var action_description = obj.printouts['Description'][0] || ''
//action_description = action_description.replace(/<\/?[^>]+(>|$)/g, "")
actions.push(
{
'policy_name': obj.printouts['policyName'][0] || '',
'policy_endyear': obj.printouts['policyEndYear'][0] || null,
'section_name': obj.printouts['sectionName'][0] || '',
'section_desc': section_desc,
'section_deadline': obj.printouts['Section deadline'][0] || null,
'section_ordinal': obj.printouts['sectionOrdinal'][0] || null,
'section_type': obj.printouts['sectionType'][0].fulltext || '',
'section_type_name': obj.printouts['sectionTypeName'][0] || '',
'action_deadline': obj.printouts['Action deadline'][0] || null,
'action_description': action_description,
'action_field': obj.printouts['Field'][0] || '',
'action_domain': obj.printouts['Domain'][0].fulltext || '',
'action_name': obj.printouts['Name'][0] || '',
'action_responsible_actor': obj.printouts['Responsible actor'],
'action_id': obj.fulltext.replace('#', '').replace(/\s/g, '').replace(':', '').replace('/', ''),
'action_id_raw': obj.fulltext
}
)
})
}
function updateOrgs(data) {
console.log(data)
actions = []
data.forEach(function (r) {
progressID = Object.keys(r)[0]
obj = r[progressID]
console.log(obj)
var businessID = obj.printouts['BusinessID'][0] || ''
// handle localized string queries and separate properties - todo refactor this out
var actors = []
var actor_ids = obj.printouts['Responsible actor']
var actors_fi = obj.printouts['actors_fi']
var actors_sv = obj.printouts['actors_sv']
var actors_en = obj.printouts['actors_en']
for (let i = 0; i < actor_ids.length; i++) {
actors.push({
id: actor_ids[i].fulltext,
fi: actors_fi[i],
sv: actors_sv[i],
en: actors_en[i]
})
}
orgs[''+businessID] = {
'name': obj.printouts['Name'][0] || '',
'businessID': businessID,
'responsible_actors': actors,
}
})
console.log(orgs)
}
function updateActors(data) {
console.log(data)
data.forEach(function (r) {
id = Object.keys(r)[0]
var name = r[id].printouts['Name'][0]
$('#actors').append('<option value="'+id+'">'+name+'</option>')
console.log('test')
})
}
async function fetch_data(lang) {
// get all Actions
const actionQuery = '[[Category:Action]]|?Part of document.Name ' + lang + '=sectionName|?Part of document.Type=sectionType|?Part of document.Type.Name ' + lang + '=sectionTypeName|?Part of document.Description ' + lang + '=sectionDesc|?Part of document.Ordinal=sectionOrdinal|?Part of document.Document.Name ' + lang + '=policyName|?Part of document.Document.Validity end=policyEndYear|?Part of document.Document.Field.Name ' + lang + '=Field|?Part of document.Document.Field=Domain|?Name ' + lang + '=Name|?Description ' + lang + '=Description|?Responsible actor|?Deadline year=Action deadline|?Part of document.Name ' + lang + '=Section name|?Part of document.Deadline year=Section deadline|limit=50'
const progressQuery = '[[Category:Progress]]|?Name|?Description|?Date|?Action|?Organization.Name=OrgName'
const actorQuery = '[[Category:Actor]]|?Name ' + lang + '=Name|limit=500'
const orgQuery = '[[Category:Organization]]|?Name|?BusinessID|?Responsible actor|?Responsible actor.Name fi=actors_fi|?Responsible actor.Name sv=actors_sv|?Responsible actor.Name en=actors_en|limit=500'
$('#spinner').show()
$('#error').hide()
return Promise.all([
executeAsk(progressQuery)
.then(updateProgressData),
executeAsk(actionQuery)
.then(updateActions),
executeAsk(orgQuery)
.then(updateOrgs)
])
.then(() => {
console.log('data loaded')
$('#spinner').hide()
console.log(actions)
console.log(progressItems)
$('#orgs').selectpicker({
actionsBox: true,
selectedTextFormat: 'count',
liveSearch: true,
multiple: true,
maxOptions: 3,
width: 'fit'
})
//$('#actors').selectpicker('selectAll');
$('#filters').collapse('show')
})
}
async function executeAsk(query) {
var results = [];
var res = null;
var offset = 0
try {
while (res == null || res.query.results.length == 50) {
_query = query + '|offset=' + offset
console.log(_query)
res = await $.ajax({
url: API_URL,
data: {
action: 'ask',
format: 'json',
api_version: 3,
query: _query
},
xhrFields: {
withCredentials: false
},
dataType: 'json'
})
offset = offset + 50
results = results.concat(res.query.results)
}
return results
} catch (error) {
$('#spinner').hide()
$('#error').text(error)
$('#error').show()
console.log(error)
}
}