User:A2569875-sandbox/blib-preview.js

维基百科,自由的百科全书

注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。

說明

藍桌圖書館(Bluedeck Library)是一個保存維基百科部分因故被刪除的有價值之條目的圖書館。然而,為了防止圖書館內容對原本的條目、模板、分類系統造成影響,因此藍桌圖書館中的模板和分類會被转义成原始碼狀態來呈現,這樣在閱讀上會有顯著的不便。

因此本插件的功能就是將藍桌圖書館中的模板和分類儘可能還原成條目原始的樣式進行呈現,如左圖的樣式。右圖為藍桌圖書館預設的呈現模式。

安装

这个功能需要在安装了插件之后才会出现。若要安装插件,请访问您的脚本页,通过复制粘贴的方式加入一行代码并保存:

importScript("User:A2569875-sandbox/blib-preview.js"); /*藍桌圖書館預覽*/
$(async ()=>{
	const _addText = "{{Doc}}";
	const page_name = mw.config.values.wgPageName;
	const page_name_lower = page_name.toLowerCase();
	const $new_node = (node=>`<${node}></${node}>`)
	const blib_content_class = "blib-mw-content-text";
	const blib_link_page = "User:Bluedeck/serve/blib-link.js"
	const blib_link_script = mw.util.getUrl(blib_link_page,{action:"raw", ctype:"text/javascript"});
	const $notice_loading = $($new_node("div")).attr("id","mw-bluedecklibrary-preview-loading")
		.append($($new_node("div")).addClass("quotebox")
			.css("margin", "auto").css("width", "50%").css("padding", "6px").css("border", "1px solid #aaa")
			.css("font-size", "88%").css("background-color", "#F9F9F9")
			.append($($new_node("div")).attr("id","mw-_addText-preview-loading-content")
				.css("background-color", "#F9F9F9").css("color", "black").css("text-align", "center").css("font-size", "larger")
				.append($($new_node("img")).attr("src","//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif")
					.attr("decoding","async").attr("data-file-width",32).attr("data-file-height",32)
					.attr("width",32).attr("height",32)
				)
			)
		);
	var mwapi = new mw.Api({ajax: {headers: {'Api-User-Agent': 'BluedeckLibraryPreview/1.0 (' + mw.config.get('wgWikiID') + ')'}}});
	
	function getLanguage(){
		var lang = mw.config.get('wgUserLanguage');
		if(lang.indexOf('zh') > -1) return mw.config.get('wgUserVariant');
		return lang;
	}

	async function get_this_page_wikitext() {
		if(mw.config.values.wgAction === "submit" && ($("#wikiPreview").length||0) > 0) return $("#wpTextbox1").val();
		const request_uri = mw.util.getUrl(page_name,{action:"raw"});
		const response = await fetch(request_uri);
		const response_text = await response.text();
		return response_text;
	}

	function blib_inverse_workload(incoming_text) { //修改自[[user:bluedeck/serve/blib-inverse.js]]
		var card_start = incoming_text.toLowerCase().indexOf("{{user:bluedeck/infr/library.card.js");
		var card_end = incoming_text.substr(card_start).indexOf("}}") + card_start;

		if(card_start !== -1 && card_end !== -1)
			incoming_text = incoming_text.substr(0, card_start) + incoming_text.substr(card_end + 2);

		return incoming_text
			.replace(/<\s*nowiki\s*>\s*(\[\[\s*\:?\s*(cat(egory)?|分[類类])\:(.|[\s])*)<\s*\/\s*nowiki\s*>/ig, "$1")
			.replace(/\[\[\s*\:?\s*(cat(egory)?|分[類类])\s*\:/ig,"[[$1:")
			//.replace(/\{\{\(\(\}\}\s*([^#][^\{\}\n]*)\}\}/g, "{{#invoke:沙盒/a2569875/BluedeckLibraryTemplate|build_template|@&$$$$~~!_template_name_!~~$$$$&@=$1}}")
			//.replace(/\{\{\(\(\}\}\s*\#/g, "{{#")
			//.replace(/\{\{\(\(\}\}/g, "{{#invoke:沙盒/a2569875/BluedeckLibraryTemplate|build_template|@&$$$$~~!_template_name_!~~$$$$&@=")
			.replace(/\{\{\(\(\}\}/g, "{{");
	}
	
	//讓功能可以由按鈕觸發
	async function parse_blib_wikitext(put_back) {
		//有圖書館卡才開始運行
		let page_divs = $(".mw-parser-output div .NavFrame, .blib-preview-card div .NavFrame"); //從條目主體裡的div中尋找圖書館卡
		console.log("藍桌圖書館預覽:進入藍桌圖書館");
		let library_card_meta;
		let library_card;
		let library_before = $($new_node("span"));
		for (let i = 0; i < page_divs.length; ++i) {  //尋找圖書館卡
			let it = page_divs[i];
			let check_text = $(it).text().replace(/\s+/g,"").toLowerCase();
			if ( check_text.startsWith("bluedecklibrary圖書館卡") || //找到圖書館卡
				check_text.startsWith("bluedecklibrary图书馆卡")) {
					library_card_meta = it.parentElement;
					break;
			}
		}
		if(!library_card_meta){
			console.log("藍桌圖書館預覽:找不到圖書館卡,退出。");
			return;
		}
		if(!($(library_card_meta.parentElement).hasClass("mw-parser-output"))) { //外層有別的東西
			let packet = $($new_node("div")); //空的最內層子物件
			//for迴圈:從圖書館卡向外搜索; 搜索到.mw-parser-output停止; 每次往外搜索一層
			for (let pptr = library_card_meta; !!pptr && !($(pptr||$new_node("span")).hasClass("mw-parser-output")); pptr = (pptr||{}).parentElement) {
				if((($(pptr).parent()||{prop:()=>""}).prop("tagName")||"").toLowerCase() === "main") break; //例外狀況的停止條件
				let pptr_parent = pptr.parentElement;
				let child_items = $($new_node("div")); //包裝子物件的容器
				for (let i = 0; i < pptr_parent.childNodes.length; ++i) { //包裝子物件
					if (pptr_parent.childNodes[i] === pptr) break; //包到目前的物件為止(不含目前的物件)
					child_items.append($(pptr_parent.childNodes[i])); //包裝進子物件容器
				}
				child_items.append($(packet)); //子物件容器裝進來自上一層迴圈(底層)的容器
				packet = $($new_node("div")).append($(child_items)); //容器更新為,包裝了剛剛那些子物件的容器
			}
			library_before = packet;
		}
		if (library_card_meta !== undefined) { //如果圖書館卡本體存在
			let lib_flag = library_card_meta.nextSibling; //嘗試搜尋圖書館卡flag
			while(((lib_flag||{}).nodeName||"").toLowerCase() != "div") {
				if ((lib_flag||{}).nextSibling) {
					lib_flag = lib_flag.nextSibling;
				} else break;
			}
			if (((lib_flag||{}).nodeName||"").toLowerCase() == "div") { //取到了有效的圖書館卡
				console.log("藍桌圖書館預覽:取得圖書館卡...");
				$(lib_flag).after($notice_loading);
				const this_page_wikitext = await get_this_page_wikitext(); //取得原始維基代碼
				const text_after_blib_inverse = blib_inverse_workload(this_page_wikitext); //還原藍桌圖書館代碼
				try {
					const data = await mwapi.post({ //解析藍桌圖書館頁面原碼解的API參數
						action: 'parse',
						uselang: getLanguage(),
						useskin: mw.config.get('skin'),
						title: (/User:Bluedecklibrary[\\\/]([^\n]+)$/i.exec(page_name)||[])[1]||page_name,
						text: text_after_blib_inverse, //已還原的藍桌圖書館代碼
						contentmodel: "wikitext",
						prop: "text|categorieshtml|categories", //包含原始結果與分類
						format: 'json'
					}); //送交wikitext解析
					if (!data || !data.parse || !data.parse.text || !data.parse.text['*']) { //解析失敗
						console.log("藍桌圖書館預覽:錯誤:藍桌圖書館頁面原碼解析失敗。");
						return; 
					}
					console.log("藍桌圖書館預覽:藍桌圖書館頁面原碼解析完畢。");
					let parsed_wiki = (data.parse.text['*'] || '').toString().trim(); //解析後的wikitext
					let cat_list = data.parse.categories || []; //解析後的分類列表
					let parsed_cats = (data.parse.categorieshtml['*'] || '').toString().trim(); //解析後的分類HTML元素
					if (parsed_wiki !== '') {
						console.log("藍桌圖書館預覽:正在部署藍桌圖書館預覽...");
						library_card = $('<div></div>').addClass("blib-preview-card"); //圖書館卡的容器
						library_card.append(library_before);
						library_card.append(library_card_meta); //裝入圖書館卡本體
						library_card.append(lib_flag); //裝入圖書館卡flag
						$mw_content_text = $("#mw-content-text").find(".mw-parser-output"); //抓取條目主體
						let $ptr = $mw_content_text; //搜尋條目主體節點
						while((($ptr.parent()||{prop:()=>""}).prop("tagName")||"").toLowerCase()!=="main") {
							$ptr = $ptr.parent();
							if ($ptr.length <= 0){ 
								$ptr = $($("#content.mw-body")[0].firstChild || document.querySelector("#bodyContent") || $mw_content_text);
								break;
							}
						}
						let $page_main = $ptr.parent(); //條目主體節點
						let $content_container = $page_main.parent() || $(".mw-content-container"); //條目內容容器節點
						let $footer_container = $(($content_container[0]||{nextElementSibling:$new_node("span")}).nextElementSibling); //條目底部節點
						let $parsed_wiki = $(parsed_wiki);
						
						$parsed_wiki.addClass(blib_content_class);
						let body = $mw_content_text //條目主體的HTML element
							.html("")	//先清空,等待替換 
							.append(library_card)	//補回圖書館卡
							.append($parsed_wiki); //貼進解析完的條目內容
						if (cat_list.length > 0) { //加入分類
							let $parsed_cats = $(parsed_cats);
							if ($("#catlinks").hasClass("catlinks-allhidden") && !$parsed_cats.hasClass("catlinks-allhidden")) {
								$("#catlinks").removeClass("catlinks-allhidden"); //如果有分類,且原始分類欄位被隱藏 就取消隱藏
							}
							$("#catlinks")[0].innerHTML = $parsed_cats[0].innerHTML || ''; //替換分類顯示欄位的內容為解析後的分類
							$footer_container.css("padding-top",0); //分類下方的空格移除
						}
						let $blib_content_class = $(`.${blib_content_class}`);
						$(".redirectText > li").css("background", "transparent url(/w/resources/src/mediawiki.action/images/redirect-ltr.svg?ff441) bottom left no-repeat").css("padding-left","47px");
						$(".redirectMsg > p").html("重新導向頁面");
						mw.hook('wikipage.content').fire($blib_content_class);
						await $.getScript(blib_link_script);
						setTimeout(function(){
							$blib_preview_card = $(".blib-preview-card");
							if ($blib_preview_card.length > 0) //移除圖書館卡中的重複元素
								$blib_preview_card.find(".bldk_dom_id_fbc2343a21e23222a82b9891f175532b8").html("");
							if (put_back) {
								$mw_content_text.prepend($($new_node("button"))
									.attr("onclick","mw.blib.blib_putback()").html("還原圖書館文章預覽")
								);
							}
						}, 500);
					    console.log("藍桌圖書館預覽:成功預覽藍桌圖書館!");
					}
				} catch (api_ex) { 
					console.log(`藍桌圖書館預覽:發生錯誤:\n${api_ex}。`);
				}
			}
		}
	}
	
	async function blib_putback() {
		const request_uri = mw.util.getUrl(page_name,{action:"raw"});
		const response = await fetch(request_uri);
		$mw_content_text = $("#mw-content-text").find(".mw-parser-output"); //抓取條目主體
		$(($mw_content_text[0])||{prepend:()=>0}).prepend($($notice_loading));
		try {
			const data = await mwapi.post({
				action: 'parse',
				uselang: getLanguage(),
				useskin: mw.config.get('skin'),
				title: page_name,
				text: await response.text(),
				contentmodel: "wikitext",
				prop: "text",
				format: 'json'
			});
			if (!data || !data.parse || !data.parse.text || !data.parse.text['*']) return; //解析失敗
			let parsed_wiki = (data.parse.text['*'] || '').toString().trim(); //解析後的wikitext
			if (parsed_wiki !== '') {
				$mw_content_text.html(parsed_wiki);
				mw.hook('wikipage.content').fire($mw_content_text);
				$mw_content_text.prepend($($new_node("button"))
					.attr("onclick","mw.blib.parse_blib_wikitext(true)").html("顯示圖書館文章預覽")
				);
			}
		} catch (API_ex) { }
	}

	mw.blib = mw.blib || {};
	mw.blib.parse_blib_wikitext = parse_blib_wikitext;
	mw.blib.blib_putback = blib_putback;
	//只有藍桌圖書館頁面才要運作
	if (page_name_lower.trim().startsWith("user:bluedecklibrary/")){
		//只有 "view" 模式才要運作
		if(mw.config.values.wgAction !== "view") {
			if(mw.config.values.wgAction === "submit" && ($("#wikiPreview").length||0) > 0) {
				$("#mw-content-text").find(".mw-parser-output").prepend($($new_node("button"))
					.attr("onclick","mw.blib.parse_blib_wikitext(true)").html("顯示圖書館文章預覽")
				);
			}
			return;
		}
		parse_blib_wikitext();
	}
});