// ==UserScript==
// @name 百度贴吧图片点击放大
// @namespace https://greasyfork.org/users/51104
// @version 1.5.11.20170331
// @description 直接在当前页面查看图片(包括签名档)原图,支持原图的多开、拖拽、缩放和垂直或水平的滚动
// @include *://tieba.baidu.com/p/*
// @include *://tieba.baidu.com/f?*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @author lliwhx
// @copyright Copyright 2016-2017 lliwhx
// @license MIT License
// ==/UserScript==
(function(window) {
"use strict";
//CSS
GM_addStyle(".BDE_Image,.j_user_sign{cursor:alias;}#Tie_enlargeImage_parentDIV{position:fixed;z-index:1005;top:0;left:0;}.Tie_enlargeImage{position:absolute;box-shadow:1px 1px 10px #000;cursor:move;}.Tie_enlargeImage:hover{z-index:1006;}#Tie_setValue_DIV{position:fixed;top:0;left:0;width:100%;height:100%;z-index:9999;background:rgba(0,0,0,0.5);}.Tie_definedDIV{position:absolute;z-index:10000;background:#fff;top:50%;left:50%;transform:translate(-50%,-50%);}.Tie_definedDIV_title{border-bottom:1px solid #f2f2f5;line-height:40px;font-size:15px;font-weight:700;padding:0 0 0 15px;}.Tie_definedDIV_point{padding:20px 40px;}.Tie_definedDIV_groupSubtitle{font-weight:bold;}.Tie_definedDIV_configItem{line-height:30px;margin:0 20px}.Tie_definedDIV_configItem select{margin:0.5em}.Tie_definedDIV_configItem br+label{margin-left:3em}.Tie_definedDIV_configItem input{vertical-align:middle;margin-right:0.5em}#Tie_debugConfig{margin:0.5em}.Tie_debugConfig_icon{position:relative;display:inline-block;top:4px;width:16px;height:16px;background-position:-350px -100px;background-image:url('https://img.t.sinajs.cn/t6/style/images/common/icon.png');background-repeat:no-repeat;}.Tie_bubble_DIV{position:absolute;visibility:hidden;max-width:280px;top:20%}.Tie_definedDIV_configItem label:hover+.Tie_bubble_DIV{visibility:visible}.Tie_bubble_content{position:relative;background:#fff;padding:6px 13px 6px 16px;border:1px solid #ccc;border-radius:3px;}.Tie_bubble_mainTxt{line-height:18px;}.Tie_bubble_bor{position:absolute;overflow:hidden;bottom:-14px;line-height:14px;}.Tie_bubble_line{border-color:#ccc transparent transparent transparent;}.Tie_bubble_br{margin:-1px 0 0 -14px;border-color:#fff transparent transparent transparent;}.Tie_bubble_bor i,.Tie_bubble_bor em{display:inline-block;width:0;height:0;border-width:7px;border-style:solid;vertical-align:top;overflow:hidden;}.Tie_definedDIV_SaveBtn{background-color:#f2f2f5;text-align:center;padding:10px 0;}.Tie_SaveBtn_a{background:#ff8140;color:#fff;font-size:15px;display:inline-block;padding:0 15px;line-height:35px;border-radius:3px;}.Tie_SaveBtn_a:hover{background:#f7671d}");
//数据缓存
var imageTarget,imageMouse,imageCount,imageButton,winResize,scriptDebug,log = function(){},
mouseWheel = /Firefox/.test(navigator.userAgent)?"DOMMouseScroll":"mousewheel",
protocol = window.location.protocol||"http",
doc = window.document,
docHeight = doc.documentElement.clientHeight-6,
docWidth = doc.documentElement.clientWidth-6,
parentElement = doc.getElementById("j_p_postlist"),
definedEvent = GM_getValue("definedEvent","click,click,1,0,1").split(","),
repairDefinedEvent = GM_getValue("repairDefinedEvent",false),
imageEvent = {
init:function(e){ //主事件
var target = e.target,image,imageSrc;
if(e.button===0&&(target.className==="BDE_Image"||target.className==="j_user_sign")){
log("图片创建","开始");
imageSrc = target.src.match(/(baidu\.com|poco\.cn)\/.+\/(\w+\.[a-zA-Z]{3,4})(?:\?v=tbs)?$/);
log("图片地址获取",function(){if(imageSrc)return "成功";else return "失败";},target.src);
if(!imageSrc) return false;
image = doc.createElement("img");
image.classList.add("Tie_enlargeImage");
image.src = imageSrc[1]==="baidu.com"?protocol + "//imgsrc.baidu.com/forum/pic/item/" + imageSrc[2]:target.src;
image.onerror = function(){
if(protocol==="https:"){
log("图片请求","https转向http");
protocol = "http:";
this.src = "http://imgsrc.baidu.com/forum/pic/item/" + imageSrc[2];
}else{
this.onerror = null;
this.onload = null;
imageSrc = null;
log("图片请求","失败");
alert("图片获取失败\n\n如多次获取失败\n请在设置里勾选“调试脚本”打印脚本日志并截图反馈给作者,以便更好的解决问题");
}
};
image.onload = function(){
log("图片创建","进行中");
var target = this,width = target.width,height = target.height,
Wboolean = width>docWidth,Hboolean = height>docHeight,
X = 6,Y = 6;
target.onerror = null;
target.onload = null;
imageSrc = null;
if(Hboolean&&!Wboolean)X = (docWidth-width)/2;
else if(!Hboolean&&!Wboolean){X = (docWidth-width)/2;Y = (docHeight-height)/2;}
else if(!Hboolean&&Wboolean)Y = (docHeight-height)/2;
target.imageData = {width:width,height:height,X:X,Y:Y}; //缓存当前图片数据
target.style.transform = "translate("+X+"px,"+Y+"px)";
parentDIV.appendChild(target);
log("图片创建",function(){target.id = Date.now();if(doc.getElementById(target.id))return "成功";else return "失败";},target.imageData);
};
image = null;
}
},
StopPropagation:function(e){
if(e.button===0&&e.target.className==="BDE_Image"){
e.stopPropagation(); //阻止冒泡,阻止图片原事件
log("阻止贴吧图片原事件","已执行");
}
},
Down:function(e){
var target = e.target,imageData = target.imageData;
imageTarget = target;
log("鼠标down事件",function(){if(!target.id)target.id = Date.now();return "开始";});
if (e.button!==0)return false;
e.preventDefault();
e.stopPropagation();
imageMouse = [e.clientX,e.clientY];
imageCount = [imageData.X-imageMouse[0],imageData.Y-imageMouse[1],6-imageData.width,6-imageData.height]; //图片宽高的偏移量,图片左右边界预留量
imageButton = true;
doc.addEventListener("mousemove",imageEvent.Move);
doc.addEventListener("mouseup",imageEvent.Up);
log("鼠标down事件","结束");
},
Move:function(e){
log("鼠标move事件","开始");
var target = imageTarget,
X = e.clientX+imageCount[0],
Y = e.clientY+imageCount[1];
imageButton = false;
log("鼠标move事件","进行中","X:"+X+"Y:"+Y);
if(X<imageCount[2]){ //左边界
target.style.transform = "translate("+imageCount[2]+"px,"+Y+"px)";
return false;
}
if(X>docWidth){ //右边界
target.style.transform = "translate("+docWidth+"px,"+Y+"px)";
return false;
}
if(Y<imageCount[3]){ //上边界
target.style.transform = "translate("+X+"px,"+imageCount[3]+"px)";
return false;
}
if(Y>docHeight){ //下边界
target.style.transform = "translate("+X+"px,"+docHeight+"px)";
return false;
}
target.style.transform = "translate("+X+"px,"+Y+"px)";
log("鼠标move事件","结束",target.style.transform);
},
Up:function(e){
log("鼠标up事件","开始");
var target = imageTarget,RegEx;
if(repairDefinedEvent&&e.clientX-imageMouse[0]===0&&e.clientY-imageMouse[1]===0){ //尝试修复关闭图片功能
log("尝试修复关闭图片功能","已执行");
imageButton = true;
}else if(scriptDebug&&!imageButton&&e.clientX-imageMouse[0]===0&&e.clientY-imageMouse[1]===0){
log("鼠标click事件判断","\n一.操作时页面不在激活状态。请保证浏览器正在被操作,在执行一次\n二.关闭图片功能可能损坏,建议修复");
}
if(!imageButton){
RegEx = target.style.transform.match(/[-0-9.]+/g);
target.imageData.X = parseFloat(RegEx[0]);
target.imageData.Y = parseFloat(RegEx[1]);
}
imageTarget = null;
imageMouse = null;
imageCount = null;
doc.removeEventListener("mousemove",imageEvent.Move);
doc.removeEventListener("mouseup",imageEvent.Up);
log("鼠标up事件","结束",imageButton);
},
Close:function(e){
log("鼠标click事件","开始");
var target = e.target;
if(imageButton){
imageButton = null;
delete target.imageData;
parentDIV.removeChild(target);
log("鼠标click事件",function(){if(!doc.getElementById(target.id))return "成功";else return "失败";});
}
},
Wheel:function(e){
var target=e.target,imageData = target.imageData,
wheelKey = definedEvent[3],
width = imageData.width,height = imageData.height,
Wboolean = width>docWidth,Hboolean = height>docHeight,
wheelXY;
log("鼠标wheel事件","开始",imageData);
e.preventDefault();
e.stopPropagation();
if(wheelKey!=="0"){
if((e.ctrlKey&&wheelKey==="1")||(e.altKey&&wheelKey==="2")||(e.shiftKey&&wheelKey==="3")){ //判断图片缩放的组合键
log("鼠标wheel缩放事件","开始");
var eX = e.clientX,eY = e.clientY,
ratioX = (eX-imageData.X)/width,ratioY = (eY-imageData.Y)/height,
wheelRatio = width+(e.wheelDelta||-e.detail*40)*definedEvent[4];
imageData.width = wheelRatio<150?150:wheelRatio;
imageData.height = imageData.width*height/width;
imageData.X = eX-(imageData.width*ratioX);
imageData.Y = eY-(imageData.height*ratioY);
log("鼠标wheel缩放事件","进行中",imageData);
target.width = imageData.width;
target.style.transform = "translate("+imageData.X+"px,"+imageData.Y+"px)"; //基于鼠标位置的缩放
log("鼠标wheel缩放事件","结束",target.style.transform);
return false;
}
}
if(!Hboolean&&!Wboolean){log("鼠标wheel滚动事件","图片小于窗口");return false;}
if(Hboolean){
wheelXY = imageData.Y+(-e.wheelDelta||e.detail*40)*definedEvent[2];
if(wheelXY>0||wheelXY<docHeight-height){
wheelXY = wheelXY>0?6:docHeight-height;
}
imageData.Y = wheelXY;
log("鼠标wheel垂直滚动事件","进行中",wheelXY);
target.style.transform = "translate("+imageData.X+"px,"+wheelXY+"px)";
log("鼠标wheel垂直滚动事件","结束",target.style.transform);
}else if(Wboolean){
wheelXY = imageData.X+(-e.wheelDelta||e.detail*40)*definedEvent[2];
if(wheelXY>0||wheelXY<docWidth-width){
wheelXY = wheelXY>0?6:docWidth-width;
}
imageData.X = wheelXY;
log("鼠标wheel水平滚动事件","进行中",wheelXY);
target.style.transform = "translate("+wheelXY+"px,"+imageData.Y+"px)";
log("鼠标wheel水平滚动事件","结束",target.style.transform);
}
}
};
//创建父DIV
var parentDIV = doc.createElement("div");
parentDIV.id = "Tie_enlargeImage_parentDIV";
doc.body.appendChild(parentDIV);
//事件委托
parentElement.addEventListener("click",imageEvent.StopPropagation,true);
parentElement.addEventListener(definedEvent[0],imageEvent.init,true);
parentDIV.addEventListener("mousedown",imageEvent.Down);
parentDIV.addEventListener(definedEvent[1],imageEvent.Close);
parentDIV.addEventListener(mouseWheel,imageEvent.Wheel);
//释放缓存
parentElement=null;
//自定义设置
var userEvent = {
init:function(){
this.create();
this.Event();
},
create:function(){
var definedDIV = doc.createElement("div"); //创建自定义DIV框架
definedDIV.id = "Tie_setValue_DIV";
definedDIV.innerHTML = "<div class='Tie_definedDIV'><div class='Tie_definedDIV_title'>自定义设置</div><div><div class='Tie_definedDIV_point'><div class='Tie_definedDIV_groupSubtitle'>请保证鼠标在图片上进行操作</div><div class='Tie_definedDIV_configItem'>默认支持鼠标左键拖拽图片</div><div class='Tie_definedDIV_configItem'>查看图片<select name='Tie_setValue'><option value='click'>单击</option><option value='dblclick'>双击</option></select></div><div class='Tie_definedDIV_configItem'>关闭图片<select name='Tie_setValue'><option value='click'>单击</option><option value='dblclick'>双击</option></select><br><label><input id='Tie_repairValue' type='checkbox'>尝试修复关闭图片功能</label></div><div class='Tie_definedDIV_configItem'>滚动图片<select name='Tie_setValue'><option value='1'>滚轮向上,上移/左移</option><option value='-1'>滚轮向下,上移/左移</option></select></div><div class='Tie_definedDIV_configItem'>缩放图片<select name='Tie_setValue'><option value='0'>关闭</option><option value='1'>Ctrl</option><option value='2'>Alt</option><option value='3'>Shift</option></select>+<select name='Tie_setValue'><option value='1'>滚轮向上放大</option><option value='-1'>滚轮向下放大</option></select></div><div class='Tie_definedDIV_configItem'>调试脚本<label><input id='Tie_debugConfig' type='checkbox'><i class='Tie_debugConfig_icon'></i></label><div class='Tie_bubble_DIV'><div class='Tie_bubble_content'><div class='Tie_bubble_mainTxt'>如果您的脚本出现问题,您可以打开调试功能。<strong>在页面进行平常的图片操作,将操作过后在浏览器控制台(快捷键:F12)输出的脚本日志截图反馈给作者</strong>,以便更好的解决问题。<br>注意,<strong>调试功能打开即生效。并且只在当前页面生效一次,刷新或关闭页面都会取消调试功能,需重新打开</strong>。<br>打开调试功能可能会增加内存占用、降低网页的反应速度甚至导致浏览卡顿。仅供维护使用,不建议一般用户打开调试功能。</div><div><span class='Tie_bubble_bor'><i class='Tie_bubble_line'></i><em class='Tie_bubble_br'></em></span></div></div></div></div></div></div><div class='Tie_definedDIV_SaveBtn'><a id='Tie_setValue_a' class='Tie_SaveBtn_a' href='javascript:void(0);'><span>确定</span></a></div></div>";
doc.body.appendChild(definedDIV);
definedDIV = null;
},
Event:function(){
var definedDIV = doc.getElementById("Tie_setValue_DIV"),
repairValue = doc.getElementById("Tie_repairValue"),
debugConfig = doc.getElementById("Tie_debugConfig"),
parentElement = doc.getElementById("j_p_postlist"),
setValue = doc.getElementsByName("Tie_setValue"),
oldDefinedEvent = definedEvent; //备份旧设置
for(var i=0;i<5;i++){
setValue[i].value = oldDefinedEvent[i];
}
if(setValue[3].value==="0")setValue[4].style.visibility = "hidden";
setValue[3].onchange = function(){
setValue[4].style.visibility = this.value==="0"?"hidden":"visible";
};
repairValue.checked = repairDefinedEvent;
debugConfig.checked = scriptDebug;
doc.getElementById("Tie_setValue_a").onclick = function(){
definedEvent = [setValue[0].value,setValue[1].value,setValue[2].value,setValue[3].value,setValue[4].value];
repairDefinedEvent = repairValue.checked;
scriptDebug = debugConfig.checked;
if(oldDefinedEvent[0]!==definedEvent[0]){
parentElement.removeEventListener(oldDefinedEvent[0],imageEvent.init,true);
parentElement.addEventListener(definedEvent[0],imageEvent.init,true);
}
if(oldDefinedEvent[1]!==definedEvent[1]){
parentDIV.removeEventListener(oldDefinedEvent[1],imageEvent.Close);
parentDIV.addEventListener(definedEvent[1],imageEvent.Close);
}
log = scriptDebug&&function(text,types,data){ //脚本调试,日志
if(typeof types==="function"){
types = types();
}
if(data===undefined)console.log(text,types);
else console.log(text,types,data);
}||function(){};
log("自定义属性设置","已执行",definedEvent+","+repairDefinedEvent);
this.onclick = null;
setValue[3].onchange = null;
doc.body.removeChild(definedDIV);
GM_setValue("definedEvent",definedEvent.toString());
GM_setValue("repairDefinedEvent",repairDefinedEvent);
definedDIV = null;repairValue = null;debugConfig = null;parentElement = null;setValue = null;oldDefinedEvent = null;
};
}
};
if(!GM_getValue("definedEvent")){
userEvent.init();
}
GM_registerMenuCommand("自定义设置", function(){
if(!doc.getElementById("Tie_setValue_DIV"))
userEvent.init();
});
window.addEventListener("resize", function(){
if(typeof winResize!==undefined){
clearTimeout(winResize);
}
winResize = setTimeout(function(){
docHeight = doc.documentElement.clientHeight-6;
docWidth = doc.documentElement.clientWidth-6;
},334);
});
})(window);