MediaWiki:OrgActionList.js: Difference between revisions

From Linjauskone
No edit summary
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
ORIGIN = 'http://localhost:8000'
ORGS_MAX_OPTIONS = 3
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() {
function updateActionView() {
Line 164: Line 50:
         document.querySelectorAll('.rowgroup-header').forEach(function(e) {         
         document.querySelectorAll('.rowgroup-header').forEach(function(e) {         
             scrollObserver.observe(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)  {
function renderActions(actions, org_actors)  {
     for(var year = 2020; year < 2026; year++)  {
     for(var year = 2020; year < 2026; year++)  {
Line 229: Line 94:
         $('#org_actions').append(year_container)
         $('#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('&times;')
        $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
}
}


Line 337: Line 100:
     groups = group_actions_by_year(actions)
     groups = group_actions_by_year(actions)
     // then by org
     // then by org
    console.log(groups)
     groups = group_by_org(groups, org_actors)
     groups = group_by_org(groups, org_actors)
    console.log(groups)
     return 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;
      }, {});
}
}


Line 385: Line 136:
     })
     })
     return groups
     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) {
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
     // years
     var result = actions.filter(action => {         
     var result = actions.filter(action => {         
Line 427: Line 148:
     })
     })
     return result
     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)
    }
}
}

Latest revision as of 11:32, 7 January 2023

ORGS_MAX_OPTIONS = 3

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 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 groupActions(actions, org_actors) {
    // group first by year
    groups = group_actions_by_year(actions)
    // then by org
    groups = group_by_org(groups, org_actors)
    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 filterActions(domains, years) {
    // years
    var result = actions.filter(action => {        
        return years.has(getActionYear(action))
    })
    // domains
    result = result.filter(action => {
        return domains.has(action.action_domain)
    })
    return result
}

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.