Jump to content

User:Awesome Aasim/linkinfo.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
if (!userAndAPageInfoLoaded) {
	var userAndAPageInfoLoaded = true;
	(function() {
		$(document).ready(async function() {
			function isIP(text) {
				return mw.util.isIPv6Address(text) || mw.util.isIPv4Address(text);
			}
			var user, page, link;
			mw.loader.load("https://en.wikipedia.org/wiki/User:Awesome_Aasim/linkinfo.css?action=raw&ctype=text/css", "text/css");
			mw.loader.using(['oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui.styles.icons-content', 'oojs-ui.styles.icons-alerts', 'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-moderation', 'oojs-ui.styles.icons-editing-core', 'oojs-ui.styles.icons-editing-functions', 'oojs-ui.styles.icons-editing-advanced', 'oojs-ui.styles.icons-user', 'oojs-ui.styles.icons-layout', 'oojs-ui.styles.icons-accessibility'], async function() {
				const OptWidget = OO.ui.MenuOptionWidget;
				// below adapted partly from Microsoft Copilot
				// Create a placeholder div where the custom context menu will attach
				const $container = $('<div class="linkinfo">').css({ position: 'absolute', zIndex: 10000 }).appendTo( document.body );
				// Define menu items
				const select = new OO.ui.SelectWidget();
				const menu = new OO.ui.MenuLayout({
					menuPanel: new OO.ui.PanelLayout({padded: true, scrollable: true, expanded: true})   
				});
				menu.$menu.append(select.$element);
				// Create popup widget to wrap the menu
				const popup = new OO.ui.PopupWidget( {
					$content: menu.$menu,
					autoClose: true,
					head: false,
					tail: false,
					anchor: false
				} );

				$container.append( popup.$element );
				$container.css({
					'user-select': 'none',
					'-webkit-user-select': 'none',
					'-moz-user-select': 'none',
					'-ms-user-select': 'none'
				});
				$(document).on("contextmenu", "a", async function(e) {
					function show() {
						popup.setSize(null, null, false);
						popup.toggle(true);
						let puWidth = popup.$element.width();
						let puHeight = popup.$element.height();
						let puPosition = popup.$element.position();
						let leftEdge = puPosition.left;
						let rightEdge = puPosition.left + puWidth;
						let topEdge = puPosition.top;
						let bottomEdge = puPosition.top + puWidth;
						let puOffset = popup.$element.offset();
						let leftEdgeOS = puOffset.left - $(window).scrollLeft();
						let rightEdgeOS = puOffset.left + puWidth - $(window).scrollLeft();
						let topEdgeOS = puOffset.top - $(window).scrollTop();
						let bottomEdgeOS = puOffset.top + puHeight - $(window).scrollTop();
						$container.css({ top: e.pageY + 'px' });
						if (puHeight < menu.$menu.height()) {
							if (Math.abs(bottomEdgeOS - window.innerHeight) > Math.abs(topEdgeOS)) {
								$container.css({ top: $container.position().top + (menu.$menu.height() - puHeight) + 1 + 'px' });
							} else {
								$container.css({ top: $container.position().top - (menu.$menu.height() - puHeight) - 1 + 'px' });
							}
							popup.toggle(false);
							popup.computePosition();
							popup.setSize(null, null, false);
							popup.toggle(true);
							// popup.setSize(null, Math.min(menu.$menu.height(), window.innerHeight), false);
						}
						if (window.innerWidth - e.pageX < puWidth) {
							$container.css({ left: e.pageX - rightEdge + 'px' });
						} else {
							$container.css({ left: e.pageX - leftEdge + 'px' });
						}
						puOffset = popup.$element.offset();
						leftEdgeOS = puOffset.left - $(window).scrollLeft();
						rightEdgeOS = puOffset.left + puWidth - $(window).scrollLeft();
						topEdgeOS = puOffset.top - $(window).scrollTop();
						bottomEdgeOS = puOffset.top + puHeight - $(window).scrollTop();
						if (rightEdgeOS >= window.innerWidth || leftEdgeOS <= 0 || bottomEdgeOS >= window.innerHeight || topEdgeOS <= 0) {
							$container.css({ top: $(window).scrollTop() + 'px', left: window.innerWidth / 2 + $(window).scrollLeft() + 'px' });
							popup.toggle(false);
							popup.computePosition();
							popup.setSize(null, null, false);
							popup.toggle(true);
						}
						puWidth = popup.$element.width();
						if (puWidth >= window.innerWidth / 2) {
							select.addItems([
								new OptWidget({ data: "close", label: "Close menu", icon: "close" })
							], 0);
						}
					}
					if ($(this).data("nolinkinfo")) {
						return;
					}
					popup.toggle( false ); // Hide if already shown
					let url = new URL($(this).attr("href"), location.origin);
					if (url.origin != location.origin || $(this).hasClass("external") || $(this).hasClass("extiw")) {
						return;
					}
					let pageName;
					if (url.pathname.search(mw.config.get("wgArticlePath").replace("$1", "")) != 0) {
						pageName = url.searchParams.get("title");
					} else {
						pageName = url.pathname.substring(mw.config.get("wgArticlePath").replace("$1", "").length, url.pathname.length);
					}
					if (!pageName) {
						return;
					}
					let title = new mw.Title(decodeURI(pageName));
					if (title.getNamespaceId() < 0) {
						return;
					}

					e.preventDefault();
					$container.css({ top: e.pageY + 'px', left: e.pageX + 'px' });
					link = url;
					select.clearItems();
					
					select.addItems([
						new OptWidget({ data: "newtab", label: "Open in new tab", icon:  "newWindow" })
					]);

					select.addItems([
						new OptWidget({ data: "copylink", label: "Copy link", icon: "link" })
					]);

					if (window.getSelection().toString()) {
						select.addItems([
							new OptWidget({ data: "copy", label: "Copy", icon: "copy" })
						]);
					}

					show();

					var showUserLinks = title.getNamespaceId() == 2 || title.getNamespaceId() == 3;
					let dataQuery = {
						"action": "query",
						"format": "json",
						"meta": "userinfo",
						"uiprop": "rights",
						"prop": "info",
						"inprop": "displaytitle|protection|subjectid|talkid|associatedpage",
						"intestactions": "edit|move|delete|undelete|protect",
						"titles": title.getPrefixedText(),
						"formatversion": 2
					};
					if (showUserLinks) {
						let user;
						if (!isIP(title.getMainText()) || title.getNamespaceId() == 3) {
							user = title.getMainText().split("/")[0];
						} else {
							user = title.getMainText();
						}
						
						dataQuery = Object.assign(dataQuery, {
							"list": "users",
							"ususers": user,
							"usprop": "blockinfo|emailable|groups|implicitgroups|cancreate|groupmemberships"
						});
					}
					let data;
					try {
						data = await $.get(mw.config.get('wgScriptPath') + '/api.php', dataQuery);
					} catch (e) {
						let $newA = $(this).clone();
						$newA.data("nolinkinfo", true);
						$newA.wrapAll("<span/>");
						select.addItems([
							new OptWidget({ label: $("<hr>"), disabled: true }),
							new OptWidget({ label: $newA.parent().prepend("Original link: "), disabled: true })
						]);
						show();
						return;
					}
					if (data.error) {
						select.addItems([
							new OptWidget({ label: $("<hr>"), disabled: true }),
							new OptWidget({ label: "Error: " + data.error.info, disabled: true })
						]);
						let $newA = $(this).clone();
						$newA.data("nolinkinfo", true);
						$newA.wrapAll("<span/>");
						select.addItems([
							new OptWidget({ label: $("<hr>"), disabled: true }),
							new OptWidget({ label: $newA.parent().prepend("Original link: "), disabled: true })
						]);
						show();
						return;
					}
					page = data.query.pages[0];
					let deletedrevs = [];
					if (page.actions.undelete) {
						deletedrevs = await $.get(mw.config.get("wgScriptPath") + "/api.php", {
							action: "query",
							format: "json",
							list: "deletedrevs",
							title: page.title,
							"formatversion": 2
						});
						deletedrevs = deletedrevs.query.deletedrevisions || [];
					}

					popup.toggle(false);
					select.addItems([
						new OptWidget({ label: $("<hr>"), disabled: true })
					]);
					function addPrimaryPageLinks() {
						select.addItems([
							new OptWidget({ data: "pageview", label: "View", flags: "progressive", icon: "eye" })
						]);
						select.addItems([
							new OptWidget({ data: "pagelink", label: "Copy as wikilink", icon: "wikiText" })
						]);
						if (page.ns % 2 == 0) {
							select.addItems([
								new OptWidget({ data: "pageassoc", label: "Discuss", icon: "speechBubbles" })
							]);
						} else {
							select.addItems([
								new OptWidget({ data: "pageassoc", label: "View primary", icon: "article" })
							]);
						}
						select.addItems([
							new OptWidget({ data: "pagelogs", label: "Page logs", icon: "viewDetails" })
						]);
					}
					if (showUserLinks) {
						user = data.query.users[0];
						select.addItems([
							new OptWidget({ label: "User options: " + user.name, disabled: true })	
						]);
						if (!user.missing && (!user.invalid || isIP(user.name))) {
							if (user.name.split("/").length == 1) {
								if (!isIP(user.name)) {
									select.addItems([
										new OptWidget({ data: "userpage", label: "Profile", flags: "progressive", icon: "userAvatar" }),
										new OptWidget({ data: "userlink", label: "Copy mention", icon: "wikiText" }),
										new OptWidget({ data: "usertalk", label: "Message", icon: "userTalk" })
									]);
								} else {
									select.addItems([
										new OptWidget({ data: "usertalk", label: "Message", flags: "progressive", icon: "userTalk" })
									]);
								}
							}
							select.addItems([
								new OptWidget({ data: "usercontribs", label: "Contributions", icon: "userContributions" }),
								new OptWidget({ data: "userperformlogs", label: "User logs", icon: "recentChanges" }),
								new OptWidget({ data: "usertargetlogs", label: "Target logs", icon: "viewDetails" })
							]);
							if (user.emailable && data.query.userinfo.rights.includes("sendemail")) {
								select.addItems([
									new OptWidget({ data: "useremail", label: "Email", icon: "message" })
								]);
							}
							if (data.query.userinfo.rights.includes("block")) {
								if (user.blockid) {
									select.addItems([
										new OptWidget({ data: "userblock", label: "Change block", flags: "destructive", icon: "block" }),
										new OptWidget({ data: "userunblock", label: "Unblock", flags: "destructive", icon: "unBlock" })
									]);
								} else {
									select.addItems([
										new OptWidget({ data: "userblock", label: "Block", flags: "destructive", icon: "block" })
									]);
								}
							}
							if (!isIP(user.name)) {
								select.addItems([
									new OptWidget({ data: "userroles", label: "User roles", icon: "userRights" }),
									new OptWidget({ data: "userid", label: "Copy user ID", icon: "markup" })
								]);
							}
							select.addItems([
								new OptWidget({ label: $("<hr>"), disabled: true })	
							]);
						}
						select.addItems([
							new OptWidget({ label: "Page options: " + page.title, disabled: true })	
						]);
						if (page.title.split("/").length != 1) {
							addPrimaryPageLinks();
						} else if (page.ns % 2 == 1) {
							select.addItems([
								new OptWidget({ data: "pagelogs", label: "Page logs", icon: "viewDetails" })
							]);
						}
					}

					if (!showUserLinks) {
						select.addItems([
							new OptWidget({ label: "Page options: " + page.title, disabled: true })	
						]);
						addPrimaryPageLinks();
					}
					
					if (page.redirect) {
						select.addItems([
							new OptWidget({ data: "pageviewredir", label: "View redirect", icon: "articleRedirect" })
						]);
					}
					
					select.addItems([
						new OptWidget({ data: "pageinfo", label: "Page information", icon: "info" })
					]);

					if (page.actions.edit) {
						if (page.missing) {
							select.addItems([
								new OptWidget({ data: "pageedit", label: "Create", icon: "articleAdd" })
							]);
						} else {
							select.addItems([
								new OptWidget({ data: "pageedit", label: "Edit", icon: "edit" })
							]);
						}
					} else {
						if (!page.missing) {
							select.addItems([
								new OptWidget({ data: "pageedit", label: "View source", icon: "editLock" })
							]);
						}
					}
					if (!page.missing) {
						select.addItems([
							new OptWidget({ data: "pagehist", label: "History", icon: "history" })
						]);
						if (page.actions.move) {
							select.addItems([
								new OptWidget({ data: "pagemove", label: "Move", icon: "literal" })
							]);
						}
						if (page.actions.delete) {
							select.addItems([
								new OptWidget({ data: "pagedel", label: "Delete", "flags": "destructive", icon: "trash" })
							]);
						}
					} else {
						if (page.actions.undelete && deletedrevs.length > 0) {
							select.addItems([
								new OptWidget({ data: "pageundel", label: "Restore", "flags": "destructive", icon: "restore" })
							]);
						}
					}
					if (page.actions.protect) {
						if (page.protection.length > 0) {
							select.addItems([
								new OptWidget({ data: "pageprot", label: "Change or Remove Protection", icon: "unLock" })
							]);
						} else {
							select.addItems([
								new OptWidget({ data: "pageprot", label: "Protect", icon: "lock" })
							]);
						}
					}
					if (!page.missing) {
						select.addItems([
							new OptWidget({ data: "pageid", label: "Copy page ID", icon: "markup" })
						]);
					}
					let $newA = $(this).clone();
					$newA.data("nolinkinfo", true);
					$newA.wrapAll("<span/>");
					select.addItems([
						new OptWidget({ label: $("<hr>"), disabled: true }),
						new OptWidget({ label: $newA.parent().prepend("Original link: "), disabled: true })
					]);
					show();
				});
				$(document).on("scroll", function() {
					popup.toggle( false );
				});

			    select.on( 'choose', async function (item) {
					let data = item.getData();
					switch (data) {
						case "close":
						popup.toggle( false );
							break;
						case "newtab":
							popup.toggle( false );
							window.open(link);
							break;
						case "copylink":
							popup.toggle( false );
							await navigator.clipboard.writeText(link.toString());
							break;
						case "copy":
							popup.toggle( false );
							await document.execCommand("copy");
							break;

						case "userpage":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `User:${user.name}`);
							break;
						case "userlink":
							popup.toggle( false );
							await navigator.clipboard.writeText(`@[[${mw.config.get("wgFormattedNamespaces")[2]}:${user.name}|${user.name}]]`);
							break;
						case "usertalk":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `User_talk:${user.name}`);
							break;
						case "usercontribs":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:Contributions/${user.name}`);
							break;
						case "userperformlogs":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:Log/${user.name}`);
							break;
						case "usertargetlogs":
							popup.toggle( false );
							location.href = (function() {
								var url = new URL(location.origin);
								url.pathname = mw.config.get("wgScriptPath") + "/index.php";
								url.searchParams.set("title", "Special:Log");
								url.searchParams.set("page", `User:${user.name}`);
								return url;
							})();
							break;
						case "useremail":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:Email/${user.name}`);
							break;
						case "userblock":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:Block/${user.name}`);
							break;
						case "userunblock":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:Unblock/${user.name}`);
							break;
						case "userroles":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:UserRights/${user.name}`);
							break;
						case "userid":
							popup.toggle( false );
							await navigator.clipboard.writeText(user.userid);
							break;

						case "pageview":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", page.title);
							break;
						case "pageassoc":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", page.associatedpage);
							break;
						case "pagelink":
							popup.toggle( false );
							await navigator.clipboard.writeText(`[[${page.title}]]`);
							break;
						case "pagelogs":
							popup.toggle( false );
							location.href = (function() {
								var url = new URL(location.origin);
								url.pathname = mw.config.get("wgScriptPath") + "/index.php";
								url.searchParams.set("title", "Special:Log");
								url.searchParams.set("page", page.title);
								return url;
							})();
							break;
						case "pageinfo":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:PageInfo/${page.title}`);
							break;
						case "pageviewredir":
							popup.toggle( false );
							location.href = (function() {
								var url = new URL(location.origin);
								url.pathname = mw.config.get("wgScriptPath") + "/index.php";
								url.searchParams.set("title", page.title);
								url.searchParams.set("redirect", "no");
								return url;
							})();
							break;
						case "pageedit":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:EditPage/${page.title}`);
							break;
						case "pagehist":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:History/${page.title}`);
							break;
						case "pagemove":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:MovePage/${page.title}`);
							break;
						case "pagedel":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:DeletePage/${page.title}`);
							break;
						case "pageundel":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:Undelete/${page.title}`);
							break;
						case "pageprot":
							popup.toggle( false );
							location.href = mw.config.get("wgArticlePath").replace("$1", `Special:ProtectPage/${page.title}`);
							break;
						case "pageid":
							popup.toggle( false );
							await navigator.clipboard.writeText(page.pageid);
							break;
					}
			    });
			});
		});
	})();
}