User:Tzusheng/Wikibench-Editquality.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | Documentation for this user script can be added at User:Tzusheng/Wikibench-Editquality. |
//<nowiki>
// Campaign Page
(function ($, mw) {
$(document).ready(function() {
var wgPageName = "User:Tzusheng/sandbox/Wikipedia:Wikibench/Campaign:Editquality";
if (mw.config.get("wgPageName") === wgPageName && mw.config.get("wgAction") === "view") {
mw.loader.using(["oojs-ui-core", "oojs-ui-widgets", "oojs-ui-windows"]).done(function() {
// init
var WIKIBENCH_PREFIX = "Tzusheng/sandbox/Wikipedia:Wikibench";
var WIKIBENCH_NAMESPACE = 2;
var entityType = "diff";
var language = "en";
var entityPageSplit = "-----";
var facets = ["editDamage", "userIntent"];
var facetNames = {
editDamage: "edit damage",
userIntent: "user intent"
};
var facetLabels = {
editDamage: ["damaging", "not damaging"],
userIntent: ["bad faith", "good faith"]
};
var facetColors = {
editDamage: ["#fee7e6", "#d5fdf4"],
userIntent: ["#fee7e6", "#d5fdf4"]
};
var userName = mw.config.get("wgUserName");
var mwApi = new mw.Api();
function calculateStandardDeviation(numbers) {
// Step 1: Calculate the mean
var sum = 0;
for (var i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
var mean = sum / numbers.length;
// Step 2: Calculate the sum of squared differences
var squaredDifferencesSum = 0;
for (var j = 0; j < numbers.length; j++) {
var difference = numbers[j] - mean;
squaredDifferencesSum += difference * difference;
}
// Step 3: Calculate the variance
var variance = squaredDifferencesSum / numbers.length;
// Step 4: Calculate the standard deviation (square root of variance)
var standardDeviation = Math.sqrt(variance);
return standardDeviation;
}
function getPrefixedPages(entityType, queryContinue, deferred, results) {
deferred = deferred || $.Deferred();
queryContinue = queryContinue || {};
results = results || [];
var prefix = WIKIBENCH_PREFIX + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/";
var params = {
action: "query",
prop: "revisions",
rvprop: "content",
generator: "allpages",
gapprefix: prefix,
gaplimit: 500,
gapnamespace: WIKIBENCH_NAMESPACE,
format: "json",
formatversion: 2
};
Object.assign(params, queryContinue)
mwApi.get(params)
.done(function(data) {
var pages = data.query.pages;
pages.forEach(function(page){
// console.log(page);
// console.log(page.revisions);
if (page.revisions !== undefined) { // band-aid
page['content'] = page.revisions[0].content;
delete page['revisions'];
results.push(page);
}
});
if(data.continue){
getPrefixedPages(entityType, data.continue, deferred, results);
}else{
deferred.resolve(results);
}
})
.fail(function(e) {
deferred.fail(e);
});
return deferred.promise();
}
getPrefixedPages(entityType).done(function(results) {
var label;
var tableDiv = $(".wikibench-data-table")
var tbody = tableDiv.find("tbody");
tbody.find("tr").remove(); // remove the empty line
function sortColumn(columnId, order) {
var header = tableDiv.find(columnId);
if (order === "ascending") {
if (header.attr("title") === "Sort ascending") { // note: title is not the current sorting state
header.click();
} else if (header.attr("title") === "Sort initial") {
header.click().click();
} else {
// do nothing because the column is already ascending
}
} else if (order === "descending") {
if (header.attr("title") === "Sort ascending") {
header.click().click();
} else if (header.attr("title") === "Sort descending") {
header.click();
} else {
// do nothing because the column is already descending
}
} else {
// do nothing
}
}
var button1 = new OO.ui.ButtonWidget({label: "provide more labels"});
button1.on("click", function() {
sortColumn("#table-header-editDamage-your-label", "ascending");
sortColumn("#table-header-label-count", "ascending");
});
var button2 = new OO.ui.ButtonWidget({label: "compare my labels"});
button2.on("click", function() {
sortColumn("#table-header-userIntent-primary-label", "descending");
sortColumn("#table-header-editDamage-primary-label", "descending");
sortColumn("#table-header-userIntent-your-label", "descending");
sortColumn("#table-header-editDamage-your-label", "descending");
});
var button3 = new OO.ui.ButtonWidget({label: "build consensus (edit damage)"});
button3.on("click", function() {
sortColumn("#table-header-label-count", "descending");
sortColumn("#table-header-editDamage-disagreement", "descending")
});
var button4 = new OO.ui.ButtonWidget({label: "build consensus (user intent)"});
button4.on("click", function() {
sortColumn("#table-header-label-count", "descending");
sortColumn("#table-header-userIntent-disagreement", "descending");
});
var layoutBefore = new OO.ui.HorizontalLayout({
items: [
new OO.ui.LabelWidget({ label: "I want to:" }),
button1,
button2,
button3,
button4
]
});
tableDiv.before(layoutBefore.$element);
var searchInputDiff = new OO.ui.SearchInputWidget({
placeholder: "oldid/newid"
});
searchInputDiff.on("enter", function() {
window.open("/wiki/Special:Diff/" + searchInputDiff.getValue(), "_blank");
});
var layoutAfter = new OO.ui.HorizontalLayout({
items: [
new OO.ui.LabelWidget({ label: "Direct submission:" }),
searchInputDiff
]
})
tableDiv.after(layoutAfter.$element);
var tableLabelColors = {};
for (var i = 0; i < facets.length; i++) {
tableLabelColors[facets[i]] = {};
for (var j = 0; j < facetLabels[facets[i]].length; j++) {
tableLabelColors[facets[i]][facetLabels[facets[i]][j]] = facetColors[facets[i]][j];
}
}
var primaryLabelCounts = {};
facets.forEach(function(f) {
primaryLabelCounts[f] = {};
facetLabels[f].forEach(function(l) {
primaryLabelCounts[f][l] = 0;
})
})
for (var r = 0; r < results.length; r++) {
label = JSON.parse(results[r].content.split(entityPageSplit)[1]);
var primaryLabel = {};
var userLabels = {};
var individualLabels = {};
var lowConfidenceIndicator = {};
for (var i = 0; i < facets.length; i++) {
var f = facets[i];
lowConfidenceIndicator[f] = false;
primaryLabel[f] = label.facets[f].primaryLabel.label;
userLabels[f] = "";
individualLabels[f] = [];
primaryLabelCounts[f][primaryLabel[f]] += 1;
for (var j = 0; j < label.facets[f].individualLabels.length; j++) {
// handle user labels
if (label.facets[f].individualLabels[j].userName === userName) {
userLabels[f] = label.facets[f].individualLabels[j].label;
if (label.facets[f].individualLabels[j].lowConfidence) {
lowConfidenceIndicator[f] = true;
}
}
// handle individual labels for disagreements
if (label.facets[f].individualLabels[j].label === facetLabels[f][0]) {
if (label.facets[f].individualLabels[j].lowConfidence) {
individualLabels[f].push(-0.5);
}
else {
individualLabels[f].push(-1);
}
}
if (label.facets[f].individualLabels[j].label === facetLabels[f][1]) {
if (label.facets[f].individualLabels[j].lowConfidence) {
individualLabels[f].push(0.5);
}
else {
individualLabels[f].push(1);
}
}
}
}
var hrefLink = "<a href=\"/wiki/User:" + WIKIBENCH_PREFIX + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/" + label.entityId.toString() + "\"></a>";
tbody.append($("<tr>")
.append($("<th>").text(label.entityId).wrapInner(hrefLink).attr("scope", "row"))
.append($("<td>").text(primaryLabel[facets[0]]).attr("bgcolor", tableLabelColors[facets[0]][primaryLabel[facets[0]]]))
.append($("<td>").text(userLabels[facets[0]] + ((lowConfidenceIndicator[facets[0]])?("*"):(""))).attr("bgcolor", tableLabelColors[facets[0]][userLabels[facets[0]]]))
.append($("<td>").text(calculateStandardDeviation(individualLabels[facets[0]]).toFixed(3)))
.append($("<td>").text(primaryLabel[facets[1]]).attr("bgcolor", tableLabelColors[facets[1]][primaryLabel[facets[1]]]))
.append($("<td>").text(userLabels[facets[1]] + ((lowConfidenceIndicator[facets[1]])?("*"):(""))).attr("bgcolor", tableLabelColors[facets[1]][userLabels[facets[1]]]))
.append($("<td>").text(calculateStandardDeviation(individualLabels[facets[1]]).toFixed(3)))
.append($("<td>").text(label.facets[facets[0]].individualLabels.length.toString()))
);
}
for (var i = 0; i < facets.length; i++) {
var f = facets[i];
var tmp0 = primaryLabelCounts[f][facetLabels[f][0]];
var tmp1 = primaryLabelCounts[f][facetLabels[f][1]];
mwApi.get({
action: "parse",
text: "{{Bar box" +
"|title=" + "Primary label distribution for " + facetNames[f] +
"|titlebar=#DDD" +
// "|left1=label" +
// "|right1=quantity" +
"|width=400px" +
"|bars=" +
"{{bar percent|" + facetLabels[f][0] + "|#b32424|" + (tmp0/(tmp0+tmp1)*100).toString() + "|" + tmp0.toString() + " (" + Math.floor(tmp0/(tmp0+tmp1)*100).toString() + "%) }}" +
"{{bar percent|" + facetLabels[f][1] + "|#14866d|" + (tmp1/(tmp0+tmp1)*100).toString() + "|" + tmp1.toString() + " (" + Math.floor(tmp1/(tmp0+tmp1)*100).toString() + "%) }}" +
// "|caption=Some stuff displayed by quantity." +
"}}",
contentmodel: "wikitext"
}).done(function(ret) {
$("#wikibench-data-curation-charts").append(ret.parse.text["*"]);
});
}
});
});
}
});
})(jQuery, mediaWiki);
// Entity Page
(function ($, mw) {
$(document).ready(function() {
// init
var wikibenchURL = "User:Tzusheng/sandbox/Wikipedia:Wikibench";
var wikibenchTalkURL = "User_talk:Tzusheng/sandbox/Wikipedia:Wikibench"
var campaignURL = wikibenchURL + "/Campaign:Editquality";
var campaignTalkURL = wikibenchTalkURL + "/Campaign:Editquality";
var entityType = "diff";
var entityPagePrefix = wikibenchURL + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/";
var entityPagePrefixArchive = wikibenchURL + "/Archive/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/";
var entityPageHeader = "{{Warning |heading=Script installation is required for reading and editing |This page is part of the Wikibench project on the English Wikipedia. Please read the [[" + campaignURL + "|project page]] and install the script to see this page correctly rendered. Do not edit the source without installing the script.}}";
var entityPageSplit = "-----";
var language = "en";
var facets = ["editDamage", "userIntent"];
var facetNames = {
editDamage: "edit damage",
userIntent: "user intent"
};
var facetLabels = {
editDamage: ["damaging", "not damaging"],
userIntent: ["bad faith", "good faith"]
};
var facetIcons = {
editDamage: ["alert", "success"],
userIntent: ["alert", "success"]
};
var facetColors = {
editDamage: ["#b32424", "#14866d"],
userIntent: ["#b32424", "#14866d"]
};
// get config
var wgPageName = mw.config.get("wgPageName");
if((wgPageName.startsWith(entityPagePrefix) || (wgPageName.startsWith(entityPagePrefixArchive))) && mw.config.get("wgAction") === "view") {
// widgets
var divRender = $(".mw-parser-output");
var diffTableHeader = "<table class=\"diff diff-contentalign-left diff-editfont-monospace\" data-mw=\"interface\"><colgroup><col class=\"diff-marker\"><col class=\"diff-content\"><col class=\"diff-marker\"><col class=\"diff-content\"></colgroup><tbody>";
var diffTableFooter = "</tbody></table>";
var diffTableContent, diffTableTitle;
var windowManager;
var noticeBox;
var revdelBox;
var newPageBox;
var primaryFieldset;
var userFieldset;
var userLabel = {};
var userLowConfidences = {};
var userNote = {};
var individualFieldset = {};
var stackBars = {};
var stackBarText = {};
var lowConfidenceHtmlSnippet = "<font color=\"#72777d\">(low confidence)</font>"
var mwApi = new mw.Api();
var entityId = wgPageName.substring(entityPagePrefix.length);
var userName = mw.config.get("wgUserName");
var userId = mw.config.get("wgUserId");
mwApi.get({
action: "parse",
page: wgPageName,
prop: "wikitext"
}).done(function(ret) {
mw.loader.using(["oojs-ui-core", "oojs-ui-widgets", "oojs-ui-windows", "mediawiki.diff.styles"]).done(function(){
var label = JSON.parse(ret.parse.wikitext["*"].split(entityPageSplit)[1]);
/* ===== WINDOR MANAGER ===== */
windowManager = new OO.ui.WindowManager();
$(document.body).append(windowManager.$element);
noticeBox = new OO.ui.MessageWidget({
type: "notice",
label: new OO.ui.HtmlSnippet("Please do not directly edit the source of this page. To update the primary or your label, click the edit buttons below. To discuss, visit the talk page. To view the labeling progress of the campaign, visit the <a href=\"/wiki/" + campaignURL + "\">campaign page</a>.")
});
revdelBox = new OO.ui.MessageWidget({
type: "warning",
label: new OO.ui.HtmlSnippet("This diff has been <a href=\"/wiki/Wikipedia:Revision_deletion\">revdel\'d</a>. Please visit the <a href=\"/wiki/" + campaignTalkURL + "\">campaign talk page</a> for an ongoing discussion about handling revdel\'d diffs.")
});
newPageBox = new OO.ui.MessageWidget({
type: "warning",
label: new OO.ui.HtmlSnippet("This diff is a new page creation. Please visit the <a href=\"/wiki/" + campaignTalkURL + "\">campaign talk page</a> for an ongoing discussion about handling new pages.")
});
/* ===== PRIMARY LABEL ===== */
primaryFieldset = new OO.ui.FieldsetLayout({
label: "Primary label",
classes: ["wikibench-entity-primary-label"],
});
var labelColor = {};
for (var i = 0; i < facets.length; i++) {
labelColor[facets[i]] = {};
for (var j = 0; j < facetLabels[facets[i]].length; j++) {
labelColor[facets[i]][facetLabels[facets[i]][j]] = facetColors[facets[i]][j];
}
}
for (var i = 0; i < facets.length; i++) {
var f = facets[i];
var facetPrimaryLabel = new OO.ui.LabelWidget({
label: new OO.ui.HtmlSnippet("<font color=\"" + labelColor[f][label.facets[f].primaryLabel.label] + "\">" + label.facets[f].primaryLabel.label + "</font>")
});
primaryFieldset.addItems(
new OO.ui.FieldLayout(facetPrimaryLabel, {
label: facetNames[f].charAt(0).toUpperCase() + facetNames[f].slice(1),
align: "left"
})
)
}
primaryFieldset.addItems([
new OO.ui.FieldLayout(
new OO.ui.LabelWidget({
label: $("<a>")
.attr("href","/wiki/User:"+label.facets[facets[0]].primaryLabel.lastModifier)
.text(label.facets[facets[0]].primaryLabel.lastModifier)
}), {
label: "Last modifier",
align: "left"
}
),
new OO.ui.FieldLayout(
new OO.ui.LabelWidget({
label: label.facets[facets[0]].primaryLabel.touched
}), {
label: "Last modified time",
align: "left"
}
)
]);
var editPrimaryBtn = new OO.ui.ButtonWidget({
label: "Edit",
disabled: true // Change to false when doing demo
});
// Make a subclass of ProcessDialog for editing the primary label
function EditPrimaryDialog( config ) {
EditPrimaryDialog.super.call( this, config );
}
OO.inheritClass( EditPrimaryDialog, OO.ui.ProcessDialog );
// Specify a name for .addWindows()
EditPrimaryDialog.static.name = "editPrimaryDialog";
EditPrimaryDialog.static.title = "Edit primary label";
EditPrimaryDialog.static.actions = [
{
flags: [ "primary", "progressive" ],
label: "Publish changes",
action: "publish"
},
{
flags: "safe",
label: "Cancel"
}
];
// Customize the initialize() function to add content and layouts:
EditPrimaryDialog.prototype.initialize = function () {
EditPrimaryDialog.super.prototype.initialize.call( this );
this.panel = new OO.ui.PanelLayout( {
padded: true,
expanded: false
} );
this.content = new OO.ui.FieldsetLayout();
this.primaryLabelMessage = new OO.ui.MessageWidget({
type: "warning",
label: new OO.ui.HtmlSnippet("When editing primary labels, <a href=\"/wiki/Wikipedia:Be_bold\">be bold</a> yet respectful of others' views. Wikibench will notify the last modifier on the <a href=\"/wiki/" + wikibenchTalkURL + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/" + entityId + "\">talk page</a> with <a href=\"/wiki/Wikipedia:Signatures#Using_four_tildes\">your signature</a> after publishing changes.")
});
this.content.addItems([this.primaryLabelMessage]);
this.primaryFacetBtns = {};
for (var i = 0 ; i < facets.length; i++) {
this.primaryFacetBtns[facets[i]] = new OO.ui.ButtonSelectWidget({
items: [
new OO.ui.ButtonOptionWidget({
data: facetLabels[facets[i]][0],
label: facetLabels[facets[i]][0],
icon: facetIcons[facets[i]][0]
}),
new OO.ui.ButtonOptionWidget({
data: facetLabels[facets[i]][1],
label: facetLabels[facets[i]][1],
icon: facetIcons[facets[i]][1]
})
]
});
this.primaryFacetBtns[facets[i]].selectItemByLabel(label.facets[facets[i]].primaryLabel.label);
this.content.addItems([
new OO.ui.FieldLayout(this.primaryFacetBtns[facets[i]], {
label: facetNames[facets[i]].charAt(0).toUpperCase() + facetNames[facets[i]].slice(1),
align: "left"
})
]);
}
this.primaryLabelSummary = new OO.ui.TextInputWidget({
placeholder: "Briefly describe your changes"
});
this.content.addItems([
new OO.ui.FieldLayout(this.primaryLabelSummary, {
label: "Edit summary",
align: "top"
})
]);
this.panel.$element.append( this.content.$element );
this.$body.append( this.panel.$element );
};
EditPrimaryDialog.prototype.getBodyHeight = function () {
return this.panel.$element.outerHeight( true );
};
// Specify processes to handle the actions.
EditPrimaryDialog.prototype.getActionProcess = function ( action ) {
if ( action === "publish" ) {
// Create a new process to handle the action
return new OO.ui.Process( function () {
var primaryLabels = {}
var summary = this.primaryLabelSummary.getValue();
for (var i = 0; i < facets.length; i++) {
primaryLabels[facets[i]] = this.primaryFacetBtns[facets[i]].findSelectedItem().getData();
}
mwApi.get({
action: "query",
prop: "revisions",
rvprop: "content",
titles: wgPageName,
format: "json"
}).done(function(ret) {
var revisions = ret.query.pages;
var pageId = Object.keys(revisions)[0];
var submitContent = JSON.parse(revisions[pageId].revisions[0]["*"].split(entityPageSplit)[1]);
var lastModifier = submitContent.facets[facets[0]].primaryLabel.lastModifier;
for (var i = 0; i < facets.length; i++) {
submitContent.facets[facets[i]].primaryLabel.lastModifier = userName;
submitContent.facets[facets[i]].primaryLabel.lastModifierId = userId;
submitContent.facets[facets[i]].primaryLabel.label = primaryLabels[facets[i]];
submitContent.facets[facets[i]].primaryLabel.touched = new Date(new Date().getTime()).toUTCString();
submitContent.facets[facets[i]].primaryLabel.autolabeled = false;
}
mwApi.postWithToken("csrf",{
action: "edit",
title: wgPageName,
section: 0,
text: entityPageHeader + "\n" + entityPageSplit + "\n" + JSON.stringify(submitContent),
summary: "Primary label change from the Wikibench entity page: " + summary,
}).done(function(result,jqXHR) {
// notify the previous labeler on the talk page
mwApi.postWithToken("csrf", {
action: "edit",
title: wikibenchTalkURL + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/" + entityId,
section: "new",
sectiontitle: "The primary label has been edited",
text: "{{Ping|" + lastModifier + "}} [[User:" + userName + "|" + userName + "]] edited the primary label that you previously submitted. If you disagree with the change, please kindly engage in a discussion on this talk page and consider seeking a third opinion if needed. ~~~~"
}).done(function(result,jqXHR) {
location.reload();
});
});
});
}, this );
}
// Fallback to parent handler
return EditPrimaryDialog.super.prototype.getActionProcess.call( this, action );
};
// Create a new process dialog window.
var editPrimaryDialog = new EditPrimaryDialog();
// Add the window to window manager using the addWindows() method.
windowManager.addWindows( [ editPrimaryDialog ] );
editPrimaryBtn.on("click", function() {
windowManager.openWindow( editPrimaryDialog );
});
var discussPrimaryBtn = new OO.ui.ButtonWidget({
label: "Talk"
});
discussPrimaryBtn.on("click", function() {
window.open("/wiki/" + wikibenchTalkURL + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/" + entityId, "_self");
})
// primaryFieldset.addItems(
// new OO.ui.FieldLayout(editPrimaryBtn, {
// align: "left"
// })
// );
primaryFieldset.addItems(
new OO.ui.FieldLayout(new OO.ui.Widget({
content: [
new OO.ui.HorizontalLayout({
items: [
editPrimaryBtn,
discussPrimaryBtn
]
})
]
}), {
align: "left"
})
);
/* ===== USER LABEL ===== */
userFieldset = new OO.ui.FieldsetLayout({
label: "Your label (" + userName + ")",
classes: ["wikibench-entity-user-label"]
});
for (var i = 0; i < facets.length; i++) {
var f = facets[i];
userLabel[f] = undefined;
userNote[f] = "";
var displayLabelName = "undefined";
label.facets[f].individualLabels.forEach(function(l) {
if (userName === l.userName) {
userLabel[f] = l.label;
userLowConfidences[f] = l.lowConfidence;
userNote[f] = l.note;
displayLabelName = "<font color=\"" + labelColor[f][l.label] + "\">" + l.label + "</font>";
if (l.lowConfidence) {
displayLabelName = displayLabelName + " " + lowConfidenceHtmlSnippet;
}
}
});
userFieldset.addItems(
new OO.ui.FieldLayout(
new OO.ui.LabelWidget({
label: new OO.ui.HtmlSnippet(displayLabelName)
}), {
label: facetNames[f].charAt(0).toUpperCase() + facetNames[f].slice(1),
align: "left"
})
);
}
var editUserBtn = new OO.ui.ButtonWidget({
label: "Edit",
disabled: true // Change to false when doing demo
});
// Make a subclass of Process Dialog for editing the user label
function EditUserLabelDialog(config) {
EditUserLabelDialog.super.call(this, config);
}
OO.inheritClass(EditUserLabelDialog, OO.ui.ProcessDialog);
EditUserLabelDialog.static.name = "editUserLabelDialog";
EditUserLabelDialog.static.title = "Edit your label";
EditUserLabelDialog.static.actions = [
{
flags: ["primary", "progressive"],
label: "Publish changes",
action: "publish"
},
{
flags: "safe",
label: "Cancel"
}
];
EditUserLabelDialog.prototype.initialize = function() {
EditUserLabelDialog.super.prototype.initialize.call(this);
this.panel = new OO.ui.PanelLayout({
padded: true,
expanded: false
});
this.content = new OO.ui.FieldsetLayout();
this.userFacetBtns = {};
this.userFacetLowConfidenceCheckboxes = {};
this.userFacetNoteInputs = {};
for (var i = 0; i < facets.length; i++) {
var f = facets[i];
this.userFacetBtns[f] = new OO.ui.ButtonSelectWidget({
items: [
new OO.ui.ButtonOptionWidget({
data: facetLabels[f][0],
label: facetLabels[f][0],
icon: facetIcons[f][0]
}),
new OO.ui.ButtonOptionWidget({
data: facetLabels[f][1],
label: facetLabels[f][1],
icon: facetIcons[f][1]
})
]
});
if (userLabel[f] !== undefined) {
this.userFacetBtns[f].selectItemByLabel(userLabel[f]);
}
this.userFacetLowConfidenceCheckboxes[f] = new OO.ui.CheckboxInputWidget();
if (userLowConfidences[f] === true) {
this.userFacetLowConfidenceCheckboxes[f].setSelected(true);
}
this.userFacetNoteInputs[f] = new OO.ui.TextInputWidget({
value: userNote[f]
})
this.content.addItems([
new OO.ui.FieldLayout(this.userFacetBtns[f], {
label: facetNames[f].charAt(0).toUpperCase() + facetNames[f].slice(1),
align: "left"
}),
new OO.ui.FieldLayout(new OO.ui.Widget({
content: [
new OO.ui.HorizontalLayout({
items: [
this.userFacetLowConfidenceCheckboxes[f],
new OO.ui.LabelWidget({label: "low confidence"})
]
})
]
}), {
label: " ",
align: "left"
}),
new OO.ui.FieldLayout(this.userFacetNoteInputs[f], {
label: "Note for " + facetNames[f],
align: "left"
})
])
}
this.panel.$element.append(this.content.$element);
this.$body.append(this.panel.$element);
}
EditUserLabelDialog.prototype.getBodyHeight = function() {
return this.panel.$element.outerHeight(true);
}
EditUserLabelDialog.prototype.getActionProcess = function(action) {
if ( action === "publish" ) {
// Create a new process to handle the action
return new OO.ui.Process( function () {
var tmpUserLabel = {};
var tmpUserLowConfidences = {};
var tmpUserNote = {};
for (var i = 0; i < facets.length; i++) {
tmpUserLabel[facets[i]] = this.userFacetBtns[facets[i]].findSelectedItem().getData();
tmpUserLowConfidences[facets[i]] = this.userFacetLowConfidenceCheckboxes[facets[i]].isSelected();
tmpUserNote[facets[i]] = this.userFacetNoteInputs[facets[i]].getValue();
}
mwApi.get({
action: "query",
prop: "revisions",
rvprop: "content",
titles: wgPageName,
format: "json"
}).done(function(ret) {
var revisions = ret.query.pages;
var pageId = Object.keys(revisions)[0];
var submitContent = JSON.parse(revisions[pageId].revisions[0]["*"].split(entityPageSplit)[1]);
for (var i = 0; i < facets.length; i++) {
var isUserLabelExist = false;
var f = facets[i];
var submitLabel = {
"userName": userName,
"userId": userId,
"label": tmpUserLabel[f],
"note": tmpUserNote[f],
"origin": "wikibench-enwiki-entity-page",
"created": new Date(new Date().getTime()).toUTCString(),
"touched": new Date(new Date().getTime()).toUTCString(),
"lowConfidence": tmpUserLowConfidences[f],
"category": []
}
for (var j = 0; j < submitContent.facets[f].individualLabels.length; j++) {
if (submitContent.facets[f].individualLabels[j].userName === userName) {
submitLabel.created = submitContent.facets[f].individualLabels[j].created;
submitContent.facets[f].individualLabels[j] = submitLabel;
isUserLabelExist = true;
break;
}
}
if (!isUserLabelExist) {
submitContent.facets[f].individualLabels.push(submitLabel);
}
}
mwApi.postWithToken("csrf",{
action: "edit",
title: wgPageName,
section: 0,
text: entityPageHeader + "\n" + entityPageSplit + "\n" + JSON.stringify(submitContent),
summary: "Individual label edit from the Wikibench entity page",
}).done(function(result,jqXHR) {
location.reload();
})
});;
}, this );
}
// Fallback to parent handler
return EditUserLabelDialog.super.prototype.getActionProcess.call( this, action );
}
var editUserLabelDialog = new EditUserLabelDialog();
windowManager.addWindows([editUserLabelDialog]);
editUserBtn.on("click", function() {
windowManager.openWindow(editUserLabelDialog);
});
userFieldset.addItems([
new OO.ui.FieldLayout(editUserBtn, {
align: "left"
})
]);
divRender.find("table").remove(); // remove warning message
divRender.find("hr").remove(); // remove horizontal line
divRender.find("p").remove(); // remove json content
divRender
.append(noticeBox.$element)
.append("<h2>Difference between revisions</h2>")
.append("<div id=\"wikibench-entity-page-diff-table\"></div>")
.append("<h2>Primary and your labels</h2>")
.append(primaryFieldset.$element)
.append(userFieldset.$element);
/* ===== INDIVIDUAL LABEL ===== */
for (var i = 0; i < facets.length; i++) {
var f = facets[i];
individualFieldset[f] = {};
var labelCount = {};
var labelLowConfidenceCount = {};
for (var j = 0; j < facetLabels[f].length; j++) {
var l = facetLabels[f][j];
labelCount[l] = 0;
labelLowConfidenceCount[l] = 0;
individualFieldset[f][l] = new OO.ui.FieldsetLayout({
icon: "expand",
classes: ["wikibench-entity-individual-labels"]
});
label.facets[f].individualLabels.forEach(function(individualLabel) {
if (individualLabel.label === l) {
var labelText = "<a href=\"/wiki/User:" + individualLabel.userName + "\">" + individualLabel.userName + "</a>";
labelCount[l]++;
if (individualLabel.lowConfidence) {
labelLowConfidenceCount[l]++;
labelText = labelText + " " + lowConfidenceHtmlSnippet;
}
individualFieldset[f][l].addItems(
new OO.ui.FieldLayout(
new OO.ui.LabelWidget({label: individualLabel.note}),
{label: new OO.ui.HtmlSnippet(labelText)}
)
);
}
});
individualFieldset[f][l].setLabel(l + " (" + labelCount[l].toString() + ")");
individualFieldset[f][l].$group.toggle(false);
}
// stack bars (assume binary labels)
var stackBarCounts = [
labelCount[facetLabels[f][0]] - labelLowConfidenceCount[facetLabels[f][0]],
labelLowConfidenceCount[facetLabels[f][0]],
labelLowConfidenceCount[facetLabels[f][1]],
labelCount[facetLabels[f][1]] - labelLowConfidenceCount[facetLabels[f][1]]
];
var stackBarTotal = 0;
var stackBarNames = [
facetLabels[f][0],
facetLabels[f][0] + " (low confidence)",
facetLabels[f][1] + " (low confidence)",
facetLabels[f][1]
];
var stackBarColors = ["#b32424", "#fee7e6", "#d5fdf4", "#14866d"]
stackBarText[f] = "{{Stacked bar|height=18px|";
for (var k = 0; k < 4; k++) {
if (stackBarCounts[k] > 0) {
var tmp = (k+1).toString();
stackBarText[f] += "A" + tmp + "=" + stackBarCounts[k].toString() + "|C" + tmp + "=" + stackBarColors[k] + "|T" + tmp + "=" + stackBarNames[k] + "|";
}
stackBarTotal += stackBarCounts[k];
}
stackBarText[f] += "Total=" + (stackBarTotal).toString() + "}}";
divRender
.append("<h2>" + facetNames[f].charAt(0).toUpperCase() + facetNames[f].slice(1) + " labels</h2>")
.append("<h3>Label distribution</h3>")
.append("<div id=\"Wikibench-StackBar-" + f + "\"></div>")
.append("<h3>Individual labels</h3>");
for (var j = 0; j < facetLabels[f].length; j++) {
var l = facetLabels[f][j];
divRender.append(individualFieldset[f][l].$element);
individualFieldset[f][l].$element.find(".oo-ui-fieldsetLayout-header").click(function(){
var header = $(this);
var content = header.next();
content.slideToggle(function () {
header.children(".oo-ui-iconElement-icon").toggleClass("oo-ui-icon-collapse").toggleClass("oo-ui-icon-expand");
});
})
}
}
// get and append the stackbars outside the for loop to bypass the await time
// p.s. await is not available in ES5
facets.forEach(function(f) {
mwApi.get({
action: "parse",
text: stackBarText[f],
contentmodel: "wikitext"
}).done(function(ret) {
$("#Wikibench-StackBar-"+f).append(ret.parse.text["*"]);
});
});
// diff table
mwApi.get({
action: "compare",
fromrev: parseInt(entityId.split("/")[0]),
torev: parseInt(entityId.split("/")[1]),
}).done(function(ret) {
diffTableContent = ret.compare["*"];
diffTableTitle =
"<tr class=\"diff-title\" lang=\"" + language + "\">" +
"<td colspan=\"2\" class=\"diff-otitle diff-side-deleted\">" +
"<div id=\"mw-diff-otitle1\">" +
"<strong><a href=\"/wiki/Special:Permalink/" + ret.compare.fromrevid + "\">Revision before edit</a></strong>" +
"</div>" +
"<div id=\"mw-diff-otitle3\"> <span class=\"comment\">Revision ID: " + ret.compare.fromrevid + "</span></div>" +
"<div id=\"mw-diff-otitle5\"></div>" +
"</td>" +
"<td colspan=\"2\" class=\"diff-ntitle diff-side-added\">" +
"<div id=\"mw-diff-ntitle1\">" +
"<strong><a href=\"/wiki/Special:Permalink/" + ret.compare.torevid + "\">Revision after edit</a></strong>" +
" (<a href=\"/wiki/Special:Diff/" + ret.compare.fromrevid + "/" + ret.compare.torevid + "\">diff page</a>)" +
"</div>" +
"<div id=\"mw-diff-ntitle3\"> <span class=\"comment\">Revision ID: " + ret.compare.torevid + "</span></div>" +
// "<div id=\"mw-diff-ntitle5\"></div>" +
"</td>" +
"</tr>" +
"<tr><td colspan=\"4\" class=\"diff-multi\" lang=\"" + language + "\">" + label.entityNote + "</td></tr>";
divRender.find("#wikibench-entity-page-diff-table").append(diffTableHeader + diffTableTitle + diffTableContent + diffTableFooter);
}).fail(function(e) {
if (entityId.split("/")[0] === "false") {
divRender.find("#wikibench-entity-page-diff-table").append(newPageBox.$element);
}
else {
divRender.find("#wikibench-entity-page-diff-table").append(revdelBox.$element);
}
});
});
});
}
});
})(jQuery, mediaWiki);
// Plug-In
/*
(function ($, mw) {
$(document).ready(function() {
if(mw.config.get("wgDiffNewId") !== null) {
// init
var wikibenchURL = "User:Tzusheng/sandbox/Wikipedia:Wikibench";
var campaignURL = "User:Tzusheng/sandbox/Wikipedia:Wikibench/Campaign:Editquality";
var entityType = "diff";
var entityPageSplit = "-----";
var facets = ["editDamage", "userIntent"];
var facetNames = {
editDamage: "edit damage",
userIntent: "user intent"
};
var facetHelp = {
editDamage: "Please check the <a href=\"/wiki/" + campaignURL + "#Label_definitions\">campaign page</a> for the definition of edit damage. The optional checkbox on the right lets you specify that you provide the label with lower confidence when you're not so sure.",
userIntent: "Please check the <a href=\"/wiki/" + campaignURL + "#Label_definitions\">campaign page</a> for the definition of user intent. The optional checkbox on the right lets you specify that you provide the label with lower confidence when you're not so sure."
};
var facetLabels = {
editDamage: ["damaging", "not damaging"],
userIntent: ["bad faith", "good faith"]
};
var facetIcons = {
editDamage: ["alert", "success"],
userIntent: ["alert", "success"]
}
var successMessage = "Your submission has been recorded";
var warningMessage = "Your submission has been recorded but is different from the primary label";
// get config
var mwApi = new mw.Api();
var diffNewId = mw.config.get("wgDiffNewId");
var diffOldId = mw.config.get("wgDiffOldId");
var userName = mw.config.get("wgUserName");
var userId = mw.config.get("wgUserId");
var revisionId; // revision ID of the entity page, not the diff page
var entityPageTitle = wikibenchURL + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/" + diffOldId.toString() + "/" + diffNewId.toString();
var entityPageHeader = "{{Warning |heading=Script installation is required for reading and editing |This page is part of the Wikibench project on the English Wikipedia. Please read the [[" + campaignURL + "|project page]] and install the script to see this page correctly rendered. Do not edit the source without installing the script.}}";
var routingMessage = "You are welcome to review other Wikipedians' labels on the <a href=\"/wiki/" + entityPageTitle + "\">entity page of this " + entityType + "</a> or close this message for resubmission.";
// labels
var primaryLabels = {};
var autolabeled = {};
var userLabels = {};
var userLowConfidences = {};
var userNotes = {};
// widgets
var facetBtns = {};
var facetLowConfidenceCheckboxes = {};
var facetWidgets = {};
var facetNoteInputs = {}; // assume notes might be different
var submitBtn;
var submitMessage;
var getEntityPage = mwApi.get({ // get the entity page. if it doesn't exist, return revisionId = "-1"
action: "query",
prop: "revisions",
rvprop: "content",
titles: entityPageTitle,
format: "json"
});
var parseEntityPage = getEntityPage.then(function(ret) {
revisionId = Object.keys(ret.query.pages)[0];
if (revisionId !== "-1") { // the entity page already exists
var revisions = ret.query.pages;
var pageId = Object.keys(revisions)[0];
var entityPageContent = JSON.parse(revisions[pageId].revisions[0]["*"].split(entityPageSplit)[1]);
facets.forEach(function(f) {
primaryLabels[f] = entityPageContent.facets[f].primaryLabel.label;
autolabeled[f] = entityPageContent.facets[f].primaryLabel.autolabeled;
entityPageContent.facets[f].individualLabels.forEach(function(l) {
if (userName === l.userName) {
userLabels[f] = l.label;
userLowConfidences[f] = l.lowConfidence;
userNotes[f] = l.note;
}
});
});
}
});
var renderPlugIn = parseEntityPage.then(function() {
mw.loader.using(["oojs-ui-core", "oojs-ui-widgets", "oojs-ui-windows"]).done(function(){
facets.forEach(function(f) {
facetBtns[f] = new OO.ui.ButtonSelectWidget({
items: [
new OO.ui.ButtonOptionWidget({
data: facetLabels[f][0],
label: facetLabels[f][0],
icon: facetIcons[f][0]
}),
new OO.ui.ButtonOptionWidget({
data: facetLabels[f][1],
label: facetLabels[f][1],
icon: facetIcons[f][1]
})
]
});
if (!$.isEmptyObject(userLabels)) {
facetBtns[f].selectItemByLabel(userLabels[f]);
}
facetBtns[f].on("choose", function(item){
userLabels[f] = item.getData();
});
facetLowConfidenceCheckboxes[f] = new OO.ui.CheckboxInputWidget();
if (!$.isEmptyObject(userLowConfidences[f])) {
facetLowConfidenceCheckboxes[f].setSelected(userLowConfidences[f]);
}
facetWidgets[f] = new OO.ui.Widget({
content: [
new OO.ui.HorizontalLayout({
items: [
facetBtns[f],
facetLowConfidenceCheckboxes[f],
new OO.ui.LabelWidget({label: "low confidence"})
]
})
]
});
facetNoteInputs[f] = new OO.ui.TextInputWidget({});
if (!$.isEmptyObject(userNotes)){
facetNoteInputs[f].setValue(userNotes[f]);
}
});
submitBtn = new OO.ui.ButtonWidget({
label: "Submit",
flags: ["primary", "progressive"]
});
submitMessage = new OO.ui.MessageWidget({
showClose: true
});
submitMessage.toggle(false);
var fieldset = new OO.ui.FieldsetLayout({
label: new OO.ui.HtmlSnippet("Wikibench Plug-In"),
id: "wikibench-diff-plugin",
help: new OO.ui.HtmlSnippet("<a href=\"/wiki/" + campaignURL + "\">Editquality Campaign</a>"),
helpInline: true
});
// if user label already exists, compare it with the primary label and update submitMessage accordingly
if (!$.isEmptyObject(userLabels)) {
var isSameAsPrimary = true;
if (!$.isEmptyObject(primaryLabels)) { // make sure the primary label exist
facets.forEach(function(f) {
if (userLabels[f] !== primaryLabels[f]) {
isSameAsPrimary = false;
}
});
}
if (isSameAsPrimary) {
submitMessage.setType("success");
submitMessage.setLabel(new OO.ui.HtmlSnippet("<strong>" + successMessage + "</strong>" + "<br>" + routingMessage));
}
else {
var primaryLabelMessage = "("
for (var i = 0; i < facets.length; i++) {
primaryLabelMessage += primaryLabels[facets[i]];
primaryLabelMessage += ", ";
}
primaryLabelMessage = primaryLabelMessage.slice(0,-2) + ")";
submitMessage.setType("warning");
submitMessage.setLabel(new OO.ui.HtmlSnippet("<strong>" + warningMessage + " " + primaryLabelMessage + "</strong>" + "<br>" + routingMessage));
}
submitMessage.toggle(true);
submitBtn.setDisabled(true);
submitBtn.toggle(false);
}
// add all the widgets to feildset
fieldset.addItems(
new OO.ui.FieldLayout(
new OO.ui.LabelWidget({label: diffOldId.toString() + "/" + diffNewId.toString()}), {
label: "Diff IDs",
align: "left"
})
);
for (var i = 0; i < facets.length; i++) {
fieldset.addItems(
new OO.ui.FieldLayout(facetWidgets[facets[i]], {
label: facetNames[facets[i]].charAt(0).toUpperCase() + facetNames[facets[i]].slice(1),
align: "left",
help: new OO.ui.HtmlSnippet(facetHelp[facets[i]])
})
);
}
for (var i = 0; i < facets.length; i++) {
fieldset.addItems(
new OO.ui.FieldLayout(facetNoteInputs[facets[i]], {
label: "Note for " + facetNames[facets[i]].toLowerCase(),
align: "left",
help: "An optional note that explains the labels you provide and, in case of low confidence, why so."
})
);
}
fieldset.addItems([
new OO.ui.FieldLayout(submitBtn, {}),
new OO.ui.FieldLayout(submitMessage, {})
]);
//$("#mw-oldid").after(fieldset.$element);
//$(".mw-revslider-container").after(fieldset.$element);
$("#contentSub").after(fieldset.$element);
submitBtn.on("click", function() {
// labels and user login are required for submission
var isLabelUndefined = false;
facets.forEach(function(f) {
if (userLabels[f] === undefined) {
isLabelUndefined = true;
}
});
if (isLabelUndefined) {
OO.ui.alert("Labels are required for submission.");
}
else if (userName === null){
OO.ui.alert("User login is required for submission.");
}
else {
// TODO: consider autolabel here
mwApi.get({ // get primary label again in case there are any changes from others
action: "query",
prop: "revisions",
rvprop: "content",
titles: entityPageTitle,
format: "json"
}).done(function(ret) {
var submitLabels = {};
var submitContent;
facets.forEach(function(f) {
submitLabels[f] = {
"userName": userName,
"userId": userId,
"label": userLabels[f],
"note": facetNoteInputs[f].getValue(),
"origin": "wikibench-enwiki-diff-plugin",
"created": new Date(new Date().getTime()).toUTCString(),
"touched": new Date(new Date().getTime()).toUTCString(),
"lowConfidence": facetLowConfidenceCheckboxes[f].isSelected(),
"category": []
}
});
if (Object.keys(ret.query.pages)[0] === "-1") { // entity page doesn't exist
submitContent = {
"entityType": entityType,
"entityId": diffOldId.toString() + "/" + diffNewId.toString(),
"entityNote": $("td.diff-multi").text(),
"facets": {}
}
facets.forEach(function(f) {
submitContent.facets[f] = {};
submitContent.facets[f]["primaryLabel"] = {
"lastModifier": userName,
"lastModifierId": userId,
"label": userLabels[f],
"touched": submitLabels[f].touched,
"autolabeled": false
};
submitContent.facets[f]["individualLabels"] = [submitLabels[f]];
});
}
else { // entity page already exists
var revisions = ret.query.pages;
var pageId = Object.keys(revisions)[0];
submitContent = JSON.parse(revisions[pageId].revisions[0]["*"].split(entityPageSplit)[1]);
for (var i = 0; i < facets.length; i++) {
var f = facets[i];
var isUserLabelExist = false;
primaryLabels[f] = submitContent.facets[f].primaryLabel.label; // get primary label again in case someone updates it in between
for (var j = 0; j < submitContent.facets[f].individualLabels.length; j++) {
if (submitContent.facets[f].individualLabels[j].userName === userName) {
submitLabels[f].created = submitContent.facets[f].individualLabels[j].created;
submitContent.facets[f].individualLabels[j] = submitLabels[f];
isUserLabelExist = true;
break;
}
}
if (isUserLabelExist && (submitContent.facets[f].individualLabels.length === 1) && (submitContent.facets[f].primaryLabel.lastModifier === userName)) {
// allow changing the primary label from the plug-in if the user is the only laber submitter
submitContent.facets[f]["primaryLabel"] = {
"lastModifier": userName,
"lastModifierId": userId,
"label": userLabels[f],
"touched": submitLabels[f].touched,
"autolabeled": false
};
primaryLabels[f] = submitContent.facets[f]["primaryLabel"].label; // update primary label for submitMessage
}
if (!isUserLabelExist) {
submitContent.facets[f]["individualLabels"].push(submitLabels[f]);
}
}
}
mwApi.postWithToken("csrf",{
action: "edit",
title: entityPageTitle,
section: 0,
text: entityPageHeader + "\n" + entityPageSplit + "\n" + JSON.stringify(submitContent),
summary: "Label submission from the Wikibench diff plug-in",
}).done(function(result,jqXHR){
var isSameAsPrimary = true;
if (!$.isEmptyObject(primaryLabels)) { // primary label already exist
facets.forEach(function(f) {
if (userLabels[f] !== primaryLabels[f]) {
isSameAsPrimary = false;
}
});
}
if (isSameAsPrimary) {
submitMessage.setType("success");
submitMessage.setLabel(new OO.ui.HtmlSnippet("<strong>" + successMessage + "</strong>" + "<br>" + routingMessage));
}
else {
var primaryLabelMessage = "("
facets.forEach(function(f) {
primaryLabelMessage += primaryLabels[f];
primaryLabelMessage += ", ";
});
primaryLabelMessage = primaryLabelMessage.slice(0,-2) + ")";
submitMessage.setType("warning");
submitMessage.setLabel(new OO.ui.HtmlSnippet("<strong>" + warningMessage + " " + primaryLabelMessage + "</strong>" + "<br>" + routingMessage));
}
submitMessage.toggle(true);
submitBtn.setDisabled(true);
submitBtn.toggle(false);
}).fail(function(code,result){
if ( code === "http" ) {
mw.log( "HTTP error: " + result.textStatus ); // result.xhr contains the jqXHR object
} else if ( code === "ok-but-empty" ) {
mw.log( "Got an empty response from the server" );
} else {
mw.log( "API error: " + code );
}
});
});
}
});
submitMessage.on("close", function() {
submitMessage.toggle(false);
submitBtn.setDisabled(false);
submitBtn.toggle(true);
});
});
});
$.when(renderPlugIn).done(function(data) {
//console.log("done");
});
}
});
})(jQuery, mediaWiki);
*/
// Evaluation page
(function ($, mw) {
$(document).ready(function() {
var wgPageName = "User:Tzusheng/sandbox/Wikipedia:Wikibench/Evaluation:Editquality";
if (mw.config.get("wgPageName") === wgPageName && mw.config.get("wgAction") === "view") {
mw.loader.using(["oojs-ui-core", "oojs-ui-widgets", "oojs-ui-windows"]).done(function() {
// init
var WIKIBENCH_PREFIX = "Tzusheng/sandbox/Wikipedia:Wikibench";
var WIKIBENCH_NAMESPACE = 2;
var RATE_LIMIT = 10;
var ROUND_PRECISION = 2;
var entityType = "diff";
var language = "en";
var entityPageSplit = "-----";
var facets = ["editDamage", "userIntent"];
var facetNames = {
editDamage: "edit damage",
userIntent: "user intent"
};
var facetLabels = {
editDamage: ["damaging", "not damaging"],
userIntent: ["bad faith", "good faith"]
};
var facetColors = {
editDamage: ["#fee7e6", "#d5fdf4"],
userIntent: ["#fee7e6", "#d5fdf4"]
};
var mwApi = new mw.Api();
var tableDiv = $("#enwiki-evaluation-editquality");
var tbody = tableDiv.find("tbody");
var progressBar = new OO.ui.ProgressBarWidget( {
progress: false
});
tableDiv.after(progressBar.$element);
// var loadDataBtn = new OO.ui.ButtonWidget({
// label: "Load " + RATE_LIMIT.toString() + " more edits"
// });
var requestLimitMessage = new OO.ui.MessageWidget({
type: "error",
showClose: true,
label: new OO.ui.HtmlSnippet("The table isn't loading due to rate limits imposed by ORES and LiftWing. Please try again later in a few seconds by refreshing your browser.")
});
requestLimitMessage.toggle(false);
requestLimitMessage.on("close", function() {
requestLimitMessage.toggle(false);
// loadDataBtn.toggle(true);
});
tableDiv.after(requestLimitMessage.$element);
var tableLabelColors = {};
for (var i = 0; i < facets.length; i++) {
tableLabelColors[facets[i]] = {};
for (var j = 0; j < facetLabels[facets[i]].length; j++) {
tableLabelColors[facets[i]][facetLabels[facets[i]][j]] = facetColors[facets[i]][j];
}
}
tableLabelColors["reverted"] = "#fee7e6";
tableLabelColors["not reverted"] = "#d5fdf4";
var probColors = "#72777d";
var tableRows = {};
// var revids = [];
var promises = [];
var liftwing = {};
var ores = {};
function calculateStandardDeviation(numbers) {
// Step 1: Calculate the mean
var sum = 0;
for (var i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
var mean = sum / numbers.length;
// Step 2: Calculate the sum of squared differences
var squaredDifferencesSum = 0;
for (var j = 0; j < numbers.length; j++) {
var difference = numbers[j] - mean;
squaredDifferencesSum += difference * difference;
}
// Step 3: Calculate the variance
var variance = squaredDifferencesSum / numbers.length;
// Step 4: Calculate the standard deviation (square root of variance)
var standardDeviation = Math.sqrt(variance);
return standardDeviation;
}
function sortColumn(columnId, order) {
var header = tableDiv.find(columnId);
if (order === "ascending") {
if (header.attr("title") === "Sort ascending") { // note: title is not the current sorting state
header.click();
} else if (header.attr("title") === "Sort initial") {
header.click().click();
} else {
// do nothing because the column is already ascending
}
} else if (order === "descending") {
if (header.attr("title") === "Sort ascending") {
header.click().click();
} else if (header.attr("title") === "Sort descending") {
header.click();
} else {
// do nothing because the column is already descending
}
} else {
// do nothing
}
}
var button1 = new OO.ui.ButtonWidget({label: "Wikibench and ORES"});
button1.on("click", function() {
sortColumn("#table-header-userIntent-ores", "descending");
sortColumn("#table-header-editDamage-ores", "descending");
sortColumn("#table-header-userIntent-wikibench", "descending");
sortColumn("#table-header-editDamage-wikibench", "descending");
});
var button2 = new OO.ui.ButtonWidget({label: "Wikibench and LiftWing"});
button2.on("click", function() {
sortColumn("#table-header-reverted-liftwing", "descending");
sortColumn("#table-header-userIntent-wikibench", "descending");
sortColumn("#table-header-editDamage-wikibench", "descending");
});
var button3 = new OO.ui.ButtonWidget({label: "ORES and LiftWing"});
button3.on("click", function() {
sortColumn("#table-header-reverted-liftwing", "descending");
sortColumn("#table-header-userIntent-ores", "descending");
sortColumn("#table-header-editDamage-ores", "descending");
});
var layoutSortBtns = new OO.ui.HorizontalLayout({
items: [
new OO.ui.LabelWidget({ label: "I want to compare:" }),
button1,
button2,
button3
]
});
tableDiv.before(layoutSortBtns.$element);
layoutSortBtns.toggle(false);
function getPrefixedPages(entityType, queryContinue, deferred, results) {
deferred = deferred || $.Deferred();
queryContinue = queryContinue || {};
results = results || [];
var prefix = WIKIBENCH_PREFIX + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/";
var params = {
action: "query",
prop: "revisions",
rvprop: "content",
generator: "allpages",
gapprefix: prefix,
gaplimit: 500,
gapnamespace: WIKIBENCH_NAMESPACE,
format: "json",
formatversion: 2
};
Object.assign(params, queryContinue)
mwApi.get(params)
.done(function(data) {
var pages = data.query.pages;
pages.forEach(function(page){
if (page.revisions !== undefined) {
page['content'] = page.revisions[0].content;
delete page['revisions'];
results.push(page);
}
});
if(data.continue){
getPrefixedPages(entityType, data.continue, deferred, results);
}else{
deferred.resolve(results);
}
})
.fail(function(e) {
deferred.fail(e);
});
return deferred.promise();
}
getPrefixedPages(entityType).done(function(results) {
// tableDiv.after(loadDataBtn.$element);
function shuffle(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
shuffle(results);
var startIndex = 0;
// loadDataBtn.on("click", function() {
var renderCount = 0;
var revids = [];
for (var i = startIndex; i < results.length; i++) {
if (renderCount >= RATE_LIMIT) {
break;
}
label = JSON.parse(results[i].content.split(entityPageSplit)[1]);
if ((label.entityId.split("/")[0] !== "false") && (label.entityNote === "")) { // exclude new page and multiple changes
var newId = label.entityId.split("/")[1];
tableRows[newId] = {};
tableRows[newId]["entityId"] = label.entityId;
tableRows[newId]["wikibench"] = {}
tableRows[newId]["ores"] = {};
facets.forEach(function(f) {
tableRows[newId]["wikibench"][f] = label.facets[f];
})
revids.push(newId);
var request1 = $.ajax({
url: 'http://api.wikimedia.org/service/lw/inference/v1/models/revertrisk-language-agnostic:predict',
crossDomain: true,
method: 'post',
contentType: 'application/x-www-form-urlencoded',
data: '{"rev_id":' + newId + ', "lang": "en"}'
}).done( function ( result, textStatus, jqXHR ) {
liftwing[result.revision_id.toString()] = result["output"];
});
promises.push(request1);
// var request2 = $.ajax({
// url: "http://ores.wikimedia.org/v3/scores/enwiki",
// data: {
// "context": "enwiki",
// "models": "damaging|goodfaith",
// "revids": newId.toString()
// },
// timeout: 30 * 1000, // 30 seconds
// dataType: "json",
// type: "GET"
// }).done(function ( result, textStatus, jqXHR ){
// ores[Object.keys(result["enwiki"]["scores"])[0]] = Object.values(result["enwiki"]["scores"])[0]
// });
// promises.push(request2);
renderCount++;
}
}
var request2 = $.ajax({
url: "http://ores.wikimedia.org/v3/scores/enwiki",
data: {
"context": "enwiki",
"models": "damaging|goodfaith",
"revids": revids.join("|")
},
timeout: 30 * 1000, // 30 seconds
dataType: "json",
type: "GET"
}).done(function ( result, textStatus, jqXHR ){
for (var r = 0; r < revids.length; r++) {
ores[revids[r].toString()] = result["enwiki"]["scores"][revids[r].toString()];
}
});
promises.push(request2);
$.when.apply(null, promises).done(function() {
if (startIndex === 0) {
tbody.find("tr").remove(); // remove the empty line
}
for (var r = 0; r < revids.length; r++) {
var row = tableRows[revids[r]];
var liftwing_prediction = liftwing[revids[r]]["prediction"] ? "reverted" : "not reverted";
var ores_prediction_editDamage = ores[revids[r]]["damaging"]["score"]["prediction"] ? "damaging" : "not damaging";
var ores_prediction_userIntent = ores[revids[r]]["goodfaith"]["score"]["prediction"] ? "good faith" : "bad faith";
var individualLabels = {};
// calculate wikibench agreement
for (var i = 0; i < facets.length; i++) {
var f = facets[i];
individualLabels[f] = [];
for (var j = 0; j < row["wikibench"][f].individualLabels.length; j++) {
// handle individual labels for disagreements
var individualLabel = row["wikibench"][f].individualLabels[j];
if (individualLabel.label === facetLabels[f][0]) {
if (individualLabel.lowConfidence) {
individualLabels[f].push(-0.5);
}
else {
individualLabels[f].push(-1);
}
}
if (individualLabel.label === facetLabels[f][1]) {
if (individualLabel.lowConfidence) {
individualLabels[f].push(0.5);
}
else {
individualLabels[f].push(1);
}
}
}
}
var hrefLink = "<a href=\"/wiki/User:" + WIKIBENCH_PREFIX + "/Entity:" + entityType.charAt(0).toUpperCase() + entityType.slice(1) + "/" + row["entityId"] + "\"></a>";
tbody.append($("<tr>")
.append($("<th>").text(row["entityId"]).wrapInner(hrefLink).attr("scope", "row"))
.append($("<td>").html(row["wikibench"][facets[0]].primaryLabel.label + " <span style=\"color:" + probColors + "\">(" + (1 - calculateStandardDeviation(individualLabels[facets[0]])).toFixed(ROUND_PRECISION).toString() + ")</span>").attr("bgcolor", tableLabelColors[facets[0]][row["wikibench"][facets[0]].primaryLabel.label]))
.append($("<td>").html(ores_prediction_editDamage + " <span style=\"color:" + probColors + "\">(" + ores[revids[r]]["damaging"]["score"]["probability"][ores[revids[r]]["damaging"]["score"]["prediction"].toString()].toFixed(ROUND_PRECISION).toString() + ")</span>").attr("bgcolor", tableLabelColors[facets[0]][ores_prediction_editDamage]))
.append($("<td>").html(row["wikibench"][facets[1]].primaryLabel.label + " <span style=\"color:" + probColors + "\">(" + (1 - calculateStandardDeviation(individualLabels[facets[1]])).toFixed(ROUND_PRECISION).toString() + ")</span>").attr("bgcolor", tableLabelColors[facets[1]][row["wikibench"][facets[1]].primaryLabel.label]))
.append($("<td>").html(ores_prediction_userIntent + " <span style=\"color:" + probColors + "\">(" + ores[revids[r]]["goodfaith"]["score"]["probability"][ores[revids[r]]["goodfaith"]["score"]["prediction"].toString()].toFixed(ROUND_PRECISION).toString() + ")</span>").attr("bgcolor", tableLabelColors[facets[1]][ores_prediction_userIntent]))
.append($("<td>").html(liftwing_prediction + " <span style=\"color:" + probColors + "\">(" + liftwing[revids[r]]["probabilities"][liftwing[revids[r]]["prediction"].toString()].toFixed(ROUND_PRECISION).toString() + ")</span>").attr("bgcolor", tableLabelColors[liftwing_prediction]))
);
}
progressBar.toggle(false);
layoutSortBtns.toggle(true);
startIndex += renderCount;
requestLimitMessage.toggle(false);
}).fail(function(e) {
// loadDataBtn.toggle(false);
requestLimitMessage.toggle(true);
progressBar.toggle(false);
});
// });
});
});
}
});
})(jQuery, mediaWiki);
// Import CSS
mw.loader.load("//meta.wikimedia.org/w/index.php?title=User:Tzusheng/Wikibench.css&action=raw&ctype=text/css", 'text/css');
// QOL
$.when( mw.loader.using( [ 'mediawiki.util' ] ), $.ready ).then( function () {
mw.util.addPortletLink(
'p-personal',
'http://en.wiki.x.io/wiki/User:Tzusheng/sandbox/Wikipedia:Wikibench/Campaign:Editquality',
'Wikibench',
'pt-wikibench',
'wikibench',
null,
'#pt-preferences'
);
} );
//</nowiki>