Merge pull request #1016 from zuzanna-maria/condorcet-ui-tweaks

Changed method choice/details tag for Weblate translation
This commit is contained in:
David Benque 2023-04-18 16:04:41 +01:00 committed by GitHub
commit c8cef7c40d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 249 additions and 149 deletions

View File

@ -25,10 +25,10 @@ define([], function () {
};
Condorcet.showCondorcetWinner = function(_answers, opts, uid, form, optionArray, listOfLists) {
var comparePairs = function() {
var pairs = getPermutations(optionArray, 2);
var pairDict = {};
pairs.forEach(function (pair) {
pairDict[pair] = 0;
@ -38,7 +38,7 @@ define([], function () {
}
});
});
var pathDictionary = {};
//Adds winner of each pairwise comparison to path
optionArray.forEach(function(option1) {
@ -60,8 +60,9 @@ define([], function () {
var schulzeMethod = function(optionArray) {
var findWeakestPath = function(optionArray) {
var pathDictionary = comparePairs(optionArray);
//Iterates through paths between two options comparing the weakest edge to current score
optionArray.forEach(function(option1) {
optionArray.forEach(function(option2) {
@ -98,12 +99,14 @@ define([], function () {
}
});
});
return pathDictionary;
};
var calculateWinner = function() {
var pathDictionary = findWeakestPath(optionArray);
//Calculate scores for each option and select winner
var winningMatches = {};
optionArray.forEach(function(option){
@ -111,9 +114,16 @@ define([], function () {
});
Object.keys(pathDictionary).forEach(function(pair) {
var option1 = pair.split(',')[0];
var option2 = pair.split(',')[1];
winningMatches[option1] ++;
winningMatches[option2] --;
Object.keys(pathDictionary).forEach(function(p) {
if (p.split(',')[1] === option1 && pathDictionary[p] > pathDictionary[pair]) {
winningMatches[option1] --;
}
});
});
var rankedResults = {};
Object.keys(winningMatches).forEach(function(option) {
if (Object.keys(rankedResults).includes(winningMatches[option].toString())) {
@ -122,79 +132,164 @@ define([], function () {
rankedResults[winningMatches[option]] = [option];
}
});
return [rankedResults, winningMatches];
var losing = [];
var winning = [];
var winningPairs = [];
Object.keys(pathDictionary).forEach(function(pair) {
var option1 = pair.split(',')[0];
var option2 = pair.split(',')[1];
losing.push(option2);
winning.push(option1);
});
Object.keys(pathDictionary).forEach(function(pair) {
var option1 = pair.split(',')[0];
if (!losing.includes(option1)) {
winningPairs.push(option1);
}
});
var winner;
var winnersArray = [];
winningPairs.forEach(function(pair) {
if (!winnersArray.includes(pair)) {
winnersArray.push(pair);
}
});
if (winnersArray.length !== 0) {
winner = winnersArray;
} else if (winnersArray.length === 0 && Object.keys(rankedResults).length === 1) {
winner = [];
} else {
winner = rankedResults[0];
}
return [winner, rankedResults];
};
return(calculateWinner());
};
var rankedPairsMethod = function (optionArray, listOfLists, _answers) {
var rankedPairsMethod = function (optionArray, listOfLists) {
var pairs = getPermutations(optionArray, 2);
var lockPairs = function() {
//'Locks' pairwise comparisons which do not create a beatpath cycle
var pathDictionary = comparePairs(listOfLists, pairs);
var items = Object.keys(pathDictionary).map(function(key) {
return [key, pathDictionary[key]];
});
//'Locks' pairwise comparisons which do not create a beatpath cycle
var pathDictionary = comparePairs(listOfLists, pairs);
var items = Object.keys(pathDictionary).sort().map(function(key) {
return [key, pathDictionary[key]];
});
var sortedItems = {};
Object.values(items).forEach(function(value) {
if (Object.keys(sortedItems).includes(value[1].toString())) {
sortedItems[value[1]].push(value[0]);
} else {
sortedItems[value[1]] = [];
sortedItems[value[1]].push(value[0]);
}
items.sort(function(first, second) {
return second[1] - first[1];
});
var rankingDict = {};
var winning = [];
var losing = [];
Object.values(sortedItems).forEach(function(v) {
v.forEach(function(val){
winning.push(val.split(',')[0]);
losing.push(val.split(',')[1]);
});
var list = [items[0][0]];
var list2 = [];
items.forEach(function(item){
opts = item[0].split(',');
if (!list2.includes(opts[0])) {
list2.push(opts[1]);
if (!list.includes(item[0])) {
list.push(item[0]);
}
}
});
optionArray.forEach(function(option){
rankingDict[option] = 0;
});
var rankingArray = [];
Object.values(rankingDict).forEach(function(pair) {
if (!rankingArray .includes(pair)) {
rankingArray .push(pair);
}
});
var winner;
if (rankingArray.length <= 1) {
optionArray.forEach(function(option){
if (winning.includes(option)) {
rankingDict[option] ++;
}
if (losing.includes(option)) {
rankingDict[option] --;
}
});
return list;
};
var rankPairs = function(optionArray, listOfLists, _answers) {
//Ranks locked pairs
var list = lockPairs(optionArray, listOfLists, _answers);
var rankDict = {};
optionArray.forEach(function(o){
rankDict[o] = 0;
list.forEach(function(pair) {
if (o === pair.split(',')[1]) {
rankDict[o] --;
} else if (o === pair.split(',')[0]) {
rankDict[o] ++;
}
}
var rankedResults = {};
Object.keys(rankingDict).forEach(function(option) {
if (Object.keys(rankedResults).includes(rankingDict[option].toString())) {
rankedResults[rankingDict[option]].push(option);
} else {
rankedResults[rankingDict[option]] = [option];
}
});
var rankedKeys = Object.keys(rankedResults).sort().map(function(key) {
return [key, rankedResults[key]];
});
var finalsortedItems = {};
Object.values(rankedKeys).forEach(function(value){
if (Object.keys(finalsortedItems).includes(value[1].toString())) {
finalsortedItems[value[1]].push(value[0]);
} else {
finalsortedItems[value[1]] = [];
finalsortedItems[value[1]].push(value[0]);
}
});
var finalRankingArray = [];
Object.values(rankingDict).forEach(function(pair) {
if (!finalRankingArray.includes(pair)) {
finalRankingArray.push(pair);
}
});
if (finalRankingArray.length > 1) {
var maxScore = Math.max.apply(null, Object.keys(rankedResults));
winner = rankedResults[maxScore];
} else if (Object.keys(sortedItems).length === 0) {
winner = [];
} else {
var index = Array.apply(null, Array(Object.keys(sortedItems).length-1)).map(function (_, i) { return i; });
index.forEach(function(i) {
pairs = Object.values(sortedItems).reverse()[i];
pairs.forEach(function(pair) {
var valIndex = winning.indexOf(pair.split(',')[1]);
winning.splice(valIndex, 1);
});
});
var rankedItems = Object.keys(rankDict).map(function(key) {
return [key, rankDict[key]];
});
rankedItems.sort(function(first, second) {
return second[1] - first[1];
});
var finalRank = [];
rankedItems.forEach(function(i){
finalRank.push(i[0]);
});
var sortedRankDict = {};
finalRank.forEach(function(opt){
sortedRankDict[opt] = rankDict[opt];
});
return [finalRank, sortedRankDict];
};
var condorcetWinner = rankPairs(optionArray, listOfLists, _answers);
return condorcetWinner;
var winnerArray = [];
winning.forEach(function(option){
if (!winnerArray.includes(option)) {
winnerArray.push(option);
}
});
if (winnerArray.length === optionArray.length) {
winner = [];
} else {
winner = winnerArray;
}
}
return [winner, rankedResults];
};
var pickMethod = function(optionArray, listOfLists, _answers, uid){
@ -202,12 +297,10 @@ define([], function () {
var schulzeWinner = schulzeMethod(optionArray, listOfLists, _answers, uid);
var rankedPairWinner = rankedPairsMethod(optionArray, listOfLists);
var method = form[uid].condorcetmethod;
if (method === "Schulze") {
condorcetWinner[0] = schulzeWinner;
condorcetWinner[1] = rankedPairWinner;
} else if (method === "Ranked Pairs") {
condorcetWinner[0] = rankedPairWinner;
condorcetWinner[1] = schulzeWinner;
if (method === "schulze") {
condorcetWinner = schulzeWinner;
} else if (method === "ranked") {
condorcetWinner = rankedPairWinner;
}
return condorcetWinner;
};

View File

@ -77,8 +77,12 @@ define([
{
Messages.form_showCondorcetMethod = "Condorcet method "; //XXX;
Messages.form_condorcetSchulze = "Schulze";
Messages.form_condorcetRanked = "Ranked Pairs";
Messages.form_showCondorcetWinner = " winner: ";
Messages.form_showDetails = "Details";
Messages.form_condorcetExtendedDisplay = "Number of matches won by each candidate: ";
Messages.form_noCondorcetWinner = "No winner";
var APP = window.APP = {
blocks: {}
@ -2894,94 +2898,97 @@ define([
var listOfLists = [];
Object.keys(_answers).forEach(function(a) {
listOfLists.push(_answers[a].msg[uid]);
if (_answers[a].msg[uid] !== undefined) {
listOfLists.push(_answers[a].msg[uid]);
}
});
return Condorcet.showCondorcetWinner(_answers, opts, uid, form, optionArray, listOfLists);
if (Object.keys(listOfLists).length !== 0) {
return Condorcet.showCondorcetWinner(_answers, opts, uid, form, optionArray, listOfLists);
}
};
var condorcetWinnerDiv = h('div.cp-form-block-content');
if (type === "sort") {
if (summary) {
if (type === "sort" && summary && showCondorcetWinner(answers, block.opts, uid, form) !== undefined) {
var calculateCondorcet = function() {
var condorcetResults = h('span');
if (showCondorcetWinner(answers, block.opts, uid, form) !== undefined) {
var rankedResults = showCondorcetWinner(answers, block.opts, uid, form)[1];
var condorcetWinner = showCondorcetWinner(answers, block.opts, uid, form)[0];
if (condorcetWinner.length > 1) {
condorcetResults.append(h('span', condorcetWinner.join(', ')));
} else if (condorcetWinner.length === 1 ) {
condorcetResults.append(h('span', condorcetWinner));
} else {
condorcetResults.append(h('span', Messages.form_noCondorcetWinner));
}
var calculateCondorcet = function() {
var condorcetWinner;
var detailedResults;
var condorcetResults = h('span');
var rankedResults = showCondorcetWinner(answers, block.opts, uid, form)[0][0];
if (form[uid].condorcetmethod === 'Schulze') {
condorcetWinner = rankedResults[Object.keys(rankedResults).length - 1];
condorcetWinner.join(', ');
condorcetWinner.forEach(function(option) {
condorcetResults.append(h('span', option));
});
detailedResults = Object.keys(rankedResults).reverse().map(function(result) {
return rankedResults[result] + ' : ' + result;
});
return [condorcetResults, detailedResults];
} else if (form[uid].condorcetmethod === 'Ranked Pairs') {
var sortedRankDict = showCondorcetWinner(answers, block.opts, uid, form)[0][1];
condorcetWinner = rankedResults[0];
detailedResults = Object.keys(sortedRankDict).map(function(result) {
return result + ' : ' + sortedRankDict[result];
});
var detailedResults = Object.keys(rankedResults).sort(function(a,b) { return a - b; }).reverse().map(function(result) {
if (rankedResults[result].length > 1) {
return rankedResults[result].join(', ') + ' : ' + result;
} else {
return rankedResults[result] + ' : ' + result;
}
return [condorcetWinner, detailedResults];
};
var dropdownOpts = ['Schulze', 'Ranked Pairs'];
var options = dropdownOpts.map(function (t) {
return {
tag: 'a',
attributes: {
'class': 'cp-form-type-value',
'data-value': t,
'href': '#',
},
content: t
};
});
var dropdownConfig = {
text: '', // Button initial text
options: options,
isSelect: true,
caretDown: true,
buttonCls: 'btn btn-secondary'
return [condorcetResults, detailedResults];
}};
var dropdownOpts = [Messages.form_condorcetSchulze, Messages.form_condorcetRanked];
var options = dropdownOpts.map(function (t) {
return {
tag: 'a',
attributes: {
'class': 'cp-form-type-value',
'data-value': t,
'href': '#',
},
content: t
};
var typeSelect = UIElements.createDropdown(dropdownConfig);
form[uid].condorcetmethod = 'Schulze';
typeSelect.setValue(form[uid].condorcetmethod);
var method = h('div.cp-dropdown-container', typeSelect[0]);
var evOnSave = Util.mkEvent();
typeSelect.onChange.reg(evOnSave.fire);
var $typeSelect = $(typeSelect);
var $selector = $typeSelect.find('a');
var condorcetWinner = h('span', { id: 'cW'}, calculateCondorcet()[0]);
condorcetWinnerDiv = h('div.cp-form-edit-type');
var detailsDiv = h('details', {id: 'dD'}, Messages.form_condorcetExtendedDisplay, h('div', calculateCondorcet()[1].join(', ')));
$selector.click(function () {
form[uid].condorcetmethod = $(this).attr('data-value');
$('#cW').replaceWith(h('span', { id: 'cW'}, calculateCondorcet()[0]));
$('#dD').replaceWith(h('details', {id: 'dD'}, Messages.form_condorcetExtendedDisplay, h('div', calculateCondorcet()[1].join(', '))));
});
condorcetWinnerDiv.append(h('div', Messages.form_showCondorcetMethod, method, Messages.form_showCondorcetWinner, condorcetWinner, detailsDiv, {style: {margin: '10px'}}));
}
}
});
var dropdownConfig = {
text: '', // Button initial text
options: options,
isSelect: true,
caretDown: true,
buttonCls: 'btn btn-secondary'
};
var typeSelect = UIElements.createDropdown(dropdownConfig);
typeSelect.setValue(dropdownOpts[0]);
var methodOptions = {0: 'schulze', 1: 'ranked'};
var optionIndex = dropdownOpts.indexOf(typeSelect.getValue());
form[uid].condorcetmethod = methodOptions[optionIndex];
var method = h('div.cp-dropdown-container', typeSelect[0]);
var evOnSave = Util.mkEvent();
typeSelect.onChange.reg(evOnSave.fire);
var $typeSelect = $(typeSelect);
var $selector = $typeSelect.find('a');
var condorcetWinner = h('span', { id: 'cW'}, calculateCondorcet()[0]);
condorcetWinnerDiv = h('div.cp-form-edit-type');
var detailsDiv = h('details', h('summary', Messages.form_showDetails), {id: 'dD'}, Messages.form_condorcetExtendedDisplay, h('div', calculateCondorcet()[1].join(', ')));
$selector.click(function () {
optionIndex = dropdownOpts.indexOf($(this).attr('data-value'));
form[uid].condorcetmethod = methodOptions[optionIndex];
$('#cW').replaceWith(h('span', { id: 'cW'}, calculateCondorcet()[0]));
$('#dD').replaceWith(h('details', h('summary', Messages.form_showDetails), {id: 'dD'}, Messages.form_condorcetExtendedDisplay, h('div', calculateCondorcet()[1].join(', '))));
});
condorcetWinnerDiv.append(h('div', Messages.form_showCondorcetMethod, method, Messages.form_showCondorcetWinner, condorcetWinner, detailsDiv, {style: {margin: '10px'}}));
}
var q = h('div.cp-form-block-question', block.q || Messages.form_default);