User:Theopolisme/stubtwinkle.js

/** * +-+ * |                     === WARNING: IN PROGRESS ===                       | * |                 Anything might break at any moment... | * |              Theopolisme's Stub Tagging for Twinkle v0.1               | * +-+ * * Imported from github. * All changes should be made in the repository, otherwise they will be lost. * * To update this script from github, you must have a local repository set up. Then * follow the instructions at. * * -- * * This is a fork AzaToth's Twinkle, the popular script sidekick for newbies, * admins, and every Wikipedian in between. Visit WP:TW for more information. */

//

( function ( window, document, $, undefined ) { // Wrap with anonymous function

var Twinkle = {}; window.Twinkle = Twinkle; // allow global access

// for use by custom modules (normally empty) Twinkle.initCallbacks = []; Twinkle.addInitCallback = function twinkleAddInitCallback( func ) { Twinkle.initCallbacks.push( func ); };

Twinkle.defaultConfig = {}; /** * Twinkle.defaultConfig.twinkle and Twinkle.defaultConfig.friendly * * This holds the default set of preferences used by Twinkle. (The |friendly| object holds preferences stored in the FriendlyConfig object.) * It is important that all new preferences added here, especially admin-only ones, are also added to * |Twinkle.config.sections| in twinkleconfig.js, so they are configurable via the Twinkle preferences panel. * For help on the actual preferences, see the comments in twinkleconfig.js. */ Twinkle.defaultConfig.twinkle = { // General summaryAd: " (TW)", deletionSummaryAd: " (TW)", protectionSummaryAd: " (TW)", userTalkPageMode: "window", dialogLargeFont: false, // Fluff (revert and rollback) openTalkPage: [ "agf", "norm", "vand" ], openTalkPageOnAutoRevert: false, markRevertedPagesAsMinor: [ "vand" ], watchRevertedPages: [ "agf", "norm", "vand", "torev" ], offerReasonOnNormalRevert: true, confirmOnFluff: false, showRollbackLinks: [ "diff", "others" ], // DI (twinkleimage) notifyUserOnDeli: true, deliWatchPage: "default", deliWatchUser: "default", // PROD watchProdPages: true, prodReasonDefault: "", logProdPages: false, prodLogPageName: "PROD log", // CSD speedySelectionStyle: "buttonClick", speedyPromptOnG7: false, watchSpeedyPages: [ "g3", "g5", "g10", "g11", "g12" ], markSpeedyPagesAsPatrolled: true, // these next two should probably be identical by default notifyUserOnSpeedyDeletionNomination:   [ "db", "g1", "g2", "g3", "g4", "g6", "g10", "g11", "g12", "a1", "a2", "a3", "a5", "a7", "a9", "a10", "f1", "f2", "f3", "f7", "f9", "f10", "u3", "t2", "t3", "p1", "p2" ], welcomeUserOnSpeedyDeletionNotification: [ "db", "g1", "g2", "g3", "g4", "g6", "g10", "g11", "g12", "a1", "a2", "a3", "a5", "a7", "a9", "a10", "f1", "f2", "f3", "f7", "f9", "f10", "u3", "t2", "t3", "p1", "p2" ], promptForSpeedyDeletionSummary: [ "db", "g1", "g2", "g3", "g4", "g6", "g7", "g8", "g10", "g11", "g12", "a1", "a2", "a3", "a5", "a7", "a9", "a10", "f2", "f4", "f7", "f8", "f10", "t2", "t3", "p1", "p2" ], openUserTalkPageOnSpeedyDelete: [ "db", "g1", "g2", "g3", "g4", "g5", "g10", "g11", "g12", "a1", "a3", "a7", "a9", "a10", "f3", "f7", "f9", "u3", "t2", "p1" ], deleteTalkPageOnDelete: false, deleteRedirectsOnDelete: true, deleteSysopDefaultToTag: false, speedyWindowHeight: 500, speedyWindowWidth: 800, logSpeedyNominations: false, speedyLogPageName: "CSD log", noLogOnSpeedyNomination: [ "u1" ], // Unlink unlinkNamespaces: [ "0", "100" ], // Warn defaultWarningGroup: "1", showSharedIPNotice: true, watchWarnings: true, blankTalkpageOnIndefBlock: false, // XfD xfdWatchDiscussion: "default", xfdWatchList: "no", xfdWatchPage: "default", xfdWatchUser: "default", // Hidden preferences revertMaxRevisions: 50, batchdeleteChunks: 50, batchDeleteMinCutOff: 5, batchMax: 5000, batchProtectChunks: 50, batchProtectMinCutOff: 5, batchundeleteChunks: 50, batchUndeleteMinCutOff: 5, deliChunks: 500, deliMax: 5000, proddeleteChunks: 50 };

// now some skin dependent config. if ( mw.config.get( "skin" ) === "vector" ) { Twinkle.defaultConfig.twinkle.portletArea = "right-navigation"; Twinkle.defaultConfig.twinkle.portletId  = "p-twinkle"; Twinkle.defaultConfig.twinkle.portletName = "TW"; Twinkle.defaultConfig.twinkle.portletType = "menu"; Twinkle.defaultConfig.twinkle.portletNext = "p-search"; } else { Twinkle.defaultConfig.twinkle.portletArea = null; Twinkle.defaultConfig.twinkle.portletId  = "p-cactions"; Twinkle.defaultConfig.twinkle.portletName = null; Twinkle.defaultConfig.twinkle.portletType = null; Twinkle.defaultConfig.twinkle.portletNext = null; }

Twinkle.defaultConfig.friendly = { // Tag groupByDefault: true, watchTaggedPages: true, markTaggedPagesAsMinor: false, markTaggedPagesAsPatrolled: true, tagArticleSortOrder: "cat", customTagList: [], // Welcome topWelcomes: false, watchWelcomes: true, welcomeHeading: "Welcome", insertHeadings: true, insertUsername: true, insertSignature: true, // sign welcome templates, where appropriate quickWelcomeMode: "norm", quickWelcomeTemplate: "welcome", customWelcomeList: [], // Talkback markTalkbackAsMinor: true, insertTalkbackSignature: true, // always sign talkback templates talkbackHeading: "Talkback", adminNoticeHeading: "Notice", mailHeading: "You've got mail!", // Shared markSharedIPAsMinor: true };

Twinkle.getPref = function twinkleGetPref( name ) { var result; if ( typeof Twinkle.prefs === "object" && typeof Twinkle.prefs.twinkle === "object" ) { // look in Twinkle.prefs (twinkleoptions.js) result = Twinkle.prefs.twinkle[name]; } else if ( typeof window.TwinkleConfig === "object" ) { // look in TwinkleConfig result = window.TwinkleConfig[name]; }

if ( result === undefined ) { return Twinkle.defaultConfig.twinkle[name]; }	return result; };

Twinkle.getFriendlyPref = function twinkleGetFriendlyPref(name) { var result; if ( typeof Twinkle.prefs === "object" && typeof Twinkle.prefs.friendly === "object" ) { // look in Twinkle.prefs (twinkleoptions.js) result = Twinkle.prefs.friendly[ name ]; } else if ( typeof window.FriendlyConfig === "object" ) { // look in FriendlyConfig result = window.FriendlyConfig[ name ]; }

if ( result === undefined ) { return Twinkle.defaultConfig.friendly[ name ]; }	return result; };

/** * **************** twAddPortlet **************** * * Adds a portlet menu to one of the navigation areas on the page. * This is necessarily quite a hack since skins, navigation areas, and * portlet menu types all work slightly different. * * Available navigation areas depend on the skin used. * Monobook: * "column-one", outer div class "portlet", inner div class "pBody". Existing portlets: "p-cactions", "p-personal", "p-logo", "p-navigation", "p-search", "p-interaction", "p-tb", "p-coll-print_export" * Special layout of p-cactions and p-personal through specialized styles. * Vector: * "mw-panel", outer div class "portal", inner div class "body". Existing portlets/elements: "p-logo", "p-navigation", "p-interaction", "p-tb", "p-coll-print_export" * "left-navigation", outer div class "vectorTabs" or "vectorMenu", inner div class "" or "menu". Existing portlets: "p-namespaces", "p-variants" (menu) * "right-navigation", outer div class "vectorTabs" or "vectorMenu", inner div class "" or "menu". Existing portlets: "p-views", "p-cactions" (menu), "p-search" * Special layout of p-personal portlet (part of "head") through specialized styles. * Modern: * "mw_contentwrapper" (top nav), outer div class "portlet", inner div class "pBody". Existing portlets or elements: "p-cactions", "mw_content" * "mw_portlets" (sidebar), outer div class "portlet", inner div class "pBody". Existing portlets: "p-navigation", "p-search", "p-interaction", "p-tb", "p-coll-print_export" * * @param String navigation -- id of the target navigation area (skin dependant, on vector either of "left-navigation", "right-navigation", or "mw-panel") * @param String id -- id of the portlet menu to create, preferably start with "p-". * @param String text -- name of the portlet menu to create. Visibility depends on the class used. * @param String type -- type of portlet. Currently only used for the vector non-sidebar portlets, pass "menu" to make this portlet a drop down menu. * @param Node nextnodeid -- the id of the node before which the new item should be added, should be another item in the same list, or undefined to place it at the end. * * @return Node -- the DOM node of the new item (a DIV element) or null */ function twAddPortlet( navigation, id, text, type, nextnodeid ) {	//sanity checks, and get required DOM nodes var root = document.getElementById( navigation ); if ( !root ) { return null; }

var item = document.getElementById( id ); if ( item ) { if ( item.parentNode && item.parentNode === root ) { return item; }		return null; }

var nextnode; if ( nextnodeid ) { nextnode = document.getElementById(nextnodeid); }

//verify/normalize input type = ( skin === "vector" && type === "menu" && ( navigation === "left-navigation" || navigation === "right-navigation" )) ? "menu" : ""; var outerDivClass; var innerDivClass; switch ( skin ) {		case "vector": if ( navigation !== "portal" && navigation !== "left-navigation" && navigation !== "right-navigation" ) { navigation = "mw-panel"; }			outerDivClass = ( navigation === "mw-panel" ) ? "portal" : ( type === "menu" ? "vectorMenu extraMenu" : "vectorTabs extraMenu" ); innerDivClass = ( navigation === "mw-panel" ) ? "body" : ( type === "menu" ? "menu" : "" ); break; case "modern": if ( navigation !== "mw_portlets" && navigation !== "mw_contentwrapper" ) { navigation = "mw_portlets"; }			outerDivClass = "portlet"; innerDivClass = "pBody"; break; default: navigation = "column-one"; outerDivClass = "portlet"; innerDivClass = "pBody"; break; }

// Build the DOM elements. var outerDiv = document.createElement( "div" ); outerDiv.className = outerDivClass + " emptyPortlet"; outerDiv.id = id; if ( type === "menu" ) { // Fix drop-down arrow image in Vector skin outerDiv.style.backgroundImage = 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAMAAAAlM38UAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA9QTFRFsbGxmpqa3d3deXl58/n79CzHcQAAAAV0Uk5T/////wD7tg5TAAAAMklEQVR42mJgwQoYBkqYiZEZAhiZUFRDxWGicEPA4nBRhNlAcYQokpVMDEwD6kuAAAMAyGMFQVv5ldcAAAAASUVORK5CYII=")'; outerDiv.style.backgroundPosition = "right 60%"; }	if ( nextnode && nextnode.parentNode === root ) { root.insertBefore( outerDiv, nextnode ); } else { root.appendChild( outerDiv ); }

var h5 = document.createElement( "h5" ); if ( type === "menu" ) { var span = document.createElement( "span" ); span.appendChild( document.createTextNode( text ) ); h5.appendChild( span );

var a = document.createElement( "a" ); a.href = "#"; span = document.createElement( "span" ); span.appendChild( document.createTextNode( text ) ); a.appendChild( span ); h5.appendChild( a ); } else { h5.appendChild( document.createTextNode( text ) ); }	outerDiv.appendChild( h5 );

var innerDiv = document.createElement( "div" ); // Not strictly necessary with type vectorTabs, or other skins. innerDiv.className = innerDivClass; outerDiv.appendChild(innerDiv);

var ul = document.createElement( "ul" ); innerDiv.appendChild( ul );

return outerDiv; }

/** * **************** twAddPortletLink **************** * Builds a portlet menu if it doesn't exist yet, and add the portlet link. * @param task: Either a URL for the portlet link or a function to execute. */ function twAddPortletLink( task, text, id, tooltip ) {	if ( Twinkle.getPref("portletArea") !== null ) { twAddPortlet( Twinkle.getPref( "portletArea" ), Twinkle.getPref( "portletId" ), Twinkle.getPref( "portletName" ), Twinkle.getPref( "portletType" ), Twinkle.getPref( "portletNext" )); }	var link = mw.util.addPortletLink( Twinkle.getPref( "portletId" ), typeof task === "string" ? task : "#", text, id, tooltip ); if ( $.isFunction( task ) ) { $( link ).click(function ( ev ) {			task;			ev.preventDefault;		}); }	return link; }

// Check if account is experienced enough to use Twinkle var twinkleUserAuthorized = Morebits.userIsInGroup( "autoconfirmed" ) || Morebits.userIsInGroup( "confirmed" );

/* **************************************** *** friendlytag.js: Tag module **************************************** * Mode of invocation:    Tab ("Tag") * Active on:             Existing articles; file pages with a corresponding file *                        which is local (not on Commons); existing subpages of *                         {Wikipedia|Wikipedia talk}:Articles for creation; *                        all redirects * Config directives in:  FriendlyConfig */

Twinkle.tag = function friendlytag {

if( ( mw.config.get('wgNamespaceNumber') === 0 || /^Wikipedia([ _]talk)?\:Articles[ _]for[ _]creation\//.exec(mw.config.get('wgPageName')) ) && mw.config.get('wgCurRevisionId') ) { Twinkle.tag.mode = 'article'; twAddPortletLink( Twinkle.tag.callback, "Tag", "stub-tag", "Add stub tags to article" ); } };

Twinkle.tag.callback = function friendlytagCallback( uid ) { var Window = new Morebits.simpleWindow( 630, (Twinkle.tag.mode === "article") ? 450 : 400 ); Window.setScriptName( "Twinkle" ); // anyone got a good policy/guideline/info page/instructional page link?? Window.addFooterLink( "Twinkle help", "WP:TW/DOC#tag" );

var form = new Morebits.quickForm( Twinkle.tag.callback.evaluate );

switch( Twinkle.tag.mode ) { case 'article': Window.setTitle( "Stub tagging" );

form.append({				type: 'select',				name: 'sortorder',				label: 'View this list:',				tooltip: 'You can change the default view order in your Twinkle preferences (WP:TWPREFS).',				event: Twinkle.tag.updateSortOrder,				list: [					{ type: 'option', value: 'cat', label: 'By categories', selected: Twinkle.getFriendlyPref('tagArticleSortOrder') === 'cat' },					{ type: 'option', value: 'alpha', label: 'In alphabetical order', selected: Twinkle.getFriendlyPref('tagArticleSortOrder') === 'alpha' }				]			});

form.append( { type: 'div', id: 'tagWorkArea' } );

if( Twinkle.getFriendlyPref('customTagList').length ) { form.append( { type: 'header', label: 'Custom tags' } ); form.append( { type: 'checkbox', name: 'articleTags', list: Twinkle.getFriendlyPref('customTagList') } ); }			break;

default: alert("Twinkle.tag: unknown mode " + Twinkle.tag.mode); break; }

form.append( { type:'submit' } );

var result = form.render; Window.setContent( result ); Window.display;

if (Twinkle.tag.mode === "article") { // fake a change event on the sort dropdown, to initialize the tag list var evt = document.createEvent("Event"); evt.initEvent("change", true, true); result.sortorder.dispatchEvent(evt); } };

Twinkle.tag.checkedTags = [];

Twinkle.tag.updateSortOrder = function(e) { var sortorder = e.target.value; var $workarea = $(e.target.form).find("div#tagWorkArea");

Twinkle.tag.checkedTags = e.target.form.getChecked("articleTags"); if (!Twinkle.tag.checkedTags) { Twinkle.tag.checkedTags = []; }

// function to generate a checkbox, with appropriate subgroup if needed var makeCheckbox = function(tag, description) { var checkbox = { value: tag, label: ": " + description }; if (Twinkle.tag.checkedTags.indexOf(tag) !== -1) { checkbox.checked = true; }		if (tag === "globalize") { checkbox.subgroup = { name: 'science', type: 'select', list: [ { label: "", value: "science-stub" }, {						label: "Region-specific subtemplates", list: [ { label: ": article deals primarily with the Australian viewpoint", value: "globalize/Australia" }, ]					}				]			};		} 		return checkbox; };

// categorical sort order if (sortorder === "cat") { var div = new Morebits.quickForm.element({			type: "div",			id: "tagWorkArea"		});

// function to iterate through the tags and create a checkbox for each one var doCategoryCheckboxes = function(subdiv, array) { var checkboxes = []; $.each(array, function(k, tag) {				var description = Twinkle.tag.article.tags[tag];				checkboxes.push(makeCheckbox(tag, description));			}); subdiv.append({				type: "checkbox",				name: "articleTags",				list: checkboxes			}); };

var i = 0; // go through each category and sub-category and append lists of checkboxes $.each(Twinkle.tag.article.tagCategories, function(title, content) {			div.append({ type: "header", id: "tagHeader" + i, label: title });			var subdiv = div.append({ type: "div", id: "tagSubdiv" + i++ });			if ($.isArray(content)) {				doCategoryCheckboxes(subdiv, content);			} else {				$.each(content, function(subtitle, subcontent) { subdiv.append({ type: "div", label: [ Morebits.htmlNode("b", subtitle) ] }); doCategoryCheckboxes(subdiv, subcontent); });			}		});

var rendered = div.render; $workarea.replaceWith(rendered); var $rendered = $(rendered); $rendered.find("h5").css({ 'font-size': '110%', 'margin-top': '1em' }); $rendered.find("div").filter(":has(span.quickformDescription)").css({ 'margin-top': '0.4em' }); }	// alphabetical sort order else { var checkboxes = []; $.each(Twinkle.tag.article.tags, function(tag, description) {			checkboxes.push(makeCheckbox(tag, description));		}); var tags = new Morebits.quickForm.element({			type: "checkbox",			name: "articleTags",			list: checkboxes		}); $workarea.empty.append(tags.render); } };

// Tags for ARTICLES start here

Twinkle.tag.article = {};

// A list of all article tags, in alphabetical order // To ensure tags appear in the default "categorized" view, add them to the tagCategories hash below.

Twinkle.tag.article.tags = { "math-stub": "math", "science-stub": "science",

};

// A list of tags in order of category // Tags should be in alphabetical order within the categories // Add new categories with discretion - the list is long enough as is!

Twinkle.tag.article.tagCategories = { "Stub Categories": { "Sciences": [ "science-stub", "math-stub" ],

};

Twinkle.tag.callbacks = { main: function( pageobj ) { var params = pageobj.getCallbackParameters, tagRe, tagText = '', summaryText = 'Added', tags = [], groupableTags = [], i, totalTags;

// Remove tags that become superfluous with this action var pageText = pageobj.getPageText.replace(/\{\{\s*(New unreviewed article|Userspace draft)\s*(\|(?:\{\{[^{}]*\}\}|[^{}])*)?\}\}\s*/ig, "");

var addTag =

if ( tagIndex > 0 ) { if( tagIndex === (totalTags - 1) ) { summaryText += ' and'; } else if ( tagIndex < (totalTags - 1) ) { summaryText += ','; }			}			};

tags.sort; totalTags = tags.length; $.each(tags, addTag);

if( Twinkle.tag.mode === 'redirect' ) { pageText += tagText; } else { pageText += tagText);		}		summaryText += ( tags.length > 0 ? ' tag' + ( tags.length > 1 ? 's' :  ) :  ) +			' to ' + Twinkle.tag.mode;

// avoid truncated summaries if (summaryText.length > (254 - Twinkle.getPref('summaryAd').length)) { summaryText = summaryText.replace(/\[\]+\|([^\+)\]\]/g, "$1"); }

pageobj.setPageText(pageText); pageobj.setEditSummary(summaryText + Twinkle.getPref('summaryAd')); pageobj.setWatchlist(Twinkle.getFriendlyPref('watchTaggedPages')); pageobj.setMinorEdit(Twinkle.getFriendlyPref('markTaggedPagesAsMinor')); pageobj.setCreateOption('nocreate'); pageobj.save;

if( Twinkle.getFriendlyPref('markTaggedPagesAsPatrolled') ) { pageobj.patrol; }	},

file: function friendlytagCallbacksFile(pageobj) { var text = pageobj.getPageText; var params = pageobj.getCallbackParameters; var summary = "Adding ";

});

if (!tagtext) { pageobj.getStatusElement.warn("User canceled operation; nothing to do"); return; }

text = tagtext + text; }

pageobj.setPageText(text); pageobj.setEditSummary(summary.substring(0, summary.length - 2) + Twinkle.getPref('summaryAd')); pageobj.setWatchlist(Twinkle.getFriendlyPref('watchTaggedPages')); pageobj.setMinorEdit(Twinkle.getFriendlyPref('markTaggedPagesAsMinor')); pageobj.setCreateOption('nocreate'); pageobj.save;

if( Twinkle.getFriendlyPref('markTaggedPagesAsPatrolled') ) { pageobj.patrol; }	} };

Twinkle.tag.callback.evaluate = function friendlytagCallbackEvaluate(e) { var form = e.target; var params = {};

switch (Twinkle.tag.mode) { case 'article': params.tags = form.getChecked( 'articleTags' ); params.group = form.group.checked; params.globalizeSubcategory = form["articleTags.globalize"] ? form["articleTags.globalize"].value : null; params.notabilitySubcategory = form["articleTags.notability"] ? form["articleTags.notability"].value : null; break; case 'file': params.svgSubcategory = form["imageTags.svgCategory"] ? form["imageTags.svgCategory"].value : null; params.tags = form.getChecked( 'imageTags' ); break; case 'redirect': params.tags = form.getChecked( 'redirectTags' ); break; default: alert("Twinkle.tag: unknown mode " + Twinkle.tag.mode); break; }

if( !params.tags.length ) { alert( 'You must select at least one tag!' ); return; }

Morebits.simpleWindow.setButtonsEnabled( false ); Morebits.status.init( form );

Morebits.wiki.actionCompleted.redirect = mw.config.get('wgPageName'); Morebits.wiki.actionCompleted.notice = "Tagging complete, reloading article in a few seconds"; if (Twinkle.tag.mode === 'redirect') { Morebits.wiki.actionCompleted.followRedirect = false; }

var wikipedia_page = new Morebits.wiki.page(mw.config.get('wgPageName'), "Tagging " + Twinkle.tag.mode); wikipedia_page.setCallbackParameters(params); switch (Twinkle.tag.mode) { case 'article': /* falls through */ case 'redirect': wikipedia_page.load(Twinkle.tag.callbacks.main); return; case 'file': wikipedia_page.load(Twinkle.tag.callbacks.file); return; default: alert("Twinkle.tag: unknown mode " + Twinkle.tag.mode); break; } };

/** * General initialization code */

var scriptpathbefore = mw.util.wikiScript( "index" ) + "?title=", scriptpathafter = "&action=raw&ctype=text/javascript&happy=yes";

// Retrieve the user's Twinkle preferences $.ajax({	url: scriptpathbefore + "User:" + encodeURIComponent( mw.config.get("wgUserName")) + "/twinkleoptions.js" + scriptpathafter,	dataType: "text",	error: function { mw.util.jsMessage( "Could not load twinkleoptions.js" ); },	success: function ( optionsText ) {

// Quick pass if user has no options if ( optionsText === "" ) { return; }

// Twinkle options are basically a JSON object with some comments. Strip those: optionsText = optionsText.replace( /(?:^(?:\/\/[^\n]*\n)*\n*|(?:\/\/[^\n]*(?:\n|$))*$)/g, "" );

// First version of options had some boilerplate code to make it eval-able -- strip that too. This part may become obsolete down the line. if ( optionsText.lastIndexOf( "window.Twinkle.prefs = ", 0 ) === 0 ) { optionsText = optionsText.replace( /(?:^window.Twinkle.prefs = |;\n*$)/g, "" ); }

try { var options = $.parseJSON( optionsText );

// Assuming that our options evolve, we will want to transform older versions: //if ( options.optionsVersion === undefined ) { // ...			// options.optionsVersion = 1; //}			//if ( options.optionsVersion === 1 ) { // ...			// options.optionsVersion = 2; //}			// At the same time, twinkleconfig.js needs to be adapted to write a higher version number into the options.

if ( options ) { Twinkle.prefs = options; }		}		catch ( e ) { mw.util.jsMessage("Could not parse twinkleoptions.js"); }	},	complete: function { $( Twinkle.load ); } });

// Developers: you can import custom Twinkle modules here // For example, mw.loader.load(scriptpathbefore + "User:UncleDouggie/morebits-test.js" + scriptpathafter);

Twinkle.load = function { // Don't activate on special pages other than "Contributions" so that they load faster, especially the watchlist. // Also, Twinkle is incompatible with Internet Explorer versions 8 or lower, so don't load there either. if ( (mw.config.get('wgNamespaceNumber') === -1 && mw.config.get('wgCanonicalSpecialPageName') !== "Contributions" && mw.config.get('wgCanonicalSpecialPageName') !== "Prefixindex") ||		($.client.profile.name === 'msie' && $.client.profile.versionNumber < 9) ) { return; }

// Load the modules in the order that the tabs should appears // User/user talk-related Twinkle.arv; Twinkle.warn; Twinkle.welcome; Twinkle.shared; Twinkle.talkback; // Deletion Twinkle.speedy; Twinkle.prod; Twinkle.xfd; Twinkle.image; // Maintenance Twinkle.protect; Twinkle.tag; // Misc. ones last Twinkle.diff; Twinkle.unlink; Twinkle.config.init; Twinkle.fluff.init; if ( Morebits.userIsInGroup('sysop') ) { Twinkle.delimages; Twinkle.deprod; Twinkle.batchdelete; Twinkle.batchprotect; Twinkle.batchundelete; }	// Run the initialization callbacks for any custom modules $( Twinkle.initCallbacks ).each(function ( k, v ) { v; }); Twinkle.addInitCallback = function ( func ) { func; };

// Increases text size in Twinkle dialogs, if so configured if ( Twinkle.getPref( "dialogLargeFont" ) ) { mw.util.addCSS( ".morebits-dialog-content, .morebits-dialog-footerlinks { font-size: 100% !important; } " +			".morebits-dialog input, .morebits-dialog select, .morebits-dialog-content button { font-size: inherit !important; }" ); } };

} ( window, document, jQuery )); // End wrap with anonymous function

//