MediaWiki:Gadget-Tooltip.js:修订间差异

(创建页面,内容为“→‎<nowiki> ← 避免被归类为有脚本错误的页面:​ // 当添加新类型浮层时,需要对应在“★”注释之后的部分添加代码 $(function (){ if (!['view', 'submit'].includes(mw.config.get('wgAction'))) return; var TOOLTIP_CACHE_BLOCK_ID = 'bili-tt-cache-block'; if (document.getElementById(TOOLTIP_CACHE_BLOCK_ID)) return; →‎避免重复调用:​ var TOOLTIP_CACHE_BLOCK = $(); var Link_CLASS_NAME = 'bili-tt'; var CACHE_TIME = 3600…”
 
无编辑摘要
第8行: 第8行:
var Link_CLASS_NAME = 'bili-tt';
var Link_CLASS_NAME = 'bili-tt';
var CACHE_TIME = 3600; // 解析内容保存在服务器和本地的缓存时间,单位是秒,如果内容不经常改的话,可以设长一些减少服务器压力,增加读取速度
var CACHE_TIME = 3600; // 解析内容保存在服务器和本地的缓存时间,单位是秒,如果内容不经常改的话,可以设长一些减少服务器压力,增加读取速度
var SMALL_SCREEN = window.innerWidth < 768;
var actions = {};
var actions = {};
第35行: 第34行:
return link;
return link;
};
};
if (!SMALL_SCREEN){
if (!fIsMobile()){
actions.listen = function(link){
actions.listen = function(link){
$(link).mouseenter(function(ev){
$(link).mouseenter(function(ev){
第72行: 第71行:
$div.show();// 显示对应的内容
$div.show();// 显示对应的内容
TOOLTIP_CACHE_BLOCK.show();
TOOLTIP_CACHE_BLOCK.show();
$('#tt-modal').modal('show'); // 显示模态框
$('#tt-modal').show(); // 显示模态框
var $btn = $('#tt-modal-btn');
var $btn = $('#tt-modal-btn');
if ($this.attr('href')){ // 跳转按钮
if ($this.attr('href')){ // 跳转按钮
第95行: 第94行:
TOOLTIP_CACHE_BLOCK = $('#' + TOOLTIP_CACHE_BLOCK_ID);
TOOLTIP_CACHE_BLOCK = $('#' + TOOLTIP_CACHE_BLOCK_ID);
$('#tt-modal').click(function(){
$('#tt-modal').click(function(){
$('#tt-modal').modal('hide'); // 任意位置点击后隐藏模态框
$('#tt-modal').hide(); // 任意位置点击后隐藏模态框
TOOLTIP_CACHE_BLOCK.children('.bili-tt-cache').hide();
TOOLTIP_CACHE_BLOCK.children('.bili-tt-cache').hide();
});
});
第123行: 第122行:
var $div = $(document.getElementById(get_div_id(tt_type,tt_name)));
var $div = $(document.getElementById(get_div_id(tt_type,tt_name)));
if ($div.length === 0){
if ($div.length === 0){
$div = new_div($link, SMALL_SCREEN ? null : function(){set_position($link);});
$div = new_div($link, fIsMobile() ? null : function(){set_position($link);});
}
}
return $div;
return $div;

2024年3月25日 (一) 10:51的版本

/* <nowiki> ← 避免被归类为有脚本错误的页面*/
// 当添加新类型浮层时,需要对应在“★”注释之后的部分添加代码
$(function (){
	if (!['view', 'submit'].includes(mw.config.get('wgAction'))) return;
	var TOOLTIP_CACHE_BLOCK_ID = 'bili-tt-cache-block';
	if (document.getElementById(TOOLTIP_CACHE_BLOCK_ID)) return; /* 避免重复调用 */
	var TOOLTIP_CACHE_BLOCK = $();
	var Link_CLASS_NAME = 'bili-tt';
	var CACHE_TIME = 3600; // 解析内容保存在服务器和本地的缓存时间,单位是秒,如果内容不经常改的话,可以设长一些减少服务器压力,增加读取速度
	
	var actions = {};
	actions.replace = function(block){ // 提取块中的第一个<a>的地址,并将整个块替换为<a>
		var inner_link = block.querySelector('a[href]'); // 获取块内的第一个a,获取其href和title,然后移除
		if (!inner_link) return block;
		
		var link = document.createElement('a');
		link.setAttribute('href', inner_link.getAttribute('href'));
		if (inner_link.innerHTML.trim() !== ""){
			var span = document.createElement('span');
			span.innerHTML = inner_link.innerHTML;
			inner_link.parentElement.insertBefore(span, inner_link);
		}
		inner_link.remove();
		
		var attrs = block.attributes;
		for(var i = attrs.length - 1; i >= 0; i--){ // 转移各项属性
			var attr = attrs[i];
			block.removeAttributeNode(attr);
			link.setAttributeNode(attr);
		}
		link.innerHTML = block.innerHTML;
		block.parentElement.insertBefore(link, block); // 取代位置
		block.remove();
		return link;
	};
	if (!fIsMobile()){
		actions.listen = function(link){
			$(link).mouseenter(function(ev){
				var $this = $(this);
				var $div = get_div($this);
				$this.data('event',ev); // 记录鼠标位置,用于在load_tooltip_lua后重新set_tt_position
 
				$div.show();
				TOOLTIP_CACHE_BLOCK.show();
				set_position($this);
			}).mouseleave(function(){
				var $this = $(this);
				TOOLTIP_CACHE_BLOCK.hide();
				get_div($this).hide();
			});
		};
		actions.init = function(range){
			// 添加缓存浮层的区域
			if (TOOLTIP_CACHE_BLOCK.length === 0){
				$("body").append('<div id="' + TOOLTIP_CACHE_BLOCK_ID + '"></div>');
				TOOLTIP_CACHE_BLOCK = $('#' + TOOLTIP_CACHE_BLOCK_ID);
			}
	
			// 为所有浮层添加事件
			$(range).find('.' + Link_CLASS_NAME).addBack('.' + Link_CLASS_NAME).each(function(){
				actions.listen(actions.replace(this));
			});
		};
	}
	else {
		actions.listen = function(link) {
			$(link).click(function(){
				var $this = $(this);
				var $div = get_div($this);
 
				$div.show();// 显示对应的内容
				TOOLTIP_CACHE_BLOCK.show();
				$('#tt-modal').show(); // 显示模态框
				var $btn = $('#tt-modal-btn');
				if ($this.attr('href')){ // 跳转按钮
					$btn.attr('href', $this.attr('href'));
					$btn.show();
				}
				else{ // 如果不是链接,隐藏按钮
					$btn.hide();
				}
				return false;
			});
		};
		actions.init = function(range){
			if (TOOLTIP_CACHE_BLOCK.length === 0){
				$("body").append('<div class="modal fade" id="tt-modal" tabindex="-1" role="dialog">'
					+ '<div class="modal-dialog">'
						+ '<div id="' + TOOLTIP_CACHE_BLOCK_ID + '">'
						+ '</div>'
						+ '<a id="tt-modal-btn" class="btn btn-primary">前往详情页</a>'
					+ '</div>'
				+ '</div>');
				TOOLTIP_CACHE_BLOCK = $('#' + TOOLTIP_CACHE_BLOCK_ID);
				$('#tt-modal').click(function(){
					$('#tt-modal').hide(); // 任意位置点击后隐藏模态框
					TOOLTIP_CACHE_BLOCK.children('.bili-tt-cache').hide();
				});
			}
			
			$(range).find('.' + Link_CLASS_NAME).addBack('.' + Link_CLASS_NAME).each(function(){
				actions.listen(actions.replace(this));
			});
		};
	}
	
	actions.init(document.getElementById('mw-content-text'));
	
	// 监听dom变动,为新插入的tt注册事件
	new MutationObserver(function(mutationsList){
		mutationsList.forEach(function(mutation){
			if (mutation.addedNodes) mutation.addedNodes.forEach(actions.init);
		});
	}).observe(document.getElementById('mw-content-text'), {
		childList: true, // 监视节点增删事件
		subtree: true // 包含所有后代节点(而不只是子节点)
	});
	
	function get_div($link){
		var tt_type = get_data($link, 'type');
		var tt_name = get_data($link, 'name').replace(' ', '_');
		var $div = $(document.getElementById(get_div_id(tt_type,tt_name)));
		if ($div.length === 0){
			$div = new_div($link, fIsMobile() ? null : function(){set_position($link);});
		}
		return $div;
	}
	function get_div_id(type, name){
		return encodeURIComponent('tt-' + type + '-' + name).replace(/%/g,'.').replace(/[~'!()*]/g,'_');
	}
	
	function get_data($node, name){
		return $node.attr("data-" + name) || "";
	}
 
	// 根据浮层大小和当前元素的位置,决定浮层的位置(尽量让浮层显示在屏幕中)
	function set_position($link) {
		var window_h = $(window).height();
		var window_w = $(window).width();
		var top = $link.offset().top - $(document).scrollTop();
		var left = $link.offset().left; // 元素左侧绝对位置,若发生换行则为第二行的开始位置
		var width = $link.outerWidth();
		var parent = $link.parent();
		var relativeLeft = $link[0].offsetLeft; // 元素第一行左侧相对于容器的位置
		var ttWidth = TOOLTIP_CACHE_BLOCK.outerWidth();
		var ttHeight = TOOLTIP_CACHE_BLOCK.outerHeight();
		
		TOOLTIP_CACHE_BLOCK.css("left","unset");
		TOOLTIP_CACHE_BLOCK.css("right","unset");
		if (relativeLeft + width > parent.innerWidth()){ // 元素左侧相对偏移+元素外侧宽度>容器内侧宽度,发生换行
			var mouseEvent = $link.data('event');
			if (mouseEvent.clientX > window_w / 2){ // 鼠标在左侧
				TOOLTIP_CACHE_BLOCK.css("right", window_w - (left + relativeLeft) + 10); // 元素第一行的左侧位置
			}
			else {
				TOOLTIP_CACHE_BLOCK.css("left", mouseEvent.clientX + 10); // 鼠标滑入位置
			}
		}
		else if (left > window_w / 2){
			TOOLTIP_CACHE_BLOCK.css("right", window_w - left + 10);
		}
		else {
			TOOLTIP_CACHE_BLOCK.css("left", left + width + 10);
		}
 
		if (ttWidth > window_h){
			top = 10;
		}
		else if (top + ttHeight > window_h){
			top = window_h - ttHeight - 10;
		}
 
		TOOLTIP_CACHE_BLOCK.css("top", top);
		
	}
 
	// 生成浮层
	function new_div($link, callback){
		callback = callback || function(){};
		var tt_type = get_data($link, 'type');
		if (tt_type === 'child'){
			$link.attr('data-name', Math.random().toString().replace('0.',''));
		}
		var tt_name = get_data($link, 'name').replace(' ', '_');
		var $div = $('<div></div>');
		$div.attr('id', get_div_id(tt_type,tt_name)).addClass('bili-tt-cache');
		// 可以为每种type的浮层,写不同的占位文本
		// 如果浮层内容简单,也可以直接将其内容使用js生成
		switch (tt_type){
			// 可以写多种类型
			// ★添加类型时,需要在此处添加新的case来为不同类型指定未加载前的占位代码
			// case 'test':
			//	 ...
			//	 break;
			case 'raw':
				$div.text(tt_name);
				break;
			case 'child':
				$link.children('.tt-child').show().appendTo($div);
				break;
		}
		$div.appendTo(TOOLTIP_CACHE_BLOCK);
		
		// 异步读取模板解析结果
		// 如果提示框内容比较简单,则可以在上面用js直接生成,不需要在此处配置
		var wikitext = '';
		switch (tt_type.slice(0,1)){
            case '@': // 模板
                var template_name = tt_type.slice(1);
				wikitext = '{{' + template_name + '|' + tt_name.replace('_', '').replaceAll('\\n', '<br>') + '}}'; // 调用tt_type对应的模板,参数为tt_name
				break;
            case '$': // 模块
                var module_name = tt_type.slice(1);
				wikitext = '{{#invoke:' + module_name + '|tooltip|' + tt_name + '}}'; // 调用tt_type对应模块的tooltip方法,参数为tt_name
                break;
			default:
				switch (tt_type){
					case 'test':
						wikitext = '{{#if:1|test|' + tt_name + '}}';
						break;
					case 'wikitext':
						wikitext = tt_name;
						break;
				}
		}
		if (wikitext){
			$div.text('加载中...');
			load_wikitext(wikitext, $div).then(callback);
		}
		else{
			callback();
		}
		
		return $div;
	}
	
	// 根据wikitext生成浮层内容
	function load_wikitext(wikitext, $div, again) {
		// 文档:https://wiki.biligame.com/pcr/api.php?action=help&modules=parse
		return $.get('/hs/api.php',{
			action: "parse", // 解析
			format: "json", // 返回内容的格式
			disablelimitreport: true, // 不返回使用内存、时间信息
			prop: "text", // 返回解析后的文本
			contentmodel: "wikitext", // 内容模型
			smaxage: CACHE_TIME,
			maxage: CACHE_TIME,
			text: wikitext, // 待解析文本
			_: mw.config.get('debug') ? Date.now() : null // 调试时不使用缓存
		}).then(function(result){
			if (result && result.parse && result.parse.text){
				$div.html(result.parse.text['*']);
			}
			else{
				throw result;
			}
		})['catch'](function(error){ // 辣鸡解析器,不让我直接.catch
			if(again){
				$div.text('读取失败');
				console.log('获取"' + wikitext + '"失败', error);
			}
			else{
				$div.text('再次尝试...');
				return load_wikitext(wikitext, $div, true);
			}
		});
	}
});
/* </nowiki> */