MediaWiki:Policy.js: Difference between revisions

From Linjauskone
No edit summary
No edit summary
 
Line 20: Line 20:
     try {
     try {
         results = await $.ajax({
         results = await $.ajax({
             url: mw.util.wikiScript( 'api' ),
             url: /api.php,
             data: {
             data: {
                 action: 'ask',
                 action: 'ask',

Latest revision as of 12:36, 1 December 2023

/* 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('&times;')
        $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)
    })
   


}());

Sivustoa ylläpitää Avoimen tieteen ja tutkimuksen (AVOTT) kansallisen koordinaation sihteeristö, joka toimii Tieteellisten seurain valtuuskunnassa (TSV) Opetus- ja kulttuuriministeriön (OKM) rahoituksella. Avoimen tieteen ja tutkimuksen koordinaatio edistää avoimen tieteen ja tutkimuksen toteutumista sekä keskustelua sen mahdollisuuksista, haasteista sekä niiden ratkaisuista Suomessa.

Webbplatsen upprätthålls av Sekretariatet för den nationella samordningen av öppen vetenskap och forskning. Sekretariatet verkar vid Vetenskapliga samfundens delegation med finansiering från undervisnings- och kulturministeriet. Samordningen främjar öppen vetenskap och forskning samt diskussion kring dess möjligheter, utmaningar och lösningar i Finland.

This website is maintained by the Secretariat of the National Coordination for Open Science and Research in Finland (AVOTT), which operates in the Federation of Finnish Learned Societies (TSV) with funding from the Ministry of Education and Culture (OKM). The Open Science and Research Coordination promotes open science and research, as well as discussion on its opportunities, challenges and their solutions in Finland.