MediaWiki:Policy.js: Difference between revisions

From Linjauskone
(Created page with "→‎Any JavaScript here will be loaded for all users on every page load.: QUERY = `Responsible role::+|?Name|?Description` selectedThemes = new Set() selectedRoles = new Set() selectedParentTypes = [] years = [] progressItems = {} tlData = [] async function executeAsk(query) { $('#spinner').show() var results; try { results = await $.ajax({ url: 'http://localhost:8888/api.php', data: { action:...")
 
No edit summary
Line 21: Line 21:
     try {
     try {
         results = await $.ajax({
         results = await $.ajax({
             url: 'http://localhost:8888/api.php',
             url: '/api.php',
             data: {
             data: {
                 action: 'ask',
                 action: 'ask',

Revision as of 12:50, 15 August 2022

/* Any JavaScript here will be loaded for all users on every page load. */


QUERY = `[[Responsible role::+]]|?Name|?Description`

selectedThemes = new Set()
selectedRoles = new Set()
selectedParentTypes = []



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
                //origin: 'localhost:8888'
            }, 
            xhrFields: {
                withCredentials: false
            },
            dataType: 'json'        
        })
        $('#spinner').hide()
        return results
    } catch(error) {
        $('#spinner').hide()
        console.log(error)
    }

}

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 processActionData(data) {
    console.log(data)
    tlData = []
    for(const theme of selectedThemes) {
        tlItem = {
            name: theme
        }
        items = []
        console.log(data)
        data.query.results.forEach(function(r) {
            actionID = Object.keys(r)[0]
            obj = r[actionID]
            actionDate = ''
            if(obj.printouts['Action deadline'][0]) {
                actionDate = new Date(parseInt(obj.printouts['Action deadline'][0].timestamp)*1000).getFullYear()
            }
            objectiveDate = ''
            if(obj.printouts['Objective deadline'][0]) {
                objectiveDate = new Date(parseInt(obj.printouts['Objective deadline'][0].timestamp)*1000).getFullYear()
            }

            actionTheme =  obj.printouts.Theme[0]

            if(theme == actionTheme) {
                items.push({
                    id: actionID.replace('#', '').replace(' ', '').replace(':', ''), 
                    name: obj.printouts.Name[0] ||'',
                    desc: obj.printouts.Description[0] || '',
                    actionDeadlineYear: actionDate,
                    objectiveDeadlineYear: objectiveDate,
                    policyEndYear: obj.printouts.policyEndYear[0] || '',
                    role: obj.printouts.Role[0] || '',
                    policyName: obj.printouts.policyName,
                    objectiveName: obj.printouts.objectiveName[0] || '',
                    objectiveDesc: obj.printouts.objectiveDesc[0] || '',
                    objectiveOrdinal: obj.printouts.objectiveOrdinal[0] || '',
                    theme: actionTheme
                })
    
            }
        })
        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.objectiveDeadlineYear != '') {
                year = item.objectiveDeadlineYear
            }
            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 new Promise(function(resolve, reject) { console.log(tlData); resolve(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('')
    query = '[[Part of objective.Policy::+]]|?Part of objective.Name=objectiveName|?Part of objective.Description=objectiveDesc|?Part of objective.Ordinal=objectiveOrdinal|?Part of objective.Policy.Name=policyName|?Part of objective.Policy.Validity End=policyEndYear|?Part of objective.Policy.Theme|?Name|?Description|?Responsible role=Role|?Deadline=Action deadline|?Part of objective.Name=Objective name|?Part of objective.Deadline=Objective deadline|limit=500'
    progressQuery = '[[Category:Progress Item]]|?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([actionData, progressData]).then(function(values) {
        console.log(values)
        progressItems = values[1]
        tlData = values[0]
        console.log(tlData)
        // extract years 
        tlData.forEach(function(i) {
            keys = Object.keys(i.items)
            keys.forEach(function(key) {
                if(years.indexOf(key) < 0 ) {
                    years.push(key)
                }
            })


            


        })
        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 muistiot')
        $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)
    $card = $('<div>', {class:'card shadow-sm'})
    $cardBody = $('<div>', {class:'card-body'}) 
    $cardText = $('<p>', {class:'card-text'}).text((item.name != '' ? item.name + '.' : '') + item.desc)
    $cardTitle = $('<h5>', {class:'card-title'}).text(item.objectiveName)
    $role = $('<h6>', {class:'card-subtitle mb-2 text-muted'}).text(item.role)
    $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.objectiveName + ' - Tavoite ' + item.objectiveOrdinal )
    $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>')
    $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)                        
        $tag = $('<span>', {class: 'tag', onclick:'$("#' + item.id + '").modal("show")'}).html('<h4>Has progress (' + 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 () {
  if ( $( "#timeline2" ).length ) {
    console.log('applying policy app');
    $('#themes input').click(function(e) {
        onThemeSelect(e.target)
    })
    $('#roles input').click(function(e) {
        onRoleFilterSelect(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.