mirror of
https://github.com/cryptpad/cryptpad.git
synced 2026-09-14 11:05:41 +05:00
Merge pull request #1016 from zuzanna-maria/condorcet-ui-tweaks
Changed method choice/details tag for Weblate translation
This commit is contained in:
commit
c8cef7c40d
@ -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;
|
||||
};
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user