MediaWiki:Policy.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
/* Any JavaScript here will be loaded for all users on every page load. */
QUERY = `[[Responsible role::+]]|?Name|?Description`
selectedThemes = new Set()
selectedRoles = new Set()
selectedTypes = new Set()
selectedYears = new Set()
years = []
progressItems = {}
tlData = []
async function executeAsk(query) {
$('#spinner').show()
var results;
try {
results = await $.ajax({
url: /api.php,
data: {
action: 'ask',
format: 'json',
api_version: 3,
query : query,
},
xhrFields: {
withCredentials: false
},
dataType: 'json'
})
$('#spinner').hide()
return results
} catch(error) {
$('#spinner').hide()
console.log(error)
}
}
function onTypeFilterSelect(e) {
if(e.checked) {
selectedTypes.add(e.value)
}
else {
selectedTypes.delete(e.value)
}
console.log(selectedTypes)
updateTimelines()
}
function onYearFilterSelect(e) {
if(e.checked) {
selectedYears.add(e.value)
}
else {
selectedYears.delete(e.value)
}
console.log(selectedYears)
updateTimelines()
}
function onRoleFilterSelect(e) {
if(e.checked) {
selectedRoles.add(e.value)
}
else {
selectedRoles.delete(e.value)
}
console.log(selectedRoles)
updateTimelines()
}
function onThemeSelect(e) {
$('#initial_state').hide()
if(e.checked) {
selectedThemes.add(e.value)
}
else {
selectedThemes.delete(e.value)
}
console.log(selectedThemes)
updateTimelines()
}
function handleAction(data) {
return new Promise(function(resolve, reject) {resolve(data.query.results)})
}
function processActionData(data) {
console.log(data)
tlData = []
for(const theme of selectedThemes) {
var tlItem = {
name: theme
}
items = []
console.log(data)
data.forEach(function(r) {
var actionID = Object.keys(r)[0]
var obj = r[actionID]
var actionDate = ''
if(obj.printouts['Action deadline'][0]) {
actionDate = obj.printouts['Action deadline'][0]
}
var sectionDate = ''
if(obj.printouts['Section deadline'][0]) {
sectionDate = obj.printouts['Section deadline'][0]
}
var actionField = obj.printouts.Field[0]
var sectionType = obj.printouts.sectionType[0] || ''
if(theme == actionField) {
var newItem = {
id: actionID.replace('#', '').replace(' ', '').replace(':', ''),
name: obj.printouts.Name[0] ||'',
desc: obj.printouts.Description[0] || '',
actionDeadlineYear: actionDate,
sectionDeadlineYear: sectionDate,
policyEndYear: obj.printouts.policyEndYear[0] || '',
role: obj.printouts['Responsible actor'][0] || '',
policyName: obj.printouts.policyName[0] || '',
objectiveName: obj.printouts.sectionName[0] || '',
objectiveDesc: obj.printouts.sectionDesc[0] || '',
objectiveOrdinal: obj.printouts.sectionOrdinal[0] || '',
sectionType: sectionType,
field: actionField
}
if(selectedTypes.size > 0) {
console.log(selectedTypes)
console.log(sectionType)
if(selectedTypes.has(sectionType)) {
console.log('hepss')
items.push(newItem)
}
}
else {
items.push(newItem)
}
}
})
console.log(items)
/*
items.sort(function(a, b) {
return a.role.localeCompare(b.role)
})
console.log(items)
*/
const groups = items.reduce((groups, item) => {
year = ''
if(item.actionDeadlineYear != '') {
year = item.actionDeadlineYear
}
else if(item.sectionDeadlineYear != '') {
year = item.sectionDeadlineYear
}
else {
year = item.policyEndYear
}
const group = (groups[year] || []);
group.push(item);
groups[year] = group;
return groups;
}, {});
if(false) {
Object.keys(groups).forEach(function(key) {
data = groups[key]
const parents = data.reduce((parents, item) => {
const parent = (parents[item.objectiveName] || []);
parent.push(item);
parents[item.objectiveName] = parent;
return parents;
}, {});
groups[key] = parents
})
}
if(selectedRoles.size > 0 ) {
console.log('Grouping by roles')
// gruop by role too
Object.keys(groups).forEach(function(key) {
_data = groups[key]
const roles = _data.reduce((roles, item) => {
for (const selectedRole of selectedRoles) {
if(item.role.indexOf(selectedRole) >= 0) {
const c = roles[selectedRole] || []
c.push(item)
roles[selectedRole] = c
}
}
return roles
}, {});
groups[key] = roles
})
}
console.log(groups)
tlItem['items'] = groups
tlData.push(tlItem)
//tlData.push(structuredClone(tlItem))
//tlData.push(structuredClone(tlItem))
}
return tlData
}
function processProgressData(data) {
console.log(data)
items = {}
data.query.results.forEach(function(r) {
progressID = Object.keys(r)[0]
obj = r[progressID]
date = ''
if(obj.printouts['Date'][0].timestamp) {
date = new Date(parseInt(obj.printouts['Date'][0].timestamp)*1000)
}
actionID = obj.printouts.Action[0].fulltext.replace('#', '').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({
actionID: actionID,
url: progressUrl,
date: date,
name: name,
desc: desc,
org: orgName
})
})
return new Promise(function(resolve, reject) {resolve(items)})
}
function updateTimelines() {
$('#timeline_content').html('')
query1 = '[[Section:+]] [[Part of document.Document.Field::Tutkimusjulkaisut]]|?Part of document.Name=sectionName|?Part of document.Type=sectionType|?Part of document.Description=sectionDesc|?Part of document.Ordinal=sectionOrdinal|?Part of document.Document.Name=policyName|?Part of document.Document.Validity end=policyEndYear|?Part of document.Field=Field|?Name|?Description|?Responsible actor|?Deadline year=Action deadline|?Part of document.Name=Section name|?Part of document.Deadline year=Section deadline|limit=500'
query2 = '[[Section:+]] [[Part of document.Document.Field::Toimintakulttuuri]]|?Part of document.Name=sectionName|?Part of document.Type=sectionType|?Part of document.Description=sectionDesc|?Part of document.Ordinal=sectionOrdinal|?Part of document.Document.Name=policyName|?Part of document.Document.Validity end=policyEndYear|?Part of document.Field=Field|?Name|?Description|?Responsible actor|?Deadline year=Action deadline|?Part of document.Name=Section name|?Part of document.Deadline year=Section deadline|limit=500'
query3 = '[[Section:+]] [[Part of document.Document.Field::Oppiminen]]|?Part of document.Name=sectionName|?Part of document.Type=sectionType|?Part of document.Description=sectionDesc|?Part of document.Ordinal=sectionOrdinal|?Part of document.Document.Name=policyName|?Part of document.Document.Validity end=policyEndYear|?Part of document.Field=Field|?Name|?Description|?Responsible actor|?Deadline year=Action deadline|?Part of document.Name=Section name|?Part of document.Deadline year=Section deadline|limit=500'
query4 = '[[Section:+]] [[Part of document.Document.Field::Data]]|?Part of document.Name=sectionName|?Part of document.Type=sectionType|?Part of document.Description=sectionDesc|?Part of document.Ordinal=sectionOrdinal|?Part of document.Document.Name=policyName|?Part of document.Document.Validity end=policyEndYear|?Part of document.Field=Field|?Name|?Description|?Responsible actor|?Deadline year=Action deadline|?Part of document.Name=Section name|?Part of document.Deadline year=Section deadline|limit=500'
progressQuery = '[[Category:Progress]]|?Name|?Description|?Date|?Action|?Organization.Name=OrgName'
if(selectedThemes.size == 0) {
return
}
// one query per theme - group by year (use action's year first, then parent's and finally policy's validity end.)
tlData = []
//actionData = executeAsk(query).then(processActionData)
progressData = executeAsk(progressQuery).then(processProgressData)
Promise.all([ executeAsk(query1).then(handleAction), executeAsk(query2).then(handleAction), executeAsk(query3).then(handleAction), executeAsk(query4).then(handleAction), progressData]).then(function(values) {
console.log(values)
progressItems = values[4]
var _tlData = values[0]
_tlData.push(...values[1], ...values[2], ...values[3])
_tlData = processActionData(_tlData)
console.log(tlData)
// extract years
years = []
_tlData.forEach(function(i) {
var keys = Object.keys(i.items)
keys.forEach(function(key) {
if(Object.keys(i.items[key]).length > 0 ) {
if(years.indexOf(key) < 0 ) {
years.push(key)
}
}
})
})
if(selectedYears.size > 0) {
years = Array.from(selectedYears)
}
years.sort()
console.log(years)
tlData = _tlData
html = createTimeline(tlData)
$('#timeline_content').html(html)
$("[data-toggle=popover]").popover();
})
}
function createProgressCard(data) {
var $card = $('<div>', {class:'card'})
$cardBody = $('<div>', {class:'card-body'})
$cardTitle = $('<h5>', {class: 'card-title'}).text(data.name)
$cardSubTitle = $('<h6>', {class:'card-subtitle mb-2 text-muted'}).text(data.date.toLocaleDateString("fi-FI"))
$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 addProgressModal(action) {
if(action.id in progressItems) {
console.log(action)
_progressItems = progressItems[action.id]
$modalContainer = $('<div>', {class:'modal', tabindex:'-1', role:'dialog', id:action.id})
$modal = $('<div>', {class:'modal-dialog', role:'document'})
$modalContent = $('<div>', {class:'modal-content'})
$modalHeader = $('<div>', {class:'modal-header'})
$title = $('<h5>', {class:'modal-title'}).text('Toimenpiteeseen liittyvät edistysaskeleet')
$titleClose = $('<button>', {type:'button', class:'close', 'data-dismiss':'modal'})
$close = $('<span>').html('×')
$titleClose.append($close)
$actionText = $('<p>', {class:'card-text'}).text((action.name != '' ? action.name + '. ' : '') + action.desc)
$actionRole = $('<h6>', {class:'card-subtitle mb-2 text-muted'}).text(action.role)
$objectiveName = $('<h5>', {class:'card-title'}).text(action.objectiveName)
$policyLink = $('<a>', {href:'#', class:'card-link'}).text(action.policyName)
$modalBody = $('<div>', {class:'modal-body'})
$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 createTimelineCard(item) {
//console.log(item)
var $card = $('<div>', {class:'card shadow-sm'})
var $cardBody = $('<div>', {class:'card-body'})
var $cardText = $('<p>', {class:'card-text'}).text((item.name != '' ? item.name + '. ' : '') + item.desc)
var $cardTitle = $('<h5>', {class:'card-title'}).text(item.role)
var $role = $('<h6>', {class:'card-subtitle mb-2 text-muted'}).text(item.role)
var $cardFooter = $('<div>', {class:'card-footer',tabindex:'0', 'data-trigger':'focus', 'data-container':'body', 'data-toggle':'popover', 'data-placement':'top', 'data-content':item.objectiveDesc}).text(item.policyName + ' - ' + item.sectionType + ' ' + item.objectiveOrdinal )
var $policyLink = $('<a>', {href:'#', class:'card-link'}).text(item.policyName)
//$tag = $('<span>', {class:'tag', tabindex:'0', 'data-trigger':'focus', 'data-container':'body', 'data-toggle':'popover', 'data-placement':'top', 'data-content':item.objectiveDesc}).html('<h4>' + item.objectiveName + ' - Tavoite ' + item.objectiveOrdinal + '</h4>')
var $header = $('<div>', {class:'card-header',tabindex:'0', 'data-trigger':'focus', 'data-container':'body', 'data-toggle':'popover', 'data-placement':'top', 'data-content':item.objectiveDesc}).text(item.objectiveName + ' - Tavoite ' + item.objectiveOrdinal )
/*
<button type="button" class="btn btn-secondary" data-container="body" data-toggle="popover" data-placement="bottom" data-content="Bottom popover">
Popover on bottom
</button>
*/
//<small class="text-muted">Last updated 3 mins ago</small>
//$cardBody.append($cardTitle)
//$card.append($header)
$cardBody.append($role)
$textContent = $('<div>', {style:'margin-bottom: 1em; overflow: scroll;height: 120px;'})
$textContent.append($cardText)
$cardBody.append($textContent)
//console.log(item.id)
//console.log(item.id in progressItems)
if(item.id in progressItems) {
//$progressButton = $('<button>', {class:'btn btn-primary', type:'button', onclick:'$("#' + item.id + '").modal("show")' }).text('Has progress (' + progressItems[item.id].length + ')')
//$cardBody.append($progressButton)
var $tag = $('<span>', {class: 'tag', onclick:'$("#' + item.id + '").modal("show")'}).html('<h4>Edistysaskeleita (' + progressItems[item.id].length + ')</h4>')
$cardBody.append($tag)
}
$card.append($cardBody)
//$cardFooter.append($policyLink)
$card.append($cardFooter)
//$deck.append($card)
addProgressModal(item)
//console.log($card)
return $card
}
function createTimeline(data) {
content = []
// header row
header = $('<div>', {class: 'container-fluid my-3 sticky-top'})
headerRow = $('<div>', {class: 'row theme-header-row'})
headerRow.append( $('<div>', {class: 'col-md-1'}) )
data.forEach(function(theme) {
headerRow.append($('<h3>', {class: 'col-md'}).text(theme.name))
})
header.append(headerRow)
content.push(header)
// year rows
console.log(progressItems)
console.log('***')
console.log(data)
years.forEach(function(year) {
$yearContainer = $('<div>', {class: 'container-fluid py-3'})
$yearRow = $('<div>', {class: 'row'})
$yearContent = $('<div>', {class: 'col-md-1'})
$yearValue = $('<div>', {class: 'card card-body sticky-top'}).text(year)
$yearContent.append($yearValue)
$yearRow.append($yearContent)
data.forEach(function(theme) {
$cards = $('<div>', {class: 'col-md', style:'min-height: 150px'})
$deck = $('<div>', {class: 'card-columns'})
if (year in theme.items) {
items = theme.items[year]
if(selectedRoles.size > 0) {
if(Object.keys(items).length > 0 ) {
$roleContainer = $('<div>', {class:'container-fluid'})
$roleRow = $('<div>', {class:'row'})
for(const role of selectedRoles) {
if(role in items) {
console.log(role)
$roleCol = $('<div>', {class:'col-sm'}).html('<h4>'+ role + '</h4>')
_items = items[role]
console.log(_items)
_items.forEach(function(item) {
_card = createTimelineCard(item)
$roleCol.append(_card)
})
$roleRow.append($roleCol)
}
}
$roleContainer.append($roleRow)
$roleContainer.append($('<style>').text('.card { margin-bottom: 15px}'))
$cards.append($roleContainer)
}
}
else {
items.forEach(function(item) {
//console.log(item)
_card = createTimelineCard(item)
//console.log(_card)
$deck.append(_card)
})
$cards.append($deck)
}
}
$yearRow.append($cards)
})
$yearContainer.append($yearRow)
content.push($yearContainer)
})
return content
}
$(function () {
$('#themes input').click(function(e) {
onThemeSelect(e.target)
})
$('#roles input').click(function(e) {
onRoleFilterSelect(e.target)
})
$('#years input').click(function(e) {
onYearFilterSelect(e.target)
})
$('#types input').click(function(e) {
onTypeFilterSelect(e.target)
})
}());