手机浏览器触摸手势

为手机浏览器添加触摸手势功能,例如↓↑回到顶部,↑↓回到底部,→←后退,←→前进,→↓关闭标签页,→↑恢复刚关闭的页面等。还有特殊的文字手势、图片手势和视频手势,还可自定义你的手势功能。推荐使用Kiwi浏览器、Yandex浏览器和火狐浏览器。

目前为 2022-09-01 提交的版本。查看 最新版本

// ==UserScript==
// @name		手机浏览器触摸手势
// @name:en		Mobile browser touch gestures
// @description	为手机浏览器添加触摸手势功能,例如↓↑回到顶部,↑↓回到底部,→←后退,←→前进,→↓关闭标签页,→↑恢复刚关闭的页面等。还有特殊的文字手势、图片手势和视频手势,还可自定义你的手势功能。推荐使用Kiwi浏览器、Yandex浏览器和火狐浏览器。
// @description:en	Add touch gestures to mobile browsers. For example, ↓↑: go to the top, ↑↓: go to the bottom, →←: go back, ←→: go forward, →↓: closes the tab, →↑: restores just closed page, etc. There are also special text gestures, picture gestures and video gestures, and you can customize your gesture functions. Recommend using Kiwi browser, Yandex browser and Firefox browser.
// @version		8.3.0
// @author		L.Xavier
// @namespace	https://gf.qytechs.cn/zh-CN/users/128493
// @match		*://*/*
// @license		MIT
// @grant		GM_setValue
// @grant		GM_getValue
// @grant		window.close
// @grant		GM_openInTab
// @grant		GM_setClipboard
// @grant		GM_addValueChangeListener
// @run-at		document-body
// ==/UserScript==
// v8.3.0		2022-09-01 - 1.新增同一方向持续滑动触发手势,图标为'▼'和'▽',具体看脚本首页。2.新增视频右滑进度'V→▼'和左滑进度'V←▼'手势。3.优化事件加载检测,视频容器查找,手势穿透方法。
(async ()=>{
	/*手势数据模块*/
	let gesture={
		'↑→↓←':'打开设置',
		'◆◆':'视频全屏',
		'●':'手势穿透',
		'→←':'后退',
		'←→':'前进',
		'↓↑':'回到顶部',
		'↑↓':'回到底部',
		'←↓':'刷新页面',
		'←↑':'新建页面',
		'→↓':'关闭页面',
		'→↑':'恢复页面',
		'↓↑●':'新页面打开',
		'↑↓●':'隐藏元素',
		'↑→':'复制页面',
		'→←→':'半屏模式',
		'→↓↑←':'视频解析',
		'T→↑':'百度翻译',
		'T←↑':'有道翻译',
		'T◆◆':'双击搜索',
		'I↓↑●':'打开图片',
		'I→↑●':'百度搜图',
		'V→':'前进10s',
		'V←':'后退10s',
		'V↑':'增加倍速',
		'V↓':'减小倍速',
		'V→●':'快进播放',
		'V→○':'停止快进',
		'V←●':'快退播放',
		'V←○':'停止快退',
		'V↑●':'增加音量',
		'V↑○':'关闭增加音量',
		'V↓●':'减少音量',
		'V↓○':'关闭减少音量',
		'V→▼':'右滑进度',
		'V→▽':'关闭右滑进度',
		'V←▼':'左滑进度',
		'V←▽':'关闭左滑进度'
	},
	pathFn={
		'打开设置':'/*ONLY TOP*/openSet();',
		'视频全屏':'videoFullScreen();',
		'手势穿透':'setTimeout(()=>{if(path.indexOf("I")>-1){path="I";return;}else if(path.indexOf("T")>-1){path="";return;}if(gestureData.touchEle.nodeName!="IMG"){let imgs=gestureData.touchEle.parentNode.getElementsByTagName("img");for(let Ti=0,len=imgs.length;Ti<len;Ti++){let imgRect=imgs[Ti].getBoundingClientRect();if(gestureData.clientX>imgRect.x && gestureData.clientX<(imgRect.x+imgRect.width) && gestureData.clientY>imgRect.y && gestureData.clientY<(imgRect.y+imgRect.height)){gestureData.touchEle=imgs[Ti];break;}}}if(gestureData.touchEle.nodeName=="IMG" && settings["图片手势"]){path="I";}else if(gestureData.touchEle.style.backgroundImage && settings["图片手势"]){gestureData.touchEle.src=gestureData.touchEle.style.backgroundImage.split(\'"\')[1];path="I";}else{path="";}});',
		'后退':'/*ONLY TOP*/history.go(-1);gestureData.backTimer=setTimeout(()=>{window.close();},500);',
		'前进':'/*ONLY TOP*/history.go(1);',
		'回到顶部':'/*WITH TOP*/let boxNode=gestureData.touchEle.parentNode;while(boxNode.nodeName!="#document"){boxNode.scrollTop=0;boxNode=boxNode.parentNode;}',
		'回到底部':'/*WITH TOP*/let boxNode=gestureData.touchEle.parentNode;while(boxNode.nodeName!="#document"){boxNode.scrollTop=boxNode.scrollHeight;boxNode=boxNode.parentNode;}',
		'刷新页面':'/*ONLY TOP*/document.documentElement.style.cssText="filter:grayscale(100%)";history.go(0);',
		'新建页面':'/*ONLY TOP*/GM_openInTab("https://limestart.cn");',
		'关闭页面':'/*ONLY TOP*/window.close();',
		'恢复页面':'/*ONLY TOP*/GM_openInTab("chrome-native://recent-tabs");',
		'新页面打开':'let linkNode=gestureData.touchEle;while(true){if(linkNode.href){GM_openInTab(linkNode.href);break;}linkNode=linkNode.parentNode;if(linkNode.nodeName=="BODY"){gestureData.touchEle.click();break;}}',
		'隐藏元素':'gestureData.touchEle.style.display="none";',
		'复制页面':'/*ONLY TOP*/GM_openInTab(location.href);',
		'半屏模式':'/*ONLY TOP*/if(gestureData.halfScreen){setTimeout(()=>{gestureData.halfScreen.remove();halfClose.remove();gestureData.halfScreen=null;document.documentElement.scrollTop=gestureData.scrollTop;},499);gestureData.scrollTop=document.body.scrollTop;let halfClose=addStyle("html{animation:halfClose 0.5s;}@keyframes halfClose{from{transform:translateY(50vh);}to{transform:translateY(0);}}");}else{gestureData.scrollTop=document.documentElement.scrollTop;gestureData.halfScreen=addStyle("html,body{height:43vh !important;overflow-x:hidden !important;}html{transform:translateY(50vh);animation:halfScreen 0.5s;}@keyframes halfScreen{from{transform:translateY(0);}to{transform:translateY(50vh);}}");document.body.scrollTop=gestureData.scrollTop;}',
		'视频解析':'/*ONLY TOP*/GM_openInTab("https://jx.parwix.com:4433/player/?url="+location.href);',
		'百度翻译':'GM_openInTab("https://fanyi.baidu.com/#auto/auto/"+gestureData.selectWords);',
		'有道翻译':'GM_openInTab("https://dict.youdao.com/w/eng/"+gestureData.selectWords);',
		'双击搜索':'GM_setClipboard(gestureData.selectWords);let regURL=/^(https?:\\/\\/)?([\\w\\-]+\\.)+\\w{2,4}(\\/\\S*)?$/;if(!regURL.test(gestureData.selectWords.replace(/\\s+$/,""))){gestureData.selectWords="https://bing.com/search?q="+encodeURIComponent(gestureData.selectWords);}else if(!/^http/.test(gestureData.selectWords)){gestureData.selectWords="//"+gestureData.selectWords;}GM_openInTab(gestureData.selectWords);',
		'打开图片':'GM_openInTab(gestureData.touchEle.src);',
		'百度搜图':'GM_openInTab("https://graph.baidu.com/details?isfromtusoupc=1&tn=pc&carousel=0&promotion_name=pc_image_shituindex&extUiData%5bisLogoShow%5d=1&image="+gestureData.touchEle.src);',
		'前进10s':'videoPlayer.currentTime+=10;gestureData.tipBox.innerHTML="+10s ";gestureData.tipBox.style.display="block";setTimeout(()=>{gestureData.tipBox.style.display="none";},500);',
		'后退10s':'videoPlayer.currentTime-=10;gestureData.tipBox.innerHTML="-10s ";gestureData.tipBox.style.display="block";setTimeout(()=>{gestureData.tipBox.style.display="none";},500);',
		'增加倍速':'if(document.webkitIsFullScreen || document.mozFullScreen){let playSpeed=videoPlayer.playbackRate;playSpeed=(playSpeed<1.5) ? playSpeed+0.25 : playSpeed+0.5;gestureData.tipBox.innerHTML="x"+playSpeed+" ∞ ";gestureData.tipBox.style.display="block";videoPlayer.playbackRate=playSpeed;setTimeout(()=>{gestureData.tipBox.style.display="none";},500)}',
		'减小倍速':'if(document.webkitIsFullScreen || document.mozFullScreen){let playSpeed=videoPlayer.playbackRate;playSpeed=(playSpeed>1.5) ? playSpeed-0.5 : ((playSpeed>0.25) ? playSpeed-0.25 : 0.25);gestureData.tipBox.innerHTML="x"+playSpeed+" ∞ ";gestureData.tipBox.style.display="block";videoPlayer.playbackRate=playSpeed;setTimeout(()=>{gestureData.tipBox.style.display="none";},500)}',
		'快进播放':'gestureData.playSpeed=videoPlayer.playbackRate;videoPlayer.playbackRate=10;gestureData.tipBox.innerHTML="x10 ";gestureData.tipBox.style.display="block";',
		'停止快进':'videoPlayer.playbackRate=gestureData.playSpeed;gestureData.tipBox.style.display="none";',
		'快退播放':'gestureData.videoTimer=setInterval(()=>{videoPlayer.currentTime-=1;},100);gestureData.tipBox.innerHTML="- x10 ";gestureData.tipBox.style.display="block";',
		'停止快退':'clearInterval(gestureData.videoTimer);gestureData.tipBox.style.display="none";',
		'增加音量':'if(document.webkitIsFullScreen || document.mozFullScreen){videoPlayer.muted=false;gestureData.tipBox.innerHTML=parseInt(videoPlayer.volume*100)+"%";gestureData.tipBox.style.display="block";let lastY=gestureData.endY;gestureData.videoTimer=setInterval(()=>{if(lastY-gestureData.endY){let tempVolume=videoPlayer.volume+(lastY-gestureData.endY)/100;videoPlayer.volume=(tempVolume>1) ? 1 : ((tempVolume<0) ? 0 : tempVolume);gestureData.tipBox.innerHTML=parseInt(videoPlayer.volume*100)+"%";lastY=gestureData.endY;}},50);}',
		'关闭增加音量':'clearInterval(gestureData.videoTimer);gestureData.tipBox.style.display="none";',
		'减少音量':'if(document.webkitIsFullScreen || document.mozFullScreen){videoPlayer.muted=false;gestureData.tipBox.innerHTML=parseInt(videoPlayer.volume*100)+"%";gestureData.tipBox.style.display="block";let lastY=gestureData.endY;gestureData.videoTimer=setInterval(()=>{if(lastY-gestureData.endY){let tempVolume=videoPlayer.volume+(lastY-gestureData.endY)/100;videoPlayer.volume=(tempVolume>1) ? 1 : ((tempVolume<0) ? 0 : tempVolume);gestureData.tipBox.innerHTML=parseInt(videoPlayer.volume*100)+"%";lastY=gestureData.endY;}},50);}',
		'关闭减少音量':'clearInterval(gestureData.videoTimer);gestureData.tipBox.style.display="none";',
		'右滑进度':'gestureData.tipBox.innerHTML=((videoPlayer.currentTime/60<10) ? "0" : "")+Math.floor(videoPlayer.currentTime/60)+" : "+((videoPlayer.currentTime%60<10) ? "0" : "")+Math.floor(videoPlayer.currentTime%60);gestureData.tipBox.style.display="block";let lastX=gestureData.endX;gestureData.videoTimer=setInterval(()=>{if(gestureData.endX-lastX){videoPlayer.currentTime+=(gestureData.endX-lastX)*(1+Math.abs(gestureData.endX-lastX)/10);lastX=gestureData.endX;}gestureData.tipBox.innerHTML=((videoPlayer.currentTime/60<10) ? "0" : "")+Math.floor(videoPlayer.currentTime/60)+" : "+((videoPlayer.currentTime%60<10) ? "0" : "")+Math.floor(videoPlayer.currentTime%60);},50);',
		'关闭右滑进度':'clearInterval(gestureData.videoTimer);gestureData.tipBox.style.display="none";',
		'左滑进度':'gestureData.tipBox.innerHTML=((videoPlayer.currentTime/60<10) ? "0" : "")+Math.floor(videoPlayer.currentTime/60)+" : "+((videoPlayer.currentTime%60<10) ? "0" : "")+Math.floor(videoPlayer.currentTime%60);gestureData.tipBox.style.display="block";let lastX=gestureData.endX;gestureData.videoTimer=setInterval(()=>{if(gestureData.endX-lastX){videoPlayer.currentTime+=(gestureData.endX-lastX)*(1+Math.abs(gestureData.endX-lastX)/10);lastX=gestureData.endX;}gestureData.tipBox.innerHTML=((videoPlayer.currentTime/60<10) ? "0" : "")+Math.floor(videoPlayer.currentTime/60)+" : "+((videoPlayer.currentTime%60<10) ? "0" : "")+Math.floor(videoPlayer.currentTime%60);},50);',
		'关闭左滑进度':'clearInterval(gestureData.videoTimer);gestureData.tipBox.style.display="none";'
	},
	settings={
		'滑动距离':0.5,
		'文字手势':true,
		'图片手势':true,
		'视频手势':true
	};
	//存储数据读取
	gesture=await GM_getValue('gesture',gesture);
	pathFn=await GM_getValue('pathFn',pathFn);
	settings=await GM_getValue('settings',settings);
	//脚本常量
	const gestureData={},limit=(((window.screen.width>window.screen.height) ? window.screen.height : window.screen.width)*0.5*settings['滑动距离'])**2/4;

	/*手势功能模块*/
	//手指滑动变量
	let _startX=0,_startY=0,timeSpan=0,pressTime=0,raiseTime=0,slideTime=0,lastTime=0,_sumXY=0,slideLimit=0,path='',fingersNum=0,gestureTimer=0,isOK=0,isClick=0,noClick=null,isPushing=0,moveTime=0,moveTimer=0;
	//修改Trusted-Types策略
	window.trustedTypes?.createPolicy('default',{createHTML:string=>string,createScript:string=>string,createScriptURL:string=>string});
	//手势执行
	async function runCode(code){
		try{await eval(code);}
		catch(error){
			if(error.toString().indexOf('unsafe-eval')>-1){
				if(!window.evalTool){
					window.evalTool=(()=>{
						let script=document.createElement('script');
						function thisParams(){
							this.window.close=window.close;
							this.GM_setValue=GM_setValue;
							this.GM_getValue=GM_getValue;
							this.GM_openInTab=GM_openInTab;
							this.GM_setClipboard=GM_setClipboard;
							this.runCode=runCode;
							this.runGesture=runGesture;
							this.videoFullScreen=videoFullScreen;
							this.findVideoBox=findVideoBox;
							this.addStyle=addStyle;
							this.openSet=openSet;
							this.gestureData=gestureData;
							this.path=path;
							this.videoPlayer=videoPlayer;
						}
						return (js)=>{
							thisParams();
							script.remove();
							script=document.createElement('script');
							script.innerHTML='try{'+js+'}catch(error){alert("“"+path+"” 手势执行脚本错误:\\n"+error+" !");}';
							document.body.appendChild(script);
						}
					})();
					await window.evalTool('window.addEventListener("popstate",()=>{clearTimeout(gestureData.backTimer);},true);window.addEventListener("beforeunload",()=>{clearTimeout(gestureData.backTimer);},true);');
				}
				await window.evalTool(code);
			}
			else{alert('“'+path+'” 手势执行脚本错误:\n'+error+' !');}
		}
	}
	async function runGesture(pathStr=''){
		if(gesture[path]){
			let code=pathFn[gesture[path]];
			if(top==self || /^[TIV]/.test(path)){runCode(code);}
			else{
				if(code.indexOf('/*ONLY TOP*/')<0){runCode(code);}
				if(code.indexOf('/*ONLY TOP*/')>-1 || code.indexOf('/*WITH TOP*/')>-1){
					isPushing=1;
					await GM_setValue('iframeUrl',location.href);
					await GM_setValue('runPath',path);
					await GM_setValue('gestureData',gestureData);
				}
			}
			path=pathStr;
		}else if(gesture[path.slice(1)] && /^[TIV]/.test(path)){
			path=path.slice(1);let code=pathFn[gesture[path]];
			if(top==self){runCode(code);}
			else{
				if(code.indexOf('/*ONLY TOP*/')<0){runCode(code);}
				if(code.indexOf('/*ONLY TOP*/')>-1 || code.indexOf('/*WITH TOP*/')>-1){
					isPushing=1;
					await GM_setValue('iframeUrl',location.href);
					await GM_setValue('runPath',path);
					await GM_setValue('gestureData',gestureData);
				}
			}
			path=pathStr;
		}
	}
	//手指按下
	function touchStart(e){
		clearTimeout(gestureTimer);
		fingersNum=e.touches.length;if(fingersNum>1){return;}
		let _X=e.changedTouches[0].screenX,_Y=e.changedTouches[0].screenY,
		calcX=(_X-gestureData.endX)**2,calcY=(_Y-gestureData.endY)**2,sumXY=calcX+calcY,
		nowTime=Date.now();timeSpan=nowTime-raiseTime;
		if(timeSpan>50 || sumXY>2500){//断触判断
			pressTime=slideTime=nowTime;isPushing=_sumXY=0;isOK=isClick=1;
			_startX=gestureData.startX=_X;_startY=gestureData.startY=_Y;
			if(timeSpan>200 || sumXY>10000){
				path='';slideLimit=limit*3;gestureData.touchEle=e.target;
				gestureData.clientX=e.changedTouches[0].clientX;gestureData.clientY=e.changedTouches[0].clientY;
				gestureData.selectWords=window.getSelection().toString();
				if(gestureData.selectWords && settings['文字手势']){path='T';}
				else if(videoPlayer && settings['视频手势']){
					let videoRect=videoPlayer.getBoundingClientRect(),offsetX=0,offsetY=0;
					if(document.webkitIsFullScreen || document.mozFullScreen){offsetX=videoRect.x;offsetY=videoRect.y-30;}
					if(gestureData.clientX>(videoRect.x-offsetX) && gestureData.clientX<(videoRect.x+videoRect.width+offsetX) && gestureData.clientY>(videoRect.y-offsetY) && gestureData.clientY<(videoRect.y+videoRect.height+offsetY)){path='V';}
				}
			}
		}else if(isClick){path=path.slice(0,-1);}noClick?.remove();
		gestureTimer=setTimeout(()=>{slideTime=Date.now();isOK=isClick=0;if(!/[●○▽]$/.test(path)){let _path=path+'○';path+='●';if(gesture[_path]){runGesture(_path);}else{runGesture(path);}}},(400+slideTime-nowTime));
	}
	//手指滑动
	async function touchMove(e){
		let nowTime=Date.now();
		if((nowTime-lastTime)<16 || fingersNum>1){return;}
		clearTimeout(gestureTimer);clearTimeout(moveTimer);
		gestureData.endX=e.changedTouches[0].screenX;gestureData.endY=e.changedTouches[0].screenY;
		let calcX=(gestureData.endX-_startX)**2,calcY=(gestureData.endY-_startY)**2,
		sumXY=calcX+calcY,lastIcon=path.slice(-1),
		diffXY=(sumXY>_sumXY) ? sumXY-_sumXY : _sumXY-sumXY;
		lastTime=nowTime;_sumXY=sumXY;
		if(diffXY>9 && !/[○▽]/.test(lastIcon)){
			isOK=isClick=0;slideTime=nowTime;
			let direction=(calcX>calcY) ? ((gestureData.endX>_startX) ? '→' : '←') : ((gestureData.endY>_startY) ? '↓' : '↑');
			if(lastIcon==direction || sumXY>(slideLimit+limit)){
				if(lastIcon!=direction && (timeSpan>200 || timeSpan<84 || 'TIV◆'.indexOf(lastIcon)>-1)){path+=direction;slideLimit=slideLimit/2;timeSpan=201;moveTime=nowTime;}
				isOK=1;_sumXY=0;_startX=gestureData.endX;_startY=gestureData.endY;
				if(moveTime){moveTimer=setTimeout(()=>{moveTime=0;let _path=path;path+='▼';if(gesture[_path+'▽']){runGesture(_path+'▽');}else{runGesture(_path);}path=path.replace('▼','');},400+moveTime-nowTime);}
			}
		}
		gestureTimer=setTimeout(()=>{slideTime=Date.now();isOK=isClick=_sumXY=0;_startX=gestureData.endX;_startY=gestureData.endY;if(!/[●○▽]/.test(lastIcon)){let _path=path+'○';path+='●';if(gesture[_path]){runGesture(_path);}else{runGesture(path);}}},(400+slideTime-nowTime));
		if(top!=self && isPushing){await GM_setValue('gestureData',gestureData);}
	}
	//手指抬起
	function touchEnd(e){
		clearTimeout(gestureTimer);clearTimeout(moveTimer);
		gestureData.endX=e.changedTouches[0].screenX;gestureData.endY=e.changedTouches[0].screenY;
		raiseTime=Date.now();isPushing=0;setTimeout(loadCheck,16);
		if(/[○▽]$/.test(path)){raiseTime-=200;runGesture();return;}
		if(fingersNum>1){raiseTime-=200;return;}
		if(isOK){gestureTimer=setTimeout(runGesture,199);}
		if(isClick){
			let calcX=(gestureData.endX-gestureData.startX)**2,calcY=(gestureData.endY-gestureData.startY)**2;
			if((calcX+calcY)>16){isClick=0;return;}
			path+='◆';if(/^V◆◆$|^T/.test(path)){e.stopPropagation();noClick=addStyle('*{pointer-events:none;}');}
		}
	}

	/*视频功能模块*/
	//video标签变量
	let videoEle=document.getElementsByTagName('video'),_videoEle=[],videoPlayer=null,oriType='portrait-primary',lockOriType='landscape-primary',isLock=0;
	//videoPlayer判定
	function setVideo(){videoPlayer=this;videoOriLock();}
	async function videoOriLock(){
		if(!videoPlayer.videoWidth){if(!videoPlayer.error && videoPlayer.offsetWidth){setTimeout(videoOriLock,100);}return;}
		videoPlayer.parentNode.appendChild(gestureData.tipBox);
		if(videoPlayer.videoWidth>videoPlayer.videoHeight){isLock=1;}
		else{isLock=0;await screen.orientation.unlock();}
		if(top!=self){window.isShow=1;await GM_setValue('isLock',isLock);}
	}
	//video全屏/退出全屏
	async function videoFullScreen(){
		if(document.webkitIsFullScreen){await document.webkitExitFullscreen();}
		else if(document.mozFullScreen){await document.mozCancelFullScreen();}
		else if(videoPlayer){
			await GM_setClipboard(videoPlayer.src);
			if(videoPlayer.webkitRequestFullscreen){await findVideoBox().webkitRequestFullscreen();}
			else if(videoPlayer.mozRequestFullScreen){await findVideoBox().mozRequestFullScreen();}
		}else if(iframeEle.length){await GM_setValue('fullscreen',Date());}
	}
	//获取video全屏样式容器
	function findVideoBox(){
		if(!videoPlayer.offsetWidth){return videoPlayer;}
		let videoBox=videoPlayer.parentNode,
		_videoBox=videoBox,
		parentEle=videoBox.parentNode,
		videoStyle=getComputedStyle(videoPlayer),
		videoWidth=Math.round(parseFloat(videoStyle.width)),
		videoHeight=Math.round(parseFloat(videoStyle.height)),
		parentStyle=getComputedStyle(parentEle),
		parentWidth=Math.round(parseFloat(parentStyle.width)),
		parentHeight=Math.round(parseFloat(parentStyle.height)),
		childStyle=getComputedStyle(videoBox),
		childWidth=Math.round(videoBox.offsetWidth+parseFloat(childStyle.marginLeft)+parseFloat(childStyle.marginRight)),
		childHeight=Math.round(videoBox.offsetHeight+parseFloat(childStyle.marginTop)+parseFloat(childStyle.marginBottom)) || Math.round(videoPlayer.offsetHeight+parseFloat(videoStyle.marginTop)+parseFloat(videoStyle.marginBottom));
		while(parentWidth>=videoWidth && parentHeight>=videoHeight && childWidth==parentEle.clientWidth && childHeight==parentEle.clientHeight && parentEle.nodeName!='HTML'){
			_videoBox=videoBox;videoBox=parentEle;
			childWidth=Math.round(parentEle.offsetWidth+parseFloat(parentStyle.marginLeft)+parseFloat(parentStyle.marginRight));
			childHeight=Math.round(parentEle.offsetHeight+parseFloat(parentStyle.marginTop)+parseFloat(parentStyle.marginBottom)) || childHeight;
			parentEle=parentEle.parentNode;parentStyle=getComputedStyle(parentEle);
			parentWidth=Math.round(parseFloat(parentStyle.width));
			parentHeight=Math.round(parseFloat(parentStyle.height)) || parentHeight;
		}
		if(videoBox.children.length==1 || videoBox.nodeName!='DIV' || !Math.round(parseFloat(getComputedStyle(videoBox).height))){videoBox=_videoBox;}
		return videoBox;
	}
	//video播放事件绑定
	function videoBind(){
		_videoEle=[];
		for(let Ti=0,len=videoEle.length;Ti<len;Ti++){
			if(!videoEle[Ti].paused){videoPlayer=videoEle[Ti];videoOriLock();}
			videoEle[Ti].addEventListener('playing',setVideo,true);
			_videoEle[Ti]=videoEle[Ti];
		}
	}
	//陀螺仪事件
	let regGYRO=()=>{
		let runTime=0;
		window.addEventListener('deviceorientation',async (e)=>{
			let nowTime=Date.now();
			if((nowTime-runTime)<500 || !isLock){return;}
			let oriHgamma=e.gamma,
			oriHbeta=(e.beta>0) ? e.beta : -e.beta;
			if((oriHbeta<70 || oriHbeta>110) && (oriHgamma<-20 || oriHgamma>20)){
				lockOriType=((oriHbeta<70 && oriHgamma<-20) || (oriHbeta>110 && oriHgamma>20)) ? 'landscape-primary' : 'landscape-secondary';
				if(window.iframeLock){await GM_setValue('lockOriType',lockOriType);}
			}
			if(document.webkitIsFullScreen || document.mozFullScreen){if(oriType!=lockOriType){oriType=lockOriType;await screen.orientation.lock(lockOriType);}}
			else{oriType='portrait-primary';}
			runTime=nowTime;
		},true);
	}

	/*工具方法模块*/
	//添加样式表
	function addStyle(css){
		let style=document.createElement('style');
		style.innerHTML=css;
		document.head.appendChild(style);
		return style;
	}
	//页面加载检测
	function loadCheck(){
		if((window.screen.width/document.documentElement.scrollWidth)>0.9){document.documentElement.style.overflowX='hidden';}
		else{document.documentElement.style.overflowX='';}
		if(videoEle.length==_videoEle.length){
			for(let Ti=0,len=_videoEle.length;Ti<len;Ti++){
				if(!_videoEle[Ti].offsetWidth){videoBind();break;}
			}
		}else if(videoEle.length!=_videoEle.length){
			if(!_videoEle.length){
				//启动重力感应
				if(regGYRO){regGYRO();regGYRO=null;}
				//tip操作提示
				gestureData.tipBox=document.createElement('div');
				gestureData.tipBox.style.cssText='width:100px;height:50px;position:absolute;text-align:center;top:calc(50% - 25px);left:calc(50% - 50px);display:none;color:#1e87f0;font-size:24px;line-height:50px;background-color:#fff;border-radius:20px;font-family:"Microsoft YaHei";z-index:2147483647;';
				//视频全屏锁定
				window.addEventListener('webkitfullscreenchange',async (e)=>{
					if(document.webkitIsFullScreen){
						let srcFindVideo=e.target.getElementsByTagName('video'),srcVideo=(e.target.nodeName=='VIDEO') ? e.target : srcFindVideo[0];
						if(!srcVideo || srcFindVideo.length>1){isLock=0;await screen.orientation.unlock();return;}
						let videoRect=srcVideo.getBoundingClientRect();
						if((videoRect.width*videoRect.height/e.target.scrollWidth/e.target.scrollHeight)<0.2){isLock=0;await screen.orientation.unlock();return;}
						if(srcVideo.paused){videoPlayer?.pause();}videoPlayer=srcVideo;videoOriLock();
						if(isLock && oriType!=lockOriType){oriType=lockOriType;await screen.orientation.lock(lockOriType);}
						let videoCss='*:has(> video){height:100% !important;width:100% !important;}';
						if(videoPlayer.width || '%'.indexOf(videoPlayer.style.width.slice(-1))<0){videoCss+='video{width:100% !important;}';}
						if(videoPlayer.height || '%'.indexOf(videoPlayer.style.height.slice(-1))<0){videoCss+='video{height:100% !important;}';}
						gestureData.videoCss=addStyle(videoCss);
					}else{oriType='portrait-primary';gestureData.videoCss?.remove();}
				},true);
				window.addEventListener('mozfullscreenchange',async (e)=>{
					if(document.mozFullScreen){
						let srcFindVideo=e.target.getElementsByTagName('video'),srcVideo=(e.target.nodeName=='VIDEO') ? e.target : srcFindVideo[0];
						if(!srcVideo || srcFindVideo.length>1){isLock=0;await screen.orientation.unlock();return;}
						let videoRect=srcVideo.getBoundingClientRect();
						if((videoRect.width*videoRect.height/e.target.scrollWidth/e.target.scrollHeight)<0.2){isLock=0;await screen.orientation.unlock();return;}
						if(srcVideo.paused){videoPlayer?.pause();}videoPlayer=srcVideo;videoOriLock();
						if(isLock && oriType!=lockOriType){oriType=lockOriType;await screen.orientation.lock(lockOriType);}
						let videoCss='*:has(> video){height:100% !important;width:100% !important;}';
						if(videoPlayer.width || '%'.indexOf(videoPlayer.style.width.slice(-1))<0){videoCss+='video{width:100% !important;}';}
						if(videoPlayer.height || '%'.indexOf(videoPlayer.style.height.slice(-1))<0){videoCss+='video{height:100% !important;}';}
						gestureData.videoCss=addStyle(videoCss);
					}else{oriType='portrait-primary';gestureData.videoCss?.remove();}
				},true);
			}
			videoBind();
		}
	}
	//手势功能设置UI
	function openSet(){
		let gestureName='',gesturePath='',clickTimer=0;
		//页面生成
		addStyle('html{font-size:62.5% !important;}*{overflow:hidden !important;}'+
					'#gestureBox{background-color:#fff;width:100%;height:100%;position:fixed;padding:0;margin:0;top:0;left:0;overflow-y:auto !important;z-index:2147483640;}'+
					'#gestureBox *{font-family:"Microsoft YaHei";margin:0;padding:0;text-align:center;font-size:2rem;line-height:4rem;user-select:none !important;}'+
					'#gestureBox ::placeholder{color:#999;font-size:1rem;line-height:2rem;}'+
					'#gestureBox h1{width:60%;height:4rem;color:#0074d9;background-color:#dee6ef;margin:1rem auto;border-radius:4rem;box-shadow:0.3rem 0.3rem 1rem #dfdfdf;}'+
					'#gestureBox #addGesture{width:5rem;height:5rem;margin:1rem auto;line-height:4.8rem;background-color:#dee6ef;color:#032e58;font-size:3rem;border-radius:5rem;box-shadow:0.1rem 0.1rem 0.5rem #dfdfdf;}'+
					'#gestureBox .gestureLi{height:6rem;width:100%;border-bottom:0.1rem solid #dfdfdf;}'+
					'#gestureBox .gestureLi p{margin:1rem 0 0 1%;width:38%;height:4rem;border-left:0.6rem solid;color:#ffb400;background-color:#fff1cf;float:left;white-space:nowrap;text-overflow:ellipsis;text-shadow:0.1rem 0.1rem 1rem #ffcb56;}'+
					'#gestureBox .gestureLi .gesturePath{margin:1rem 0 0 3%;float:left;width:38%;height:4rem;background-color:#f3f3f3;color:#000;box-shadow:0.1rem 0.1rem 0.5rem #ccc9c9;border-radius:1rem;white-space:nowrap;text-overflow:ellipsis;}'+
					'#gestureBox .gestureLi .delGesture{margin:1rem 2% 0 0;width:5rem;height:4rem;float:right;color:#f00;text-decoration:line-through;}'+
					'#gestureBox #revisePath{background-color:rgba(0,0,0,0.7);width:100%;height:100%;position:fixed;top:0;left:0;z-index:2147483641;display:none;color:#000;}'+
					'#gestureBox #revisePath span{width:5rem;height:5rem;font-size:5rem;line-height:5rem;position:absolute;}'+
					'#gestureBox #revisePath div{color:#3339f9;position:absolute;width:30%;height:4rem;font-size:4rem;bottom:15%;}'+
					'#gestureBox #revisePath p{color:#3ba5d8;position:absolute;top:15%;font-size:4rem;height:4rem;width:100%;}'+
					'#gestureBox #revisePath #path{top:40%;color:#ffee03;height:100%;word-wrap:break-word;font-size:6rem;line-height:6rem;}'+
					'#gestureBox #editGesture{background-color:#fff;width:100%;height:100%;position:fixed;top:0;left:0;z-index:2147483641;display:none;color:#000;}'+
					'#gestureBox #editGesture p{color:#3339f9;font-size:3rem;text-align:left;margin:3rem 0 0 3rem;width:100%;height:3rem;line-height:3rem;}'+
					'#gestureBox #editGesture #gestureName{margin-top:2rem;width:80%;height:4rem;color:#000;border:0.1rem solid #dadada;border-radius:1rem;text-align:left;padding:0 1rem;}'+
					'#gestureBox #editGesture .label_box>label{display:inline-block;margin-top:2rem;position:relative;}'+
					'#gestureBox #editGesture .label_box>label>input{position:absolute;top:0;left:-2rem;}'+
					'#gestureBox #editGesture .label_box>label>div{width:8rem;border:#ddd solid 1px;height:4rem;color:#666;position:relative;}'+
					'#gestureBox #editGesture .label_box>label>input:checked + div{border:#d51917 solid 1px;color:#d51917;}'+
					'#gestureBox #editGesture .label_box>label>input:checked + div:after{content:"";display:block;width:2rem;height:2rem;background-color:#d51917;transform:skewY(-45deg);position:absolute;bottom:-1rem;right:0;z-index:2147483642;}'+
					'#gestureBox #editGesture .label_box>label>input:checked + div:before{content:"";display:block;width:3px;height:8px;border-right:#fff solid 2px;border-bottom:#fff solid 2px;transform:rotate(35deg);position:absolute;bottom:2px;right:4px;z-index:2147483643;}'+
					'#gestureBox #editGesture #pathFn{overflow-y:auto !important;width:80%;margin-top:2rem;height:40%;text-align:left;line-height:2.2rem;padding:1rem;border:0.1rem solid #dadada;border-radius:1rem;}'+
					'#gestureBox #editGesture button{width:10rem;height:5rem;font-size:3rem;line-height:5rem;display:inline-block;color:#fff;background-color:#2866bd;margin:3rem 1rem 0rem 1rem;border:none;}'+
					'#gestureBox #settingsBox{overflow-y:auto !important;background-color:#fff;width:100%;height:100%;position:fixed;top:0;left:0;z-index:2147483641;display:none;color:#000;}'+
					'#gestureBox #settingsBox p{color:#3339f9;text-align:left;margin:3rem 0 0 3rem;float:left;height:2rem;line-height:2rem;clear:both;}'+
					'#gestureBox #settingsBox .slideRail{overflow:initial !important;width:20rem;background-color:#a8a8a8;float:left;margin:4rem 0 0 1rem;height:0.2rem;position:relative;}'+
					'#gestureBox #settingsBox .slideRail .slideButton{line-height:3rem;color:#fff;background-color:#2196f3;width:3rem;height:3rem;border-radius:3rem;font-size:1.5rem;position:absolute;top:-1.5rem;left:-15px;box-shadow:1px 1px 6px #5e8aee;}'+
					'#gestureBox #settingsBox .switch{position:relative;display:inline-block;width:6rem;height:3rem;float:left;margin:2.5rem 42% 0 1rem;}'+
					'#gestureBox #settingsBox .switch input{display:none;}'+
					'#gestureBox #settingsBox .slider{border-radius:3rem;position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;transition:0.4s;}'+
					'#gestureBox #settingsBox .slider:before{border-radius:50%;position:absolute;content:"";height:2.6rem;width:2.6rem;left:0.2rem;bottom:0.2rem;background-color:white;transition:0.4s;}'+
					'#gestureBox #settingsBox input:checked + .slider{background-color:#2196F3;}'+
					'#gestureBox #settingsBox input:checked + .slider:before{transform:translateX(3rem);}'+
					'#gestureBox #settingsBox #saveSettings{display:block;clear:both;width:10rem;height:5rem;font-size:3rem;line-height:5rem;color:#fff;background-color:#2866bd;border:none;margin:4rem 0 0 calc(50% - 5rem);float:left;}');
		let gestureBox=document.createElement('div');
		gestureBox.id='gestureBox';
		document.body.appendChild(gestureBox);
		gestureBox.innerHTML='<h1 id="openSettings">手势轨迹设置</h1><div id="addGesture">+</div><div id="gestureUL"></div>'+
						'<div id="revisePath"><span style="top:0;left:0;text-align:left;">┌</span><span style="top:0;right:0;text-align:right;">┐</span><span style="bottom:0;left:0;text-align:left;">└</span><span style="bottom:0;right:0;text-align:right;">┘</span>'+
						'<p>请滑动手指</p><p id="path"></p><div id="clearPath" style="left:10%;">清除</div><div id="cancleRevise" style="right:10%;">保存</div></div>'+
						'<div id="editGesture"><p>手势名称:</p><input type="text" id="gestureName" maxlength="12" placeholder="最大输入12个字符">'+
						'<p>手势类型:</p><div class="label_box"><label><input type="radio" id="GG" name="gestureType" value=""><div>一般</div></label><label><input type="radio" id="T" name="gestureType" value="T"><div>文字</div></label><label><input type="radio" id="I" name="gestureType" value="I"><div>图片</div></label><label><input type="radio" id="V" name="gestureType" value="V"><div>视频</div></label></div>'+
						'<p>手势执行脚本:</p><textarea id="pathFn" placeholder="可用变量说明↓\n 	gestureData:手势数据常量,如果你需要在不同手势间传递变量,你可以赋值gestureData.变量名=变量值;\n	gestureData.touchEle:手指触摸的源元素;\n	gestureData.selectWords:选中的文字;\n	[gestureData.startX,gestureData.startY]触摸开始坐标;\n	[gestureData.endX,gestureData.endY]触摸结束坐标;\n	path:滑动的路径;\n	videoPlayer:正在播放的视频元素。'+
						'\n\n可用方法说明↓\n	addStyle(CSS样式):将CSS样式添加到网页上;\n	runGesture():以path为路径执行手势,你可以修改path后执行此方法;\n	GM_openInTab(链接):打开链接;\n	GM_setClipboard(文本):复制文本到剪切板;\n	GM_setValue(变量名,变量值):在油猴中存储数据;\n	GM_getValue(变量名,默认值):从油猴中取出数据,没有则使用默认值。'+
						'\n\n可识别代码注释说明(仅对一般手势生效)↓\n	默认情况:存在iframe时,所有手势只会在触发手势的页面对象执行!\n 	添加/*ONLY TOP*/:手势只在顶级页面对象执行;\n	添加/*WITH TOP*/:手势同时在当前页面对象和顶级页面对象执行。"></textarea>'+
						'<div style="width:100%;height:1px;"></div><button id="saveGesture">保存</button><button id="closeEdit">关闭</button></div>'+
						'<div id="settingsBox"><h1>功能开关设置</h1><span id="settingList"></span><button id="saveSettings">保存</button></div>';
		let pathEle=document.getElementById('path');

		//编辑手势
		function editGesture(){
			gestureName=this.parentNode.getAttribute('name');
			if(['打开设置','视频全屏','手势穿透'].indexOf(gestureName)>-1){alert('该手势脚本无法修改!');return;}
			gesturePath=this.parentNode.getAttribute('path');
			let selectType=(/^[TIV]/.test(gesturePath)) ? gesturePath.slice(0,1) : 'GG';
			document.getElementById(selectType).click();
			document.getElementById('gestureName').value=gestureName;
			document.getElementById('pathFn').value=pathFn[gestureName];
			document.getElementById('editGesture').style.display='block';
		}
		//修改路径
		function revisePath(){
			gestureName=this.parentNode.getAttribute('name');
			gesturePath=this.parentNode.getAttribute('path');
			pathEle.innerHTML='';
			window.removeEventListener('touchmove',touchMove,true);
			window.removeEventListener('touchend',touchEnd,true);
			document.getElementById('revisePath').style.display='block';
		}
		//删除手势
		async function delGesture(){
			gestureName=this.parentNode.getAttribute('name');
			if(['打开设置','视频全屏','手势穿透'].indexOf(gestureName)>-1){alert('该手势无法删除!');return;}
			gesturePath=this.parentNode.getAttribute('path');
			delete pathFn[gestureName];
			delete gesture[gesturePath];
			await GM_setValue('pathFn',pathFn);
			await GM_setValue('gesture',gesture);
			init();
		}
		//滑动条
		function silideBar(e){
			if(fingersNum>1){return;}path='';
			let endX=e.changedTouches[0].screenX,
			diffX=endX-_startX,
			leftPX=parseFloat(this.style.left)+diffX;
			if(leftPX>=-15 && leftPX<=(this.parentNode.offsetWidth-15)){
				this.style.left=leftPX+'px';
				leftPX=(leftPX+15)/this.parentNode.offsetWidth;
				this.innerHTML=leftPX.toFixed(1);
				_startX=endX;
			}
		}
		//界面初始化
		function init(){
			document.getElementById('gestureUL').innerHTML='';
			for(gestureName in pathFn){
				gesturePath='';
				for(let Ti in gesture){
					if(gesture[Ti]==gestureName){gesturePath=Ti;break;}
				}
				document.getElementById('gestureUL').innerHTML+='<div class="gestureLi" name="'+gestureName+'" path="'+gesturePath+'"><p>'+gestureName+'</p><div class="gesturePath">'+gesturePath+'</div><div class="delGesture">删除</div></div>';
			}
			//操作绑定
			let gestureEle=document.querySelectorAll('#gestureBox .gestureLi p');
			for(let Ti=0,len=gestureEle.length;Ti<len;Ti++){
				gestureEle[Ti].addEventListener('click',editGesture,true);
			}
			gestureEle=document.querySelectorAll('#gestureBox .gestureLi .gesturePath');
			for(let Ti=0,len=gestureEle.length;Ti<len;Ti++){
				gestureEle[Ti].addEventListener('click',revisePath,true);
			}
			gestureEle=document.querySelectorAll('#gestureBox .gestureLi .delGesture');
			for(let Ti=0,len=gestureEle.length;Ti<len;Ti++){
				gestureEle[Ti].addEventListener('click',delGesture,true);
			}
		}
		init();

		//.新建手势
		document.getElementById('addGesture').addEventListener('click',()=>{
			gestureName=gesturePath='';
			document.getElementById('GG').click();
			document.getElementById('gestureName').value='';
			document.getElementById('pathFn').value='';
			document.getElementById('editGesture').style.display='block';
		},true);
		//保存手势
		document.getElementById('saveGesture').addEventListener('click',async ()=>{
			if(!document.getElementById('gestureName').value){alert('请输入手势名称!');return;}
			if(pathFn[document.getElementById('gestureName').value] && gestureName!=document.getElementById('gestureName').value){alert('该手势名称已被占用!');return;}
			delete pathFn[gestureName];
			delete gesture[gesturePath];
			let typeEle=document.getElementsByName('gestureType');
			for(let Ti=0,len=typeEle.length;Ti<len;Ti++){
				if(typeEle[Ti].checked){
					gesturePath=(gestureName && gesturePath.indexOf('[')<0) ? ((/^[TIV]/.test(gesturePath)) ? typeEle[Ti].value+gesturePath.slice(1) : typeEle[Ti].value+gesturePath) : (typeEle[Ti].value+'['+document.getElementById('gestureName').value+']');
					break;
				}
			}
			gesture[gesturePath]=document.getElementById('gestureName').value;
			pathFn[document.getElementById('gestureName').value]=document.getElementById('pathFn').value;
			await GM_setValue('pathFn',pathFn);
			await GM_setValue('gesture',gesture);
			init();
			document.getElementById('editGesture').style.display='none';
		},true);
		//关闭编辑
		document.getElementById('closeEdit').addEventListener('click',()=>{
			document.getElementById('editGesture').style.display='none';
		},true);
		//路径修改事件
		document.getElementById('revisePath').addEventListener('touchstart',()=>{
			if(fingersNum>1){return;}
			clearTimeout(gestureTimer);
			gestureTimer=setTimeout(()=>{slideTime=Date.now();isClick=0;if(!/[●○▼▽]$/.test(pathEle.innerHTML)){pathEle.innerHTML+='●';}},(400+slideTime-Date.now()));
		},true);
		document.getElementById('revisePath').addEventListener('touchmove',(e)=>{
			let nowTime=Date.now();
			if((nowTime-lastTime)<16 || fingersNum>1){return;}
			clearTimeout(gestureTimer);clearTimeout(moveTimer);
			gestureData.endX=e.changedTouches[0].screenX;gestureData.endY=e.changedTouches[0].screenY;
			let calcX=(gestureData.endX-_startX)**2,calcY=(gestureData.endY-_startY)**2,
			sumXY=calcX+calcY,lastIcon=pathEle.innerHTML.slice(-1),
			diffXY=(sumXY>_sumXY) ? sumXY-_sumXY : _sumXY-sumXY;
			lastTime=nowTime;_sumXY=sumXY;
			if(diffXY>9 && !/[○▼▽]/.test(lastIcon)){
				isClick=0;slideTime=nowTime;
				let direction=(calcX>calcY) ? ((gestureData.endX>_startX) ? '→' : '←') : ((gestureData.endY>_startY) ? '↓' : '↑');
				if(lastIcon==direction || sumXY>limit*4){
					if(lastIcon!=direction){pathEle.innerHTML+=direction;moveTime=nowTime;}
					_sumXY=0;_startX=gestureData.endX;_startY=gestureData.endY;
					if(moveTime){moveTimer=setTimeout(()=>{moveTime=0;pathEle.innerHTML+='▼';},400+moveTime-nowTime);}
				}
			}
			gestureTimer=setTimeout(()=>{slideTime=Date.now();isClick=_sumXY=0;_startX=gestureData.endX;_startY=gestureData.endY;if(!/[●○▼▽]/.test(lastIcon)){pathEle.innerHTML+='●';}},(400+slideTime-nowTime));
		},true);
		document.getElementById('revisePath').addEventListener('touchend',(e)=>{
			clearTimeout(gestureTimer);clearTimeout(moveTimer);
			if(!isClick || fingersNum>1){return;}
			let lastIcon=pathEle.innerHTML.slice(-1);
			if((pressTime-raiseTime)<200){
				raiseTime=Date.now()-200;
				if(lastIcon=='●'){clearTimeout(clickTimer);pathEle.innerHTML=pathEle.innerHTML.slice(0,-1)+'○';}
				else if(lastIcon=='○'){clearTimeout(clickTimer);pathEle.innerHTML=pathEle.innerHTML.slice(0,-1)+'●';}
				else if(lastIcon=='▼'){clearTimeout(clickTimer);pathEle.innerHTML=pathEle.innerHTML.slice(0,-1)+'▽';}
				else if(lastIcon=='▽'){clearTimeout(clickTimer);pathEle.innerHTML=pathEle.innerHTML.slice(0,-1)+'▼';}
				else{pathEle.innerHTML+='◆';}
			}else{
				raiseTime=Date.now();
				clickTimer=setTimeout(()=>{if(!/[○▼▽]/.test(lastIcon)){pathEle.innerHTML+='◆';}},400);
			}
		});
		//清除路径
		document.getElementById('clearPath').addEventListener('touchend',(e)=>{
			e.stopPropagation();e.preventDefault();
			clearTimeout(gestureTimer);
			if(!isClick || fingersNum>1){return;}
			if((pressTime-raiseTime)<200){
				raiseTime=Date.now()-200;
				pathEle.innerHTML='';
			}else{
				raiseTime=Date.now();
				pathEle.innerHTML=pathEle.innerHTML.slice(0,-1);
			}
		});
		//保存修改路径
		document.getElementById('cancleRevise').addEventListener('touchend',async (e)=>{
			e.stopPropagation();e.preventDefault();
			clearTimeout(gestureTimer);
			if(!isClick || fingersNum>1){return;}
			if(pathEle.innerHTML){
				if(gestureName=='视频全屏' && pathEle.innerHTML.slice(-1)!='◆'){alert('视频全屏需要以◆结尾!');return;}
				if(gesture[pathEle.innerHTML]=='手势穿透'){alert('路径与"手势穿透"功能冲突!');return;}
				if(/^[TIV]/.test(gesturePath)){pathEle.innerHTML=gesturePath.slice(0,1)+pathEle.innerHTML;}
				delete gesture[gesturePath];
				if(gesture[pathEle.innerHTML]){
					let pathTXT=((/^[TIV]/.test(gesturePath)) ? gesturePath.slice(0,1) : '')+'['+gesture[pathEle.innerHTML]+']';
					gesture[pathTXT]=gesture[pathEle.innerHTML];
				}
				gesture[pathEle.innerHTML]=gestureName;
				await GM_setValue('gesture',gesture);
				init();
			}
			window.addEventListener('touchmove',touchMove,{capture:true,passive:true});
			window.addEventListener('touchend',touchEnd,{capture:true,passive:true});
			document.getElementById('revisePath').style.display='none';
		});
		//打开功能开关设置
		document.getElementById('openSettings').addEventListener('dblclick',()=>{
			document.getElementById('settingsBox').style.display='block';
			let settingList=document.getElementById('settingList');
			settingList.innerHTML='';
			for(let Ti in settings){
				settingList.innerHTML+='<p>'+Ti+':</p>';
				if(typeof(settings[Ti])=='boolean'){
					settingList.innerHTML=(settings[Ti]) ? (settingList.innerHTML+'<label class="switch"><input type="checkbox" id="'+Ti+'" checked><div class="slider"></div></label>') : (settingList.innerHTML+'<label class="switch"><input type="checkbox" id="'+Ti+'" ><div class="slider"></div></label>');
				}else if(typeof(settings[Ti])=='number'){
					settingList.innerHTML+='<div class="slideRail"><div class="slideButton" id="'+Ti+'"></div></div>';
					let slideButton=document.getElementById(Ti),
					leftPX=slideButton.parentNode.offsetWidth*settings[Ti]-15;
					slideButton.style.left=leftPX+'px';
					slideButton.innerHTML=settings[Ti].toFixed(1);
				}
			}
			let slideList=document.getElementsByClassName('slideButton');
			for(let Ti=0,len=slideList.length;Ti<len;Ti++){
				slideList[Ti].addEventListener('touchmove',silideBar,true);
			}
		},true);
		//保存功能开关设置
		document.getElementById('saveSettings').addEventListener('click',async ()=>{
			for(let Ti in settings){
				if(typeof(settings[Ti])=='boolean'){
					settings[Ti]=document.getElementById(Ti).checked;
				}else if(typeof(settings[Ti])=='number'){
					settings[Ti]=parseFloat(document.getElementById(Ti).innerHTML);
				}
			}
			await GM_setValue('settings',settings);
			document.getElementById('settingsBox').style.display='none';
		},true);
	}

	/*功能补充模块*/
	let iframeEle=document.getElementsByTagName('iframe');
	//检测事件是否添加
	(function regEvent(){if(getComputedStyle(document.documentElement).userSelect!='text'){
	if(top==self){
		//禁止缩放
		if((window.screen.width/document.documentElement.scrollWidth)>0.9){
			document.documentElement.style.overflowX='hidden';
			let meta=document.querySelector('meta[name="viewport"][content*="initial-scale"]:not([content*="user-scalable"])');
			if(meta){meta.content+=',user-scalable=no';}
		}
		//清除后退关闭定时器
		window.addEventListener('popstate',()=>{clearTimeout(gestureData.backTimer);},true);
		window.addEventListener('beforeunload',()=>{clearTimeout(gestureData.backTimer);},true);
		//iframe手势在顶级页面执行
		GM_addValueChangeListener('runPath',async (name,old_value,new_value,remote)=>{
			if(remote && !document.hidden && new_value){
				isPushing=1;path=new_value;
				let _gestureData=await GM_getValue('gestureData',gestureData),iframeUrl=await GM_getValue('iframeUrl'),iframe=iframeEle[0];
				gestureData.startX=_gestureData.startX;gestureData.startY=_gestureData.startY;
				gestureData.endX=_gestureData.endX;gestureData.endY=_gestureData.endY;
				for(let Ti=0,len=iframeEle.length;Ti<len;Ti++){
					if(iframeEle[Ti].src==iframeUrl){iframe=iframeEle[Ti];break;}
				}
				gestureData.touchEle=iframe;
				let ifrRect=iframe.getBoundingClientRect();
				gestureData.clientX=_gestureData.clientX+ifrRect.x;gestureData.clientY=_gestureData.clientY+ifrRect.y;
				runGesture();
				await GM_setValue('runPath','');
			}
		});
		//iframe坐标传递
		GM_addValueChangeListener('gestureData',(name,old_value,new_value,remote)=>{
			if(remote && !document.hidden && isPushing){
				gestureData.endX=new_value.endX;gestureData.endY=new_value.endY;
			}
		});
	}else{
		//iframe视频全屏
		GM_addValueChangeListener('fullscreen',async (name,old_value,new_value,remote)=>{
			if(remote && !document.hidden){
				loadCheck();
				if(window.isShow){
					await GM_setClipboard(videoPlayer.src);
					if(videoPlayer.webkitRequestFullscreen){await findVideoBox().webkitRequestFullscreen();}
					else if(videoPlayer.mozRequestFullScreen){await findVideoBox().mozRequestFullScreen();}
				}
			}
		});
		//iframe屏幕方向记录
		GM_addValueChangeListener('lockOriType',async (name,old_value,new_value,remote)=>{
			if(remote && !document.hidden && new_value && window.isShow){
				lockOriType=new_value;
				await GM_setValue('lockOriType','');
			}
		});
	}
	//iframe锁定
	GM_addValueChangeListener('isLock',async (name,old_value,new_value,remote)=>{
		if(remote && !document.hidden && new_value>-1){
			if(top==self){
				if(regGYRO){regGYRO();regGYRO=null;}
				window.iframeLock=1;
				isLock=new_value;
				if(!isLock){await screen.orientation.unlock();}
				await GM_setValue('isLock',-1);
			}else{window.isShow=0;}
		}
	});
	//解除选中限制
	addStyle('html,*{user-select:text !important;}');
	//手势事件注册(不可用)
	window.addEventListener('touchstart',touchStart,{capture:true,passive:true});
	window.addEventListener('touchmove',touchMove,{capture:true,passive:true});
	window.addEventListener('touchend',touchEnd,{capture:true,passive:true});}
	//*页面加载完成停止检测
	if(document.readyState!='complete'){setTimeout(regEvent,16);}})();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址