Thành viên:CDzWik/common.js

Bách khoa toàn thư mở Wikipedia

Chú ý: Sau khi lưu thay đổi trang, bạn phải xóa bộ nhớ đệm của trình duyệt để nhìn thấy các thay đổi. Google Chrome, Firefox, Internet ExplorerSafari: Giữ phím ⇧ Shift và nhấn nút Reload/Tải lại trên thanh công cụ của trình duyệt. Để biết chi tiết và hướng dẫn cho các trình duyệt khác, xem Trợ giúp:Xóa bộ nhớ đệm.

/**
 * Giữ mã nguồn ở MediaWiki:Common.js một cách tối thiểu vì nó sẽ được tải
 * vô điều kiện cho mọi thành viên ở tất cả các trang wiki. Nếu có thể hãy tạo
 * công cụ (gadget) và để nó kích hoạt mặc định thay vì đặt ở đây (vì công cụ
 * là các mô đun ResourceLoader tối ưu hóa tối đa với khả năng ghi các phần phụ
 * thuộc).
 *
 * Vì Common.js không phải là công cụ, không có chỗ để khai báo phần phụ thuộc
 * cho nó, do đó ta phải tải chậm với mw.loader.using khi cần và thực hiện toàn
 * bộ trong lần gọi lại lần nữa. Trong phần lớn trường hợp các phần phụ thuộc
 * này sẽ được tải trước khi tải mã ở đây.
 *
 * Nhiều nội dung trang này lấy từ các phiêu bản cập nhật năm 2019 của trang
 * [[:en:MediaWiki:Common.js]] tại Wikipedia Tiếng Anh. Nội dung còn lại hầu hết
 * là mã do các thành viên thêm vào dùng cho Wikipedia tiếng Việt hoặc của
 * các phiên bản cũ tại Wikipedia Tiếng Anh đã bị xóa do bảo trì nhưng vì
 * Wikipedia Tiếng Việt vẫn còn sử dụng nên được giữ lại và đặt bên dưới phần
 * "MÃ DÀNH RIÊNG CHO WIKIPEDIA TIẾNG VIỆT". Xin hãy chú ý trước khi xóa
 * hoặc thay đổi những mã này.
 */

/* global mw, $ */
/* jshint strict:false, browser:true */

