全站通知:

烟雨江湖:Tooltip演示

来自烟雨江湖WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

什么是Tooltip

安装

  • 安装必须拥有 管理员小部件编辑者 权限,普通用户请跳过此章节

正式版

  • 推荐方法此方法安装后,能自动同步更新
1、在 https://wiki.biligame.com/你管理的BWIKI/MediaWiki:Gadget-section-Editing 页面添加标题文字
编辑
注意:如果已有标题文字则跳过此步
2、在 https://wiki.biligame.com/你管理的BWIKI/MediaWiki:Gadgets-definition 页面添加标题代码
==Editing==
注意:如果已有 ==Editing== 标题则跳过此步
3、在==Editing==标题下添加以下代码
* Tooltip  [ResourceLoader|default] | Tooltip.js | Tooltip.css
4、在 https://wiki.biligame.com/你管理的BWIKI/MediaWiki:Gadget-Tooltip 页面添加以下描述
'''Tooltip''': 。
5、在 https://wiki.biligame.com/你管理的BWIKI/MediaWiki:Gadget-Tooltip.css 页面添加以下代码
body>#bili-tt-cache-block{
	position: fixed;
    z-index: 999;
}
#bili-tt-cache-block{
	display: none;
	border:#000 solid 1px;
}
 
/* 模态框 */
#tt-modal>.modal-dialog{
	display: flex;
    flex-direction: column;
    justify-content: center;
	min-height: 100%;
	margin: 0; /* 避免影响height计算*/
}
#tt-modal #bili-tt-cache-block {
    margin: 20px;
}
#tt-modal .bili-tt-cache{
    position: relative;
}
#tt-modal .btn{
    display: block;
    margin: 10px;
    font-size: 18px;
}
注意:其中#bili-tt-cache-block是浮动窗的样式,转载用户可以修改此项
6、在 https://wiki.biligame.com/你管理的BWIKI/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; // 解析内容保存在服务器和本地的缓存时间,单位是秒,如果内容不经常改的话,可以设长一些减少服务器压力,增加读取速度
	var SMALL_SCREEN = window.innerWidth < 768;
	
	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 (!SMALL_SCREEN){
		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').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').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, SMALL_SCREEN ? 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 + '}}'; // 调用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/wiki/api.php?action=help&modules=parse
		return $.get('/yanyu/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> */
注意:其中要将末尾的return $.get('/yanyu/api.php',{中的yanyu改成本地站名就可以实现本地化
  • 至此已完成安装,在 参数设置 中勾选后即可启用。

使用方法

  • 请针对不同的使用需求选择最适合的使用方式。

插入普通文本

普通文本

<span class="bili-tt" data-type="raw" data-name="456">普通文本</span>

方式2

解析wikitext

<span class="bili-tt" data-type="wikitext" data-name="<nowiki>[[file:Chenyuanfeng.png|link=]]</nowiki>">解析wikitext</span>

方式3

将tooltip写在内部

<span class="bili-tt" data-type="child">将tooltip写在内部<span class="tt-child" style="display:none">内容</span></span>

方式4

以name为参数,调用指定模块的tooltip方法

<span class="bili-tt" data-type="$GongFa" data-name="吐纳法">以name为参数,调用指定模块的tooltip方法</span>

方式5

以name为参数,调用指定模板

<span class="bili-tt" data-type="@物品悬浮" data-name="白炼石">以name为参数,调用指定模板</span>