User:Evad37/rater.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | This user script seems to have a documentation page at User:Evad37/rater. |
/***************************************************************************************************
Rater --- by Evad37
> Helps assess WikiProject banners.
> Main version: 0-alpha (for full version, see config.script.version below)
***************************************************************************************************/
// <nowiki>
$( function($) {
/* ========== Config ============================================================================ */
// A global object that stores all the page and user configuration and settings
var config = {};
// Script info
config.script = {
// Advert to append to edit summaries
advert: ' ([[User:Evad37/rater.js|Rater]])',
version: '0.2.0-alpha'
};
// MediaWiki configuration values
config.mw = mw.config.get( [
'wgPageName',
'wgNamespaceNumber',
'wgUserName',
'wgFormattedNamespaces',
'wgMonthNames',
'wgRevisionId'
] );
config.regex = {
// Pattern to find templates, which may contain other templates
template: /\{\{\s*(.+?)\s*(\|(?:.|\n)*?(?:(?:\{\{(?:.|\n)*?(?:(?:\{\{(?:.|\n)*?\}\})(?:.|\n)*?)*?\}\})(?:.|\n)*?)*|)\}\}\n?/g,
// Pattern to find `|param=value` or `|value`, where `value` can only contain a pipe
// if within square brackets (i.e. wikilinks) or braces (i.e. templates)
templateParams: /\|(?!(?:[^{]+}|[^\[]+]))(?:.|\s)*?(?=(?:\||$)(?!(?:[^{]+}|[^\[]+])))/g
};
config.deferred = {};
config.bannerDefaults = {
classes: [
' ',
'FA',
'FL',
'A',
'GA',
'B',
'C',
'Start',
'Stub',
'List'
],
importances: [
' ',
'Top',
'High',
'Mid',
'Low'
],
extendedClasses: [
'Category',
'Draft',
'File',
'Portal',
'Project',
'Template',
'Bplus',
'Future',
'Current',
'Disambig',
'NA',
'Redirect',
'Book'
],
extendedImportances: [
'Bottom',
'NA'
]
};
config.shellTemplates = [
'WikiProject banner shell',
'WikiProjectBanners',
'WikiProject Banners',
'WPB',
'WPBS',
'Wikiprojectbannershell',
'WikiProject Banner Shell',
'Wpb',
'WPBannerShell',
'Wpbs',
'Wikiprojectbanners',
'WP Banner Shell',
'WP banner shell',
'Bannershell',
'Wikiproject banner shell',
'WikiProject Banners Shell',
'WikiProjectBanner Shell',
'WikiProjectBannerShell',
'WikiProject BannerShell',
'WikiprojectBannerShell',
'WikiProject banner shell/redirect',
'WikiProject Shell',
'Banner shell',
'Scope shell',
'Project shell'
];
// Do not operate on Special: pages, nor on non-existent pages or their talk pages
if ( config.mw.wgNamespaceNumber < 0 || $('li.new[id|=ca-nstab]').length ) {
return;
}
// For User and User_talk namespaces, only operate on subpages
if (
config.mw.wgNamespaceNumber >= 2 &&
config.mw.wgNamespaceNumber <= 3 &&
config.mw.wgPageName.indexOf('/') === -1
) {
return;
}
// Load Morebits gadget if not already available
if ( window.Morebits == null ) {
importScript('MediaWiki:Gadget-morebits.js');
importStylesheet( 'MediaWiki:Gadget-morebits.css' );
}
// Load extra.js if not already available
if ( window.extraJs == null ) {
importScript('User:Evad37/extra.js');
}
mw.loader.using( ['mediawiki.util'], function () {
// Add portlet link
mw.util.addPortletLink( 'p-cactions', '#', 'Rater', 'ca-rater', 'Rate quality and importance' );
$('#ca-rater').click(function(e) {
e.preventDefault();
mw.loader.using( ['mediawiki.api', 'mediawiki.Title', 'mediawiki.RegExp',
'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows', 'jquery.ui.dialog'], function () {
/* ========== CSS =============================================================================== */
// TODO: convert to .css subpage and load using importStylesheet()
// Attribution: Diff styles from <https://en.wikipedia.org/wiki/Wikipedia:AutoWikiBrowser/style.css>
mw.util.addCSS(
/* --- Main dialog styles ----------------------------------------------------------------- */
'.rater-dialog-row { padding:0.2em; border-bottom: 1px solid #777; }'+
'.rater-dialog-row span { padding-right:0.5em; white-space:nowrap }'+
'.rater-dialog-row:nth-child(even) { background-color:#e0e0e0; }'+
'.rater-dialog-row > div:nth-child(2) { clear:left; }'+
'.rater-dialog-paraInput input { width:6em; margin:0 0.15em; }'+
'.rater-dialog-autofill { border:1px dashed #cd20ff; padding:0.2em; margin-right:0.2em; }'+
'.rater-dialog-autofill::after { content:"autofilled"; color:#cd20ff; font-weight:bold; font-size:96% }'+
'.rater-dialog-dropdown { width:5em; margin-left:0.2em; }'+
/* --- Diff styles ----------------------------------------------------------------------- */
'table.diff, td.diff-otitle, td.diff-ntitle { background-color: white; }'+
'td.diff-otitle, td.diff-ntitle { text-align: center; }'+
'td.diff-marker { text-align: right; font-weight: bold; font-size: 1.25em; }'+
'td.diff-lineno { font-weight: bold; }'+
'td.diff-addedline, td.diff-deletedline, td.diff-context { font-size: 88%; vertical-align: top; white-space: -moz-pre-wrap; white-space: pre-wrap; }'+
'td.diff-addedline, td.diff-deletedline { border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; }'+
'td.diff-addedline { border-color: #a3d3ff; }'+
'td.diff-deletedline { border-color: #ffe49c; }'+
'td.diff-context { background: #f3f3f3; color: #333333; border-style: solid; border-width: 1px 1px 1px 4px; border-color: #e6e6e6; border-radius: 0.33em; }'+
'.diffchange { font-weight: bold; text-decoration: none; }'+
'table.diff { border: none; width: 98%; border-spacing: 4px;'+
/* Ensure that colums are of equal width: */ 'table-layout: fixed; }'+
'td.diff-addedline .diffchange, td.diff-deletedline .diffchange { border-radius: 0.33em; padding: 0.25em 0; }'+
'td.diff-addedline .diffchange { background: #d8ecff; }'+
'td.diff-deletedline .diffchange { background: #feeec8; }'+
'table.diff td { padding: 0.33em 0.66em; }'+
'table.diff col.diff-marker { width: 2%; }'+
'table.diff col.diff-content { width: 48%; }'+
'table.diff td div {'+
/* Force-wrap very long lines such as URLs or page-widening char strings. */
'word-wrap: break-word;'+
/* As fallback (FF<3.5, Opera <10.5), scrollbars will be added for very wide cells
instead of text overflowing or widening */
'overflow: auto;'+
'}'
);
/* ========== API =============================================================================== */
var API = new mw.Api( {
ajax: {
headers: {
'Api-User-Agent': 'Rater/' + config.script.version +
' ( https://en.wikipedia.org/wiki/User:Evad37/Rater )'
}
}
} );
/* ---------- API for ORES ---------------------------------------------------------------------- */
API.getORES = function(revisionID) {
return $.get('https://ores.wikimedia.org/v3/scores/enwiki?models=wp10&revids='+revisionID);
};
/* ========== Page class ======================================================================== */
// Constructor
var Page = function(title) {
try {
mw.Title.call(this, decodeURIComponent(title));
} catch(e) {
throw new Error('Unable to parse title "'+title+'"');
}
this.talk = null;
this.subject = null;
this.banners = [];
};
//Constructor with a null return instead of an exception for invalid titles.
Page.newFromText = function(t) {
if ( mw.Title.newFromText(t) ) {
return new Page(t);
} else {
return null;
}
};
// ---------- Page prototype -------------------------------------------------------------------- */
// Inherited from mw.Title
Page.prototype = Object.create(mw.Title.prototype);
Page.prototype.constructor = Page;
// Additional functions
Page.prototype.getTalk = function() {
if ( this.talk === null ) {
// talk page not yet set, so set it now
if ( this.getNamespaceId()%2 === 1 ) {
// Page is itself a talk page
this.talk = this.getPrefixedText();
} else {
this.talk = mw.Title.newFromText(
this.getMain(),
this.getNamespaceId()+1
).getPrefixedText();
}
}
return this.talk;
};
Page.prototype.getSubject = function() {
if ( this.subject === null ) {
// subject page not yet set, so set it now
if ( this.getNamespaceId()%2 === 0 ) {
// Page is itself a subject page
this.subject = this.getPrefixedText();
} else {
this.subject = mw.Title.newFromText(
this.getMain(),
this.getNamespaceId()-1
).getPrefixedText();
}
}
return this.subject;
};
Page.prototype.getListasAutofill = function() {
var name = this.getMainText().replace(/\s\(.*\)/, '');
var lastSpaceIndex = name.lastIndexOf(' ');
return name.slice(lastSpaceIndex+1) + ', ' + name.slice(0, lastSpaceIndex);
};
Page.prototype.getRedirectOrPrefixedText = function() {
return ( this.redirectsTo ) ? this.redirectsTo.getPrefixedText() : this.getPrefixedText();
};
Page.prototype.getRedirectOrMainText = function() {
return ( this.redirectsTo ) ? this.redirectsTo.getMainText() : this.getMainText();
};
Page.prototype.getBannerFromNameOrRedirect = function(bannerNameOrRedirect) {
if ( !this.banners ) {
return false;
}
var toCheckPrefixedText = mw.Title.newFromText('Template:'+bannerNameOrRedirect).getPrefixedText();
for ( var i=0; i<this.banners.length; i++ ) {
if (
this.banners[i].getPrefixedText() === toCheckPrefixedText ||
this.banners[i].getRedirectOrPrefixedText() === toCheckPrefixedText
) {
return this.banners[i];
}
}
return false;
};
Page.prototype.getTalkpageTopSection = function() {
var self = this;
var gotTalkpageTopSection = $.Deferred();
var processTalk = function (result) {
var id = result.query.pageids;
self.oldTopSection = ( id < 0 ) ? '' : result.query.pages[id].revisions[0]['*'];
gotTalkpageTopSection.resolve();
};
API.get( {
action: 'query',
prop: 'revisions',
rvprop: 'content',
rvsection: '0',
titles: self.getTalk(),
indexpageids: 1
} )
.done( processTalk )
.fail( gotTalkpageTopSection.reject );
return gotTalkpageTopSection;
};
Page.prototype.getLatestSubjectRevisionID = function() {
var self = this;
var gotRevisionID = $.Deferred();
if ( config.mw.wgNamespaceNumber === 0 && config.mw.wgRevisionId !== 0 ) {
self.latestSubjectRevisionID = config.mw.wgRevisionId;
return gotRevisionID.resolve();
}
var processRevision = function(result) {
var id = result.query.pageids;
if ( id < 0 ) {
gotRevisionID.reject();
return;
}
self.latestSubjectRevisionID = result.query.pages[id].revisions[0].revid;
gotRevisionID.resolve();
};
API.get( {
action: 'query',
format: 'json',
prop: 'revisions',
titles: self.getSubject(),
rvprop: 'ids',
indexpageids: 1
} )
.done( processRevision )
.fail( gotRevisionID.reject );
return gotRevisionID;
};
Page.prototype.getOresScore = function() {
var self = this;
var gotOresScore = $.Deferred();
$.when( self.latestSubjectRevisionID || self.getLatestSubjectRevisionID() )
.done( function() {
API.getORES(self.latestSubjectRevisionID)
.done(function(result) {
var data = result.enwiki.scores[self.latestSubjectRevisionID].wp10;
if ( data.error ) {
gotOresScore.reject(data.error.type, data.error.message);
return;
}
self.oresScore = data.score.prediction;
gotOresScore.resolve();
})
.fail( gotOresScore.reject );
})
.fail( gotOresScore.reject );
return gotOresScore;
};
Page.prototype.makeEdit = function() {
var self = this;
var editMade = $.Deferred();
API.postWithToken( 'csrf', {
action: 'edit',
title: self.getTalk(),
text: self.makeNewTopSection(),
section: 0,
summary: self.makeEditSummary() + config.script.advert
} )
.done( editMade.resolve )
.fail( editMade.reject );
return editMade;
};
Page.prototype.makePreview = function() {
var self = this;
var madePreview = $.Deferred();
API.get({
action: 'parse',
contentmodel: 'wikitext',
text: self.makeNewTopSection(),
title: self.getTalk()
})
.done(function(result) {
if ( !result || !result.parse || !result.parse.text || !result.parse.text['*'] ){
madePreview.reject('Empty result');
}
madePreview.resolve(result.parse.text['*']);
})
.fail(madePreview.reject);
return madePreview;
};
Page.prototype.makeDiff = function() {
var self = this;
var madeDiff = $.Deferred();
API.get({
action: "compare",
format: "json",
fromtext: self.oldTopSection,
fromcontentmodel: "wikitext",
totext: self.makeNewTopSection(),
tocontentmodel: "wikitext",
prop: "diff"
})
.done(function(result) {
if ( !result || !result.compare || !result.compare['*'] ){
madeDiff.reject('Empty result');
console.log('[Rater][makeDiff] Empty result :');
console.log(result);
return;
}
var diffTable = $('<table>').append(
$('<tr>').append(
$('<th>').attr({'colspan':'2', 'scope':'col'}).text('Latest revision'),
$('<th>').attr({'colspan':'2', 'scope':'col'}).text('New text')
),
result.compare['*']
);
madeDiff.resolve(diffTable);
})
.fail(madeDiff.reject);
return madeDiff;
};
Page.prototype.makeNewTopSection = function() {
var self = this;
var wikitext = {
above: '',
projects: '',
below: ''
};
if ( self.oldTopSection && self.banners ) {
var firstBannerIndex = self.banners.reduce(function(currentMinIndex, banner) {
if ( banner.isNew() ) {
return currentMinIndex;
}
return Math.min(
currentMinIndex,
self.oldTopSection.indexOf(banner.rawWikitext)
);
}, Infinity);
var afterLastBannerIndex = self.banners.reduce(function(currentMaxIndex, banner) {
if ( banner.isNew() ) {
return currentMaxIndex;
}
return Math.max(
currentMaxIndex,
self.oldTopSection.indexOf(banner.rawWikitext) + banner.rawWikitext.length
);
}, -1);
if ( firstBannerIndex >= afterLastBannerIndex ) {
// TODO: ask for user confirmation
// Place new banners at end of top section
wikitext.projects = self.oldTopSection;
} else {
wikitext.above = self.oldTopSection.slice(0, firstBannerIndex).trim();
wikitext.projects = self.oldTopSection.slice(firstBannerIndex, afterLastBannerIndex).trim();
wikitext.below = self.oldTopSection.slice(afterLastBannerIndex).trim();
}
}
wikitext.projects = self.banners.reduce(function(newWikitext, banner) {
// Not touched (and not new, and redirect not bypassed)
if ( $.isEmptyObject(banner.touched) && !banner.isNew() && !banner.bypassRedirect ) {
return newWikitext;
}
// Marked for removal
if ( banner.remove ) {
if ( banner.isNew() ) { return newWikitext; }
return newWikitext.replace(banner.rawWikitext, '');
}
// Existing banner that's been modified
if ( !banner.isNew() ) {
return newWikitext.replace(banner.rawWikitext.trim(), banner.buildWikitext());
}
// New banner
return newWikitext += '\n' + banner.buildWikitext();
}, wikitext.projects);
return (wikitext.above + '\n' + wikitext.projects + '\n' + wikitext.below).trim();
};
Page.prototype.makeEditSummary = function() {
return this.banners.reduce(function(changes, banner) {
// Not touched (and not new, and redirect not bypassed)
if ( $.isEmptyObject(banner.touched) && !banner.isNew() && !banner.bypassRedirect ) {
return changes;
}
// New and removed, no action needed
if ( banner.remove && banner.isNew() ) {
return changes;
}
// Symbol
var symbol = '';
if ( banner.remove ) {
symbol = '−';
} else if ( banner.isNew() ) {
symbol = '+';
}
// Transclusion name, without WikiProject prefix
var name = banner.getTransclusionName().replace('WikiProject ','');
// Ratings, if touched
var rating = '';
if ( !banner.remove ) {
var classRating = ( banner.touched.class ) ? banner.parameters.class.trim() : '';
var impRating = ( banner.touched.importance ) ? banner.parameters.importance.trim() : '';
if ( classRating && impRating ) {
rating = classRating + '/' + impRating;
} else {
rating = classRating || impRating || '';
}
if ( rating ) {
rating = ' (' + rating + ')';
}
}
return changes += ' ' + symbol + name + rating + ';';
}, 'Assessment:').slice(0,-1);
};
Page.prototype.setRedirectsTo = function(pageObjects) {
var gotRedirects = $.Deferred();
if ( pageObjects == null ) {
pageObjects = this;
}
var pageObjectsToCheck = ( $.isArray(pageObjects) ) ? pageObjects : [pageObjects];
var processRedirects = function(result) {
if ( !result || !result.query ) {
gotRedirects.reject();
return;
}
if ( result.query.redirects ) {
$.each(result.query.redirects, function(_index, redirect) {
for ( var i=0; i<pageObjectsToCheck.length; i++ ) {
if ( pageObjectsToCheck[i].getPrefixedText() === redirect.from ) {
pageObjectsToCheck[i].redirectsTo = Page.newFromText(redirect.to);
break;
}
}
});
}
gotRedirects.resolve();
};
API.get({
'action': 'query',
'format': 'json',
'titles': pageObjectsToCheck.map(function(pageObj) {
return pageObj.getPrefixedText();
}),
'redirects': 1
})
.done( processRedirects )
.fail( gotRedirects.reject );
return gotRedirects;
};
Page.prototype.setTemplatesBanners = function() {
var self = this;
var gotTemplatesBanners = $.Deferred();
if ( self.oldTopSection === '' ) {
return gotTemplatesBanners.resolve();
}
var makeTemplatesObjectsArray = function(wikitext) {
// Reset lastindex of regex pattern so that test will work
config.regex.template.lastIndex = 0;
if ( !config.regex.template.test(wikitext) ) {
return [];
}
return wikitext.match(config.regex.template).map(Template.newFromRawWikitext);
};
var isShellTemplate = function(templateObject) {
return -1 !== $.inArray(templateObject.getMainText(), config.shellTemplates);
};
// Initially finds top-level templates only (not templates within template parameters)
var talkpageTemplates = makeTemplatesObjectsArray(self.oldTopSection);
// Find sub-templates within WikiProject banner shell
var shellTemplate = talkpageTemplates.filter(isShellTemplate)[0];
if ( shellTemplate && shellTemplate.parameters[1] ) {
var talkpageSubtemplates = makeTemplatesObjectsArray(shellTemplate.parameters[1]);
// Merge subtemplates into main array
$.merge(talkpageTemplates, talkpageSubtemplates);
}
// Check for redirects, then filter out non-banners
$.when(self.setRedirectsTo(talkpageTemplates), config.deferred.gotListOfBanners)
.done(function(){
var talkpageBanners = talkpageTemplates.filter(function(templateObject) {
return -1 !== $.inArray(templateObject.getRedirectOrMainText(), config.banners);
});
self.banners = talkpageBanners;
gotTemplatesBanners.resolve();
})
.fail(function() { gotTemplatesBanners.reject(); });
return gotTemplatesBanners;
};
/* ========== Template class ==================================================================== */
// Constructor
var Template = function(title, parameters, rawWikitext) {
try {
Page.call(this, decodeURIComponent(title));
} catch(e) {
throw new Error('Unable to parse template title "'+title+'"');
}
this.parameters = parameters || {};
this.rawWikitext = rawWikitext || null;
this.isProjectBanner = null;
this.touched = {};
};
// Utility function
/**
* makeParamsObject
*
* Converts a string containg template parameters into an object of parameter names (or positons)
* and their values.
*
* @param {string} wikitext
* Wikitext containg parameters
* @return {object} Object with key:value pairs correspoinding to |parameter=value pairs.
*/
Template.makeParamsObject = function(wikitext) {
var params = {};
var unnamedParamCount = 0;
var parts = wikitext.match(config.regex.templateParams);
for ( var i=0; i<parts.length; i++ ) {
if ( parts[i].trim() === '|' ) {
//Empty unnamed parameter, i.e. {{foo||bar}}
unnamedParamCount++;
continue;
}
var equalsIndex = parts[i].indexOf('=');
if ( equalsIndex === -1 ) {
//unnamed parameter
unnamedParamCount++;
params[unnamedParamCount.toString()] = parts[i].slice(1).trim();
} else {
params[parts[i].slice(1, equalsIndex).trim()] = parts[i]
.slice(equalsIndex+1).trim();
}
}
return params;
};
// Constructor from raw wikitext, i.e. `{{TemplateName|value1|para2=value2|para3=value3}}`
Template.newFromRawWikitext = function(rawWikitext) {
// Reset lastindex of regex pattern so that exec will work
config.regex.template.lastIndex = 0;
var parts = config.regex.template.exec(rawWikitext);
if ( !parts || !parts[0] || !parts[1] ) {
throw new Error('Unable to parse template from wikitext: ' + rawWikitext);
}
var params = ( parts[2] ) ? Template.makeParamsObject(parts[2]) : null;
return new Template('Template:'+parts[1], params, parts[0]);
};
// ---------- Template prototype ---------------------------------------------------------------- */
// Inherited from Page
Template.prototype = Object.create(Page.prototype);
Template.prototype.constructor = Template;
// Additional functions
Template.prototype.isNew = function() {
return this.rawWikitext === null;
};
Template.prototype.getParamValue = function(param) {
return this.parameters[param] || null;
};
Template.prototype.setParamValue = function(param, val) {
this.parameters[param] = val;
this.touched[param] = true;
};
Template.prototype.deleteParam = function(param) {
delete this.parameters[param];
this.touched[param] = true;
};
Template.prototype.getTransclusionName = function() {
if ( this.bypassRedirect ) {
return this.redirectsTo.getMainText();
}
return this.getMainText();
};
Template.prototype.getLinkedName = function() {
if ( this.bypassRedirect ) {
return extraJs.makeLink(this.redirectsTo.getPrefixedText(), this.redirectsTo.getMainText());
}
return extraJs.makeLink(this.getPrefixedText(), this.getMainText());
};
// Banner-specific functions
Template.prototype.parseClassesAndImportances = function() {
var self = this;
var parsed = $.Deferred();
if ( self.classes && self.importances ) {
return parsed.resolve();
}
var testWikitext = config.bannerDefaults.extendedClasses.map(function(c) {
return '{{' + self.getMainText() + '|class=' + c + '}}';
}).join('/n') +
config.bannerDefaults.extendedImportances.map(function(i) {
return '{{' + self.getMainText() + '|importane=' + i + '}}';
}).join('/n');
var processCategories = function(result) {
var catsHtml = result.parse.categorieshtml['*'];
self.classes = $.merge(
$.merge([], config.bannerDefaults.classes),
config.bannerDefaults.extendedClasses.filter(function(c) {
return catsHtml.indexOf(c+'-Class') !== -1;
})
);
self.importances = $.merge(
$.merge([], config.bannerDefaults.importances),
config.bannerDefaults.extendedImportances.filter(function(i) {
return catsHtml.indexOf(i+'-importance') !== -1;
})
);
parsed.resolve();
};
API.get({
action: 'parse',
title: 'Talk:Sandbox',
text: testWikitext,
prop: 'categorieshtml'
}).done(processCategories)
.fail(parsed.reject);
return parsed;
};
Template.prototype.makeParameterSuggestions = function() {
var self = this;
var gotParams = $.Deferred();
if ( self.parameterSuggestions ) { return gotParams.resolve(); }
var processTemplatedata = function(result) {
// Figure out page id (beacuse action=templatedata doesn't have an indexpageids option)
var id = $.map(result.pages, function( _value, key ) { return key; });
if ( result.pages[id].notemplatedata || !result.pages[id].paramOrder ) {
gotParams.reject();
return;
}
self.parameterSuggestions = result.pages[id].paramOrder.filter(function(paramName) {
return ( paramName !== 'class' && paramName !== 'importance' );
})
.map(function(paramName) {
return {data: paramName};
});
gotParams.resolve();
};
API.get({
action: 'templatedata',
titles: self.getRedirectOrPrefixedText(),
doNotIgnoreMissingTitles: 1
})
.done( processTemplatedata )
.fail( gotParams.reject );
return gotParams;
};
Template.prototype.getUnusedParamterSuggestions = function() {
return this.parameterSuggestions || [];
/*
if ( !this.parameterSuggestions ) {
return [];
}
return this.parameterSuggestions.filter(function(param) {
return self.templateObject.parameters[param.data] == null;
});
*/
};
Template.prototype.buildWikitext = function() {
var paras = '';
if ( !$.isEmptyObject(this.parameters) ) {
paras = ' ' + $.map(this.parameters, function(val, name) {
return '|'+name+'='+val;
}).join(' ');
}
return '{{' + this.getTransclusionName() + paras + '}}';
};
/* ========== ComboBoxInputPrompt class ========================================================== */
// Subclass of OOjs UI ProcessDialog
var ComboBoxInputPrompt = function( config ) {
ComboBoxInputPrompt.super.call( this, config );
};
OO.inheritClass( ComboBoxInputPrompt, OO.ui.ProcessDialog );
// Specify a name for .addWindows()
ComboBoxInputPrompt.static.name = 'comboBoxInput';
// Specify the static configurations: title and action set
ComboBoxInputPrompt.static.actions = [
{ flags: 'primary', label: 'Add', action: 'add' },
{ flags: 'safe', label: 'Cancel' }
];
// Customize the initialize() function to add content and layouts:
ComboBoxInputPrompt.prototype.initialize = function () {
ComboBoxInputPrompt.super.prototype.initialize.call( this );
this.panel = new OO.ui.PanelLayout( { padded: true, expanded: false } );
this.content = new OO.ui.FieldsetLayout();
this.input = new OO.ui.ComboBoxInputWidget( {
$overlay: this.$overlay,
//validate: 'non-empty',
//autofocus: true,
menu: {
filterFromInput: true
}
});
this.input.$pending.addClass( 'oo-ui-pendingElement-pending' );
this.field = new OO.ui.FieldLayout( this.input, {
label: ' ',//placeholder
align: 'top'
} );
this.content.addItems([ this.field ]);
this.panel.$element.append( this.content.$element );
this.$body.append( this.panel.$element );
this.input.connect( this, { 'change': 'onInputChange' } );
this.input.connect( this, { 'enter': 'onEnterPress' } );
};
// Specify any additional functionality required by the window (disable opening an empty URL, in this case)
ComboBoxInputPrompt.prototype.onInputChange = function ( value ) {
this.actions.setAbilities( {
add: !!value.length
} );
};
ComboBoxInputPrompt.prototype.onEnterPress = function() {
this.executeAction('add');
};
// Specify the dialog height (or don't to use the automatically generated height).
ComboBoxInputPrompt.prototype.getBodyHeight = function () {
return this.panel.$element.outerHeight( true )*1.1;
};
// Use getSetupProcess() to set up the window with data passed to it at the time of opening.
ComboBoxInputPrompt.prototype.getSetupProcess = function ( data ) {
var self = this;
data = data || {};
return ComboBoxInputPrompt.super.prototype.getSetupProcess.call( this, data )
.next( function () {
if ( data.label ) {
self.field.setLabel(data.label);
}
if ( data.help ) {
self.field.setNotices([data.help]);
}
// Set up contents based on data
$.when( data.optionsReady )
.done(function() {
self.input.setOptions(
data.makeOptions()
);
})
.fail(function() {
if ( data.failnotice ) {
self.field.setNotices(
( data.help ) ? [data.help, data.failnotice] : [data.failnotice]
);
self.updateSize();
}
})
.always(function() {
self.input.$pending.removeClass( 'oo-ui-pendingElement-pending' );
});
}, this );
};
// Specify processes to handle the actions.
ComboBoxInputPrompt.prototype.getActionProcess = function ( action ) {
var self = this;
if ( action === 'add' ) {
// Close dialog, passing through the input data
return new OO.ui.Process( function () {
self.close({input: self.input.getValue()});
});
}
// Fallback to parent handler
return ComboBoxInputPrompt.super.prototype.getActionProcess.call( this, action );
};
// Use the getTeardownProcess() method to perform actions whenever the dialog is closed.
// This method provides access to data passed into the window's close() method
// or the window manager's closeWindow() method.
ComboBoxInputPrompt.prototype.getTeardownProcess = function ( data ) {
return ComboBoxInputPrompt.super.prototype.getTeardownProcess.call( this, data );
// .first( function () {
// // Perform any cleanup as needed
// }, this );
};
/* ========== Dialog class ====================================================================== */
// Constructor
var Dialog = function(currentPage) {
this.page = currentPage;
// Make an new dialog/interface window
this.interfaceWindow = new Morebits.simpleWindow(
Math.min(900, Math.floor(window.innerWidth*0.8)),
Math.floor(window.innerHeight*0.9)
);
this.interfaceWindow.setTitle('Rater [v.'+config.script.version+']');
this.interfaceWindow.addFooterLink('script documentation', 'WP:RATER');
this.interfaceWindow.addFooterLink('feedback', 'WT:RATER');
this.interfaceWindow.setContent(
$('<div>')
.attr('id', 'rater-dialog')
.append(
//$('<div>').attr('id', 'rater-dialog-header'),
$('<div>').attr('id', 'rater-dialog-body')
)
.get(0)
);
$('a.ui-dialog-titlebar-close.ui-corner-all').remove();
$('#rater-dialog').parent().css('background-color', '#f0f0f0');
this.$footerButtons = $('#rater-dialog').parent().nextAll('.ui-dialog-buttonpane')
.find('span.morebits-dialog-buttons');
this.interfaceWindow.display();
};
// Overlay dialog (for previews, diffs, etc)
Dialog.showOverlayDialog = function(contentDeferred, heading) {
var overlayDialog = new OO.ui.MessageDialog();
config.windowManager.addWindows( [ overlayDialog ] );
var instance = config.windowManager.openWindow( overlayDialog, {
title: heading,
message: 'Loading...',
size: 'larger',
actions: [ {
action: 'accept',
label: 'Close',
flags: 'primary'
} ]
} );
instance.opened.then( function() {
contentDeferred.done(function(contentHtml){
overlayDialog.$element.find('label.oo-ui-messageDialog-message').empty().after(contentHtml);
overlayDialog.updateSize();
})
.fail(function(code, jqxhr) {
overlayDialog.$element.find('label.oo-ui-messageDialog-message').empty().append(
heading + ' failed.',
( code == null ) ? '' : ' ' + extraJs.makeErrorMsg(code, jqxhr)
);
});
});
instance.closed.then(function(){ config.windowManager.clearWindows(); });
};
// ---------- Dialog prototype ------------------------------------------------------------------ */
// --- Basic manipulation: ---
// Append content to header
//Dialog.prototype.addToHeader = function($content) {
// $('#rater-dialog-header').append($content);
//};
// Append content to body
Dialog.prototype.addToBody = function($content) {
$('#rater-dialog-body').append($content);
};
// Add buttons to footer
Dialog.prototype.setFooterButtons = function($buttons, mode) {
if ( mode === 'prepend' ) {
this.$footerButtons.prepend($buttons);
} else if ( mode === 'append' ) {
this.$footerButtons.append($buttons);
} else {
this.$footerButtons.empty().append($buttons);
}
};
// Clear dialog
Dialog.prototype.emptyContent = function() {
$('#rater-dialog-body').empty();
};
// Display dialog
Dialog.prototype.display = function() {
this.interfaceWindow.display();
};
// Reset height
Dialog.prototype.resetHeight = function() {
this.interfaceWindow.setHeight(Math.floor(window.innerHeight*0.9));
};
// Close dialog
Dialog.prototype.close = function() {
this.interfaceWindow.close();
};
// --- Make interface elements: ---
Dialog.icons = {
'delete': {
'source': '/media/wikipedia/commons/thumb/1/18/OOjs_UI_icon_close-ltr.svg/40px-OOjs_UI_icon_close-ltr.svg.png',
'tooltip': 'Remove template'
},
'clear': {
'source': '/media/wikipedia/commons/thumb/5/54/OOjs_UI_icon_noWikiText-ltr.svg/40px-OOjs_UI_icon_noWikiText-ltr.svg.png',
'tooltip': 'Clear parameters'
},
'bypass': {
'source': '/media/wikipedia/commons/thumb/5/5d/OOjs_UI_icon_newline-rtl.svg/40px-OOjs_UI_icon_newline-rtl.svg.png',
'tooltip': 'Bypass redirect'
},
'ores': {
'source': '/media/wikipedia/commons/thumb/5/51/Objective_Revision_Evaluation_Service_logo.svg/40px-Objective_Revision_Evaluation_Service_logo.svg.png',
'tooltip': 'Machine-predicted quality from ORES'
}
};
Dialog.makeIcon = function(iconName, clickable) {
return $('<img>').attr({
'src': Dialog.icons[iconName].source,
'title': Dialog.icons[iconName].tooltip,
'alt': iconName,
'width': '20px',
'height': '20px'
}).addClass('rater-dialog-'+iconName)
.css( (clickable===false) ? {} : {'float':'left', 'cursor':'pointer', 'margin-right':'0.2em'});
};
Dialog.makeDropdown = function(values, selectedValue) {
var $dropdown = $('<select>')
.addClass('rater-dialog-dropdown')
.append(
values.map(function(val) {
return $('<option>').attr('value', val.toLowerCase()).text(val);
})
);
if ( selectedValue != null ) {
$dropdown.children("[value='"+selectedValue.toLowerCase()+"']").attr('selected', 'selected');
}
return $dropdown;
};
Dialog.makeParamInput = function(currentVal, param) {
return $('<span>').addClass('rater-dialog-paraInput').append(
$('<label>').text(param),
$('<input>').attr('type', 'text').val(currentVal),
$('<a>').attr('title', 'remove').text('x'),
$('<wbr>')
);
};
Dialog.makeButton = function(options) {
var $button = new OO.ui.ButtonWidget(options).$element;
$button.children().css({'padding-top':'0.5em','padding-bottom':'0.4em'});
return $button;
};
Dialog.makeFramelessButton = function(options) {
options.framed = false;
var $button = new OO.ui.ButtonWidget(options).$element;
$button.css('padding','0')
.children().css({'padding-top':'0.3em','padding-bottom':'0.3em'})
.children().css('font-weight','normal');
return $button;
};
Dialog.prototype.makeRow = function(templateObject) {
var self = this;
var $row = $('<div>');
var setParamHandlers = function() {
var $span = $(this);
var $label = $span.children('label');
var $input = $span.children('input');
var $a = $span.children('a');
$input.blur(function() {
if ( templateObject.parameters[$label.text()] !== $input.val().trim() ) {
templateObject.setParamValue($label.text(), $input.val().trim());
}
});
$a.click(function() {
templateObject.deleteParam($label.text());
self.rebuildRow($row, templateObject);
});
};
var removeTemplate = Dialog.makeIcon('delete').click(function() {
templateObject.remove = true;
templateObject.isProjectBanner = false;
$row.remove();
});
var clearTemplate = Dialog.makeIcon('clear').click(function() {
$.each(templateObject.parameters, function(paraName) {
templateObject.setParamValue(paraName, null);
});
self.rebuildRow($row, templateObject);
});
var templateName = $('<span>').addClass('rater-dialog-templateName').append(
'{{',
templateObject.getLinkedName(),
'}}'
);
var bypassRedirect = '';
if ( templateObject.redirectsTo && !templateObject.bypassRedirect ) {
bypassRedirect = Dialog.makeIcon('bypass').click(function() {
templateObject.bypassRedirect = true;
templateName.empty().append(
'{{',
templateObject.getLinkedName(),
'}}'
);
$(this).remove();
});
}
var classDropdown = Dialog.makeDropdown(
templateObject.classes,
templateObject.parameters.class || templateObject.parameters.Class
).change(function() {
var newValue = $(this).val();
if (
templateObject.parameters.class && ( newValue.toLowerCase() === templateObject.parameters.class.toLowerCase() )||
templateObject.parameters.Class && ( newValue.toLowerCase() === templateObject.parameters.Class.toLowerCase() )
) {
return;
}
templateObject.setParamValue('class', newValue);
if ( templateObject.parameters.Class ) {
templateObject.parameters.Class = null;
}
});
var importanceDropdown = Dialog.makeDropdown(
templateObject.importances,
templateObject.parameters.importance || templateObject.parameters.Importance
).change(function() {
var newValue = $(this).val();
if (
templateObject.parameters.importance && ( newValue.toLowerCase() === templateObject.parameters.importance.toLowerCase() ) ||
templateObject.parameters.Importance && ( newValue.toLowerCase() === templateObject.parameters.Importance.toLowerCase() )
) {
return;
}
templateObject.setParamValue('importance', newValue);
if ( templateObject.parameters.Class ) {
templateObject.parameters.Class = null;
}
});
var listasParam = '';
if ( templateObject.getRedirectOrMainText() === 'WikiProject Biography' ) {
if ( templateObject.parameters.listas ) {
listasParam = Dialog.makeParamInput(templateObject.parameters.listas, 'listas');
} else {
listasParam = Dialog.makeParamInput(self.page.getListasAutofill(), 'listas')
.addClass('rater-dialog-autofill')
.on('keypress change', function(){
$(this).removeClass('rater-dialog-autofill').off('keypress change');
});
}
listasParam.find('a').hide();
listasParam.each(setParamHandlers);
}
var addParam = $('<span>').append(
Dialog.makeFramelessButton({
label: '[add parameter]',
icon: 'tableAddColumnBefore'
})
);
addParam.click(function() {
var sugesstionsReady = templateObject.makeParameterSuggestions();
var prompt = new ComboBoxInputPrompt();
config.windowManager.addWindows( [ prompt ] );
instance = config.windowManager.openWindow( prompt, {
label: 'Add parameter',
optionsReady: sugesstionsReady,
makeOptions: function() {
return templateObject.getUnusedParamterSuggestions();
},
failnotice: new OO.ui.HtmlSnippet(
$('<span>').css({'color':'#555', 'font-size':'92%'}).append(
'Parameter suggestions not available.',
$('<p>').append(
'This WikiProject banner has not been configured for use with this tool. See the ',
extraJs.makeLink('User:Evad37/rater#TemplateData_quick_tutorial', 'TemplateData quick tutorial'),
' or ask for help on ',
extraJs.makeLink('User talk:Evad37/rater.js', ' the script\'s talk page'),
'.'
)
)
)
} );
instance.opened.then( function() {
prompt.input.focus();
});
instance.closed.then( function ( data ) {
config.windowManager.clearWindows();
if ( !data || !data.input ) {
// No input data - ie cancelled
return;
}
if ( templateObject.parameters[data.input] != null ) {
alert('There is already a ' + data.input + ' parameter!');
return;
}
templateObject.parameters[data.input] = '';
self.rebuildRow($row, templateObject);
} );
});
var otherParams = $('<div>').append(
$.map(templateObject.parameters, function(val, param) {
if (
val === null ||
param.toLowerCase() === 'class' ||
param.toLowerCase() === 'importance' ||
( param === 'listas' &&
templateObject.getRedirectOrMainText() === 'WikiProject Biography' )
) {
return '';
}
return Dialog.makeParamInput(val, param);
}),
addParam
);
otherParams.children('span').each(setParamHandlers);
//var moreless = $('<a>').addClass('rater-dialog-moreless').text('[+/-]').click(function() {
// otherParams.toggle();
//);
return $row.addClass('rater-dialog-row').append(
$('<div>').append(
removeTemplate,
clearTemplate,
templateName,
bypassRedirect,
$('<span>').addClass('rater-dialog-row-class').append(
'Class:',
classDropdown
),
$('<span>').addClass('rater-dialog-row-importance').append(
'Importance:',
importanceDropdown
),
listasParam
//moreless
),
otherParams
);
};
Dialog.prototype.makeActionsRow = function() {
var self = this;
var addProject = Dialog.makeButton({
label: 'Add WikiProject',
icon: 'add',
flags: ['progressive']
})
.click(function() {
var prompt = new ComboBoxInputPrompt();
config.windowManager.addWindows( [ prompt ] );
instance = config.windowManager.openWindow( prompt, {
label: 'Add Template:',
optionsReady: config.deferred.gotListOfBanners,
makeOptions: function() { return config.bannerOptions; }
} );
instance.opened.then( function() {
prompt.input.focus();
});
instance.closed.then( function ( data ) {
config.windowManager.clearWindows();
if ( !data || !data.input ) { return; }
var existingBanner = self.page.getBannerFromNameOrRedirect(data.input);
if ( existingBanner && !existingBanner.remove ) {
alert('There is already a {{' + existingBanner.getTransclusionName() + '}} banner!');
return;
}
var templateObject;
if ( existingBanner ) {
existingBanner.remove = false;
existingBanner.parameters = {};
templateObject = existingBanner;
} else {
templateObject = new Template('Template:'+data.input);
templateObject.isProjectBanner = true;
self.page.banners.push(templateObject);
}
$.when(
!!existingBanner || templateObject.setRedirectsTo(),
!!existingBanner || templateObject.parseClassesAndImportances()
).then( function() {
var newRow = self.makeRow(templateObject).insertBefore('#rater-dialog-actions');
self.autofillClassAndImportance(newRow);
} );
} );
});
var removeAll = Dialog.makeButton({
label: 'Remove all',
icon: 'close',
flags: ['destructive']
}).click(function() {
$.each(self.page.banners, function(_index, templateObject) {
templateObject.remove = true;
});
$('div.rater-dialog-row').not('#rater-dialog-actions').remove();
});
var clearAll = Dialog.makeButton({
label: 'Clear all',
icon: 'noWikiText'
}).click(function() {
$.each(self.page.banners, function(_index, templateObject) {
$.each(templateObject.parameters, function(paraName) {
templateObject.setParamValue(paraName, null);
});
});
self.refresh();
});
var bypassAllRedirects = '';
if ( $('img.rater-dialog-bypass').length ) {
bypassAllRedirects = Dialog.makeButton({
label: 'Bypass redirects',
icon: 'arrowNext'
}).click(function() {
$.each(self.page.banners, function(_index, templateObject) {
if ( templateObject.redirectsTo && !templateObject.bypassRedirect ) {
templateObject.bypassRedirect = true;
}
});
self.refresh();
});
}
var classForAllDropdown = Dialog.makeDropdown(config.bannerDefaults.classes).change(function() {
var newValue = $(this).val();
$('span.rater-dialog-row-class > select').val(newValue).change();
}).prepend($('<option>').attr('disabled','disabled').text('Class'));
var importanceForAllDropdown = Dialog.makeDropdown(config.bannerDefaults.importances).change(function() {
var newValue = $(this).val();
$('span.rater-dialog-row-importance > select').val(newValue).change();
}).prepend($('<option>').attr('disabled','disabled').text('Importance'));
var setAll = Dialog.makeButton({
label: 'Set all',
icon: 'tag'
});
setAll.find('span.oo-ui-labelElement-label').append(
classForAllDropdown,
importanceForAllDropdown
);
var oresPrediction = '';
if ( self.page.oresScore ) {
oresPrediction = $('<div>').append(
Dialog.makeIcon('ores', false),
' ',
extraJs.makeLink('mw:ORES', 'ORES'),
' Predicted class: ',
$('<b>').text(self.page.oresScore)
);
}
return $('<div>').attr('id', 'rater-dialog-actions').addClass('rater-dialog-row').append(
oresPrediction,
$('<div>').append(
addProject,
removeAll,
clearAll,
bypassAllRedirects,
setAll
)
);
};
Dialog.prototype.makeButtons = function() {
if ( this.$footerButtons.children().length !== 0 ) {
return;
}
var self = this;
var cancel = Dialog.makeButton({
label: 'Cancel',
framed: false,
flags: ['destructive']
}).click(function() { self.close(); });
var save = Dialog.makeButton({
label: 'Save changes',
flags: ['primary', 'progressive']
}).click(function() { self.onSaveClick(); });
var preview = Dialog.makeButton({
label: 'Show preview'
}).click(function() {
Dialog.showOverlayDialog( self.page.makePreview(), 'Preview' );
});
var showdiff = Dialog.makeButton({
label: 'Show changes'
}).click(function() {
Dialog.showOverlayDialog( self.page.makeDiff(), 'Diff' );
});
self.setFooterButtons([save, preview, showdiff, cancel]);
};
Dialog.prototype.onSaveClick = function() {
var self = this;
var close = Dialog.makeButton({
label: 'Close'
}).click(function() { self.close(); });
self.emptyContent();
self.setFooterButtons(null);
self.addToBody('Saving...');
$.when( self.page.makeEdit() )
.done( function() {
self.addToBody('Done!');
})
.fail( function(code, jqxhr) {
self.addToBody('Failed. ' + extraJs.makeErrorMsg(code, jqxhr));
} )
.always(function() {
self.setFooterButtons(close);
});
};
Dialog.prototype.autofillClassAndImportance = function($rowDiv) {
var self = this;
var $top = $rowDiv || $('#rater-dialog-body');
// Autofill empty classes (if possible)
var extrapolateClassFromExisting = function() {
var classes = $('span.rater-dialog-row-class > select').map(function() {
return $(this).val();
}).get().sort();
if ( -1 === $.inArray(' ', classes) ) {
return false;
}
return classes.filter(function(c) {
return c!== ' ';
})[0];
};
var extrapolateClassFromOres = function() {
if ( !self.page.oresScore ) {
return null;
}
return ( self.page.oresScore.toLowerCase() === 'stub' ) ? 'stub' : 'start';
};
var extrapolated = extrapolateClassFromExisting() || extrapolateClassFromOres();
if ( extrapolated ) {
$top.find('span.rater-dialog-row-class > select').each(function() {
var $this = $(this);
if ( $this.val() === ' ' ) {
$this.val(extrapolated).change();
$this.parent().addClass('rater-dialog-autofill')
.on('keypress change', function(){
$(this).removeClass('rater-dialog-autofill').off('keypress change');
});
}
});
}
// Autofill empty importances to 'low' (articles only)
if ( config.mw.wgNamespaceNumber <= 1 ) {
$top.find('span.rater-dialog-row-importance > select').each(function() {
var $this = $(this);
if ( $this.val() === ' ' ) {
$this.val('low').change();
$this.parent().addClass('rater-dialog-autofill')
.on('keypress change', function(){
$(this).removeClass('rater-dialog-autofill').off('keypress change');
});
}
});
}
};
Dialog.prototype.build = function(isInitialBuild) {
var self = this;
var isBuilt = $.Deferred();
var parseBanners = '';
if ( self.page.banners ) {
parseBanners = self.page.banners.map(function(banner) {
return banner.parseClassesAndImportances();
});
}
$.when.apply(null, parseBanners).then(function() {
if ( self.page.banners ) {
self.addToBody(
self.page.banners.map(function(banner) {
if ( banner.remove ) {
return '';
}
return self.makeRow(banner);
})
);
}
self.addToBody(self.makeActionsRow());
if ( isInitialBuild && self.page.banners.length>0 ) {
self.autofillClassAndImportance();
}
self.makeButtons();
self.resetHeight();
isBuilt.resolve();
});
return isBuilt;
};
Dialog.prototype.refresh = function() {
this.emptyContent();
this.build();
};
Dialog.prototype.rebuildRow = function(rowDiv, banner) {
this.makeRow(banner).insertAfter(rowDiv);
rowDiv.remove();
};
/* ========== ============ ====================================================================== */
var getListOfProjectBanners = function() {
config.deferred.gotListOfBanners = $.Deferred();
var bannerNames = [];
var processQuery = function(result) {
if ( !result.query || !result.query.categorymembers ) {
// No results
// TODO: error or warning ********
config.deferred.gotListOfBanners.reject();
return;
}
// Gather titles into array - excluding "Template:" prefix
var resultTitles = result.query.categorymembers.map(function(info) {
return info.title.slice(9);
});
Array.prototype.push.apply(bannerNames, resultTitles);
// Continue query if needed
if ( result.continue ) {
doApiQuery($.extend(query, result.continue));
return;
}
config.banners = bannerNames;
config.deferred.gotListOfBanners.resolve();
};
var query = {
action: 'query',
format: 'json',
list: 'categorymembers',
cmtitle: 'Category:WikiProject banners with quality assessment',
cmprop: 'title',
cmnamespace: '10',
cmlimit: '500'
};
var doApiQuery = function(q) {
API.get( q )
.done( processQuery )
.fail( function(code, jqxhr) {
console.warn('[Rater] ' + extraJs.makeErrorMsg(code, jqxhr, 'Could not retrieve pages from [Category:WikiProject banners with quality assessment]'));
config.deferred.gotListOfBanners.reject();
} );
};
doApiQuery(query);
return config.deferred.gotListOfBanners;
};
var makeBannerOptions = function() {
config.deferred.gotBannerOptions = $.Deferred();
config.bannerOptions = config.banners.map(function(bannerName) {
return {
data: bannerName,
label: bannerName.replace('WikiProject ', '')
};
});
};
/* ========== Set up current page and dialog ==================================================== */
var currentPage = Page.newFromText(config.mw.wgPageName);
var dialog = new Dialog(currentPage);
dialog.addToBody(
$('<div>').attr('id', 'dialog-loading').append(
$('<p>').attr('id', 'dialog-loading-0').css('font-weight', 'bold').text('Initialising:'),
$('<p>').attr('id', 'dialog-loading-1').text('Loading talkpage wikitext...'),
$('<p>').attr('id', 'dialog-loading-2').text('Parsing talkpage templates...'),
$('<p>').attr('id', 'dialog-loading-3').text('Retrieving quality prediction...').hide(),
$('<p>').attr('id', 'dialog-loading-4').text('Building interface...')
)
);
var showTaskDone = function(taskNumber) {
$('#dialog-loading-'+taskNumber).append(' Done!');
};
var showTaskFailed = function(taskNumber, code, jqxhr) {
$('#dialog-loading-'+taskNumber).append(
' Failed.',
( code == null ) ? '' : ' ' + extraJs.makeErrorMsg(code, jqxhr)
);
};
// Load and parse talk page
var talkDeferred = currentPage.getTalkpageTopSection()
.done(function() { showTaskDone(1); })
.fail(function(code, jqxhr) { showTaskFailed(1, code, jqxhr); })
.then(function(){
return currentPage.setTemplatesBanners()
.done(function() { showTaskDone(2); })
.fail(function(code, jqxhr) { showTaskFailed(2, code, jqxhr); });
});
// Retrieve rating from ORES
var oresDeferred = '';
if ( config.mw.wgNamespaceNumber <= 1 ) {
$('#dialog-loading-3').show();
oresDeferred = currentPage.getOresScore()
.done(function() { showTaskDone(3); })
.fail(function(code, jqxhr) { showTaskFailed(3, code, jqxhr); });
}
// Build dialog
$.when(oresDeferred, talkDeferred).then(function() { dialog.build(true); })
.done(function(){
showTaskDone(4);
$('#dialog-loading').hide(600);
})
.fail(function(code, jqxhr) { showTaskFailed(4, code, jqxhr); });
// Get list of all projects (but don't wait for this before displaying dialog)
getListOfProjectBanners().done( makeBannerOptions );
// Make OOjs UI window manager
config.windowManager = new OO.ui.WindowManager();
// - place above Morebits SimpleWindow, which has z-index of ~1000
config.windowManager.$element.css('z-index', '2000');
$( 'body' ).append( config.windowManager.$element );
/* ========== End of file closure wrappers ===================================================== */
});
});
});
});