mw.loader.using(["mediawiki.util"]).done(() => {
	/* Bắt đầu gọi lại mw.loader.using */

	/**
	 * Sửa bố cục Trang Chính
	 *
	 * Miêu tả: Thêm một liên kết bổ sung đến danh sách đầy đủ các phiên bản ngôn ngữ hiện có.
	 * Bảo trì: [[:en:User:AzaToth]], [[:en:User:R. Koot]], [[:en:User:Alex Smotrov]]
	 */
	if (
		mw.config.get("wgPageName") === "Trang_Chính" ||
		mw.config.get("wgPageName") === "Thảo_luận:Trang_Chính"
	) {
		$(() => {
			mw.util.addPortletLink(
				"p-lang",
				"//meta.wikimedia.org/w/index.php?title=List_of_Wikipedias&uselang=vi",
				"Danh sách đầy đủ",
				"interwiki-completelist",
				"Danh sách đầy đủ các phiên bản Wikipedia"
			);
		});
	}

	/**
	 * Đổi hướng User:Name/skin.js và skin.css đến các trang giao diện hiện tại
	 * (trừ khi trang 'skin' thực sự tồn tại)
	 * @source: http://www.mediawiki.org/wiki/Snippets/Redirect_skin.js
	 * @rev: 2
	 */
	if (mw.config.get("wgArticleId") === 0 && mw.config.get("wgNamespaceNumber") === 2) {
		const titleParts = mw.config.get("wgPageName").split("/");
		/* Make sure there was a part before and after the slash
           and that the latter is 'skin.js' or 'skin.css' */
		if (titleParts.length === 2) {
			const userSkinPage = `${titleParts.shift()}/${mw.config.get("skin")}`;
			if (titleParts.slice(-1) === "skin.js") {
				window.location.href = mw.util.getUrl(`${userSkinPage}.js`);
			} else if (titleParts.slice(-1) === "skin.css") {
				window.location.href = mw.util.getUrl(`${userSkinPage}.css`);
			}
		}
	}

	/**
	 * Map addPortletLink sang mw.util
	 * @deprecated: Dùng mw.util.addPortletLink thay thế.
	 */

	/**
	 * Trích xuất một tham số URL từ URL hiện tại
	 * @deprecated: Dùng mw.util.getParamValue với lối thoát thích hợp
	 */

	/**
	 * Kiểm tra nếu một phần tử có một lớp nhất định
	 * @deprecated:  Use $(element).hasClass() instead.
	 */

	/**
	 * @source www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL
	 * @rev 6
	 */
	const extraCSS = mw.util.getParamValue("withCSS");
	const extraJS = mw.util.getParamValue("withJS");

	if (extraCSS) {
		if (extraCSS.match(/^MediaWiki:[^&<>=%#]*\.css$/)) {
			mw.loader.load(`/w/index.php?title=${extraCSS}&action=raw&ctype=text/css`, "text/css");
		} else {
			mw.notify("Chỉ cho phép các trang từ không gian tên MediaWiki", {
				title: "Giá trị withCSS không hợp lệ"
			});
		}
	}

	if (extraJS) {
		if (extraJS.match(/^MediaWiki:[^&<>=%#]*\.js$/)) {
			mw.loader.load(`/w/index.php?title=${extraJS}&action=raw&ctype=text/javascript`);
		} else {
			mw.notify("Chỉ cho phép các trang từ không gian tên MediaWiki.", {
				title: "Giá trị withJS không hợp lệ"
			});
		}
	}

	/**
	 * WikiMiniAtlas
	 *
	 * Miêu tả: WikiMiniAtlas là một cửa sổ bật lên và kéo bản đồ thế giới.
	 *          Kịch bản này khiến tất cả các liên kết tọa độ của chúng tôi hiển thị nút bật lên WikiMiniAtlas.
	 *          Bản thân đoạn mã nằm trên meta vì nó được sử dụng bởi nhiều dự án.
	 *          Xem [[Meta:WikiMiniAtlas]] để biết thêm thông tin.
	 * Chú ý - nên sử dụng dịch vụ này để thay thế bằng mw:Help:Extension:Kartographer
	 */
	$(() => {
		const require_wikiminiatlas =
			$('a.external.text[href*="geohack"]').length || $("div.kmldata").length;
		if (require_wikiminiatlas) {
			mw.loader.load(
				"//meta.wikimedia.org/w/index.php?title=MediaWiki:Wikiminiatlas.js&action=raw&ctype=text/javascript"
			);
		}
	});

	/**
	 * Bảng có thể thu gọn; được thực hiện với mw-collapsible
	 * Kiểu dáng cũng được đặt ra để tránh FOUC
	 *
	 * Cho phép các bảng được thu gọn, chỉ hiển thị tiêu đề. Xem [[:en:Help:Collapsing]].
	 * @version 3.0.0 (2018-05-20)
	 * @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js
	 * @author [[:en:User:R. Koot]]
	 * @author [[:en:User:Krinkle]]
	 * @author [[:en:User:TheDJ]]
	 * @deprecated Từ MediaWiki 1.20: Dùng class="mw-collapsible" thay vào đó
	 * được hỗ trợ trong lõi MediaWiki. Có thể bắt đầu từ MediaWiki 1.32
	 */
	function makeCollapsibleMwCollapsible($content) {
		const $tables = $content
			.find("table.collapsible:not(.mw-collapsible)")
			.addClass("mw-collapsible");

		$.each($tables, (index, table) => {
			// mw.log.warn( 'This page is using the deprecated class collapsible. Please replace it with mw-collapsible.');
			if ($(table).hasClass("collapsed")) {
				$(table).addClass("mw-collapsed");
				// mw.log.warn( 'This page is using the deprecated class collapsed. Please replace it with mw-collapsed.');
			}
		});
		if ($tables.length > 0) {
			mw.loader.using("jquery.makeCollapsible").then(() => {
				$tables.makeCollapsible();
			});
		}
	}
	mw.hook("wikipage.content").add(makeCollapsibleMwCollapsible);

	/**
	 * Thêm hỗ trợ cho mw-collapsible cho autocollapse, innercollapse và outercollapse
	 *
	 * Bảo trì: TheDJ
	 */
	function mwCollapsibleSetup($collapsibleContent) {
		let $element;
		let $toggle;
		const autoCollapseThreshold = 2;
		$.each($collapsibleContent, (index, element) => {
			$element = $(element);
			if ($element.hasClass("collapsible")) {
				$element
					.find("tr:first > th:first")
					.prepend($element.find("tr:first > * > .mw-collapsible-toggle"));
			}
			if (
				$collapsibleContent.length >= autoCollapseThreshold &&
				$element.hasClass("autocollapse")
			) {
				$element.data("mw-collapsible").collapse();
			} else if ($element.hasClass("innercollapse")) {
				if ($element.parents(".outercollapse").length > 0) {
					$element.data("mw-collapsible").collapse();
				}
			}
			// because of colored backgrounds, style the link in the text color
			// to ensure accessible contrast
			$toggle = $element.find(".mw-collapsible-toggle");
			if ($toggle.length) {
				// Make the toggle inherit text color
				if ($toggle.parent()[0].style.color) {
					$toggle.find("a").css("color", "inherit");
				}
			}
		});
	}

	mw.hook("wikipage.collapsibleContent").add(mwCollapsibleSetup);

	/**
	 * Thanh điều hướng động (thử nghiệm)
	 *
	 * Miêu tả: Xem [[:en:Wikipedia:NavFrame]].
	 * Bảo trì: ĐÃ KHÔNG ĐƯỢC BẢO TRÌ
	 */

	const collapseCaption = "ẩn";
	const expandCaption = "hiện";

	// thiết lập từ trong ngôn ngữ của chúng ta
	const navigationBarHide = `[${collapseCaption}]`;
	const navigationBarShow = `[${expandCaption}]`;

	/**
	 * Hiển thị và ẩn nội dung và hình ảnh (nếu có) của các thanh điều hướng.
	 *
	 * @param {number} indexNavigationBar The index of navigation bar to be toggled
	 * @param {jQuery.Event} event Event object
	 */
	function toggleNavigationBar(indexNavigationBar, event) {
		const navToggle = document.getElementById(`NavToggle${indexNavigationBar}`);
		const navFrame = document.getElementById(`NavFrame${indexNavigationBar}`);
		let navChild;

		if (!navFrame || !navToggle) {
			return false;
		}

		// If shown now
		if (navToggle.firstChild.data === navigationBarHide) {
			for (navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling) {
				if ($(navChild).hasClass("NavContent")) {
					navChild.style.display = "none";
				}
			}
			navToggle.firstChild.data = navigationBarShow;

			// If hidden now
		} else if (navToggle.firstChild.data === navigationBarShow) {
			for (navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling) {
				if ($(navChild).hasClass("NavContent")) {
					navChild.style.display = "block";
				}
			}
			navToggle.firstChild.data = navigationBarHide;
		}

		event.preventDefault();
	}

	/**
	 * Thêm nút hiển/ẩn vào thanh điều hướng.
	 *
	 * @param {jQuery} $content
	 */
	function createNavigationBarToggleButton($content) {
		let j;
		let navChild;
		let navToggle;
		let navToggleText;
		let isCollapsed;
		let indexNavigationBar = 0;
		// Iterate over all < div >-elements
		const $divs = $content.find("div.NavFrame:not(.mw-collapsible)");
		$divs.each((i, navFrame) => {
			indexNavigationBar++;
			navToggle = document.createElement("a");
			navToggle.className = "NavToggle";
			navToggle.setAttribute("id", `NavToggle${indexNavigationBar}`);
			navToggle.setAttribute("href", "#");
			$(navToggle).on("click", $.proxy(toggleNavigationBar, null, indexNavigationBar));

			isCollapsed = $(navFrame).hasClass("collapsed");
			/**
			 * Check if any children are already hidden.  This loop is here for backwards compatibility:
			 * the old way of making NavFrames start out collapsed was to manually add style="display:none"
			 * to all the NavPic/NavContent elements.  Since this was bad for accessibility (no way to make
			 * the content visible without JavaScript support), the new recommended way is to add the class
			 * "collapsed" to the NavFrame itself, just like with collapsible tables.
			 */
			for (
				navChild = navFrame.firstChild;
				navChild !== null && !isCollapsed;
				navChild = navChild.nextSibling
			) {
				if ($(navChild).hasClass("NavPic") || $(navChild).hasClass("NavContent")) {
					if (navChild.style.display === "none") {
						isCollapsed = true;
					}
				}
			}
			if (isCollapsed) {
				for (navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling) {
					if ($(navChild).hasClass("NavPic") || $(navChild).hasClass("NavContent")) {
						navChild.style.display = "none";
					}
				}
			}
			navToggleText = document.createTextNode(isCollapsed ? navigationBarShow : navigationBarHide);
			navToggle.appendChild(navToggleText);

			// Tìm NavHead và đính kèm liên kết chuyển đổi (Phải phức tạp vì việc xử lý đầu tiên của Moz bị cấm)
			for (j = 0; j < navFrame.childNodes.length; j++) {
				if ($(navFrame.childNodes[j]).hasClass("NavHead")) {
					navToggle.style.color = navFrame.childNodes[j].style.color;
					navFrame.childNodes[j].appendChild(navToggle);
				}
			}
			navFrame.setAttribute("id", `NavFrame${indexNavigationBar}`);
		});
	}

	mw.hook("wikipage.content").add(createNavigationBarToggleButton);

	/**
	 * Thông báo sửa đổi ma thuật ****************************************************
	 *
	 * Mô tả: Thêm thông báo sửa đổi cho trang định hướng và TSNDS.
	 * Bảo trì: [[:en:User:RockMFR]]
	 */
	function addEditIntro(name) {
		$(".mw-editsection, #ca-edit, #ca-ve-edit")
			.find("a")
			.each(function (i, el) {
				el.href = `${$(this).attr("href")}&editintro=${name}`;
			});
	}

	if (mw.config.get("wgNamespaceNumber") === 0) {
		$(() => {
			if (document.getElementById("disambigbox")) {
				addEditIntro("Bản_mẫu:Disambig_editintro");
			}
		});

		$(() => {
			const cats = mw.config.get("wgCategories");
			if (!cats) {
				return;
			}
			if (
				$.inArray("Nhân vật còn sống", cats) !== -1 ||
				$.inArray("Nhân vật có thể còn sống", cats) !== -1
			) {
				addEditIntro("Bản_mẫu:BLP_editintro");
			}
		});
	}

	/* Các hành động cụ thể cho trang sửa đổi */
	if (mw.config.get("wgAction") === "edit" || mw.config.get("wgAction") === "submit") {
		/**
		 * Sửa lỗi nhắc tóm tắt để hoàn tác
		 *
		 *  Khắc phục chức năng hoàn tác kết hợp với "nhắc nhở tóm tắt không sửa đổi"
		 *  thực tế phàn nàn về việc sửa đổi bị thiếu, nếu để nguyên bản tóm tắt sửa đổi.
		 *  Thêm bởi [[:en:User:Deskana]], mã bởi [[:en:User:Tra]].
		 *  Xem thêm [[phab:T10912]].
		 */
		$(() => {
			if (
				document.location.search.indexOf("undo=") !== -1 &&
				document.getElementsByName("wpAutoSummary")[0]
			) {
				document.getElementsByName("wpAutoSummary")[0].value = "1";
			}
		});
	}

	/* MÃ DÀNH RIÊNG CHO WIKIPEDIA TIẾNG VIỆT */
	/* Dùng để đảm bảo Wikipedia Tiếng Việt hoạt động đúng do một số hệ thống vẫn dùng mã giao diện cũ */

	/* Kết các đoạn mã lưu bên ngoài */

	if (
		mw.config.get("wgAction") === "edit" ||
		mw.config.get("wgAction") === "submit" ||
		mw.config.get("wgCanonicalSpecialPageName") === "Upload"
	) {
		// Mã chỉ dành riêng cho trang sửa đổi
		importScript("MediaWiki:Common.js/edit.js");
	} else if (mw.config.get("wgCanonicalSpecialPageName") === "Watchlist") {
		// Mã chỉ dành riêng cho danh sách theo dõi
		importScript("MediaWiki:Common.js/watchlist.js");
	}

	/* Sửa kết xuất phông chữ Unicode trên Windows XP */
	if (navigator.appVersion.search(/windows nt 5/i) !== -1) {
		mw.util.addCSS(
			'.IPA { font-family: "Lucida Sans Unicode", "Arial Unicode MS"; } ' +
				'.Unicode { font-family: "Arial Unicode MS", "Lucida Sans Unicode"; } '
		);
	}

	/** Liên kết interwiki đến các bài chọn lọc ***************************************
	 *
	 *  Chức năng: Chuyển dấu chấm trước các liên kết liên wiki của các bài chọn lọc
	 *             thành dấu sao
	 *  Người bảo trì: [[:en:User:R. Koot]]
	 */
	function LinkFA() {
		if (document.getElementById("p-lang")) {
			const InterwikiLinks = document.getElementById("p-lang").getElementsByTagName("li");

			for (let i = 0; i < InterwikiLinks.length; i++) {
				const className = InterwikiLinks[i].className.match(/interwiki-[-\w]+/);
				if (
					document.getElementById(`${className}-fa`) &&
					InterwikiLinks[i].className.indexOf("badge-featuredarticle") === -1
				) {
					InterwikiLinks[i].className += " FA";
					InterwikiLinks[i].title = "Liên kết này dẫn đến bài chọn lọc.";
				} else if (
					document.getElementById(`${className}-ga`) &&
					InterwikiLinks[i].className.indexOf("badge-goodarticle") === -1
				) {
					InterwikiLinks[i].className += " GA";
					InterwikiLinks[i].title = "Liên kết này dẫn đến bài chất lượng tốt.";
				}
			}
		}
	}
	mw.hook("wikipage.content").add(LinkFA);

	/**
	 * Gắn bảng giới thiệu vào đầu [[Trợ giúp:Chỗ thử]].
	 */
	mw.hook("wikipage.content").add(() => {
		if (
			mw.config.get("wgPageName") !== "Trợ_giúp:Chỗ_thử" ||
			mw.config.get("wgAction") !== "view"
		) {
			return;
		}
		const introp = mw.html.element("div", {id:"sbox"}, "{{Các thông báo sửa đổi/Trang/Trợ giúp:Chỗ thử}}");
		$("#mw-content-text").wrapInner("<div class='sandbox'></div>").prepend(introp);
	});

	/**
	 * Chọn chế độ sửa đổi theo cookie khi bấm liên kết đỏ.
	 */
	mw.hook("wikipage.content").add(() => {
		if (mw.cookie.get("VEE", "") === "wikitext") {
			$(".noarticletext, .searchresults h2")
				.find("a")
				.each((idx, elt) => {
					const uri = new mw.Uri(elt.href);
					if ("veaction" in uri.query) {
						uri.query.action = uri.query.veaction;
						elt.href = uri.toString();
					}
				});
		}
	});

	/**
	 * Cho phép hiện/ẩn phần tử tùy công cụ Biên dịch nội dung được kích hoạt.
	 */
	mw.hook("wikipage.content").add(() => {
		if (Number.parseInt(mw.user.options.get("cx")) === 1) {
			$(document.documentElement).addClass("cx-available");
		}
	});

	/* Cố định liên kết "Tải tập tin lên"
	 */
	mw.hook("wikipage.content").add(() => {
		$("#t-upload a").attr("href", mw.util.getUrl("Wikipedia:Trình tải lên tập tin"));
	});

	// Kết quả từ Wikidata
	// [[:Tập tin:Wdsearch script screenshot.png]]
	if (
		mw.config.get("wgCanonicalSpecialPageName") === "Search" ||
		(mw.config.get("wgArticleId") === 0 && mw.config.get("wgCanonicalSpecialPageName") === false)
	) {
		mw.loader.load(
			"//en.wikipedia.org/w/index.php?title=MediaWiki:Wdsearch.js&action=raw&ctype=text/javascript"
		);
	}

	/**
	 * Mã ẩn các liên kết đến công cụ Dịch nội dung (đặt tạm thời)
	 */

	function hideContentTranslation() {
		if (
			mw.config
				.get("wgUserGroups", [])
				.every(
					(userGroup) => ["sysop", "eliminator", "extendedconfirmed"].indexOf(userGroup) === -1
				)
		) {
			mw.util.addCSS("#cx-language { display: none; }");
			mw.util.addCSS(".cx-campaign-translations { display: none; }");
			mw.util.addCSS(".cx-contributions-translation { display: none; }");
			if (mw.config.get("wgCanonicalSpecialPageName") === "ContentTranslation") {
				mw.loader.using("oojs-ui").then(() => {
					OO.ui
						.alert(
							"Không thể sử dụng công cụ này vì bạn không phải là Thành viên được xác nhận mở rộng."
						)
						.done(() => {
							window.location.href = mw.util.getUrl("Wikipedia:Biên dịch");
						});
				});
			}
		}
	}

	mw.hook("wikipage.content").add(hideContentTranslation);

	/* Hết mã dành cho Wikipedia Tiếng Việt */

	/* Hết gọi mw.loader.using callback */
});

// https://www.mediawiki.org/wiki/ResourceLoader/Migration_guide_(users)#Legacy_removals
// This can be removed once all clients have been updated for this search https://global-search.toolforge.org/?q=hookEvent&regex=1&namespaces=&title=
window.hookEvent = (name, fn) => {
	$(window).on(name, fn);
};
/* KHÔNG THÊM MÃ DƯỚI DÒNG NÀY */