您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Hold mouse button over link to open it in new tab. Requires to release mouse to take effect due to popup restrictions.
- // ==UserScript==
- // @name Hold to new tab
- // @description Hold mouse button over link to open it in new tab. Requires to release mouse to take effect due to popup restrictions.
- // @namespace util
- // @include *
- // @version 2016.2.15.18.05
- // @grant none
- // @author Jakub Mareda aka MXXIV
- // @run-at document-start
- // ==/UserScript==
- // Timeout after mousedown when the new tab timeout should be started
- // this timeout is to prevent flickering when clicking links normally
- var startCoundownTimeout = null;
- var startCountdownTime = 100; //140;
- // the actual countdown before displaying the link
- var countdownTimeout = null;
- var countdownTime = 500;
- // Time when the mouse was pressed down
- var mouseDownTime = -1;
- // Target link
- var link = null;
- // progress bar object, initialized later
- var progressBar;
- function mouseDown(e) {
- // only left button
- if(e.button != 0)
- return;
- var el = e.target;
- //console.log("Mousedown");
- while(el!=null) {
- if(el.tagName && el.tagName.toLowerCase()=="a") {
- link = el;
- //console.log("... link!");
- startPreCountdown(e.clientX, e.clientY);
- return;
- }
- el = el.parentNode;
- }
- //console.log("... not a link.");
- }
- // Counts but doesn't display anything yet
- function startPreCountdown(x,y) {
- mouseDownTime = performance.now();
- // add cancel listeners
- link.addEventListener("mouseout", failIfLeftButton);
- link.addEventListener("mouseup", failIfLeftButton);
- window.addEventListener("onunload", stopFail);
- // Don't use delay if delay is off
- if(startCountdownTime>0) {
- startCountdownTimeout = setTimeout(startCountdown, startCountdownTime, x, y);
- }
- else {
- startCountdown(x, y);
- }
- }
- // Starts displaying the loader
- function startCountdown(x,y) {
- progressBar.x = x;
- progressBar.y = y;
- progressBar.start();
- countdownTimeout = setTimeout(stopExec, countdownTime);
- }
- // Stop and do the action
- function stopExec() {
- //console.log("Open in new tab: "+link.href);
- if(link.target!="_blank") {
- if(link.target)
- link.setAttribute("oldtarget", link.target);
- link.target = "_blank";
- removeBlankOnClick(link);
- }
- //link.dispatchEvent(new MouseEvent("click"));
- stop();
- }
- // stop and do nothing
- function stopFail() {
- //console.log("No action on "+link.href);
- stop();
- }
- function failIfLeftButton(mouseEvent) {
- if(mouseEvent.button == 0)
- stopFail();
- }
- function stop() {
- progressBar.stop();
- clearTimeout(countdownTimeout);
- countdownTimeout = null;
- clearTimeout(startCountdownTimeout);
- startCountdownTimeout = null;
- // clear listeners
- link.removeEventListener("mouseout", failIfLeftButton);
- link.removeEventListener("mouseup", failIfLeftButton);
- window.removeEventListener("onunload", stopFail);
- }
- function calculateTimePercentage() {
- var dt = performance.now()-mouseDownTime;
- return (dt/(startCountdownTime+countdownTime))*100;
- }
- function Renderer(callback) {
- this.percents = 0;
- this.x = 0;
- this.y = 0;
- this.getPercents = callback;
- this.colorFull = "rgba(86,125,255,0.8)";
- this.colorEmpty = "rgba(86,125,255,0.2)";
- this.rendering = false;
- // cached callback
- this.renderLoop = this.renderLoop.bind(this);
- }
- Renderer.prototype = {
- init: function() {
- var div = this.div;
- if(!div) {
- var div = this.div = document.createElement("div");
- div.style.position = "fixed";
- div.style.width = "40px";
- div.style.height = "6px";
- div.style.fontSize = "0px";
- div.innerHTML = "This div is used to render progress bar for New tab userscript.";
- div.style.display = "none";
- document.body.appendChild(div);
- }
- return div;
- },
- render: function() {
- var div = this.div?this.div:this.init();
- div.style.top = (this.y-8)+"px";
- // hardcoded half width
- div.style.left = (this.x-20)+"px";
- var c = this.colorFull,
- c2 = this.colorEmpty;
- var perc = Math.round(this.percents)+"";
- div.style.background = "linear-gradient(to right, "+c+" 0%,"+c+" "+perc+"%,"+c2+" "+perc+"%,"+c2+" 100%)";
- },
- renderLoop: function() {
- if(this.rendering) {
- if(this.getPercents)
- this.percents = this.getPercents();
- this.render();
- requestAnimationFrame(this.renderLoop);
- }
- },
- start: function() {
- this.rendering = true;
- (this.div ? this.div:this.init()).style.display = "block";
- this.renderLoop();
- },
- stop: function() {
- this.rendering = false;
- if(this.div)
- this.div.style.display = "none";
- }
- }
- progressBar = new Renderer(calculateTimePercentage);
- window.addEventListener("mousedown", mouseDown);
- function cancelEvent(e) {
- e.preventDefault();
- console.log("Cancel ", e.type);
- window.removeEventListener(e.type, cancelEvent);
- return false;
- }
- function cancelNext(evtName) {
- window.addEventListener(evtName, cancelEvent);
- }
- /** remove target="_blank" - or set it to original value **/
- function removeBlank(e) {
- // it must happen AFTER the click event does what it should
- setTimeout((()=>{
- if(this.hasAttribute("oldtarget")) {
- this.setAttribute("target", this.getAttribute("oldtarget"));
- this.removeAttribute("oldtarget");
- }
- else {
- this.removeAttribute("target");
- }
- }).bind(this), 0);
- this.removeEventListener(e.type, removeBlank);
- }
- function removeBlankOnClick(link) {
- link.addEventListener("click", removeBlank);
- }