_ _    _ _____  ___   __                       
 __      _(_) | _(_)___ / ( _ ) / /_   ___ ___  _ __ ___  
 \ \ /\ / / | |/ / | |_ \ / _ \| '_ \ / __/ _ \| '_ ` _ \ 
  \ V  V /| |   <| |___) | (_) | (_) | (_| (_) | | | | | |
   \_/\_/ |_|_|\_\_|____/ \___/ \___(_)___\___/|_| |_| |_|

User:Ahecht/sandbox/Scripts/draft-sorter.js

In today's article we will explore the topic of User:Ahecht/sandbox/Scripts/draft-sorter.js, a fascinating topic that has captured the attention of millions of people around the world. User:Ahecht/sandbox/Scripts/draft-sorter.js is a broad and diverse topic that encompasses a wide variety of aspects, from its impact on society to its implications in daily life. Throughout this article, we will analyze in depth different aspects related to User:Ahecht/sandbox/Scripts/draft-sorter.js, offering a complete and detailed vision that will allow our readers to better understand the importance and relevance of this topic.
//jshint maxerr:512
//jshint esnext:false
//jshint esversion:8

//Based on ] <nowiki>
( function ( $, mw ) { mw.loader.using( , function () {
	mw.loader.load( "mediawiki.ui.input", "text/css" );
	var api = new mw.Api();

	if ( mw.config.get( "wgNamespaceNumber" ) !== 118 ) { 
		if ( mw.util.getParamValue('draftsorttrigger') ) {
			// "Next draft" was clicked, but we ended up on a non-draft page
			nextDraft();
			return;
		} else {
			return;
		}
	}

	var portletLink = mw.util.addPortletLink("p-cactions", "#", "Sort draft (sandbox)", "pt-draftsort", "Manage WikiProject tags");
	$( portletLink ).click( function ( e ) {
		e.preventDefault();

		// If it's already there, don't duplicate
		if ( $( "#draft-sorter-wrapper" ).length ) { return; }
		
		// Configure defaults
		//var templateCache = mw.config.get("wgFormattedNamespaces")+":"+mw.config.get("wgUserName")+"/Scripts/draft-sorter.json";
		var templateCache = "Wikipedia:WikiProject Articles for creation/WikiProject templates.json";
		
		// Define the form
		var form = $( "<div>" )
			.attr( "id", "draft-sorter-wrapper" )
			.css( { "background-image": "url(https://upload.wikimedia.org/wikipedia/commons/e/e2/OOjs_UI_icon_tag-ltr-progressive.svg)",
					"background-repeat": "no-repeat",
					"background-position-y": "center",
					"background-size": "50px",
					"min-height": "50px",
					"margin": "1em auto",
					"border": "thin solid #BBB",
					"padding": "0.5em 50px",
					"display": "inline-block",
					"border-radius": "0.25em"
			} ).append( $( "<span>" )
				.text( "Loading form..." )
				.css( "color", "gray" )
			);
		// Add the form to the page
		form.insertAfter( "#contentSub" );

		var select = $( "<select>" )
			.attr( "id", "draft-sorter-form" )
			.attr( "multiple", "multiple" );
		
		var submitButton = new OO.ui.ButtonWidget ()
				.setLabel( "Submit" )
				.setFlags(  )
				.on("click", function ( e ) { submit(); } );
		
		var cancelButton = new OO.ui.ButtonWidget ()
				.setLabel( "Cancel" )
				.setFlags(  )
				.on("click", function( e ) {
					$( "#draft-sorter-wrapper" ).remove();
					window.location.replace( window.location.href.replace("draftsorttrigger=y","") );
				} );

		var nextButton = new OO.ui.ButtonWidget ()
			.setIcon( "next" )
			.setLabel( "Skip" )
			.on("click", function ( e ) { nextDraft(); } );

		// Determine what templates are already on the talk page
		var existingProjects = ;
		var wikiprojects = {};

		api.get( {
				action: "query",
				titles: "Draft talk:" + mw.config.get( "wgTitle" ),
				generator: "templates",
				redirects: "1",
				gtllimit: "max",
		} ).done (function (data) {
			if (data && data.query && data.query.pages) {
				$.each(data.query.pages, function (i) {
					var item = data.query.pages.title.match(/^Template:(WikiProject\s*)$/i);
					if (item && item && item != "WikiProject banner shell") {
						existingProjects.push(item);
					}
				} );
			}
			console.log( "Project templates found on talk page: ");
			console.log( existingProjects );
			fetchJSONList(templateCache).then( (cachedList) => {
				wikiprojects = cachedList;
				constructForm();
			} );
		} ).fail (function() {
			console.log("Retrieving project templates from talk page failed.");
			fetchJSONList(templateCache).then( (cachedList) => {
				wikiprojects = cachedList;
				constructForm();
			} );
		});
		
		predicts = ;
		
		async function fetchJSONList(listName) {
			var parsedList = {}, listData;
			
			var query = {
				action:'parse',
				prop:'wikitext',
				page: listName,
				formatversion: '2',
				origin: '*'
			};
			
			try {
				listData = await api.get( query );
			} catch (jsonerror) {
				console.warn("Unable to fetch contents of " + listName + ":");
				console.log(jsonerror);
			}
			
			if (listData && listData.parse && listData.parse.wikitext) {
				try {
					parsedList = JSON.parse(listData.parse.wikitext);
				} catch (jsonerror) {
					console.warn("Error parsing JSON list " + listName + ":");
					console.log(jsonerror);
				}
			}
		
			return parsedList;
		}
		
		function nextDraft() {
			// Special:RandomInCategory isn't random, use toolforge instead
			if (nextButton) {
				nextButton.setLabel( "Loading..." ).setDisabled( true );
			}
			window.location.href = "https://randomincategory.toolforge.org/Pending_AfC_submissions?draftsorttrigger=y&cmnamespace=118&cmtype=page&returntype=subject&server=" + mw.config.get("wgServerName");
		}
		
		function showPredicts() {
			$( "#draft-sorter-status" ).append( "<li>Suggested categories from <a href=\"https://www.mediawiki.orghttps://wiki386.com/en/ORES#Topic_routing\">ORES</a>:<ul id=\"draft-sorter-suggest\"></ul></li>" );
			predicts.forEach( function(item) { 
				function addWithLink(p) {
					$( "#draft-sorter-suggest" ).append(
						$( "<li>" ).text( item + " (" ).append(
							$( "<a>" ).text("add").click(
								function() {
									$( select ).val( 
										$( select ).val().concat(  )
									).trigger("chosen:updated");
								}
							)
						).append( ")" )
					);
				}
				
				var singularItem = item.replace(/s$/, '');
				if( !existingProjects.includes( "WikiProject " + item ) 
					&& wikiprojects
				) { //Prediction matches a WikiProject and doesn't already exist
					addWithLink(item);
				} else if( singularItem != item
					&& !existingProjects.includes( "WikiProject " + singularItem ) 
					&& wikiprojects
				) { //Singular form of prediction matches a WikiProject and doesn't exist
					addWithLink(singularItem);
				} else { //Prediction doesn't match a WikiProject or already exists
					$( "#draft-sorter-suggest" ).append( 
						$( "<li>" ).append( item  )
					);
				}
			} );
			return;
		}
		
		function getPredicts() {
			var lang = mw.config.get("wgServerName").split(".wikipedia.org");
			if (lang.length == 1) return;
			
			const liftWingExternalEndpoint = "https://api.wikimedia.org/service/lw/inference/v1/models/";
			let headers = new Headers({
			    "Content-Type": "application/json",
				"User-Agent": "draft-sorter (https://en.wikipedia.orghttps://wiki386.com/en/User:Ahecht/Scripts/draft-sorter.js)"
			});
			var revID = mw.config.get( "wgCurRevisionId" );
			var model = (lang == "en") ? "enwiki-drafttopic" : "outlink-topic-model";
			var postBody = JSON.stringify({
				"rev_id":  revID,
				"lang": lang,
				"page_title": mw.config.get("wgPageName")
			});

			fetch(liftWingExternalEndpoint + model + ":predict", {
				method: "POST",
				headers: new Headers({
				    "Content-Type": "application/json",
					"User-Agent": "draft-sorter (https://en.wikipedia.orghttps://wiki386.com/en/User:Ahecht/Scripts/draft-sorter.js)"
					}),
				body: postBody
			}).then(response => response.json()).then(data => {
				var prediction = ;
				var dbName = mw.config.get("wgDBname");
				
				if(data && data && data.scores &&
					data.scores &&
					data.scores.drafttopic &&
					data.scores.drafttopic.score &&
					data.scores.drafttopic.score.prediction) {
					prediction = data.scores.drafttopic.score.prediction;
				} else if (data && data.prediction && data.prediction.results) {
					data.prediction.results.forEach( p => {
						if (p && p.topic) prediction.push(p.topic);
					} );
				} 
				
				if (prediction.length) {
					console.log("Got ORES response! Raw predictions:");
					console.log(prediction);
					
					prediction.forEach( function (item) {
						var last = item.split(".");
						var penultimate = item.split(".");
						if ( last.substr(-1) == "*" ) {
							// Filter out redundant starred predictions
							if (prediction.find(element => (
								element.split(".") != last &&
								element.split(".") == penultimate
							) ) ) {
								console.log("Prediction \"" + last + "\" excluded.");
								last = null;
							} else {
								last = penultimate;
							}
						}
						
						if ( wikiprojects ) {
							// WikiProject found, no need to try splitting
							predicts.push(last);
						} else if ( last ) {
							// Can't find wikiProject, try splitting
							var splitLast = last.split(/( & | and )/);
							for (i=0;i<=splitLast.length;i+=2) {
								splitLast = splitLast.charAt(0).toUpperCase()
									+ splitLast.slice(1);
								predicts.push( splitLast );
							}
						}
					} );
					console.log("Filtered predictions:");
					console.log(predicts);
					showPredicts();
				} else {
					console.warn("Error finding predictions in ORES response:");
					console.warn(data);
				}
			} ).catch( e => console.warn("Error retrieving ORES data: " + e) );

			return;
		}

		// Construct the form
		function constructForm() {
			mw.loader.load( "oojs-ui.styles.icons-movement"); 
			
			Object.keys(wikiprojects).sort().forEach( function(name) {
				select.append( $( "<option>" )
					.attr( "value", wikiprojects )
					.text( name ) );
			} );
			form.hide();
			form.empty();
			form.append( $( "<span>" )
				.text( "Tag WikiProjects: " )
				.css( {
					"font-size": "115%",
					"font-weight": "bold"
				} )
			);
			form.append( select );
			form.append( "&#32;&#32;" );
			form.append( submitButton.$element );
			form.append( cancelButton.$element );
			form.append( nextButton.$element );
			form.append ( $( "<ul>" )
				.attr( "id", "draft-sorter-status" )
			);
			form.show();
			$( select )
				.val( existingProjects )
				.chosen( {"placeholder_text_multiple": "Select some WikiProjects"} )
				.on("change", function(evt, params) { //Make existing projects undeletable
					$( "#draft-sorter-status" ).empty();
					if ( predicts.length > 0 ) { showPredicts(); }
					if ( params.deselected && existingProjects.includes(params.deselected) ) {
						$( select ).val( $( select ).val().concat() ).trigger("chosen:updated");
						$( "#draft-sorter-status" ).prepend( $( "<li>" )
							.text( "Draft Sorter cannot remove existing WikiProjects." )
							.addClass( "error" )
						);
					}
				} );

			// Add completed form to the page
			$( '#draft-sorter-wrapper' ).replaceWith(form);
			getPredicts();
			return;
		}

		// The submission function
		function submit() {
			$( "#draft-sorter-form" )
				.attr("disabled", true)
				.trigger("chosen:updated");
			submitButton
				.setLabel( "Submitting..." )
				.setDisabled( true );
			cancelButton
				.setLabel ( "Close" );
				
			var newTags = ;

			$( "#draft-sorter-form" ).val().forEach( function (element) {
				if ( !existingProjects.includes(element) ) {
					newTags.push(element);
				}
			} );

			console.log( newTags.length + " new tag(s): " + newTags.join(", ") );
			var statusList = $( "#draft-sorter-status" )
				.html( "<li>Saving " + newTags.length + " new tags.</li>" );
			var showStatus = function ( status ) {
				return $( "<li>" )
					.text( status )
					.appendTo( statusList );
			};
			var newText = "";
			newTags.forEach( function ( element ) {
					newText += "{{" + element + "|importance=|class=draft}}\n";
			} );

			function editTalk(text, prefix) {
				var params = {
					action: "edit", section: "0",
					title: "Draft talk:" + mw.config.get( "wgTitle" ),
					summary: "Tagging draft: +" + newTags.join(", +") +
						" (])",
				};
				params = text;

				api.postWithEditToken( params ).done( function ( data ) {
					if ( data && data.edit && data.edit.result && data.edit.result === "Success" ) {
						showStatus( "Edit saved successfully! (" )
							.append( $( "<a>" )
								.text( "reload" )
								.attr( "href", "#" )
								.click( function () {
									window.location.replace( 
										window.location.href.replace("draftsorttrigger=y","")
									);
								} )
							).append( ")" );
						submitButton.setLabel( "Submitted" );
						nextButton.setLabel( "Next draft" ).setFlags(  );
					} else {
						showStatus( "Couldn't save due to error: " + JSON.stringify( data ) );
					}
				} ).fail( function ( error ) {
					showStatus( "Couldn't save due to error: " + JSON.stringify( error ) );
				} );
				return;
			}

			api.get( {
				action: "query",
				titles: "Draft talk:" + mw.config.get( 'wgTitle' ),
				prop: "templates",
				tltemplates: "Template:WikiProject_banner_shell"
			} ).done (function (data) {
				var bannerShellUsed = Object.entries(data.query.pages).templates;
				if(typeof(bannerShellUsed) == "object" && bannerShellUsed.length > 0) {
					api.get( {
						action: "parse",
						page: "Draft talk:" + mw.config.get( 'wgTitle' ),
						prop: "wikitext",
						section: "0"
					} ).done (function (data) {
						var talkText = data.parse.wikitext;
						if (typeof(talkText) == "string") {
							var pattern = /(\{\{\s*(?:Wiki?Project?banners??shell(?:\/redirect)?|(?:(?:WP)??Banner|(?:Wiki)?Project|Scope)?shell|Multiplewikiprojects|WikiProject?Banners?|WPBS?)\s*\|(?:\s*+\s*=*)*\s*(?:\\n)*?)/im;
							if (talkText.search(pattern) >= 0) {
								newText = talkText.replace( pattern, ("$1" + newText) );
								editTalk(newText,"");
							} else {
								console.log("Banner shell on talk page, but not found in wikitext: " + talkText);
								editTalk(newText,"prepend");
							}
						} else {
							console.log("typeof(talkText) = " + typeof(talkText));
							editTalk(newText,"prepend");
						}
					} ).fail (function (error) {
						console.warn( "Couldn't retrieve talk page text due to error: " + JSON.stringify( error ) );
						editTalk(newText,"prepend");
					} );
				} else if(newTags.length > 2) {
					console.log("typeof(bannerShellUsed) = " + typeof(bannerShellUsed) );
					newText = "{{WikiProject banner shell|\n" + newText + "}}";
					editTalk(newText,"prepend");
				} else {
					console.log("typeof(bannerShellUsed) = " + typeof(bannerShellUsed) + "; newTags.length = " + newTags.length);
					editTalk(newText,"prepend");
				}
			} ).fail( function ( error ) {
				console.warn( "Couldn't retrieve templates on talk page due to error: " + JSON.stringify( error ) );
				editTalk(newText,"prepend");
			} );
			return;
		}
	} );
	if (mw.util.getParamValue('draftsorttrigger')) {
		$( portletLink ).trigger("click");
	}
} ) }( jQuery, mediaWiki ) );
//</nowiki>