MediaWiki:Gadget-WikiLabels.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
(function(){
// For convenience...
Date.prototype.format = function (mask, utc) {
return strftime(mask, this);
};
})();
//
// strftime
// github.com/samsonjs/strftime
// @_sjs
//
// Copyright 2010 - 2015 Sami Samhuri <sami@samhuri.net>
//
// MIT License
// http://sjs.mit-license.org
//
;(function() {
var DefaultLocale = {
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
AM: 'AM',
PM: 'PM',
am: 'am',
pm: 'pm',
formats: {
D: '%m/%d/%y',
F: '%Y-%m-%d',
R: '%H:%M',
T: '%H:%M:%S',
X: '%T',
c: '%a %b %d %X %Y',
r: '%I:%M:%S %p',
v: '%e-%b-%Y',
x: '%D'
}
},
defaultStrftime = new Strftime(DefaultLocale, 0, false),
isCommonJS = typeof module !== 'undefined',
namespace;
// CommonJS / Node module
if (isCommonJS) {
namespace = module.exports = adaptedStrftime;
namespace.strftime = deprecatedStrftime;
}
// Browsers and other environments
else {
// Get the global object. Works in ES3, ES5, and ES5 strict mode.
namespace = (function() { return this || (1,eval)('this'); }());
namespace.strftime = adaptedStrftime;
}
// Deprecated API, to be removed in v1.0
var _require = isCommonJS ? "require('strftime')" : "strftime";
var _deprecationWarnings = {};
function deprecationWarning(name, instead) {
if (!_deprecationWarnings[name]) {
if (typeof console !== 'undefined' && typeof console.warn == 'function') {
console.warn("[WARNING] " + name + " is deprecated and will be removed in version 1.0. Instead, use `" + instead + "`.");
}
_deprecationWarnings[name] = true;
}
}
namespace.strftimeTZ = deprecatedStrftimeTZ;
namespace.strftimeUTC = deprecatedStrftimeUTC;
namespace.localizedStrftime = deprecatedStrftimeLocalized;
// Adapt the old API while preserving the new API.
function adaptForwards(fn) {
fn.localize = defaultStrftime.localize.bind(defaultStrftime);
fn.timezone = defaultStrftime.timezone.bind(defaultStrftime);
fn.utc = defaultStrftime.utc.bind(defaultStrftime);
}
adaptForwards(adaptedStrftime);
function adaptedStrftime(fmt, d, locale) {
// d and locale are optional, check if this is (format, locale)
if (d && d.days) {
locale = d;
d = undefined;
}
if (locale) {
deprecationWarning("`" + _require + "(format, [date], [locale])`", "var s = " + _require + ".localize(locale); s(format, [date])");
}
var strftime = locale ? defaultStrftime.localize(locale) : defaultStrftime;
return strftime(fmt, d);
}
adaptForwards(deprecatedStrftime);
function deprecatedStrftime(fmt, d, locale) {
if (locale) {
deprecationWarning("`" + _require + ".strftime(format, [date], [locale])`", "var s = " + _require + ".localize(locale); s(format, [date])");
}
else {
deprecationWarning("`" + _require + ".strftime(format, [date])`", _require + "(format, [date])");
}
var strftime = locale ? defaultStrftime.localize(locale) : defaultStrftime;
return strftime(fmt, d);
}
function deprecatedStrftimeTZ(fmt, d, locale, timezone) {
// locale is optional, check if this is (format, date, timezone)
if ((typeof locale == 'number' || typeof locale == 'string') && timezone == null) {
timezone = locale;
locale = undefined;
}
if (locale) {
deprecationWarning("`" + _require + ".strftimeTZ(format, date, locale, tz)`", "var s = " + _require + ".localize(locale).timezone(tz); s(format, [date])` or `var s = " + _require + ".localize(locale); s.timezone(tz)(format, [date])");
}
else {
deprecationWarning("`" + _require + ".strftimeTZ(format, date, tz)`", "var s = " + _require + ".timezone(tz); s(format, [date])` or `" + _require + ".timezone(tz)(format, [date])");
}
var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).timezone(timezone);
return strftime(fmt, d);
};
var utcStrftime = defaultStrftime.utc();
function deprecatedStrftimeUTC(fmt, d, locale) {
if (locale) {
deprecationWarning("`" + _require + ".strftimeUTC(format, date, locale)`", "var s = " + _require + ".localize(locale).utc(); s(format, [date])");
}
else {
deprecationWarning("`" + _require + ".strftimeUTC(format, [date])`", "var s = " + _require + ".utc(); s(format, [date])");
}
var strftime = locale ? utcStrftime.localize(locale) : utcStrftime;
return strftime(fmt, d);
};
function deprecatedStrftimeLocalized(locale) {
deprecationWarning("`" + _require + ".localizedStrftime(locale)`", _require + ".localize(locale)");
return defaultStrftime.localize(locale);
};
// End of deprecated API
// Polyfill Date.now for old browsers.
if (typeof Date.now !== 'function') {
Date.now = function() {
return +new Date();
};
}
function Strftime(locale, customTimezoneOffset, useUtcTimezone) {
var _locale = locale || DefaultLocale,
_customTimezoneOffset = customTimezoneOffset || 0,
_useUtcBasedDate = useUtcTimezone || false,
// we store unix timestamp value here to not create new Date() each iteration (each millisecond)
// Date.now() is 2 times faster than new Date()
// while millisecond precise is enough here
// this could be very helpful when strftime triggered a lot of times one by one
_cachedDateTimestamp = 0,
_cachedDate;
function _strftime(format, date) {
var timestamp;
if (!date) {
var currentTimestamp = Date.now();
if (currentTimestamp > _cachedDateTimestamp) {
_cachedDateTimestamp = currentTimestamp;
_cachedDate = new Date(_cachedDateTimestamp);
timestamp = _cachedDateTimestamp;
if (_useUtcBasedDate) {
// how to avoid duplication of date instantiation for utc here?
// we tied to getTimezoneOffset of the current date
_cachedDate = new Date(_cachedDateTimestamp + getTimestampToUtcOffsetFor(_cachedDate) + _customTimezoneOffset);
}
}
date = _cachedDate;
}
else {
timestamp = date.getTime();
if (_useUtcBasedDate) {
date = new Date(date.getTime() + getTimestampToUtcOffsetFor(date) + _customTimezoneOffset);
}
}
return _processFormat(format, date, _locale, timestamp);
}
function _processFormat(format, date, locale, timestamp) {
var resultString = '',
padding = null,
isInScope = false,
length = format.length,
extendedTZ = false;
for (var i = 0; i < length; i++) {
var currentCharCode = format.charCodeAt(i);
if (isInScope === true) {
// '-'
if (currentCharCode === 45) {
padding = '';
continue;
}
// '_'
else if (currentCharCode === 95) {
padding = ' ';
continue;
}
// '0'
else if (currentCharCode === 48) {
padding = '0';
continue;
}
// ':'
else if (currentCharCode === 58) {
extendedTZ = true;
continue;
}
switch (currentCharCode) {
// Examples for new Date(0) in GMT
// 'Thursday'
// case 'A':
case 65:
resultString += locale.days[date.getDay()];
break;
// 'January'
// case 'B':
case 66:
resultString += locale.months[date.getMonth()];
break;
// '19'
// case 'C':
case 67:
resultString += padTill2(Math.floor(date.getFullYear() / 100), padding);
break;
// '01/01/70'
// case 'D':
case 68:
resultString += _processFormat(locale.formats.D, date, locale, timestamp);
break;
// '1970-01-01'
// case 'F':
case 70:
resultString += _processFormat(locale.formats.F, date, locale, timestamp);
break;
// '00'
// case 'H':
case 72:
resultString += padTill2(date.getHours(), padding);
break;
// '12'
// case 'I':
case 73:
resultString += padTill2(hours12(date.getHours()), padding);
break;
// '000'
// case 'L':
case 76:
resultString += padTill3(Math.floor(timestamp % 1000));
break;
// '00'
// case 'M':
case 77:
resultString += padTill2(date.getMinutes(), padding);
break;
// 'am'
// case 'P':
case 80:
resultString += date.getHours() < 12 ? locale.am : locale.pm;
break;
// '00:00'
// case 'R':
case 82:
resultString += _processFormat(locale.formats.R, date, locale, timestamp);
break;
// '00'
// case 'S':
case 83:
resultString += padTill2(date.getSeconds(), padding);
break;
// '00:00:00'
// case 'T':
case 84:
resultString += _processFormat(locale.formats.T, date, locale, timestamp);
break;
// '00'
// case 'U':
case 85:
resultString += padTill2(weekNumber(date, 'sunday'), padding);
break;
// '00'
// case 'W':
case 87:
resultString += padTill2(weekNumber(date, 'monday'), padding);
break;
// '16:00:00'
// case 'X':
case 88:
resultString += _processFormat(locale.formats.X, date, locale, timestamp);
break;
// '1970'
// case 'Y':
case 89:
resultString += date.getFullYear();
break;
// 'GMT'
// case 'Z':
case 90:
if (_useUtcBasedDate && _customTimezoneOffset === 0) {
resultString += "GMT";
}
else {
// fixme optimize
var tzString = date.toString().match(/\((\w+)\)/);
resultString += tzString && tzString[1] || '';
}
break;
// 'Thu'
// case 'a':
case 97:
resultString += locale.shortDays[date.getDay()];
break;
// 'Jan'
// case 'b':
case 98:
resultString += locale.shortMonths[date.getMonth()];
break;
// ''
// case 'c':
case 99:
resultString += _processFormat(locale.formats.c, date, locale, timestamp);
break;
// '01'
// case 'd':
case 100:
resultString += padTill2(date.getDate(), padding);
break;
// ' 1'
// case 'e':
case 101:
resultString += padTill2(date.getDate(), padding == null ? ' ' : padding);
break;
// 'Jan'
// case 'h':
case 104:
resultString += locale.shortMonths[date.getMonth()];
break;
// '000'
// case 'j':
case 106:
var y = new Date(date.getFullYear(), 0, 1);
var day = Math.ceil((date.getTime() - y.getTime()) / (1000 * 60 * 60 * 24));
resultString += padTill3(day);
break;
// ' 0'
// case 'k':
case 107:
resultString += padTill2(date.getHours(), padding == null ? ' ' : padding);
break;
// '12'
// case 'l':
case 108:
resultString += padTill2(hours12(date.getHours()), padding == null ? ' ' : padding);
break;
// '01'
// case 'm':
case 109:
resultString += padTill2(date.getMonth() + 1, padding);
break;
// '\n'
// case 'n':
case 110:
resultString += '\n';
break;
// '1st'
// case 'o':
case 111:
resultString += String(date.getDate()) + ordinal(date.getDate());
break;
// 'AM'
// case 'p':
case 112:
resultString += date.getHours() < 12 ? locale.AM : locale.PM;
break;
// '12:00:00 AM'
// case 'r':
case 114:
resultString += _processFormat(locale.formats.r, date, locale, timestamp);
break;
// '0'
// case 's':
case 115:
resultString += Math.floor(timestamp / 1000);
break;
// '\t'
// case 't':
case 116:
resultString += '\t';
break;
// '4'
// case 'u':
case 117:
var day = date.getDay();
resultString += day === 0 ? 7 : day;
break; // 1 - 7, Monday is first day of the week
// ' 1-Jan-1970'
// case 'v':
case 118:
resultString += _processFormat(locale.formats.v, date, locale, timestamp);
break;
// '4'
// case 'w':
case 119:
resultString += date.getDay();
break; // 0 - 6, Sunday is first day of the week
// '12/31/69'
// case 'x':
case 120:
resultString += _processFormat(locale.formats.x, date, locale, timestamp);
break;
// '70'
// case 'y':
case 121:
resultString += ('' + date.getFullYear()).slice(2);
break;
// '+0000'
// case 'z':
case 122:
if (_useUtcBasedDate && _customTimezoneOffset === 0) {
resultString += extendedTZ ? "+00:00" : "+0000";
}
else {
var off;
if (_customTimezoneOffset !== 0) {
off = _customTimezoneOffset / (60 * 1000);
}
else {
off = -date.getTimezoneOffset();
}
var sign = off < 0 ? '-' : '+';
var sep = extendedTZ ? ':' : '';
var hours = Math.floor(Math.abs(off / 60));
var mins = Math.abs(off % 60);
resultString += sign + padTill2(hours) + sep + padTill2(mins);
}
break;
default:
resultString += format[i];
break;
}
padding = null;
isInScope = false;
continue;
}
// '%'
if (currentCharCode === 37) {
isInScope = true;
continue;
}
resultString += format[i];
}
return resultString;
}
var strftime = _strftime;
strftime.localize = function(locale) {
return new Strftime(locale || _locale, _customTimezoneOffset, _useUtcBasedDate);
};
strftime.timezone = function(timezone) {
var customTimezoneOffset = _customTimezoneOffset;
var useUtcBasedDate = _useUtcBasedDate;
var timezoneType = typeof timezone;
if (timezoneType === 'number' || timezoneType === 'string') {
useUtcBasedDate = true;
// ISO 8601 format timezone string, [-+]HHMM
if (timezoneType === 'string') {
var sign = timezone[0] === '-' ? -1 : 1,
hours = parseInt(timezone.slice(1, 3), 10),
minutes = parseInt(timezone.slice(3, 5), 10);
customTimezoneOffset = sign * ((60 * hours) + minutes) * 60 * 1000;
// in minutes: 420
}
else if (timezoneType === 'number') {
customTimezoneOffset = timezone * 60 * 1000;
}
}
return new Strftime(_locale, customTimezoneOffset, useUtcBasedDate);
};
strftime.utc = function() {
return new Strftime(_locale, _customTimezoneOffset, true);
};
return strftime;
}
function padTill2(numberToPad, paddingChar) {
if (paddingChar === '' || numberToPad > 9) {
return numberToPad;
}
if (paddingChar == null) {
paddingChar = '0';
}
return paddingChar + numberToPad;
}
function padTill3(numberToPad) {
if (numberToPad > 99) {
return numberToPad;
}
if (numberToPad > 9) {
return '0' + numberToPad;
}
return '00' + numberToPad;
}
function hours12(hour) {
if (hour === 0) {
return 12;
}
else if (hour > 12) {
return hour - 12;
}
return hour;
}
// firstWeekday: 'sunday' or 'monday', default is 'sunday'
//
// Pilfered & ported from Ruby's strftime implementation.
function weekNumber(date, firstWeekday) {
firstWeekday = firstWeekday || 'sunday';
// This works by shifting the weekday back by one day if we
// are treating Monday as the first day of the week.
var weekday = date.getDay();
if (firstWeekday === 'monday') {
if (weekday === 0) // Sunday
weekday = 6;
else
weekday--;
}
var firstDayOfYear = new Date(date.getFullYear(), 0, 1),
yday = (date - firstDayOfYear) / 86400000,
weekNum = (yday + 7 - weekday) / 7;
return Math.floor(weekNum);
}
// Get the ordinal suffix for a number: st, nd, rd, or th
function ordinal(number) {
var i = number % 10;
var ii = number % 100;
if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) {
return 'th';
}
switch (i) {
case 1: return 'st';
case 2: return 'nd';
case 3: return 'rd';
}
}
function getTimestampToUtcOffsetFor(date) {
return (date.getTimezoneOffset() || 0) * 60000;
}
}());
( function ( $, OO ) {
var ifundef = function ( val, then ) {
if ( val !== undefined && val !== null ) {
return val;
} else {
return then;
}
};
OO.ui.instantiateFromParameters = function ( config, fieldMap ) {
var className = config[ 'class' ],
error, widget;
fieldMap = fieldMap || {};
if ( typeof OO.ui[className] === 'undefined' ) {
throw 'Unable to load OO.ui.' + className;
}
error = OO.ui.preprocessConfig( config, fieldMap );
// Pass out errors
if ( error ) {
return error;
}
if ( className === 'FieldLayout' ) {
widget = config.fieldWidget;
delete config.fieldWidget;
widget = new OO.ui.FieldLayout( widget, config );
} else {
widget = new OO.ui[className]( config );
if ( config.name !== undefined ) {
fieldMap[config.name] = widget;
}
}
return widget;
};
OO.ui.preprocessConfig = function ( config, fieldMap ) {
var newItems,
error = false;
fieldMap = fieldMap || {};
if ( config.items ) {
newItems = [];
$.each( config.items, function ( index, item ) {
var newItem = OO.ui.instantiateFromParameters( item, fieldMap );
if ( newItem.$element ) {
// A proper OOUI
newItems.push( newItem );
} else {
error = newItem;
}
} );
config.items = newItems;
}
if ( config.fieldWidget ) {
config.fieldWidget = OO.ui.instantiateFromParameters( config.fieldWidget,
fieldMap );
}
$.each( config, function ( name, value ) {
if ( String( name ).substr( 0, 1 ) === '$' ) {
config[name] = $( value );
} else if ( typeof value === 'object' && $.isPlainObject( value ) ) {
OO.ui.preprocessConfig( value, fieldMap );
}
} );
if ( error ) {
return error;
}
};
OO.ui.getWidgetValue = function ( widget ) {
switch ( widget.constructor ){
case OO.ui.ActionWidget:
case OO.ui.ButtonGroupWidget:
case OO.ui.ButtonWidget:
case OO.ui.DecoratedOptionWidget:
case OO.ui.DropdownWidget:
case OO.ui.IconWidget:
case OO.ui.IndicatorWidget:
case OO.ui.LabelWidget:
case OO.ui.MenuOptionWidget:
case OO.ui.MenuSelectOptionWidget:
case OO.ui.OutlineControlsWidget:
case OO.ui.OutlineOptionWidget:
case OO.ui.OutlineSelectWidget:
case OO.ui.PopupButtonWidget:
case OO.ui.PopupWidget:
case OO.ui.ProgressBarWidget:
case OO.ui.RadioOptionWidget:
return widget.getData();
case OO.ui.ButtonOptionWidget:
case OO.ui.CheckboxInputWidget:
return widget.isSelected();
case OO.ui.RadioSelectWidget:
if ( widget.getSelectedItem() ) {
return widget.getSelectedItem().getData();
} else {
return null;
}
break;
case OO.ui.ButtonInputWidget:
case OO.ui.DropdownInputWidget:
case OO.ui.RadioInputWidget:
return ifundef( widget.getData(), widget.getValue() );
case OO.ui.MenuSelectWidget:
case OO.ui.ButtonSelectWidget:
if ( widget.getSelectedItem() ) {
return widget.getSelectedItem().getData();
} else {
return null;
}
break;
case OO.ui.ComboboxInputWidget:
if ( widget.getMenu().getSelectedItem() ) {
return widget.getMenu().getSelectedItem().getData();
} else {
return null;
}
break;
case OO.ui.SearchWidget:
return widget.getQuery().getValue();
case OO.ui.TextInputWidget:
case OO.ui.ToggleButtonWidget:
case OO.ui.ToggleSwitchWidget:
return widget.getValue();
default:
if(widget.getData){
return widget.getValue();
}else{
return null;
}
}
};
OO.ui.setWidgetValue = function ( widget, value ) {
switch ( widget.constructor ){
case OO.ui.ActionWidget:
case OO.ui.ButtonGroupWidget:
case OO.ui.ButtonWidget:
case OO.ui.DecoratedOptionWidget:
case OO.ui.DropdownWidget:
case OO.ui.IconWidget:
case OO.ui.IndicatorWidget:
case OO.ui.LabelWidget:
case OO.ui.MenuOptionWidget:
case OO.ui.MenuSelectOptionWidget:
case OO.ui.OutlineControlsWidget:
case OO.ui.OutlineOptionWidget:
case OO.ui.OutlineSelectWidget:
case OO.ui.PopupButtonWidget:
case OO.ui.PopupWidget:
case OO.ui.ProgressBarWidget:
case OO.ui.RadioOptionWidget:
widget.setData(value);
break;
case OO.ui.ButtonOptionWidget:
case OO.ui.CheckboxInputWidget:
widget.setSelected(value);
break;
case OO.ui.RadioSelectWidget:
widget.selectItem( widget.getItemFromData(value) );
break;
case OO.ui.ButtonInputWidget:
case OO.ui.DropdownInputWidget:
case OO.ui.RadioInputWidget:
widget.setData(value);
break;
case OO.ui.MenuSelectWidget:
case OO.ui.ButtonSelectWidget:
widget.selectItem( widget.getItemFromData(value) );
break;
case OO.ui.ComboboxInputWidget:
widget.getMenu().selectItem( widget.getMenu().getItemFromData(value) );
break;
case OO.ui.SearchWidget:
widget.getQuery().setValue(value);
break;
case OO.ui.TextInputWidget:
case OO.ui.ToggleButtonWidget:
case OO.ui.ToggleSwitchWidget:
widget.setValue(ifundef(value, ""));
break;
default:
if(widget.setValue){
return widget.setValue(value);
}else{
return null;
}
}
};
} )( jQuery, OO );
(function($, OO){
var html2text = function(html){
return $("<div>").html(html).text();
};
/**
* Basically just a drop-down box and a button
*
*/
OO.ui.SemanticOperationsSelector = function(opts){
OO.ui.SemanticOperationsSelector.super.apply( this );
var meaningsLabel = opts.meaningsLabel;
var meanings = opts.meanings;
this.objects = opts.objects;
this.actions = opts.actions;
this.$element = $("<div>").addClass("semantic-operations-selector");
this.meaningSelector = new OO.ui.SemanticMeaningSelector({
label: meaningsLabel,
meanings: meanings
});
this.meaningSelector.on("add", this.handleSemanticMeaningAdd.bind(this));
this.$element.append(this.meaningSelector.$element);
this.semanticMap = {};
this.$workspace = $("<div>").addClass("workspace");
this.$element.append(this.$workspace);
};
OO.inheritClass( OO.ui.SemanticOperationsSelector, OO.ui.Widget );
OO.ui.SemanticOperationsSelector.prototype.getValue = function(){
var valueMap = {}, sos, meaning;
for( meaning in this.semanticMap ){
if( this.semanticMap.hasOwnProperty(meaning) ){
sos = this.semanticMap[meaning];
valueMap[meaning] = sos.getValue();
}
}
return valueMap;
};
OO.ui.SemanticOperationsSelector.prototype.setValue = function(meanings){
var meaningValue, meaning, sos;
this.clear();
for( meaningValue in meanings ){
if( meanings.hasOwnProperty(meaningValue) ){
meaning = this.meaningSelector.getDataFor(meaningValue);
this.addMeaning(meaning, meanings[meaningValue]);
}
}
};
OO.ui.SemanticOperationsSelector.prototype.handleSemanticMeaningAdd = function() {
this.addMeaning(this.meaningSelector.getSelected());
};
OO.ui.SemanticOperationsSelector.prototype.addMeaning = function(meaning, operations){
operations = operations || [];
if ( !meaning ) {
// TODO: consider alerting
alert("No meaning selected");
}else if ( this.semanticMap[meaning.value] !== undefined ){
alert("Meaning " + meaning.label + " already selected");
}else{
var sos = new OO.ui.SyntacticOperationsSelector({
meaning: meaning,
objects: this.objects,
actions: this.actions,
operations: operations
});
this.semanticMap[meaning.value] = sos;
this.$workspace.append(sos.$element);
sos.on('close', this.handleCloseSelector.bind(this));
}
this.meaningSelector.reset();
};
OO.ui.SemanticOperationsSelector.prototype.handleCloseSelector = function(sos){
this.removeMeaning(sos);
};
OO.ui.SemanticOperationsSelector.prototype.removeMeaning = function(sos){
//remove the select from semanticMap
sos.$element.remove();
delete this.semanticMap[sos.meaning.value];
};
OO.ui.SemanticOperationsSelector.prototype.clear = function(){
for(var meaningValue in this.semanticMap){
if ( this.semanticMap.hasOwnProperty(meaningValue) ){
this.removeMeaning(this.semanticMap[meaningValue]);
}
}
this.meaningSelector.reset();
};
/**
* Basically just a drop-down box and a button
*
*/
OO.ui.SemanticMeaningSelector = function(opts){
OO.ui.SemanticMeaningSelector.super.apply( this );
var label = opts.label,
meanings = opts.meanings,
items = [];
this.meaningData = {};
this.$element = $("<div>").addClass("semantic-meaning-selector");
// Menu elements
for(var i=0; i < meanings.length; i++){
var meaning = meanings[i];
var $label = $('<span>').attr('title', html2text(meaning.description));
this.meaningData[meaning.value] = meaning;
items.push(
new OO.ui.MenuOptionWidget({ data: meaning, $label: $label,
label: meaning.label})
);
}
this.dropdown = new OO.ui.DropdownWidget( {
label: label,
menu: {items: items},
classes: ['meanings']
} );
this.$element.append(this.dropdown.$element);
this.button = new OO.ui.ButtonWidget( {
flags: ['constructive', 'primary'],
icon: 'add',
classes: ['add']
} );
this.$element.append(this.button.$element);
this.button.on('click', this.handleButtonClick.bind(this));
};
OO.inheritClass( OO.ui.SemanticMeaningSelector, OO.ui.Widget );
OO.ui.SemanticMeaningSelector.prototype.handleButtonClick = function(){
this.emit('add');
};
OO.ui.SemanticMeaningSelector.prototype.getSelected = function(){
if( this.dropdown.getMenu().getSelectedItem() ){
return this.dropdown.getMenu().getSelectedItem().getData();
}else{
return null;
}
};
OO.ui.SemanticMeaningSelector.prototype.getDataFor = function(meaningValue){
return this.meaningData[meaningValue];
};
OO.ui.SemanticMeaningSelector.prototype.reset = function(){
this.dropdown.getMenu().selectItem(); // This should deselect and reset
};
/**
* Contains a semantic meaning -- allows the selection of syntactic
* operations
*
*/
OO.ui.SyntacticOperationsSelector = function(opts){
OO.ui.SyntacticOperationsSelector.super.apply( this );
this.meaning = opts.meaning;
var objects = opts.objects;
var actions = opts.actions;
var operations = opts.operations;
this.operationMap = {};
this.$element = $("<div>").addClass("syntactic-operations-selector");
this.closer = new OO.ui.ButtonWidget({
icon: "remove",
framed: false,
flags: "destructive",
classes: ["closer"]
});
this.$element.append(this.closer.$element);
this.closer.on('click', this.handleCloserClick.bind(this));
this.$title = $("<div>").addClass("title").text(this.meaning.label);
this.$element.append(this.$title);
this.$description = $("<div>").addClass("description").html(this.meaning.description);
this.$element.append(this.$description);
this.operationSelector = new OO.ui.OperationSelector({
objects: objects,
actions: actions
});
this.operationSelector.on('add', this.handleOperationAdd.bind(this));
this.$element.append(this.operationSelector.$element);
this.$workspace = $("<div>").addClass("workspace");
this.$element.append(this.$workspace);
for(var i=0; i<operations.length; i++){
var operationValue = operations[i];
var operation = this.operationSelector.getDataFor(operationValue);
this.addOperation(operation);
}
};
OO.inheritClass( OO.ui.SyntacticOperationsSelector, OO.ui.Widget );
OO.ui.SyntacticOperationsSelector.prototype.getValue = function(){
var key, sop, values = [];
for( key in this.operationMap ) {
if( this.operationMap.hasOwnProperty( key ) ){
sop = this.operationMap[key];
values.push({
object: sop.object.value,
action: sop.action.value
});
}
}
return values;
};
OO.ui.SyntacticOperationsSelector.prototype.clear = function(){
var key, sop;
for( key in this.operationMap ) {
if( this.operationMap.hasOwnProperty( key ) ){
sop = this.operationMap[key];
sop.close();
}
}
};
OO.ui.SyntacticOperationsSelector.prototype.setValue = function(operations){
var i, key, sop, operationValue, operation;
for( i = 0; i < operations.length; ++i ) {
operationValue = operations[i];
operation = this.operationsSelector.getDataFor(operationValue);
sop = new OO.ui.SyntacticOperation({
object: operation.object,
action: operation.action
});
this.operationMap[key] = sop;
}
};
OO.ui.SyntacticOperationsSelector.prototype.handleOperationAdd = function(){
var operation = this.operationSelector.getSelected();
if( operation ){
this.addOperation(operation);
} else {
// alert("No operation selected!"); already errored
}
};
OO.ui.SyntacticOperationsSelector.prototype.addOperation = function(operation){
//check if we already have an instance of this object/action pair
// if we don't, add it to the workspace
if( !operation ) { return; }
var key = operation.object.value + "-" + operation.action.value;
if(this.operationMap[key] === undefined){
var sop = new OO.ui.SyntacticOperation({
object: operation.object,
action: operation.action
});
sop.on('close', this.handleObjectActionClose.bind(this));
this.$workspace.append(sop.$element);
this.operationMap[key] = sop;
}else{
alert("'" + key + "' has already been added.");
}
};
OO.ui.SyntacticOperationsSelector.prototype.handleObjectActionClose = function(sop){
//remove from operationMap
var key = sop.object.value + "-" + sop.action.value;
delete this.operationMap[key];
};
OO.ui.SyntacticOperationsSelector.prototype.handleCloserClick = function(){
this.close();
};
OO.ui.SyntacticOperationsSelector.prototype.close = function(){
//destroy the object and emit an event
this.$element.remove();
this.emit('close', this);
};
OO.ui.OperationSelector = function(opts){
OO.ui.OperationSelector.super.apply( this );
var objects = opts.objects,
actions = opts.actions,
objectItems = [],
actionItems = [];
this.$element = $("<div>").addClass("object-action-selector");
// Object menu elements
this.objectMap = {};
for(var i=0; i < objects.length; i++){
var object = objects[i];
var $objectLabel = $('<span>').attr('title', html2text(object.description));
this.objectMap[object.value] = object;
objectItems.push(
new OO.ui.MenuOptionWidget({ data: object, $label: $objectLabel,
label: object.label })
);
}
this.objects = new OO.ui.DropdownWidget( {
label: "objects",
menu: {items: objectItems},
classes: ['objects']
} );
this.$element.append(this.objects.$element);
// Action menu elements
this.actionMap = {};
for(var j=0; j < actions.length; j++){
var action = actions[j];
var $actionLabel = $('<span>').attr('title', html2text(action.description));
this.actionMap[action.value] = action;
actionItems.push(
new OO.ui.MenuOptionWidget({ data: action, $label: $actionLabel,
label: action.label})
);
}
this.actions = new OO.ui.DropdownWidget( {
label: "actions",
menu: {items: actionItems},
classes: ['actions']
} );
this.$element.append(this.actions.$element);
// Add button
this.button = new OO.ui.ButtonWidget( {
icon: 'add',
flags: 'constructive',
classes: ['add']
} );
this.$element.append(this.button.$element);
this.button.on('click', this.handleButtonClick.bind(this));
};
OO.inheritClass( OO.ui.OperationSelector, OO.ui.Widget );
OO.ui.OperationSelector.prototype.handleButtonClick = function(){
this.emit("add");
};
OO.ui.OperationSelector.prototype.getSelected = function(){
if ( !this.objects.getMenu().getSelectedItem() ) {
alert("No object selected.");
} else if ( !this.actions.getMenu().getSelectedItem() ) {
alert("No action selected.");
} else {
return {
object: this.objects.getMenu().getSelectedItem().getData(),
action: this.actions.getMenu().getSelectedItem().getData()
};
}
};
OO.ui.OperationSelector.prototype.getDataFor = function(operationValue) {
return {
object: this.objectMap[operationValue.object],
action: this.actionMap[operationValue.action]
};
};
OO.ui.SyntacticOperation = function(opts){
OO.ui.SyntacticOperation.super.apply( this );
this.object = opts.object;
this.action = opts.action;
this.$element = $("<div>").addClass("object-action");
this.$object = $("<div>").addClass("object").text(this.object.label);
this.$element.append(this.$object);
this.$action = $("<div>").addClass("action").text(this.action.label);
this.$element.append(this.$action);
this.closer = new OO.ui.ButtonWidget({
icon: "remove",
framed: false,
flags: 'destructive',
classes: ["closer"]
});
this.$element.append(this.closer.$element);
this.closer.on('click', this.handleCloserClick.bind(this));
};
OO.inheritClass( OO.ui.SyntacticOperation, OO.ui.Widget );
OO.ui.SyntacticOperation.prototype.close = function(){
this.$element.remove();
this.emit('close', this);
};
OO.ui.SyntacticOperation.prototype.handleCloserClick = function(){
// TODO: Destroy this and emit an event
this.close();
};
})(jQuery, OO);
(function($, OO){
var html2text = function(html){
return $("<div>").html(html).text();
};
var Workspace = function(opts){
this.emptyMessage = opts.emptyMessage || "";
this.$element = $("<div>").addClass("workspace");
this.empty(true);
};
Workspace.prototype.empty = function(setEmpty){
if( setEmpty === undefined ){
return this.$element.hasClass('empty');
}else{
if( setEmpty ){
this.$element.addClass('empty');
this.$element.html(this.emptyMessage);
this.items = {};
}else{
this.$element.removeClass('empty');
this.$element.html("");
}
}
};
Workspace.prototype.add = function(name, $subElement){
if( this.empty() ){
this.empty(false);
}
this.$element.append($subElement);
this.items[name] = $subElement;
};
Workspace.prototype.remove = function(name){
var $subElement = this.items[name];
if( !$subElement ){
console.log("Sub element " + name + " not found -- can't be removed.");
} else {
$subElement.remove();
delete this.items[name];
if( Object.keys(this.items).length === 0){
this.empty(true);
}
}
};
/**
* Basically just a drop-down box and a button
*
*/
OO.ui.SemanticsSelector = function(opts){
OO.ui.SemanticsSelector.super.apply( this );
var meaningsLabel = opts.meaningsLabel;
var meanings = opts.meanings;
var emptyMessage = opts.emptyMessage;
this.$element = $("<div>").addClass("semantics-selector");
this.meaningSelector = new OO.ui.SemanticMeaningSelector({
label: meaningsLabel,
meanings: meanings
});
this.meaningSelector.on("add", this.handleSemanticMeaningAdd.bind(this));
this.$element.append(this.meaningSelector.$element);
this.semanticMap = {};
this.workspace = new Workspace({emptyMessage: emptyMessage});
this.$element.append(this.workspace.$element);
};
OO.inheritClass( OO.ui.SemanticsSelector, OO.ui.Widget );
OO.ui.SemanticsSelector.prototype.getValue = function(){
var valueList = [], meaning;
for( meaning in this.semanticMap ){
if( this.semanticMap.hasOwnProperty(meaning) ){
valueList.push(meaning);
}
}
if ( valueList.length > 0 ){
return valueList;
}else{
return null;
}
};
OO.ui.SemanticsSelector.prototype.setValue = function(meanings){
meanings = meanings || [];
var meaningValue, sm;
this.clear();
for(var i=0; i < meanings.length; i++){
sm = this.meaningSelector.getDataFor(meanings[i]);
this.addMeaning(sm);
}
};
OO.ui.SemanticsSelector.prototype.handleSemanticMeaningAdd = function() {
this.addMeaning(this.meaningSelector.getSelected());
};
OO.ui.SemanticsSelector.prototype.addMeaning = function(meaning){
if ( !meaning ) {
// TODO: consider alerting
alert("No meaning selected");
}else if ( this.semanticMap[meaning.value] !== undefined ){
alert("Meaning " + meaning.label + " already selected");
}else{
var sm = new OO.ui.SemanticMeaning({meaning: meaning});
this.semanticMap[meaning.value] = sm;
this.workspace.add(meaning.value, sm.$element);
sm.on('close', this.handleCloseSelector.bind(this));
}
this.meaningSelector.reset();
};
OO.ui.SemanticsSelector.prototype.handleCloseSelector = function(sm){
this.removeMeaning(sm);
};
OO.ui.SemanticsSelector.prototype.removeMeaning = function(sm){
//remove the select from semanticMap
this.workspace.remove(sm.meaning.value);
delete this.semanticMap[sm.meaning.value];
};
OO.ui.SemanticsSelector.prototype.clear = function(){
for(var meaningValue in this.semanticMap){
if ( this.semanticMap.hasOwnProperty(meaningValue) ){
this.removeMeaning(this.semanticMap[meaningValue]);
}
}
this.meaningSelector.reset();
};
/**
* Basically just a drop-down box and a button
*
*/
OO.ui.SemanticMeaningSelector = function(opts){
OO.ui.SemanticMeaningSelector.super.apply( this );
var label = opts.label,
meanings = opts.meanings,
items = [];
this.meaningData = {};
this.$element = $("<div>").addClass("semantic-meaning-selector");
// Menu elements
for(var i=0; i < meanings.length; i++){
var meaning = meanings[i];
var $label = $('<span>').attr('title', html2text(meaning.description));
this.meaningData[meaning.value] = meaning;
items.push(
new OO.ui.MenuOptionWidget({ data: meaning, $label: $label,
label: meaning.label})
);
}
this.dropdown = new OO.ui.DropdownWidget( {
label: label,
menu: {items: items},
classes: ['meanings']
} );
this.$element.append(this.dropdown.$element);
this.button = new OO.ui.ButtonWidget( {
flags: ['constructive', 'primary'],
icon: 'add',
classes: ['add']
} );
this.$element.append(this.button.$element);
this.button.on('click', this.handleButtonClick.bind(this));
};
OO.inheritClass( OO.ui.SemanticMeaningSelector, OO.ui.Widget );
OO.ui.SemanticMeaningSelector.prototype.handleButtonClick = function(){
this.emit('add');
};
OO.ui.SemanticMeaningSelector.prototype.getSelected = function(){
if( this.dropdown.getMenu().getSelectedItem() ){
return this.dropdown.getMenu().getSelectedItem().getData();
}else{
return null;
}
};
OO.ui.SemanticMeaningSelector.prototype.getDataFor = function(meaningValue){
return this.meaningData[meaningValue];
};
OO.ui.SemanticMeaningSelector.prototype.reset = function(){
this.dropdown.getMenu().selectItem(); // This should deselect and reset
};
/**
* Contains a semantic meaning
*
*/
OO.ui.SemanticMeaning = function(opts){
OO.ui.SemanticMeaning.super.apply( this );
this.meaning = opts.meaning;
this.$element = $("<div>").addClass("semantic-meaning");
this.closer = new OO.ui.ButtonWidget({
icon: "remove",
framed: false,
flags: "destructive",
classes: ["closer"]
});
this.$element.append(this.closer.$element);
this.closer.on('click', this.handleCloserClick.bind(this));
this.$title = $("<div>").addClass("title").text(this.meaning.label);
this.$element.append(this.$title);
this.$description = $("<div>").addClass("description").html(this.meaning.description);
this.$element.append(this.$description);
};
OO.inheritClass( OO.ui.SemanticMeaning, OO.ui.Widget );
OO.ui.SemanticMeaning.prototype.handleCloserClick = function(){
this.close();
};
OO.ui.SemanticMeaning.prototype.close = function(){
//destroy the object and emit an event
this.$element.remove();
this.emit('close', this);
};
})(jQuery, OO);
(function($){
if (window.wikiLabels) {
throw "wikiLabels is already defined! Exiting.";
}
window.wikiLabels = {
config: {
serverRoot: "//ores.wikimedia.org/labels",
prefix: "wikilabels-"
}
};
})(jQuery);
( function (mw, $, WL) {
var API = function () {};
API.prototype.request = function (data) {
data['format'] = "json";
var deferred = $.Deferred(),
ajaxPromise = $.ajax(
mw.config.get('wgServer') + mw.util.wikiScript( 'api' ),
{
dataType: "jsonp",
data: data
}
);
ajaxPromise.done(function (doc, status, jqXHR) {
if (!doc.error) {
if (doc.warnings) {
console.warn(doc.warnings);
}
deferred.resolve(doc);
} else {
console.error(doc.error);
deferred.reject(doc.error);
}
}.bind(this));
ajaxPromise.fail(function (jqXHR, status, err) {
var errorData = { code: status, message: err };
console.error(errorData);
deferred.reject(errorData);
}.bind(this));
return deferred.promise();
};
API.prototype.getRevision = function(revId, params){
var defaultParams = {
action: "query",
prop: "revisions",
revids: revId
},
deferred = $.Deferred();
this.request($.extend(defaultParams, params || {}))
.done(function(doc){
var id, page, includePage, i, rev;
try {
if (doc.query.badrevids) {
deferred.reject( {
code: "revision not found",
message: WL.i18n( 'Could not get metadata for revision $1', revId)
} );
return;
}
for (id in doc.query.pages) {
if (doc.query.pages.hasOwnProperty(id)) {
page = doc.query.pages[id];
}
}
includePage = $.extend({}, page);
delete includePage['revisions'];
for (i = 0; i < page.revisions.length; i++) {
rev = page.revisions[i];
rev['page'] = includePage;
// Cache the diff
deferred.resolve(rev);
}
} catch(err) {
deferred.reject( {
code: "api error",
message: WL.i18n( "Could not parse MediaWiki API's response") + ': ' + err
} );
}
}.bind(this))
.fail(function(doc){
deferred.reject(doc);
}.bind(this));
return deferred.promise();
};
API.prototype.diffTo = function(revId, diffToId){
var tableRows, deferred = $.Deferred();
this.getRevision(diffToId, {'rvdiffto': revId})
.done(function(doc){
if( doc['diff'] ){
tableRows = doc['diff']['*'];
}else{
tableRows = "";
}
deferred.resolve(tableRows);
}.bind(this))
.fail(function(doc){
deferred.fail(doc);
}.bind(this));
return deferred.promise();
};
API.prototype.diffToPrevious = function(revId){
var deferred = $.Deferred();
this.getRevision(revId, {rvprop: "ids|parsedcomment"})
.done(function(rev){
if ( rev.parentid ) {
this.diffTo(revId, rev.parentid)
.done(function(tableRows){
deferred.resolve( {
revId: rev.revid,
title: rev.page.title,
comment: rev.parsedcomment || "",
tableRows: tableRows
} );
}.bind(this))
.fail(function(doc){
deferred.reject(doc);
}.bind(this));
} else {
this.getRevision(revId, {rvprop: "content"})
.done(function(contentRev){
deferred.resolve( {
revId: rev.revid,
title: rev.page.title,
tableRows: API.creationDiff(contentRev['*'])
} );
}.bind(this))
.fail(function(doc){
deferred.reject(doc);
});
}
}.bind(this))
.fail(function(doc){
deferred.reject(doc);
}.bind(this));
return deferred.promise();
};
API.creationDiff = function(content){
return '<tr>\n' +
'<td colspan="2" class="diff-lineno">Line 1:</td>\n' +
'<td colspan="2" class="diff-lineno">Line 1:</td>\n' +
'</tr>\n' +
'<tr>\n' +
'<td colspan="2" class="diff-empty"> </td>\n' +
'<td class="diff-marker">+</td>\n' +
'<td class="diff-addedline"><div>' + content + '</div></td>' +
'</tr>';
};
API.prototype.wikitext2HTML = function(wikitext, title){
title = title || 'CURRENT PAGE';
var params = {
action: "parse",
prop: "text",
title: title,
text: wikitext.substring(0, 4000),
contentmode: "wikitext"
},
deferred = $.Deferred();
this.request(params)
.done(function(doc){
deferred.resolve(
doc['parse']['text']['*']
);
}.bind(this))
.fail(function(doc){
deferred.reject(doc);
}.bind(this));
return deferred.promise();
};
wikiLabels.api = new API();
})(mediaWiki, jQuery, wikiLabels);
( function ($, WL) {
var Config = function(obj) {
Config.prototype.update.call(this, obj);
};
Config.prototype.update = function (update) {
$.extend(this, update, true); // Deep merge
};
WL.config = new Config(WL.config || {});
}(jQuery, wikiLabels));
( function ( $, OO, WL ) {
var Form = function ( fieldset, fieldMap ) {
this.fieldMap = fieldMap;
this.$element = $( '<div>' ).addClass( WL.config.prefix + 'form' );
this.$fieldset = $('<div>').addClass( 'fieldset' );
this.$element.append(this.$fieldset);
this.$fieldset.append( fieldset.$element );
this.$controls = $( '<div>' ).addClass( 'controls' );
this.$element.append( this.$controls );
this.abandonButton = new OO.ui.ButtonWidget( {
label: WL.i18n('Abandon'),
align: 'inline',
classes: ['abandon'],
flags: [ 'primary', 'destructive' ]
} );
this.$controls.append( this.abandonButton.$element );
this.abandonButton.on( 'click', this.handleAbandonClick.bind( this, this.abandonButton.$element ) );
this.abandoned = $.Callbacks();
this.submitButton = new OO.ui.ButtonWidget( {
label: WL.i18n('Save'),
align: 'inline',
classes: ['save'],
flags: [ 'primary', 'progressive' ]
} );
this.$controls.append( this.submitButton.$element );
this.submitButton.on( 'click', this.handleSubmitClick.bind( this, this.submitButton.$element ) );
this.submitted = $.Callbacks();
};
Form.prototype.handleSubmitClick = function ( button ) {
$( button ).injectSpinner( WL.config.prefix + 'submit-spinner' );
this.submit();
};
Form.prototype.handleAbandonClick = function ( button ) {
var confirmed = confirm(WL.i18n('Are you sure that you want to abandon this task?'));
if ( !confirmed ) {
return;
}
$( button ).injectSpinner( WL.config.prefix + 'abandon-spinner' );
this.abandon();
};
Form.prototype.getValues = function () {
var name, valueMap = {};
for ( name in this.fieldMap ) {
if ( this.fieldMap.hasOwnProperty( name ) ) {
valueMap[name] = OO.ui.getWidgetValue( this.fieldMap[name] );
}
}
return valueMap;
};
Form.prototype.setValues = function (valueMap) {
var name;
valueMap = valueMap || {};
for ( name in this.fieldMap ) {
if ( this.fieldMap.hasOwnProperty( name ) ) {
OO.ui.setWidgetValue( this.fieldMap[name], valueMap[name] );
}
}
return valueMap;
};
Form.prototype.clear = function () {
this.setValues(null);
};
Form.prototype.hide = function () {
this.$element.hide();
};
Form.prototype.show = function () {
this.$element.show();
};
Form.prototype.submit = function () {
var fieldName,
labelData = this.getValues();
// TODO: This is hacky. Constraints should be specified in the form config
for ( fieldName in labelData ) {
if (labelData.hasOwnProperty(fieldName) && labelData[fieldName] === null) {
if (!confirm(WL.i18n("'$1' not completed. Submit anyway?", [fieldName]))) {
return;
}
}
}
this.submitted.fire( labelData );
};
Form.prototype.abandon = function () {
this.abandoned.fire();
};
Form.fromConfig = function ( config, langChain ) {
var i, fieldset, fieldDoc, field, fieldMap,
i18n = function ( key ) {
var i, lang;
langChain = WL.util.oneOrMany(langChain);
for (i = 0; i < langChain.length; i++) {
lang = langChain[i];
if (config.i18n && config.i18n[lang] && config.i18n[lang][key]) {
return config.i18n[lang][key];
}
}
return "<" + key + ">";
};
// Create a new fieldset & load the translated fields
fieldset = new OO.ui.FieldsetLayout( {
//label: WL.util.applyTranslation( config.title, i18n )
} );
fieldMap = {};
for ( i in config.fields ) {
if ( config.fields.hasOwnProperty( i ) ) {
fieldDoc = WL.util.applyTranslation( config.fields[i], i18n );
field = OO.ui.instantiateFromParameters( fieldDoc, fieldMap );
fieldset.addItems( [ field ] );
}
}
return new Form( fieldset, fieldMap );
};
WL.Form = Form;
} )( jQuery, OO, wikiLabels );
( function (mw, $, OO, WL) {
/**
* Home
*
*/
var Home = function ($element) {
var i, instance;
if ( $element === undefined || $element.length === 0 ) {
throw "$element must be a defined element";
}
if ( $element.attr('id') !== WL.config.prefix + "home" ) {
throw "Expected $element to have id='" + WL.config.prefix + "home'";
}
if ( WL.Home.instances ) {
for (i = 0; i < WL.Home.instances.length; i++) {
instance = WL.Home.instances[i];
if ( instance.$element.is($element) ) {
throw "Home is already loaded on top of " + $element.attr('id');
}
}
}
this.$element = $element;
WL.Home.instances.push(this)
this.$menu = this.$element.find("> .menu, > .wikilabels-menu");
if ( this.$menu === undefined || this.$menu.length !== 1 ) {
throw "#" + WL.config.prefix + "home > .wikilabels-menu must be a single defined element";
}
this.campaignList = new CampaignList();
this.campaignList.worksetActivated.add(this.handleWorksetActivation.bind(this));
this.connector = new Connector();
this.workspace = new WL.Workspace(
this.$element.find(".wikilabels-workspace")
);
this.$element.append(this.workspace.$element);
this.workspace.labelSaved.add(this.handleLabelSaved.bind(this));
this.workspace.newWorksetRequested.add(this.handleNewWorksetRequested.bind(this));
WL.user.updateStatus();
WL.user.statusChanged.add(this.handleUserStatusChange.bind(this));
this.handleUserStatusChange();
};
Home.instances = [];
Home.prototype.handleUserStatusChange = function () {
if ( WL.user.authenticated() ) {
this.campaignList.load();
this.$menu.empty();
this.$menu.append(this.campaignList.$element);
} else {
this.$menu.empty();
this.$menu.append(this.connector.$element);
}
};
Home.prototype.handleWorksetActivation = function ( campaign, workset ) {
this.campaignList.selectWorkset(workset);
this.workspace.loadWorkset(campaign.id, workset.id);
};
Home.prototype.handleLabelSaved = function ( campaignId, worksetId, tasks, labels ) {
var campaign, workset;
campaign = this.campaignList.get(campaignId);
workset = campaign.worksetList.get(worksetId);
workset.updateProgress(tasks, labels);
campaign.updateButtonState();
};
Home.prototype.handleNewWorksetRequested = function () {
var campaign = this.campaignList.get(this.workspace.campaignId);
campaign.assignNewWorkset();
};
/**
* Connector Widget
*
*
*/
var Connector = function () {
this.$element = $("<div>").addClass("connector");
this.button = new OO.ui.ButtonWidget( {
label: WL.i18n("connect to server"),
flags: ["progressive"]
} );
this.$element.append(this.button.$element);
this.button.on('click', this.handleButtonClick.bind(this));
};
Connector.prototype.handleButtonClick = function (e) {
WL.user.initiateOAuth();
};
/**
* Campaign List Widget
*
*/
var CampaignList = function () {
this.$element = $("<div>").addClass("campaign-list");
this.$header = $("<h2>").text(WL.i18n("Campaigns"));
this.$element.append(this.$header);
this.$container = $("<div>").addClass("container");
this.$element.append(this.$container);
this.campaigns = {};
this.selectedWorkset = null;
this.worksetActivated = $.Callbacks();
};
CampaignList.prototype.handleWorksetActivation = function ( campaign, workset ) {
this.worksetActivated.fire( campaign, workset );
};
CampaignList.prototype.get = function (campaignId) {
return this.campaigns[campaignId];
};
CampaignList.prototype.clear = function () {
this.$container.empty();
this.campaigns = {};
};
CampaignList.prototype.load = function () {
var query;
if ( !WL.user.authenticated() ) {
throw "Cannot load campaign list when user is not authenticated.";
}
this.clear();
query = WL.server.getCampaigns();
query.done( function (doc) {
var i, campaign;
for ( i = 0; i < doc['campaigns'].length; i++) {
campaign = new Campaign(doc['campaigns'][i]);
this.push(campaign);
}
}.bind(this));
query.fail( function (doc) {
this.$element.html(doc.code + ":" + doc.message);
}.bind(this));
};
CampaignList.prototype.push = function (campaign) {
this.campaigns[campaign.id] = campaign;
this.$container.append(campaign.$element);
campaign.worksetActivated.add(this.handleWorksetActivation.bind(this));
};
CampaignList.prototype.selectWorkset = function ( workset ) {
if (this.selectedWorkset) {
this.selectedWorkset.select(false);
}
this.selectedWorkset = workset;
if (this.selectedWorkset) {
this.selectedWorkset.select(true);
}
};
/**
* Campaign Widget
*
*/
var Campaign = function (campaignData) {
this.$element = $("<div>").addClass("campaign");
this.expander = new OO.ui.ToggleButtonWidget( {
label: "+",
value: false,
classes: [ "expander" ]
} );
this.$element.append(this.expander.$element);
this.expander.on('change', this.handleExpanderChange.bind(this));
this.$name = $("<div>").addClass("name");
this.$element.append(this.$name);
this.worksetList = new WorksetList();
this.$element.append(this.worksetList.$element);
this.worksetList.worksetActivated.add(this.handleWorksetActivation.bind(this));
this.$controls = $("<div>").addClass("controls");
this.$element.append(this.$controls);
this.newButton = new OO.ui.ButtonWidget( {
label: WL.i18n("request workset")
} );
this.$controls.append(this.newButton.$element);
this.newButton.on('click', this.handleNewButtonClick.bind(this));
this.expanded = $.Callbacks();
this.worksetActivated = $.Callbacks();
this.load(campaignData);
};
Campaign.prototype.handleExpanderChange = function ( expanded ) {
this.expand(expanded);
};
Campaign.prototype.handleNewButtonClick = function (e) {
this.assignNewWorkset();
};
Campaign.prototype.handleWorksetActivation = function ( workset ) {
this.worksetActivated.fire(this, workset);
};
Campaign.prototype.assignNewWorkset = function () {
WL.server.assignWorkset(this.id)
.done( function (doc) {
var workset = new Workset(doc['workset']);
this.worksetList.push(workset);
this.worksetActivated.fire(this, workset);
}.bind(this))
.fail( function (doc) {
alert(doc.code + ": " + doc.message);
}.bind(this));
};
Campaign.prototype.updateButtonState = function () {
if ( this.worksetList.complete() ) {
this.newButton.setDisabled(false);
} else {
this.newButton.setDisabled(true);
}
};
Campaign.prototype.load = function (campaignData) {
var query;
this.id = campaignData['id'];
this.$name.text(campaignData['name']);
WL.server.getUserWorksetList(
WL.user.id, campaignData['id']
)
.done( function (doc) {
var i, workset;
this.worksetList.clear();
for (i = 0; i < doc['worksets'].length; i++) {
workset = new Workset(doc['worksets'][i]);
this.worksetList.push(workset);
}
this.updateButtonState();
}.bind(this) )
.fail( function (doc) {
alert(WL.i18n("Could not load workset list: $1", [JSON.stringify(doc)]));
}.bind(this) );
};
Campaign.prototype.expand = function (expanded) {
if ( expanded === undefined) {
return this.$element.hasClass("expanded");
} else if ( expanded ) {
this.$element.addClass("expanded");
this.expander.setLabel("-");
this.expanded.fire(expanded);
return this;
} else {
this.$element.removeClass("expanded");
this.expander.setLabel("+");
return this;
}
};
/**
* Workset List Widget
*
*/
var WorksetList = function () {
this.$element = $("<div>").addClass("workset-list");
this.$container = $("<div>").addClass("container");
this.$element.append(this.$container);
this.worksets = {};
this.worksetActivated = $.Callbacks();
};
WorksetList.prototype.handleWorksetActivation = function (workset) {
this.worksetActivated.fire(workset);
};
WorksetList.prototype.push = function (workset) {
this.$container.append(workset.$element);
this.worksets[workset.id] = workset;
workset.activated.add(this.handleWorksetActivation.bind(this));
};
WorksetList.prototype.get = function (worksetId) {
return this.worksets[worksetId];
};
WorksetList.prototype.clear = function () {
// Clear the container
this.$container.empty();
this.worksets = {};
};
WorksetList.prototype.complete = function () {
var key, workset;
for ( key in this.worksets ) {
if (this.worksets.hasOwnProperty(key)) {
workset = this.worksets[key];
if ( !workset.completed ) {
return false;
}
}
}
return true;
};
/**
* Workset Widget
*
*/
var Workset = function (worksetData) {
this.$element = $("<div>").addClass("workset");
this.$element.click(this.handleClick.bind(this));
this.$controls = $("<div>").addClass("controls");
this.$element.append(this.$controls);
this.openButton = new OO.ui.ButtonWidget( {
label: WL.i18n("open"),
classes: [ 'button', 'open' ],
flags: [ 'constructive' ]
} );
this.openButton.on('click', this.handleButtonClick.bind(this));
this.reviewButton = new OO.ui.ButtonWidget( {
label: WL.i18n("review"),
classes: [ 'button', 'review' ],
flags: [ 'constructive' ],
framed: false
} );
this.reviewButton.on('click', this.handleButtonClick.bind(this));
this.progressContent = $("<span>");
this.progress = new OO.ui.ProgressBarWidget( {
progress: 0,
content: [this.progressContent],
classes: [ 'progress' ]
} );
this.$element.append(this.progress.$element);
this.completed = false;
this.activated = $.Callbacks();
this.load(worksetData);
};
Workset.prototype.handleClick = function (e) {
this.activated.fire(this);
};
Workset.prototype.handleButtonClick = function (e) {
this.activated.fire(this);
};
Workset.prototype.load = function (worksetData) {
this.id = worksetData['id'];
this.campaignId = worksetData['campaign_id'];
this.created = worksetData['created'];
this.updateProgress(worksetData.stats.tasks, worksetData.stats.labeled);
};
Workset.prototype.updateProgress = function (tasks, labeled) {
var percent = ((labeled / tasks) || 0) * 100;
this.completed = labeled === tasks;
if ( this.completed ) {
this.$controls.html(this.reviewButton.$element);
} else {
this.$controls.html(this.openButton.$element);
}
this.progress.setProgress( percent );
this.progressContent.text( this.formatProgress(tasks, labeled) );
};
Workset.prototype.formatProgress = function (tasks, labeled) {
return (new Date(this.created * 1000)).format(WL.i18n("date-format")) + " " +
"(" + String(labeled) + "/" + String(tasks) + ")";
};
Workset.prototype.select = function (selected) {
if ( selected === undefined) {
return this.$element.hasClass("selected");
} else if ( selected ) {
this.$element.addClass("selected");
return this;
} else {
this.$element.removeClass("selected");
return this;
}
};
WL.Home = Home;
})(mediaWiki, jQuery, OO, wikiLabels);
( function (mw, WL) {
var format = function (str, args) {
return str.replace(
/\$[0-9]+/,
function (m) { return args[parseInt(m.substring(1), 10) - 1] || m;}
);
};
var i18n = function (key, args) {
var i, lang,
langChain = mw.language.getFallbackLanguageChain();
for (i = 0; i < langChain.length; i++) {
lang = langChain[i];
if (WL.config.messages[lang] && WL.config.messages[lang][key]) {
return format(WL.config.messages[lang][key], args);
}
}
return "<" + format(key, args) + ">";
};
WL.i18n = i18n;
})(mediaWiki, wikiLabels);
( function (mw, $, WL) {
var Server = function () {};
Server.prototype.request = function (relPath, data, method) {
var deferred = $.Deferred();
method = method || "GET";
$.ajax(
this.absPath.apply(this, relPath),
{
dataType: "json",
method: method,
jsonp: false,
crossDomain: true,
xhrFields: {withCredentials: true},
data: data || {}
}
)
.done(function (doc, status, jqXHR) {
if (!doc.error) {
deferred.resolve(doc);
} else {
console.error(doc.error);
deferred.reject(doc.error);
}
}.bind(this))
.fail(function (jqXHR, status, err) {
try {
var errorMessage = JSON.parse(jqXHR.responseText).error.message;
}
catch(parseError) {
var errorMessage = "Unable to parse response";
}
var errorData = { code: jqXHR.status, status: status, message: errorMessage };
console.error(errorData);
deferred.reject(errorData);
}.bind(this));
return deferred.promise();
};
Server.prototype.absPath = function(/* relative path parts */){
var serverRoot = WL.config.serverRoot,
relPath = WL.util.pathJoin.apply(this, Array.prototype.slice.call(arguments));
return serverRoot.replace(/\/+$/g, "") + "/" + relPath.replace(/^\/+/g, "") + "/";
};
Server.prototype.getCampaigns = function () {
return this.request(
["campaigns", mw.config.get('wgDBname')]
);
};
Server.prototype.whoami = function () {
return this.request(
["auth", "whoami"]
);
};
Server.prototype.getUserWorksetList = function (userId, campaignId) {
return this.request(
["users", userId, campaignId],
{ worksets: "stats" }
);
};
Server.prototype.assignWorkset = function (campaignId) {
return this.request(
["campaigns", mw.config.get('wgDBname'), campaignId],
{ workset: "stats"},
"POST"
);
};
Server.prototype.getWorkset = function (campaignId, worksetId) {
return this.request(
["campaigns", mw.config.get('wgDBname'), campaignId, worksetId],
{ tasks: "", campaign: "" }
);
};
Server.prototype.getForm = function (formName) {
return this.request(
["forms", formName]
);
};
Server.prototype.saveLabel = function (campaignId, worksetId, taskId, labelData) {
return this.request(
["campaigns", mw.config.get('wgDBname'), campaignId, worksetId, taskId],
{ label: JSON.stringify(labelData) },
"POST"
);
};
Server.prototype.abandonLabel = function (campaignId, worksetId, taskId) {
return this.request(
["campaigns", mw.config.get('wgDBname'), campaignId, worksetId, taskId],
{},
"DELETE"
);
};
WL.server = new Server();
})(mediaWiki, jQuery, wikiLabels);
( function (mw, $, WL) {
var User = function () {
this.id = null;
$(window).focus(this.handleRefocus.bind(this));
this.statusChanged = $.Callbacks();
};
User.prototype.handleRefocus = function (e) {
this.updateStatus();
};
User.prototype.updateStatus = function () {
var oldId = this.id;
WL.server.whoami()
.done(function(doc){
this.id = doc['user']['id'];
if ( oldId !== this.id ) {
console.log("Setting user_id to " + this.id);
this.statusChanged.fire();
}
}.bind(this))
.fail(function(doc){
this.id = null;
}.bind(this));
};
User.prototype.initiateOAuth = function () {
var oauthWindow = window.open(
WL.server.absPath("auth", "initiate"), "OAuth",
'height=768,width=1024'
);
if (window.focus) {
oauthWindow.focus();
}
};
User.prototype.authenticated = function () {
return this.id !== null;
};
WL.user = new User();
})(mediaWiki, jQuery, wikiLabels);
( function (mw, $, WL) {
WL.util = {
applyTranslation: function ( value, lookup ) {
var str, arr, transArray, i, obj, transObj, key;
if ( typeof value === 'string' ) {
// If a string, look to see if we need to translate it.
str = value;
if ( str.charAt( 0 ) === '<' && str.charAt( str.length - 1 ) === '>' ) {
// Lookup translation
return lookup( str.substr( 1, str.length - 2 ) );
} else {
// No translation necessary
return str;
}
} else if ( $.isArray( value ) ) {
// Going to have to recurse for each item
arr = value;
transArray = [];
for ( i in arr ) {
if ( arr.hasOwnProperty(i) ) {
transArray.push( WL.util.applyTranslation( arr[i], lookup ) );
}
}
return transArray;
} else if ( typeof value === 'object' ) {
// Going to have to recurse for each value
obj = value;
transObj = {};
for ( key in obj ) {
if ( obj.hasOwnProperty( key ) ) {
transObj[ key ] = WL.util.applyTranslation( obj[key], lookup );
}
}
return transObj;
} else {
// bool or numeric == A-OK
return value;
}
},
oneOrMany: function (val) {
if ($.isArray(val)) {
return val;
} else {
return [val];
}
},
linkToTitle: function (title, label) {
var url = mw.util.getUrl( title );
return $("<a>").attr('href', url).text(label || title);
},
linkToDiff: function (revId, label) {
var url = mw.config.get('wgServer') +
mw.config.get('wgArticlePath').replace("$1", "?diff=" + revId);
return $("<a>").attr('target', '_blank').attr('href', url).text(label || revId);
},
pathJoin: function (/* path parts */) {
var args = Array.prototype.slice.call(arguments);
// Split the inputs into a list of path commands.
var parts = [];
for (var i = 0, l = args.length; i < l; i++) {
parts = parts.concat(String(args[i]).split("/"));
}
// Interpret the path commands to get the new resolved path.
var newParts = [];
for (i = 0, l = parts.length; i < l; i++) {
var part = parts[i];
// Remove leading and trailing slashes
// Also remove "." segments
if (!part || part === ".") continue;
// Interpret ".." to pop the last segment
if (part === "..") newParts.pop();
// Push new path segments.
else newParts.push(part);
}
// Preserve the initial slash if there was one.
if (parts[0] === "") newParts.unshift("");
// Turn back into a single string path.
return newParts.join("/") || (newParts.length ? "/" : ".");
}
};
})(mediaWiki, jQuery, wikiLabels);
( function (mw, $, WL) {
var View = function (taskListData) {
this.$element = $("<div>").addClass(WL.config.prefix + "view");
this.taskMap = null;
this.tasks = [];
this.selectedTaskInfo = null;
this.taskSelected = $.Callbacks();
this.worksetCompleted = new WorksetCompleted();
this.worksetCompleted.newWorksetRequested.add(this.handleNewWorksetRequested.bind(this));
this.newWorksetRequested = $.Callbacks();
this.load(taskListData);
};
OO.initClass(View);
View.prototype.handleNewWorksetRequested = function ( ) {
this.newWorksetRequested.fire();
};
View.prototype.load = function (taskListData) {
var i, taskData, taskInfo;
this.taskMap = {};
for (i = 0; i < taskListData.length; i++) {
taskData = taskListData[i];
taskInfo = { i: i, data: taskData };
this.tasks.push(taskInfo);
this.taskMap[taskData.id] = i;
}
};
View.prototype.show = function (taskId) {
if (this.taskMap[taskId] === undefined) {
throw "Could not find data for task_id=" + taskId;
} else {
this.select(this.tasks[this.taskMap[taskId]]);
}
};
View.prototype.select = function (taskInfo) {
var oldTaskInfo = this.selectedTaskInfo;
this.selectedTaskInfo = taskInfo;
if (oldTaskInfo !== this.selectedTaskInfo) {
this.taskSelected.fire(taskInfo.data.id);
}
this.present(this.selectedTaskInfo);
};
View.prototype.present = function (taskInfo) {
var jsonString = JSON.stringify(taskInfo, null, 2);
this.$element.html($("<pre>").text(jsonString)); // spacing set pprint
};
View.prototype.showCompleted = function () {
this.$element.html(this.worksetCompleted.$element);
};
var DiffToPrevious = function(taskListData) {
DiffToPrevious.super.call( this, taskListData );
this.$element.addClass(WL.config.prefix + "diff-to-previous");
};
OO.inheritClass(DiffToPrevious, View);
DiffToPrevious.prototype.load = function (taskListData) {
DiffToPrevious.super.prototype.load.call( this, taskListData );
this.preCacheDiffs();
};
DiffToPrevious.prototype.present = function (taskInfo) {
if(taskInfo.diff){
this.presentDiff(taskInfo.diff);
} else {
WL.api.diffToPrevious(taskInfo.data['data']['rev_id'])
.done( function (diff) {
this.tasks[taskInfo.i].diff = diff; // Cache!
this.presentDiff(diff);
}.bind(this) )
.fail( function (doc) {
var error = $("<pre>").addClass("error");
this.$element.html(error.text(JSON.stringify(doc, null, 2)));
}.bind(this) );
}
};
DiffToPrevious.prototype.preCacheDiffs = function (index) {
var query, revId;
index = index || 0;
if ( index >= this.tasks.length ) {
// We're done here
return null;
} else if ( this.tasks[index].diff !== undefined ) {
//Already cached this diff. Recurse!
this.preCacheDiffs(index + 1);
} else {
//We don't have the diff. Go get it.
revId = this.tasks[index].data['data']['rev_id'];
query = WL.api.diffToPrevious(revId);
query.done( function (diff) {
console.log("pre-caching diff for " + revId);
this.tasks[index].diff = diff;
// Recurse!
this.preCacheDiffs(index + 1);
}.bind(this) );
query.fail( function (doc) {
// Recurse!
this.preCacheDiffs(index + 1);
}.bind(this) );
}
};
DiffToPrevious.prototype.presentDiff = function(diff){
var diffLink,
title = WL.util.linkToTitle(diff.title).addClass("title"),
description = $("<div>").addClass("description"),
comment = $("<div>").addClass("comment"),
direction = $("#mw-content-text").attr("dir"),
diffTable = (direction == 'rtl' ?
$("<table>").addClass("diff diff-contentalign-right") :
$("<table>").addClass("diff diff-contentalign-left"));
this.$element.empty();
this.$element.append(title);
diffLink = WL.util.linkToDiff(diff.revId).prop('outerHTML');
description.html(WL.i18n("Diff for revision $1", [diffLink]));
this.$element.append(description);
this.$element.append(comment.html(diff.comment));
if (diff.tableRows) {
diffTable.append(
"<col class='diff-marker' />" +
"<col class='diff-content' />" +
"<col class='diff-marker' />" +
"<col class='diff-content' />"
);
diffTable.append(diff.tableRows);
this.$element.append(diffTable);
} else {
this.$element.append(
$("<div>").addClass("no-difference")
.text(WL.i18n("No difference"))
);
}
};
var PageAsOfRevision = function(taskListData) {
PageAsOfRevision.super.call( this, taskListData );
this.$element.addClass(WL.config.prefix + "page-as-of-revision")
.addClass('display-page-html');
};
OO.inheritClass(PageAsOfRevision, View);
PageAsOfRevision.prototype.present = function(taskInfo) {
if (taskInfo.title && taskInfo.html) {
this.presentPage(taskInfo.title, taskInfo.html);
} else {
WL.api.getRevision(
taskInfo.data['data']['rev_id'],
{
'rvprop': "content",
'rvparse': true
}
)
.done( function (doc) {
this.tasks[taskInfo.i].html = doc['*']; // Cache!
this.tasks[taskInfo.i].title = doc['page']['title']; // Cache!
this.presentPage(doc['page']['title'], doc['*']);
}.bind(this) )
.fail( function (doc) {
var error = $("<pre>").addClass("error");
this.$element.html(error.text(JSON.stringify(doc, null, 2)));
}.bind(this) );
}
};
PageAsOfRevision.prototype.presentPage = function(title, html) {
this.$element.html("");
this.$element.append(
$("<h1>").text(title)
.attr('id', "firstHeading")
.addClass("firstHeading")
);
this.$element.append(
$("<div>").html(html)
.addClass("mw-body-content")
.attr('id', "bodyContent")
);
};
var ParsedWikitext = function(taskListData) {
ParsedWikitext.super.call( this, taskListData );
this.$element.addClass(WL.config.prefix + "parsed-wikitext")
.addClass('display-page-html');
};
OO.inheritClass(ParsedWikitext, View);
ParsedWikitext.prototype.present = function(taskInfo) {
if (taskInfo.html) {
this.presentHTML(taskInfo.html);
} else {
WL.api.wikitext2HTML(taskInfo.data['data']['wikitext'])
.done( function (html) {
this.tasks[taskInfo.i].html = html; // Cache!
this.presentHTML(html);
}.bind(this) )
.fail( function (doc) {
var error = $("<pre>").addClass("error");
this.$element.html(error.text(JSON.stringify(doc, null, 2)));
}.bind(this) );
}
};
ParsedWikitext.prototype.presentHTML = function(html) {
this.$element.html(html);
};
var WorksetCompleted = function () {
this.$element = $("<div>").addClass("completed");
this.$message = $("<div>").addClass("message")
.text(WL.i18n("Workset complete!"));
this.$element.append(this.$message);
this.newWorkset = new OO.ui.ButtonWidget( {
label: WL.i18n("Request new workset"),
classes: [ "new-button" ]
} );
this.$element.append(this.newWorkset.$element);
this.newWorkset.on('click', this.handleNewWorksetClick.bind(this));
this.newWorksetRequested = $.Callbacks();
};
WorksetCompleted.prototype.handleNewWorksetClick = function () {
this.newWorksetRequested.fire();
};
WL.views = {
View: View,
DiffToPrevious: DiffToPrevious,
PageAsOfRevision: PageAsOfRevision,
ParsedWikitext: ParsedWikitext
};
}(mediaWiki, jQuery, wikiLabels));
( function (mw, $, OO, WL) {
var Workspace = function ($element) {
if ( $element === undefined || $element.length === 0 ) {
throw '$element must be a defined element';
}
this.$element = $element;
this.$element.hide();
this.campaignId = null;
this.worksetId = null;
this.taskList = null;
this.form = null;
this.view = null;
this.$parent = $element.parent();
this.$menu = $('<div>').addClass( 'wikilabels-menu' );
this.$element.append(this.$menu);
this.fullscreenToggle = new OO.ui.ToggleButtonWidget( {
label: WL.i18n('fullscreen'),
classes: ['fullscreen']
} );
this.$menu.append(this.fullscreenToggle.$element);
this.fullscreenToggle.on('change', this.handleFullscreenChange.bind(this));
this.$container = $('<div>').addClass('container');
this.$element.append(this.$container);
this.labelSaved = $.Callbacks();
this.newWorksetRequested = $.Callbacks();
};
Workspace.prototype.handleFormSubmission = function ( labelData ) {
this.saveLabel(labelData);
};
Workspace.prototype.handleFormAbandon = function () {
this.abandonLabel();
};
Workspace.prototype.handleTaskSelection = function (task) {
if (task) {
this.view.show(task.id);
this.form.setValues(task.label.data);
this.form.show();
}
};
Workspace.prototype.handleFullscreenChange = function (e) {
this.fullscreen(this.fullscreenToggle.getValue());
};
Workspace.prototype.handleNewWorksetRequested = function () {
this.newWorksetRequested.fire();
};
Workspace.prototype.loadWorkset = function (campaignId, worksetId) {
var taskList, form, view,
query = WL.server.getWorkset(campaignId, worksetId);
this.clear();
this.$element.show();
query.done( function (doc) {
var formQuery;
// Use this when debugging to make sure that errors in view construction
// are reported with a full stack trace. Otherwise, keep it commented
// out.
try {
view = new WL.views[doc['campaign']['view']](doc['tasks']);
} catch (err) {
console.error(err.stack);
alert(WL.i18n('Could not load view "$1": '
+ '$2\nUsing simple task viewer.', [doc['campaign']['view'], err]));
view = new WL.views.View(doc['tasks']);
}
taskList = new TaskList(doc['tasks']);
formQuery = WL.server.getForm(doc['campaign']['form']);
formQuery.done( function (formDoc) {
try {
form = WL.Form.fromConfig(formDoc['form'], mw.language.getFallbackLanguageChain());
this.load(campaignId, worksetId, taskList, form, view);
} catch (err) {
console.error(err.stack);
alert(WL.i18n(
'Could not load form "$1": \n$2', [doc['campaign']['form'], err]
));
}
}.bind(this));
formQuery.fail( function (errorDoc) {
alert(WL.i18n(
'Could not load form "$1": \n$2',
[doc['campaign']['form'], JSON.stringify(errorDoc, null, 2)]
));
}.bind(this) );
}.bind(this) );
};
Workspace.prototype.load = function (campaignId, worksetId, taskList, form, view) {
var firstTask;
this.clear();
this.campaignId = campaignId;
this.worksetId = worksetId;
this.taskList = taskList;
this.$container.append(taskList.$element);
this.taskList.taskSelected.add(this.handleTaskSelection.bind(this));
this.form = form;
this.$container.append(form.$element);
this.form.submitted.add(this.handleFormSubmission.bind(this));
this.form.abandoned.add(this.handleFormAbandon.bind(this));
this.view = view;
this.$container.append(view.$element);
this.view.newWorksetRequested.add(this.handleNewWorksetRequested.bind(this));
this.fullscreenToggle.setDisabled(false);
firstTask = this.taskList.selectByIndex(0);
this.view.show(firstTask.id);
};
Workspace.prototype.saveLabel = function (labelData) {
var fieldName,
fieldsMissingValues,
task = this.taskList.selectedTask;
if ( !task ) {
alert(WL.i18n("Can't save label. No task is selected!"));
}
WL.server.saveLabel(this.campaignId, this.worksetId, task.id, labelData)
.done( function (doc) {
var tasks, labels;
task.label.load(doc['label']);
tasks = this.taskList.length();
labels = this.taskList.labeled();
this.labelSaved.fire(this.campaignId, this.worksetId, tasks, labels);
if ( this.taskList.last() && this.taskList.complete() ) {
this.taskList.select(null);
this.form.clear();
this.form.hide();
this.view.showCompleted();
} else {
this.taskList.next();
}
$.removeSpinner( WL.config.prefix + 'submit-spinner' );
}.bind(this));
};
Workspace.prototype.abandonLabel = function () {
var fieldName,
fieldsMissingValues,
task = this.taskList.selectedTask;
if ( !task ) {
alert("Can't abandon task. No task is selected!");
}
WL.server.abandonLabel(this.campaignId, this.worksetId, task.id)
.done( function (doc) {
var tasks, labels;
// TODO: Fix API response
task.label.load({'data': true}, 'abandoned');
tasks = this.taskList.length();
labels = this.taskList.labeled();
// Let's assume it's saved
this.labelSaved.fire(this.campaignId, this.worksetId, tasks, labels);
if ( this.taskList.last() && this.taskList.complete() ) {
this.taskList.select(null);
this.form.clear();
this.form.hide();
this.view.showCompleted();
} else {
this.taskList.next();
}
$.removeSpinner( WL.config.prefix + 'abandon-spinner' );
}.bind(this));
};
Workspace.prototype.fullscreen = function (fullscreen) {
if ( fullscreen === undefined) {
return this.$element.hasClass('fullscreen');
} else if ( fullscreen ) {
$('body').append(this.$element);
this.$element.addClass('fullscreen');
return this;
} else {
this.$parent.append(this.$element);
this.$element.removeClass('fullscreen');
return this;
}
};
Workspace.prototype.clear = function () {
this.$container.empty();
this.fullscreenToggle.setDisabled(true);
};
var TaskList = function (taskListData) {
this.$element = $('<div>').addClass('task-list');
this.$header = $('<div>').addClass('header').text(WL.i18n("Workset"));
this.$element.append(this.$header);
this.tasks = null;
this.$tasks = $('<div>').addClass('tasks');
this.$element.append(this.$tasks);
this.$tasksTable = $('<table>').addClass('table');
this.$tasks.append(this.$tasksTable);
this.$tasksRow = $('<tr>').addClass('row');
this.$tasksTable.append(this.$tasksRow);
this.selectedTaskInfo = null;
this.taskSelected = $.Callbacks();
this.load(taskListData);
};
TaskList.prototype.handleTaskActivation = function (task) {
this.select(task);
};
TaskList.prototype.load = function (taskListData) {
var taskData, task, i;
this.$tasksRow.empty(); // Just in case there was something in there.
this.tasks = [];
for (i = 0; i < taskListData.length; i++) {
taskData = taskListData[i];
task = new Task(i, taskData);
task.activated.add(this.handleTaskActivation.bind(this));
this.tasks.push(task);
this.$tasksRow.append(task.$element);
}
};
TaskList.prototype.select = function (task) {
if (this.selectedTask) {
this.selectedTask.select(false);
}
if (task) {
task.select(true);
}
this.selectedTask = task;
this.taskSelected.fire(task);
};
TaskList.prototype.selectByIndex = function (index) {
if (index >= this.tasks.length) {
throw "Could not select task. Index " + index + " out of bounds.";
}
this.select(this.tasks[index]);
return this.tasks[index];
};
TaskList.prototype.shift = function (delta) {
var newI;
if (!this.selectedTask) {
throw "No task assigned. Can't shift().";
}
newI = (this.selectedTask.i + delta) % this.tasks.length;
this.select(this.tasks[newI]);
};
TaskList.prototype.next = function () {
return this.shift(1);
};
TaskList.prototype.prev = function () {
return this.shift(-1);
};
TaskList.prototype.last = function () {
if ( this.selectedTask ) {
return this.selectedTask.i === this.tasks.length - 1;
} else {
throw "No task selected";
}
};
TaskList.prototype.labeled = function () {
var i, task,
labeledTasks = 0;
for (i = 0; i < this.tasks.length; i++) {
task = this.tasks[i];
labeledTasks += task.isCompleted();
}
return labeledTasks;
};
TaskList.prototype.complete = function () {
var i, task;
for (i = 0; i < this.tasks.length; i++) {
task = this.tasks[i];
if (!task.isCompleted()) {
return false;
}
}
return true;
};
TaskList.prototype.length = function () {
return this.tasks.length;
};
var Task = function (i, taskData) {
this.$element = $('<td>').addClass( 'task');
this.$element.click(this.handleClick.bind(this));
this.i = i;
this.selected = $.Callbacks();
this.activated = $.Callbacks();
this.load(taskData);
};
Task.prototype.handleClick = function (e) {
if ( !this.disable() ) {
this.activated.fire(this);
}
};
Task.prototype.load = function (taskData) {
this.$element.empty();
this.id = taskData.id;
this.data = taskData['task_data'];
this.label = new Label(taskData['labels'][0]);
this.$element.append(this.label.$element);
};
Task.prototype.select = function (selected) {
if ( selected === undefined) {
return this.$element.hasClass('selected');
} else if ( selected ) {
this.$element.addClass('selected');
this.selected.fire();
return this;
} else {
this.$element.removeClass('selected');
return this;
}
};
Task.prototype.setWidth = function (width) {
this.$element.css('width', width);
};
Task.prototype.disable = function (disabled) {
if ( disabled === undefined) {
return this.$element.hasClass('disabled');
} else if ( disabled ) {
this.$element.addClass('disabled');
return this;
} else {
this.$element.removeClass('disabled');
return this;
}
};
Task.prototype.isCompleted = function () {
return this.label.isCompleted() || this.isAbandoned();
};
Task.prototype.isAbandoned = function () {
return this.label.$element.hasClass('abandoned');
};
var Label = function (labelData) {
this.$element = $("<div>").addClass("label");
this.timestamp = null;
this.data = null;
this.load(labelData);
};
Label.prototype.load = function (labelData, className) {
labelData = labelData || {};
this.timestamp = labelData['timestamp'];
this.data = labelData['data'];
this.complete(this.data !== undefined && this.data !== null, className);
};
Label.prototype.complete = function (completed, className) {
className = className || 'completed';
if ( completed === undefined ) {
return this.$element.hasClass(className);
} else if ( completed ) {
this.$element.addClass(className);
return this;
} else {
this.$element.removeClass(className);
return this;
}
};
Label.prototype.isCompleted = function(classNames) {
classNames = classNames || ['completed'];
for ( var i in classNames ) {
if ( this.$element.hasClass( classNames[i] ) ) {
return true;
}
}
return false;
};
wikiLabels.Workspace = Workspace;
})(mediaWiki, jQuery, OO, wikiLabels);
(function($, WL){
WL.config.messages = {
"ar": {
"'$1' not completed. Submit anyway?": "'$1' غير مكتمل. أرسل على أي حال؟",
"@metadata": {
"authors": [
"Maroen1990",
"محمد أحمد عبد الفتاح",
"Ghassanmas",
"DRIHEM"
]
},
"Campaigns": "الحملات",
"Diff for revision $1": "معرفة الإختلافات للمراجعة $1",
"No difference": "لا يوجد فرق",
"Request new workset": "طلب شريحة جديد من العينات",
"Review": "مراجعة",
"Save": "حفظ",
"Submit label": "أكد التعيين",
"Workset": "شريحة",
"Workset complete!": "الشريحة اكتملت !",
"connect to server": "اتصل مع خادم البيانات",
"date-format": "%d-%m-%Y",
"fullscreen": "ملء الشاشة",
"open": "افتح",
"request workset": "اطلب شريحة من العينات",
"review": "راجع"
},
"ba": {
"'$1' not completed. Submit anyway?": "'$1' тамамланмаған. Барыбер ебәрергәме?",
"@metadata": {
"authors": [
"Lizalizaufa",
"Айсар",
"Танзиля Кутлугильдина",
"Янмурза Баки"
]
},
"Campaigns": "Кампаниялар",
"Diff for revision $1": "$1ды тикшереү айырмаһы",
"No difference": "Айырмалар юҡ",
"Request new workset": "Яңы эш йыйылмаһы һорарға",
"Review": "Тикшереү",
"Save": "Һаҡларға",
"Submit label": "Билдә ебәрергә",
"Workset": "Эш тупланмаһы",
"Workset complete!": "Эшсе йыйылма әҙер!",
"connect to server": "Сервер менән бәйләнеш урынлаштырыу",
"date-format": "%d-%m-%Y",
"fullscreen": "тулы экранлы",
"open": "Асырға",
"request workset": "эш йыйылмаһын һорарға",
"review": "Тикшереү"
},
"bn": {
"'$1' not completed. Submit anyway?": "'$1' সম্পূর্ণ করা হয়নি। যাইহোক জমা দিবেন?",
"@metadata": {
"authors": [
"Aftabuzzaman"
]
},
"Campaigns": "প্রচারাভিযান",
"Diff for revision $1": "$1 সংস্করণের জন্য পার্থক্য",
"No difference": "কোন পার্থক্য নেই",
"Request new workset": "নতুন কাজের সেটের অনুরোধ করুন",
"Review": "পর্যালোচনা",
"Save": "সংরক্ষণ",
"Submit label": "লেভেল জমা দিন",
"Workset": "কাজের সেট",
"Workset complete!": "কাজের সেট সম্পূর্ণ!",
"connect to server": "সার্ভারের সাথে সংযোগ করুন",
"date-format": "%d-%m-%Y",
"fullscreen": "পূর্ণপর্দা",
"open": "খুলুন",
"request workset": "কাজের সেটের অনুরোধ করুন",
"review": "পর্যালোচনা"
},
"ce": {
"@metadata": {
"authors": [
"Умар"
]
},
"Review": "Таллар",
"Save": "Ӏалашъян"
},
"de": {
"'$1' not completed. Submit anyway?": "Das Feld „$1“ wurde nicht ausgefüllt. Trotzdem übermitteln?",
"@metadata": {
"authors": [
"Metalhead64"
]
},
"Abandon": "Abbrechen",
"Are you sure that you want to abandon this task?": "Bist du sicher, dass du diese Aufgabe abbrechen möchtest?",
"Campaigns": "Kampagnen",
"Can't save label. No task is selected!": "Bezeichnung konnte nicht gespeichert werden. Keine Aufgabe ausgewählt!",
"Could not get metadata for revision $1": "Die Metadaten für die Version $1 konnten nicht abgerufen werden",
"Could not load form \"$1\": \n$2": "Formular „$1“ konnte nicht geladen werden:\n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Ansicht „$1“ konnte nicht geladen werden: $2\nEs wird der einfache Aufgabenbetrachter verwendet.",
"Could not load workset list: $1": "Arbeitssatzliste konnte nicht geladen werden: $1",
"Could not parse MediaWiki API's response": "Die Antwort der MediaWiki-API konnte nicht geparst werden",
"Diff for revision $1": "Unterschied für die Version $1",
"No difference": "Kein Unterschied",
"Request new workset": "Neuen Arbeitssatz anfordern",
"Review": "Überprüfen",
"Save": "Speichern",
"Submit label": "Bezeichnung übermitteln",
"Workset": "Arbeitssatz",
"Workset complete!": "Arbeitssatz vollständig!",
"connect to server": "Verbinde zum Server",
"date-format": "%Y-%m-%d",
"fullscreen": "Vollbild",
"open": "offen",
"request workset": "Arbeitssatz anfordern",
"review": "überprüfen"
},
"diq": {
"'$1' not completed. Submit anyway?": "$1 pır niya. Fına zi wa bırışi yo?",
"@metadata": {
"authors": [
"Kumkumuk",
"Marmase",
"Mirzali"
]
},
"Abandon": "Terk ke",
"Are you sure that you want to abandon this task?": "Şıma qayılê ena wecifa ra bıvıciyê?",
"Campaigns": "Qampanyay",
"Can't save label. No task is selected!": "Nişan qeyd nêbi. Teslağo nêweçineyeno",
"Could not get metadata for revision $1": "Revizyonê $1 metdatay nêgeriyay",
"Could not load form \"$1\": \n$2": "$2 \"$1\" ra ber nêbı",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Bar nêbi \"$1\": $2\nBasit wezife mocner bıasne",
"Could not load workset list: $1": "Listeya gurenayışi bar nêbi:$1",
"Could not parse MediaWiki API's response": "Cewaba MediaWiki API'y nêagozneyê",
"Diff for revision $1": "Seba revizyonê $1 rê Diff",
"No difference": "Ferk çıni yo",
"Request new workset": "Kumeya kardê newi bıwaz",
"Review": "çım ra raviyarne",
"Save": "Qeyd ke",
"Submit label": "Etiketi arz ke",
"Workset": "Kumeya kari",
"Workset complete!": "Kumeya kari bi temam",
"connect to server": "Rovıteri ya gre bı",
"date-format": "%Y-%m-%d",
"fullscreen": "Tam ekran",
"open": "Ake",
"request workset": "Kumeya kari bıwaz",
"review": "Çımraraviyarnayış"
},
"en": {
"'$1' not completed. Submit anyway?": "The field \"$1\" was not filled. Submit anyway?",
"@metadata": [],
"Abandon": "Abandon",
"Are you sure that you want to abandon this task?": "Are you sure that you want to abandon this task?",
"Campaigns": "Campaigns",
"Can't save label. No task is selected!": "Can't save label. No task is selected!",
"Could not get metadata for revision $1": "Could not get metadata for revision $1",
"Could not load form \"$1\": \n$2": "Could not load form \"$1\": \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Could not load view \"$1\": $2\nUsing simple task viewer.",
"Could not load workset list: $1": "Could not load workset list: $1",
"Could not parse MediaWiki API's response": "Could not parse MediaWiki API's response",
"Diff for revision $1": "Diff for revision $1",
"No difference": "No difference",
"Request new workset": "Request new workset",
"Review": "Review",
"Save": "Save",
"Submit label": "Submit label",
"Workset": "Workset",
"Workset complete!": "Workset complete!",
"connect to server": "connect to server",
"date-format": "%Y-%m-%d",
"fullscreen": "fullscreen",
"open": "open",
"request workset": "request workset",
"review": "review"
},
"en-gb": {
"'$1' not completed. Submit anyway?": "'$1' not completed. Submit anyway?",
"@metadata": {
"authors": [
"Andibing",
"Usandaru555",
"Codynguyen1116"
]
},
"Abandon": "Abandon",
"Are you sure that you want to abandon this task?": "Are you sure that you want to abandon this task?",
"Campaigns": "Campaigns",
"Can't save label. No task is selected!": "Can't save label. No task is selected!",
"Could not get metadata for revision $1": "Could not get metadata for revision $1",
"Could not load form \"$1\": \n$2": "Could not load form \"$1\": \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Could not load view \"$1\": $2\nUsing simple task viewer.",
"Could not load workset list: $1": "Could not load workset list: $1",
"Could not parse MediaWiki API's response": "Could not parse MediaWiki API's response",
"Diff for revision $1": "Diff for revision $1",
"No difference": "No difference",
"Request new workset": "Request new workset",
"Review": "Review",
"Save": "Save",
"Submit label": "Submit label",
"Workset": "Workset",
"Workset complete!": "Workset complete!",
"connect to server": "connect to server",
"date-format": "%Y-%m-%d",
"fullscreen": "fullscreen",
"open": "open",
"request workset": "request workset",
"review": "review"
},
"eo": {
"@metadata": {
"authors": [
"Robin van der Vliet"
]
},
"Save": "Konservi",
"date-format": "%Y-%m-%d"
},
"es": {
"'$1' not completed. Submit anyway?": "'$1' incompleto. ¿Entrar de todas formas?",
"@metadata": {
"authors": [
"Macofe"
]
},
"Abandon": "Abandonar",
"Are you sure that you want to abandon this task?": "¿Estás seguro de que quieres abandonar esta tarea?",
"Campaigns": "Campañas",
"Can't save label. No task is selected!": "No se puede guardar la etiqueta. No hay ninguna tarea seleccionada.",
"Could not get metadata for revision $1": "No se pudieron obtener los metadatos para la revisión $1",
"Could not load form \"$1\": \n$2": "No se pudo cargar el formulario \"$1\": \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "No se pudo cargar la vista \"$1\": $2\nSe utiliza el visor de tareas simple.",
"Could not parse MediaWiki API's response": "No se pudo analizar la respuesta de la API de MediaWiki",
"Diff for revision $1": "Revisar diferencia $1",
"No difference": "No hay diferencia",
"Request new workset": "Solicitar nuevo grupo de tareas",
"Review": "Revisar",
"Save": "Guardar",
"Submit label": "Enviar etiqueta",
"Workset": "Grupo",
"Workset complete!": "¡Grupo de tareas finalizado!",
"connect to server": "Conectar al servidor",
"date-format": "%d-%m-%Y",
"fullscreen": "Pantalla completa",
"open": "abrir",
"request workset": "Solicitar grupo de tareas",
"review": "Revisar"
},
"fa": {
"'$1' not completed. Submit anyway?": "'$1' باز است. آیا مطمئنید؟",
"@metadata": {
"authors": [
"Reza1615",
"Ladsgroup"
]
},
"Abandon": "رها شده",
"Are you sure that you want to abandon this task?": "آیا مطمئن هستید که میخواهید این فعالیت را رها کنید؟",
"Campaigns": "کمپینها",
"Can't save label. No task is selected!": "امکان ذخیره وجود ندارد. تسکی انتخاب نشدهاست.",
"Could not get metadata for revision $1": "امکان گرفتن اطلاعات ویرایش $1 وجود ندارد.",
"Could not load workset list: $1": "امکان بارگاری فهرست مجموعه کاری $1 وجود ندارد",
"Could not parse MediaWiki API's response": "نمیتوان پاسخ API مدیاویکی را تجزیه کرد",
"Diff for revision $1": "تغییرات برای ویرایش $1",
"No difference": "بدون تغییر",
"Request new workset": "درخواست یک مجموعه جدید",
"Review": "بازبینی",
"Save": "ذخیره",
"Submit label": "برچسب را بفرست",
"Workset": "مجموعه کاری",
"Workset complete!": "مجموعه کامل شد!",
"connect to server": "اتصال به سرور",
"date-format": "%Y-%m-%d",
"fullscreen": "تمام صفحه",
"open": "باز",
"request workset": "درخواست یک مجموعه",
"review": "بازبینی"
},
"fi": {
"@metadata": {
"authors": [
"Mikahama"
]
},
"Campaigns": "Kampanjat",
"Review": "Tarkasta",
"Save": "Tallenna",
"Submit label": "Lähetä etiketti",
"connect to server": "yhdistä palvelimeen",
"fullscreen": "koko näyttö",
"review": "Tarkasta"
},
"fr": {
"'$1' not completed. Submit anyway?": "'$1' incomplet. Soumettre quand même ?",
"@metadata": {
"authors": [
"Gomoko",
"Wladek92"
]
},
"Abandon": "Abandonner",
"Are you sure that you want to abandon this task?": "Êtes-vous sûr de vouloir abandonner cette tâche ?",
"Campaigns": "Campagnes",
"Can't save label. No task is selected!": "Impossible d’enregistrer le libellé. Aucune tâche n’est sélectionnée !",
"Could not get metadata for revision $1": "Impossible d'obtenir les métadonnées pour la révision $1",
"Could not load form \"$1\": \n$2": "Impossible de charger le formulaire « $1 » : \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Impossible de charger la vue « $1 » : $2\nUtilisation de l’affichage de tâche simple.",
"Could not load workset list: $1": "Impossible de charger la liste de travaux : $1",
"Could not parse MediaWiki API's response": "Impossible d'analyser le réponse de l'API MediaWiki",
"Diff for revision $1": "Différence pour la révision $1",
"No difference": "Aucune différence",
"Request new workset": "Demander un nouvel ensemble de données",
"Review": "Relecture",
"Save": "Sauvegarder",
"Submit label": "Soumettre l'étiquette",
"Workset": "Ensemble de données",
"Workset complete!": "Ensemble de données terminé !",
"connect to server": "Connecter au serveur",
"date-format": "%d-%m-%Y",
"fullscreen": "Plein écran",
"open": "ouvrir",
"request workset": "Demander l'ensemble de données",
"review": "Relecture"
},
"gl": {
"'$1' not completed. Submit anyway?": "'$1' non se completou. Enviar igualmente?",
"@metadata": {
"authors": [
"Banjo",
"Elisardojm"
]
},
"Abandon": "Abandonar",
"Are you sure that you want to abandon this task?": "Está seguro de querer abandonar esta tarefa?",
"Campaigns": "Campañas",
"Can't save label. No task is selected!": "Non se pode gardar a etiqueta. Non hai ningunha tarefa seleccionada.",
"Could not get metadata for revision $1": "Non se puideron obter os metadatos para a revisión $1",
"Could not load form \"$1\": \n$2": "Non se puido cargar o formulario \"$1\": \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Non se puido cargar a vista \"$1\": $2\nUtilízase o visor de tarefas simple.",
"Could not load workset list: $1": "Non se puido cargar a lista de traballo: $1",
"Could not parse MediaWiki API's response": "Non se puido analizar a resposta da API de MediaWiki",
"Diff for revision $1": "Diferenzas para a revisión $1",
"No difference": "Non hai diferenzas",
"Request new workset": "Solicitar novo grupo de tarefas",
"Review": "Revisar",
"Save": "Gardar",
"Submit label": "Enviar etiqueta",
"Workset": "Grupo de tarefas",
"Workset complete!": "Grupo de tarefas rematado!",
"connect to server": "Conectar ó servidor",
"date-format": "%d-%m-%Y",
"fullscreen": "pantalla completa",
"open": "abrir",
"request workset": "Solicitar grupo de tarefas",
"review": "revisar"
},
"he": {
"'$1' not completed. Submit anyway?": "השדה \"$1\" לא מולא. לשלוח בכל־זאת?",
"@metadata": {
"authors": [
"Amire80"
]
},
"Abandon": "להפסיק",
"Are you sure that you want to abandon this task?": "האם להפסיק את המשימה הזאת?",
"Campaigns": "מבצעים",
"Can't save label. No task is selected!": "אי־אפשר לשמור תווית. לא נבחרה משימה!",
"Could not get metadata for revision $1": "לא היה אפשר לקבל מטא־נתונים עבור גרסה $1",
"Could not load form \"$1\": \n$2": "לא היה אפשר לטעון את הטופס \"$1\":\n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "לא היה אפשר לטעון את התצוגה \"$1\": $2\nישמש מציג משימות פשוט.",
"Could not load workset list: $1": "לא היה אפשר לטעון רשימת ערכות עבודה: $1",
"Could not parse MediaWiki API's response": "לא היה אפשר לפענח את התגובה של ה־API של מדיה־ויקי",
"Diff for revision $1": "הבדל גרסאות עבור $1",
"No difference": "אין הבדל",
"Request new workset": "בקשת רשימה טיפול חדשה",
"Review": "סקירה",
"Save": "שמירה",
"Submit label": "שליחת סיווג",
"Workset": "רשימת טיפול",
"Workset complete!": "רשימת הטיפול הושלמה!",
"connect to server": "התחברות לשרת",
"date-format": "%Y-%m-%d",
"fullscreen": "מסך מלא",
"open": "פתיחה",
"request workset": "בקשת רשימת טיפול",
"review": "סקירה"
},
"hu": {
"'$1' not completed. Submit anyway?": "A(z) „$1” még nincs kész. Mégis elküldöd?",
"@metadata": {
"authors": [
"Tgr",
"Wolf Rex"
]
},
"Abandon": "Kihagyás",
"Are you sure that you want to abandon this task?": "Biztosan ki akarod hagyni ezt a feladatot?",
"Campaigns": "Kampányok",
"Can't save label. No task is selected!": "Nem tudom elmenteni az osztályozást, egyik feladat sincs kiválasztva!",
"Could not get metadata for revision $1": "Nem sikerült lekérni a(z) $1 lapváltozat metaadatait",
"Could not load form \"$1\": \n$2": "Nem sikerült betölteni a(z) \"$1\" űrlapot:\n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Nem sikerült betölteni a(z) \"$1\" nézetet: $2\nAz egyszerű feladatnézőt használom helyette.",
"Could not load workset list: $1": "Nem sikerült betölteni a munkahalmaz-listát: $1",
"Could not parse MediaWiki API's response": "Nem sikerült értelmezni a MediaWiki API válaszát",
"Diff for revision $1": "Diff a $1 változatra",
"No difference": "Nincs különbség",
"Request new workset": "Új munkaadag lekérése",
"Review": "Átnézés",
"Save": "Mentés",
"Submit label": "Címke elküldése",
"Workset": "Munkaadag",
"Workset complete!": "A munkaadag kész!",
"connect to server": "csatlakozás a szerverhez",
"date-format": "%Y.%m.%d.",
"fullscreen": "teljes képernyő",
"open": "megnyitás",
"request workset": "munkaadag lekérése",
"review": "átnézés"
},
"hu-formal": {
"@metadata": {
"authors": [
"Futhark1988"
]
},
"Review": "Áttekintés",
"Save": "Mentés",
"fullscreen": "teljes képernyő",
"review": "Áttekintés"
},
"id": {
"'$1' not completed. Submit anyway?": "Kolom '$1' belum diisi. Lanjut mengirimkan?",
"@metadata": {
"authors": [
"Rachmat.Wahidi",
"Arifin.wijaya"
]
},
"Abandon": "Abaikan",
"Are you sure that you want to abandon this task?": "Apakah Anda yakin ingin mengabaikan tugas ini?",
"Campaigns": "Kampanye",
"Can't save label. No task is selected!": "Tidak dapat menyimpan label. Tidak ada tugas dipilih!",
"Could not get metadata for revision $1": "Tidak dapat menemukan metadata untuk revisi $1",
"Could not load form \"$1\": \n$2": "Tidak dapat memuat formulir \"$1\":\n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Tidak dapat memuat tampilan \"$1\": $2.\nMenggunakan penampil tugas sederhana.",
"Could not load workset list: $1": "Tidak dapat memuat daftar rangkaian tugas: $1",
"Could not parse MediaWiki API's response": "Tidak dapat memilah respons API MediaWiki",
"Diff for revision $1": "Beda untuk revisi $1",
"No difference": "Tidak ada perbedaan",
"Request new workset": "Minta pekerjaan baru",
"Review": "Tinjau",
"Save": "Simpan",
"Submit label": "Kirim label",
"Workset": "Pekerjaan",
"Workset complete!": "Pekerjaan selesai!",
"connect to server": "sambung ke server",
"date-format": "%d-%m-%Y",
"fullscreen": "layar penuh",
"open": "buka",
"request workset": "minta pekerjaan",
"review": "tinjau"
},
"it": {
"'$1' not completed. Submit anyway?": "'$1' non completo. Inviare comunque?",
"@metadata": {
"authors": [
"Beta16"
]
},
"Abandon": "Abbandona",
"Are you sure that you want to abandon this task?": "Sei sicuro che vuoi abbandonare questa attività?",
"Campaigns": "Campagne",
"Can't save label. No task is selected!": "Impossibile salvare l'etichetta. Non è stata selezionata alcuna attività!",
"Could not get metadata for revision $1": "Impossibile ottenere i metadati per la versione $1",
"Could not load form \"$1\": \n$2": "Impossibile caricare il modulo \"$1\": \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Impossibile caricare la vista \"$1\": $2\nUtilizza il visualizzatore semplice dell'attività.",
"Could not load workset list: $1": "Impossibile caricare l'elenco workset: $1",
"Could not parse MediaWiki API's response": "Impossibile analizzare la risposta delle API MediaWiki",
"Diff for revision $1": "Differenze per la modifica $1",
"No difference": "Nessuna differenza",
"Request new workset": "Richiedi un nuovo workset",
"Review": "Valuta",
"Save": "Salva",
"Submit label": "Invia etichetta",
"Workset": "Workset",
"Workset complete!": "Workset completo!",
"connect to server": "Connessione al server",
"date-format": "%d-%m-%Y",
"fullscreen": "Schermo intero",
"open": "Apri",
"request workset": "Richiesta workset",
"review": "Valuta"
},
"ja": {
"'$1' not completed. Submit anyway?": "'$1'は完了してません。本当に送信しますか?",
"@metadata": {
"authors": [
"Thibaut120094"
]
},
"Abandon": "放棄",
"Campaigns": "作戦",
"Diff for revision $1": "版$1の差分",
"No difference": "差分なし",
"Request new workset": "新しい作業単位を要請する",
"Review": "レビュー",
"Save": "保存",
"Submit label": "付箋を送信",
"Workset": "作業単位",
"Workset complete!": "作業単位は完了しました!",
"connect to server": "サーバーに接続",
"date-format": "%Y年%m月%d日",
"fullscreen": "全画面",
"open": "開く",
"request workset": "作業単位を要請",
"review": "レビュー"
},
"khw": {
"'$1' not completed. Submit anyway?": "'$1' نامکمل۔ واقعی روانہ کورے؟",
"@metadata": [],
"Campaigns": "مہمات",
"Diff for revision $1": "تبدیلیاں برائے اعادہ $1",
"No difference": "کیہ تبدیلی نیکی",
"Request new workset": "درخواست جدید مجموعہ کار",
"Review": "نظر ثانی",
"Save": "محفوظ کورے",
"Submit label": "لیبل روانہ کورے",
"Workset": "مجموعہ کار",
"Workset complete!": "مجموعہ کار مکمل!",
"connect to server": "سرورو سم کنیکٹ کورے",
"date-format": "%Y-%m-%d",
"fullscreen": "مکمل سکرین",
"open": "کھولاو کورے",
"request workset": "درخواست مجموعہ کار",
"review": "نظر ثانی"
},
"ko": {
"'$1' not completed. Submit anyway?": "'$1' 필드는 완성되지 않았습니다. 그래도 제출할까요?",
"@metadata": {
"authors": [
"Revi",
"Ykhwong",
"아라"
]
},
"Abandon": "버리기",
"Are you sure that you want to abandon this task?": "이 작업을 정말로 포기하겠습니까?",
"Campaigns": "캠페인",
"Can't save label. No task is selected!": "레이블을 저장할 수 없습니다. 작업이 선택되지 않았습니다!",
"Could not get metadata for revision $1": "판 $1의 메타데이터를 가져오지 못했습니다",
"Could not load form \"$1\": \n$2": "\"$1\" 양식을 불러올 수 없습니다: \n$2",
"Could not parse MediaWiki API's response": "미디어위키 API의 응답의 구문을 분석하지 못했습니다",
"Diff for revision $1": "판 $1의 차이",
"No difference": "차이 없음",
"Request new workset": "새 작업셋 요청",
"Review": "검토",
"Save": "저장",
"Submit label": "레이블 제출",
"Workset": "작업셋",
"Workset complete!": "작업셋 완료!",
"connect to server": "서버에 연결",
"date-format": "%Y-%m-%d",
"fullscreen": "전체 화면",
"open": "열기",
"request workset": "작업셋 요청",
"review": "검토하기"
},
"ksh": {
"'$1' not completed. Submit anyway?": "Dat Fäld „$1“ es nit ennjeföllt. Trozdämm loßscheke?",
"@metadata": {
"authors": [
"Purodha"
]
},
"Abandon": "Ophühre!",
"Are you sure that you want to abandon this task?": "Wells De heh di Aufjahb verhaftesch nit mih han?",
"Campaigns": "Kampannje",
"Could not get metadata for revision $1": "Mer kunnte kein Metta-Dahte för de Väsjohn $1 krijje.",
"Could not load form \"$1\": \n$2": "Mer kunnte et Fommolaa „$1“ nit lahde:\n$2",
"Could not parse MediaWiki API's response": "Mer kunnte dem MehdijaWikki singe <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> sing Antwoot nit verschtonn.",
"Diff for revision $1": "Ongerscheide för de Väsjohn $1",
"No difference": "Keine Ongerscheid",
"Review": "Jähjelässe",
"Save": "Faßhalde",
"connect to server": "en Verbendong mem ẞööver opnämme",
"date-format": "%Y-%m-%d",
"fullscreen": "op der janze Beldscherm jonn",
"open": "offe",
"review": "Jähjelässe"
},
"lb": {
"'$1' not completed. Submit anyway?": "D'Feld \"$1\" ass net ausgefëllt. Trotzdem späicheren?",
"@metadata": {
"authors": [
"Robby"
]
},
"Abandon": "Opginn",
"Are you sure that you want to abandon this task?": "Sidd Dir sécher datt Dir dës Aufgab wëllt opginn?",
"Campaigns": "Campagnen",
"Can't save label. No task is selected!": "Etikett konnt net gespäichert ginn. Et ass keng Aufgab erausgesicht!",
"Could not get metadata for revision $1": "D'Metadate fir d'Versioun $1 goufen net fonnt",
"Could not load form \"$1\": \n$2": "De Formulaire \"$1\" konnt net geluede ginn:\n$2",
"Diff for revision $1": "Ënnerscheed fir d'Versioun $1",
"No difference": "Keen Ënnerscheed",
"Review": "Nokucken",
"Save": "Späicheren",
"Submit label": "Etikett schécken",
"connect to server": "mam Server verbannen",
"date-format": "%d.%m.%Y",
"fullscreen": "ganzen Ecran",
"open": "opmaachen",
"review": "Nokucken"
},
"lt": {
"@metadata": {
"authors": [
"Zygimantus"
]
},
"Campaigns": "Kampanijos",
"No difference": "Jokio skirtumo",
"Review": "Apžvalga",
"Save": "Išsaugoti",
"Submit label": "Pateikti etiketę",
"connect to server": "prisijungti prie serverio",
"date-format": "%Y-%m-%d",
"fullscreen": "pilnas ekranas",
"review": "Apžvalga"
},
"mk": {
"'$1' not completed. Submit anyway?": "„$1“ не е довршено. Сепак да поднесам?",
"@metadata": {
"authors": [
"Bjankuloski06"
]
},
"Abandon": "Напушти",
"Are you sure that you want to abandon this task?": "Дали сигурно сакате да ја напуштите задачава?",
"Campaigns": "Походи",
"Can't save label. No task is selected!": "Не можам да го зачувам натписот. Немате избрано задача!",
"Could not get metadata for revision $1": "Не можев да ги добијам метаподатоците за преработката $1",
"Could not load form \"$1\": \n$2": "Не можев да го вчитам образецот „$1“: \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Не можев да го вчитам прегледот „$1“: $2\nКористам прост прегледник на задачи.",
"Could not load workset list: $1": "Не можев да го вчитам збирот задачи: $1",
"Could not parse MediaWiki API's response": "Не можев да го расчленам одговорот од приложникот на МедијаВики",
"Diff for revision $1": "Разлика за прераб. $1",
"No difference": "Нема разлика",
"Request new workset": "Побарај нов збир задачи",
"Review": "Провери",
"Save": "Зачувај",
"Submit label": "Поднеси натпис",
"Workset": "Збир задачи",
"Workset complete!": "Збирот задачи е завршен!",
"connect to server": "поврзи се со опслужувачот",
"date-format": "%Y-%m-%d",
"fullscreen": "цел екран",
"open": "отвори",
"request workset": "побарај збир задачи",
"review": "провери"
},
"nl": {
"'$1' not completed. Submit anyway?": "'$1' niet voltooid. Toch verzenden?",
"@metadata": [],
"Campaigns": "Campagnes",
"Diff for revision $1": "Verschil voor bewerking $1",
"No difference": "Geen verschil",
"Request new workset": "Nieuwe werkset opvragen",
"Review": "Beoordelen",
"Save": "Opslaan",
"Submit label": "Label verzenden",
"Workset": "Werkset",
"Workset complete!": "Werkset voltooid!",
"connect to server": "verbinden met server",
"date-format": "%d-%m-%Y",
"fullscreen": "fullscreen",
"open": "openen",
"request workset": "werkset opvragen",
"review": "beoordelen"
},
"no": {
"@metadata": []
},
"oc": {
"@metadata": {
"authors": [
"Cedric31"
]
},
"Abandon": "Abandonar",
"Campaigns": "Campanhas",
"No difference": "Pas cap de diferéncia",
"Review": "Relectura",
"Save": "Enregistrar",
"Submit label": "Sometre l'etiqueta",
"Workset": "Grop",
"Workset complete!": "Ensemble de donadas acabat !",
"connect to server": "Connectar al servidor",
"date-format": "%d-%m-%Y",
"fullscreen": "Ecran plen",
"open": "dobrir",
"request workset": "Demandar l'ensemble de donadas",
"review": "Relectura"
},
"pl": {
"'$1' not completed. Submit anyway?": "Nie zakończono prac nad '$1'. Przesłać mimo to?",
"@metadata": {
"authors": [
"Mateon1",
"Chrumps",
"The Polish"
]
},
"Abandon": "Porzuć",
"Are you sure that you want to abandon this task?": "Czy na pewno chcesz zrezygnować z tego zadania?",
"Campaigns": "Osiągnięcia",
"Can't save label. No task is selected!": "Nie można zapisać etykiety. Nie wybrano żadnego zadania!",
"Could not get metadata for revision $1": "Nie można uzyskać metadanych dla wersji $1",
"Could not load form \"$1\": \n$2": "Nie można pobrać formularza „$1”:\n$2",
"Diff for revision $1": "Diff dla edycji $1",
"No difference": "Brak różnic",
"Request new workset": "Pobierz nowy zestaw danych",
"Review": "Przejrzyj",
"Save": "Zapisz",
"Submit label": "Prześlij metkę",
"Workset": "Zestaw danych",
"Workset complete!": "Ukończono prace nad zestawem danych!",
"connect to server": "połącz z serwerem",
"date-format": "%Y-%m-%d",
"fullscreen": "pełny ekran",
"open": "otwórz",
"request workset": "Pobierz zestaw danych",
"review": "Przejrzyj"
},
"ps": {
"@metadata": {
"authors": [
"Ahmed-Najib-Biabani-Ibrahimkhel"
]
},
"Request new workset": "نوې کارټولگه غوښتل",
"Review": "بياکتنه",
"Save": "خوندي کول",
"Submit label": "لېبل سپارل",
"Workset": "کارټولگه",
"Workset complete!": "کارټولگه بشپړ شوه!",
"connect to server": "پالنگر سره اړيکمنېدل",
"date-format": "%Y-%m-%d",
"fullscreen": "ډکه پرده",
"open": "پرانيستل",
"review": "بياکتنه"
},
"pt": {
"'$1' not completed. Submit anyway?": "O campo '$1' não foi preenchido. Submeter mesmo assim?",
"@metadata": {
"authors": [
"Vitorvicentevalente",
"Gato Preto",
"He7d3r"
]
},
"Abandon": "Abandonar",
"Are you sure that you want to abandon this task?": "Tem a certeza que deseja abandonar esta tarefa?",
"Campaigns": "Campanhas",
"Can't save label. No task is selected!": "Não foi possível salvar o rótulo. Nenhuma tarefa está selecionada!",
"Could not get metadata for revision $1": "Não foi possível obter metadados para a edição $1",
"Could not load form \"$1\": \n$2": "Não foi possível carregar o formulário \"$1\": \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Não foi possível carregar a visualização \"$1\": $2\nUsando o visualizador simples de tarefas.",
"Diff for revision $1": "Diferenças para a revisão $1",
"No difference": "Nenhuma diferença",
"Request new workset": "Solicitar um novo grupo de tarefas",
"Review": "Revisar",
"Save": "Gravar",
"Submit label": "Submeter o rótulo",
"Workset": "Grupo",
"Workset complete!": "Conjunto de trabalho concluído!",
"connect to server": "conectar ao servidor",
"date-format": "%d-%m-%Y",
"fullscreen": "ecrã completo",
"open": "abrir",
"request workset": "solicitar um grupo de tarefas",
"review": "Rever"
},
"pt-br": {
"'$1' not completed. Submit anyway?": "'$1' não completado. Enviar mesmo assim?",
"@metadata": {
"authors": [
"Luk3",
"Dianakc"
]
},
"Campaigns": "Campanhas",
"Diff for revision $1": "Diferencial para a revisão $1",
"No difference": "Sem diferencial",
"Request new workset": "Solicitar novo grupo de tarefas",
"Review": "Revisar",
"Save": "Salvar",
"Submit label": "Enviar rótulo",
"Workset": "Grupo",
"connect to server": "conectar ao servidor",
"date-format": "%d-%m-%Y",
"fullscreen": "tela cheia",
"open": "abrir",
"review": "revisar"
},
"qqq": {
"'$1' not completed. Submit anyway?": "When the user tries to send an assessment of a diff in which not all form fields were filled. $1 is the name of the field, such as \"Damaging\" or \"Good faith\".",
"@metadata": {
"authors": [
"Liuxinyu970226",
"EpochFail",
"Ladsgroup",
"Tgr",
"Purodha"
]
},
"Abandon": "{{Identical|Abandon}}",
"Campaigns": "This is the header for a list of \"campaigns\". Campaigns in WikiLabels are collections of items to be annotated.\n{{Identical|Campaign}}",
"Diff for revision $1": "This message is shown above an edit diff. The $1 will be replaced with a link to the MediaWiki Special:Diff interface. The text of the link is a number (the revision ID).",
"No difference": "This message is shown in place of an edit diff when no change was made to a page. This happens with a no-op edit is saved.",
"Request new workset": "This message is displayed on a button that, when clicked, will provide the user with a collection of items for annotation. A \"workset\" is this collection of items.",
"Review": "This message is displayed on a button that, when pressed, will open up a collection of past work for review.\n{{Identical|Review}}",
"Save": "This message will be displayed on a button that, when clicked, will save an annotation of an item.\n{{Identical|Save}}",
"Submit label": "This message will be displayed on a button that, when clicked, will submit an annotation (label) to the server to be stored and shared with others.",
"Workset": "A \"workset\" is this collection of to be annotated. It is a subset of all items in a \"campaign\" that a user intends to work on.",
"Workset complete!": "This message will be displayed when a user has completed annotating all of the items in a workset.",
"connect to server": "This message will be displayed on a button that, when clicked, will initiate a connection with a server.",
"date-format": "This is a formatting string for a date. See http://strftime.org/ for a reference for what the symbols mean. \n\n* %Y - 4 digit year\n* %m - 2 digit month\n* %d - 2 digit day",
"fullscreen": "Going to screen-wide mode",
"open": "{{Identical|Open}}",
"request workset": "Asking a new working set to label from the server",
"review": "{{Identical|Review}}"
},
"ru": {
"'$1' not completed. Submit anyway?": "'$1' не готово. Отправить всё равно?",
"@metadata": [],
"Campaigns": "Кампании",
"Diff for revision $1": "Diff для ревизии $1",
"No difference": "Различий нет",
"Request new workset": "Запросить новый рабочий набор",
"Review": "Проверка",
"Save": "Сохранить",
"Submit label": "Отправить пометку",
"Workset": "Рабочий набор",
"Workset complete!": "Рабочий набор готов!",
"connect to server": "Установить соединение с сервером",
"date-format": "%d-%m-%Y",
"fullscreen": "полный экран",
"open": "открыть",
"request workset": "Запросить рабочий набор",
"review": "проверка"
},
"sv": {
"'$1' not completed. Submit anyway?": "'$1' är inte slutförd. Skicka ändå?",
"@metadata": {
"authors": [
"WikiPhoenix",
"Josve05a",
"Jopparn",
"Johan",
"Ainali"
]
},
"Abandon": "Slutför ej",
"Are you sure that you want to abandon this task?": "Är du säker på att du vill lämna denna uppgift utan att slutföra den?",
"Campaigns": "Kampanjer",
"Can't save label. No task is selected!": "Kan inte spara etiketten. Ingen uppgift är vald!",
"Could not get metadata for revision $1": "Kunde inte hämta metadata för version $1",
"Could not load form \"$1\": \n$2": "Kunde inte ladda formulär \"$1\": \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Kunde inte hämta vyn \"$1\": $2\nAnvänder enkel vy.",
"Could not load workset list: $1": "Kunde inte hämta uppsättning redigeringar: $1",
"Could not parse MediaWiki API's response": "Det gick inte att tolka MediaWiki-API:ets svar",
"Diff for revision $1": "Skillnad för ändring $1",
"No difference": "Ingen skillnad",
"Request new workset": "Begär en ny uppsättning",
"Review": "Granska",
"Save": "Spara",
"Submit label": "Skicka etikett",
"Workset": "Uppsättning",
"Workset complete!": "Uppsättningen klar!",
"connect to server": "anslut till server",
"date-format": "%Y-%m-%d",
"fullscreen": "helskärm",
"open": "öppna",
"request workset": "begär uppsättning",
"review": "granska"
},
"tr": {
"'$1' not completed. Submit anyway?": "'$1' tamamlanmadı. Genede sunulsun mu?",
"@metadata": [],
"Campaigns": "Girişimler",
"Diff for revision $1": "$1 değisikliği için diff",
"No difference": "Fark yoktur",
"Request new workset": "Yeni iş kümesi iste",
"Review": "İncele",
"Save": "Kaydet",
"Submit label": "Etiketi sun",
"Workset": "İş kümesi",
"Workset complete!": "İş kümesi tamamlandı!",
"connect to server": "sunucuya bağlan",
"date-format": "%Y-%m-%d",
"fullscreen": "tam ekran",
"open": "açık",
"request workset": "iş kümesi iste",
"review": "incele"
},
"uk": {
"'$1' not completed. Submit anyway?": "Поле «$1» не заповнено. Все одно надіслати?",
"@metadata": {
"authors": [
"Alex Khimich",
"Piramidion"
]
},
"Abandon": "Покинути",
"Are you sure that you want to abandon this task?": "Ви впевнені, що хочете відмовитися від цього завдання?",
"Campaigns": "Кампанії",
"Can't save label. No task is selected!": "Не можу зберегти мітку. Немає обраних завдань!",
"Could not get metadata for revision $1": "Не можу отримати метадані для перегляду $1",
"Could not load form \"$1\": \n$2": "Не може завантажити з «$1»: \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Не вдалося завантажити перегляд «$1»: $2\nВикористовується простий переглядач завдань.",
"Could not load workset list: $1": "Не вдалося завантажити список робочих наборів: $1",
"Could not parse MediaWiki API's response": "Не вдалося обробити відповідь MediaWiki API",
"Diff for revision $1": "Різниця для версії $1",
"No difference": "Немає різниці",
"Request new workset": "Запитати новий робочий набір",
"Review": "Перевірка",
"Save": "Зберегти",
"Submit label": "Надіслати мітку",
"Workset": "Робочий набір",
"Workset complete!": "Робочий набір готовий!",
"connect to server": "під'єднатись до сервера",
"date-format": "%Y-%m-%d",
"fullscreen": "повний екран",
"open": "відкрити",
"request workset": "запитати робочий набір",
"review": "перевірити"
},
"ur": {
"@metadata": [],
"Campaigns": "مہمات",
"Diff for revision $1": "تبدیلیاں برائے اعادہ $1",
"No difference": "کوئی تبدیلی نہیں",
"Request new workset": "درخواست جدید مجموعہ کار",
"Review": "نظر ثانی",
"Save": "محفوظ کریں",
"Submit label": "لیبل روانہ کریں",
"Workset": "مجموعہ کار",
"Workset complete!": "مجموعہ کار مکمل!",
"connect to server": "سرور سے مربوط کریں",
"fullscreen": "مکمل سکرین",
"open": "کھولیں",
"request workset": "درخواست مجموعہ کار",
"review": "نظر ثانی"
},
"vi": {
"'$1' not completed. Submit anyway?": "'$1' chưa hoàn tất. Bạn vẫn muốn gửi đi?",
"@metadata": {
"authors": [
"Minh Nguyen"
]
},
"Abandon": "Bỏ rơi",
"Are you sure that you want to abandon this task?": "Bạn có chắc chắn muốn bỏ rơi việc làm này?",
"Campaigns": "Chiến dịch",
"Can't save label. No task is selected!": "Không thể lưu nhãn vì chưa chọn việc làm.",
"Could not get metadata for revision $1": "Không thể lấy siêu dữ liệu của phiên bản $1",
"Could not load form \"$1\": \n$2": "Không thể tải biểu mẫu “$1”: \n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "Không thể tải khung nhìn “$1”: $2\nSẽ sử dụng trình xem việc làm đơn giản.",
"Could not load workset list: $1": "Không thể tải danh sách bộ việc làm: $1",
"Could not parse MediaWiki API's response": "Không thể phân tích phản hồi của API MediaWiki",
"Diff for revision $1": "Khác biệt của phiên bản $1",
"No difference": "Không có sự khác biệt",
"Request new workset": "Yêu cầu gói công việc mới",
"Review": "Kiểm tra lại",
"Save": "Lưu lại",
"Submit label": "Gửi nhãn",
"Workset": "Gói công việc",
"Workset complete!": "Gói công việc đã hoàn tất!",
"connect to server": "kết nối tới máy chủ",
"date-format": "%Y-%m-%d",
"fullscreen": "toàn màn hình",
"open": "mở",
"request workset": "yêu cầu gói công việc",
"review": "kiểm tra lại"
},
"zh-hans": {
"'$1' not completed. Submit anyway?": "字段“$1”未填满。是否仍要提交?",
"@metadata": {
"authors": [
"Liuxinyu970226"
]
},
"Abandon": "放弃",
"Are you sure that you want to abandon this task?": "您确定要放弃此任务么?",
"Campaigns": "通告",
"Can't save label. No task is selected!": "不能保存标签。没有选择任务!",
"Could not get metadata for revision $1": "不能获取修订版本$1的元数据",
"Could not load form \"$1\": \n$2": "不能从“$1”加载:\n$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "不能加载视图“$1”:$2\n正在使用简易任务浏览器。",
"Could not load workset list: $1": "不能加载工作集列表:$1",
"Could not parse MediaWiki API's response": "不能解析MediaWiki API的相应",
"Diff for revision $1": "版本$1的差异",
"No difference": "无差异",
"Request new workset": "请求新工作集",
"Review": "复核",
"Save": "保存",
"Submit label": "提交标签",
"Workset": "工作集",
"Workset complete!": "工作集已完成!",
"connect to server": "连接至服务器",
"date-format": "%Y-%m-%d",
"fullscreen": "全屏",
"open": "开启",
"request workset": "请求工作集",
"review": "复核"
},
"zh-hant": {
"'$1' not completed. Submit anyway?": "'$1' 未填入內容。確定送出?",
"@metadata": {
"authors": [
"Kly"
]
},
"Abandon": "放棄",
"Are you sure that you want to abandon this task?": "您確定您要放棄此項任務?",
"Campaigns": "Campaigns",
"Can't save label. No task is selected!": "因沒有選擇任務而無法儲存標籤!",
"Could not get metadata for revision $1": "無法獲取修訂版本$1的元數據",
"Could not load form \"$1\": \n$2": "無法從$1載入:$2",
"Could not load view \"$1\": $2\nUsing simple task viewer.": "無法載入視圖「$1」:$2\n正使用簡易的任務瀏覽器",
"Could not load workset list: $1": "無法載入工作集合清單:$1",
"Could not parse MediaWiki API's response": "無法解析維基媒體API的回應內容",
"Diff for revision $1": "版本$1的差異",
"No difference": "无差異",
"Request new workset": "要求新工作集",
"Review": "檢閱",
"Save": "儲存",
"Submit label": "送出標籤",
"Workset": "工作集",
"Workset complete!": "工作集已完成!",
"connect to server": "連線至伺服器",
"date-format": "%Y-%m-%d",
"fullscreen": "全螢幕",
"open": "開啟",
"request workset": "要求工作集",
"review": "檢閱"
}
};
})(jQuery, wikiLabels);