您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Erase parts of any webpage --annoyances, ads, images, etc., permanently with just, Ctrl + Left-Click.
当前为
// ==UserScript== // @name WebEraser // @version 1.2.1 // @namespace sfswe // @description Erase parts of any webpage --annoyances, ads, images, etc., permanently with just, Ctrl + Left-Click. // @include * // @require https://code.jquery.com/jquery-3.1.0.js // @require https://code.jquery.com/ui/1.12.0/jquery-ui.js // @resource jqueryUiCss https://code.jquery.com/ui/1.12.0/themes/base/jquery-ui.css // @resource whiteCurtains https://github.com/SloaneFox/imgstore/raw/master/whiteCurtains.jpg // @icon https://github.com/SloaneFox/imgstore/raw/master/WebEraserIcon.jpg // @run-at document-start // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_getResourceURL // ==/UserScript== // // History // // updated Oct 2016. v1.2.1 Adapted for use also in Google Chrome/Chromium web browser. // updated Sept 2016. v.1.2 Added user option to turn on the monitoring for new nodes (node mutations). if (!chromeInit()) $(main); var iframe=window!=window.parent, border_width=6; var host=window.document.location.host, pathname=window.document.location.pathname, webpage=host+pathname, website=host; var erasedElems=getHidElems(), askedAlready, gelem, gelems, gpre_elem, whiteCurtains_res="whiteCurtains", bblinker, promptOpen, rbcl="sfswe-redborder", pbcl="sfswe-prevborder", tbcl="sfswe-transparentborder"; var tab="      "; // tab=5spaces, emsp=4spaces, but HTML tab in a <pre> wider hence extra emsp's. var curtain_icon=getValue("ownImageAddr","")||GM_getResourceURL(whiteCurtains_res), curtain_cnt=0; var zaplists=new zaplist_composite(), overlay=false; var config=getValue("config",{keepLayout:"checked",monitor:{}}); if (!config.monitor) config.monitor={}; Number.prototype.in=function(){for (i of Array.from(arguments)) if (this==i) return true;}; // Use brackets with a literal, eg, (2).in(3,4,2); Number.prototype.inRange=function(min,max){ if (this >=min && this<=max) return true;}; // Ditto. Number.prototype.withinRangeOf=function(range,target){ return this.inRange(target-range,target+range); }; // Ditto. String.prototype.truncate=function(maxsize) { if (this.length<=maxsize+5) return this; else return this.slice(0,maxsize/2)+"..."+webpage.slice(-maxsize/2); }; //sumarize with ellipsis //thousand's comma, call Number.toLocaleString() if (iframe) console.log=x=>null; //logger(); // Logs from doc start. document.addEventListener("scroll", function(e){ if (!overlay) return; e.preventDefault();e.stopPropagation();e.stopImmediatePropagation();},true); function main() { //timer(); init_jquery(); inner_eraseElements(); //$(window).click(handleClick); window.addEventListener("click",handleClick,true); GM_addStyle( jqueryui_dialog_css //GM_getResourceText ("jqueryUiCss") +".sfswe-prevborder { border-color:transparent !important;border-width:"+border_width+"px !important;border-style:double !important; }" +".sfswe-transparentborder { border-color:transparent !important;border-width:"+border_width+"px !important;border-style:double !important; }" +".sfswe-redborder { border-color:red !important; border-width:"+border_width+"px !important;border-style:double !important; }" ); // A later defined rule has precedence when both rules in effect. //setTimeout(inner_eraseElements,1500); GM_registerMenuCommand("Erase Web Elements ["+(erasedElems?"some erased":"none erased")+"]", eraseElementsCmd,"","", "E"); setTimeout(reattachTornCurtains,2000); gelems=$(); } //main() function keypressHandler(event) { try{ //while prompt is open. //console.log("keypressHandler",event.key); var ip=$("#sfswe-seledel:enabled"); if (ip.length) { //live typing of selector. setTimeout(ip=>{ var cval=ip.val(); if ($(cval).length) { // may unwind. highlightElement(0,"off",null,true); highlightElement($(cval),null,null,true); } },500,ip); } else { // widen/narrow switch(event.key) { case "w": widen(); break; case "n": narrow(); break; default: return; } return false; } } catch(e) {console.error("An key handler error:"+e+" "+e.lineNumber);} }; function handleClick(e,iframe_click) { try { if (e.shiftKey || e.altKey || e.metaKey) return; if (e.ctrlKey) { // cut item, delete element if (e.preventDefault) {e.preventDefault(); e.stopPropagation();} if (!iframe_click) { var seltext_len=window.getSelection().toString().length; window.status="webEraser, Ctrl-Click, on HTML element:"+e.target.tagName+" "+seltext_len+" "+iframe; console.log(window.status,e.target); if (seltext_len != 0) return; if (e.target.blur) e.target.blur(); if (iframe) { window.parent.postMessage("sfswe-iframe-click","*"); // msg,origin return false; } } var permrm, target=e.target; while (/HTMLUnknownElement/.test(target.toString())) target=target.parentNode; //Avoid non HTML tags. if ($(target).is(".WebEraserCurtain")) { let reply=confirm("This will completely remove selected item, continue?"); if (reply!=null) openCurtains("zap",$(target).siblings("img").addBack()); } else if (!askedAlready) checkIfPermanentRemoval(target,function(permrm){ if (permrm==false) { askedAlready=true;alert("You hit TEMP, ctrl-click from now until page is reloaded will merely remove elements from the page temporarily. ");} if (permrm!=undefined) inner_eraseElements("from Click"); //undefined==>escape (cancel) }); else target.style.setProperty("display","none","important"); return false; } // endif e.ctrlKey } catch(e) { console.error("Click handling error:"+e+" "+e.lineNumber); } }; //handleClick() window.addEventListener('message', function(e){ //reads postMessage(). if (e.data!="sfswe-iframe-click") return; var iframeEl=$("iframe").filter(function(){ return this.contentWindow==e.source; }); handleClick({target:iframeEl[0],ctrlKey:true},"iframe_click"); }, false); function sprompt(pretext,initval,cb,cancelbtnText="Cancel",okbtnText="OK") { // "Cancel" returns null reply, empty "OK" returns "" reply, Escape key returns undefined reply. undefined==null is true. but not for "" var input_tag, input_style="width:80%;font-size:small;"; if (initval!==undefined) input_tag=initval.length<50 ? "input" : (input_style="width:95%;height:100px;","textarea"); var content=$("<div class=sfswe-content tabindex=2 style='outline:none;white-space:pre-wrap;'><div >"+pretext+"</div>" +(initval!==undefined ? "<"+input_tag+" spellcheck='false' style='"+input_style+"' tabindex='1'></"+input_tag+">":"")+"</div>"); content.find("input:not(:checkbox),textarea").val(initval); var sp1=$(document).scrollTop(); var dfunc=content.dialog.bind(content); var dialog=content.dialog({ modal: true, width:"60%", // position: { my: "center", at: "center center-25%", of: window }, // Greater percent further to top. buttons: { [cancelbtnText]: function() { cb(null, $(this).find("input,textarea").val()); dfunc("close");}, [okbtnText]: function() { cb($(this).find("input,textarea").val()||""); dfunc("close"); } }, close: function(e) { dialog.off("keydown"); $(document).scrollTop(sp1); if (e.key=="Escape") cb(undefined);dfunc("destroy");} }).parent(); dialog.wrap("<div class=sfswe-sprompt></div>"); // allows css rules to exclude other jqueryUi css on webpage from own settings, a dialog.keydown(function(e){ if (e.key == "Enter" && !/textarea/i.test(e.target.tagName)) $("button:contains("+okbtnText+")",this).click(); }); dialog.css({"z-index":2147483647, position:"fixed", top: "50px"}); dialog.find(".ui-dialog-titlebar").remove(); // No img in css for close 'x' at top right so remove. Title bar not in normal confirm anyhow. dialog.draggable("option","handle", ".ui-dialog-buttonpane"); // dialog.resizable(); setTimeout(function(){content.focus();},100); return dialog; //.ui-dialog } function sconfirm(msg,cb,cancelbtnText,okbtnText) { return sprompt(msg,undefined,cb,cancelbtnText,okbtnText); } function checkIfPermanentRemoval(target,cb) { // called from click handler. var parent=target.parentNode, index=0; var msg="Permanently erase selected element(s) — now seen on page with a red border that blinks?" +"\nUse 'w' and 'n' keys freely, to widen and narrow your selection." +"\nEscape quits, Enter OKs. Use the GM menu <a href='#abc"+Math.random().toString(36)+"'>Erase Web Elements</a> to edit internal code." +"\nHit Temp button below for ctrl-click to erase element(s) temporarily and inhibit this prompting until reload." +"\n\nInternal code for selected<span id=fsfpe-tagel></span>element is:<br>" +"<div style='display:inline-block; position:relative;width:100%'><input disabled id=sfswe-seledel style='width:80%;margin:10px;'>" +"<div style='position:absolute; left:0; right:0; top:0; bottom:0;'></div></div>"; $(document).keypress(keypressHandler); var dialog=sconfirm(msg,function(reply) { // null for cancel button, undefined for escape, otherwise, "" or string. $(document).off('keypress'); $(":data(pewiden-trace)").data("pewiden-trace",""); // remove trace if (reply==="") reply=$("#sfswe-seledel").val().trim(); // reply=="" for ok (ok for confirm of seledel text.) if (reply===undefined) { highlightElement(0,"off","restore"); cb(undefined); return; } //undefined for Escape. if (reply) { sconfirm("Click 'Site' to erase from any page visited on this website, "+website +",\n\nClick 'Page' button to erase selected elements from webpage, "+webpage +".\n\nInternal code for Element:\n\t"+reply,function(reply2, iptxt){ if (reply2===null) addToHidElements(reply); // btn1 -> null, btn2 -> "<string>" null==undefined else if (reply2!=undefined) addToHidElements(reply+" site"); highlightElement(0,"off","restore"); if (reply2!=undefined && $("#sfswe-checkbox6:checked").length) zaplists.add(reply); cb(true); },"Page","Site"); return; }// if reply highlightElement(0,"off","restore"); cb(false); },"Temp","OK"); //confirm(msg); dialog.find(".ui-dialog-buttonpane").prepend("<input id=sfswe-checkbox6 type=checkbox style='margin-left:3px;'><label style='vertical-align: text-bottom;margin-left:7px;'>Completely delete element.</label>"); dialog.find("a").click(eraseElementsCmd); $("#sfswe-seledel").next().click(e=>{ var that=$(e.target).prev(); //, ip=$("<input style='width:80%;' value='"+that.val().trim()+"'>"); that[0].disabled=false; that.next().css("display","none"); that[0].setSelectionRange(999,999); that.focus(); that.blur(e=>{e.target.disabled=true;$(e.target).next().css("display",""); }); }); highlightElement(target); setTimeout(function(){dialog[0].scrollIntoView();},100); }//end checkIfPermanentRemoval() function eraseElementsCmd() { try{ // Called from GM script command menu and from click on prompt. // var sitewide, erasedElems, page_erasedElems=[], site_erasedElems=[], no_sels; erasedElems=getHidElems("withSite"); no_sels=!erasedElems?0:erasedElems.split(/,/).length; var dialog=sprompt( "To erase elements on this page at "+website +", give a selector for it eg, 'DIV#main_column site', optional word 'site' erases the element at the entire website. " +"For more than one selector use commas to separate"+(no_sels?", currently there is/are "+no_sels+" below":"")+". To remove element hiding leave blank. Reload if necessary." , erasedElems.replace(/,/g,", \n"), function(reply){ try{ if (reply == null) return; //cancel ==> null, undefined==> escape. (null is == to undefined!) config={monitor:config.monitor}; delete config.monitor[website]; if ($("#sfswe-checkbox:checked").length) config.noAnimation="checked"; if ($("#sfswe-checkbox2:checked").length) config.keepLayout="checked"; if ($("#sfswe-checkbox3:checked").length) config.hideCurtains="checked"; if ($("#sfswe-checkbox5:checked").length) config.monitor[website]="checked"; if ($("#sfswe-checkbox4:checked").length) { toggleCurtains(); sprompt("Please enter http address of curtain image to be used. If giving left and right images sperate with a space. Leave empty to reset. Accepts base64 image strings.","",function(reply2){ if (reply2!=null) { setValue("ownImageAddr",reply2); curtain_icon=reply2||GM_getResourceURL(whiteCurtains_res); $(".WebEraserCurtain").attr("src",curtain_icon); } toggleCurtains(); }); } else { reply=reply.replace(/\s*,\s*/g,",").replace(/(?=[^,])\n(?=[^,])/g,",").split(/,/); // , newline->comma if none; if no comma all is put in [0] $(reply).each((i,str)=>{ //!!TBD check for dups. if (str=="") return; str=str.trim(); if (/\ssite$/.test(str)) site_erasedElems.push(str.replace(/\ssite$/,"")); else page_erasedElems.push(str); }); try{$(reply);} catch(e){alert("Bad selector given."); throw(e);} setValue("config",config); setValue(website+":erasedElems",site_erasedElems.toString()); setValue(webpage+":erasedElems",page_erasedElems.toString()); zaplists.update(); openCurtains(); $(".Web-Eraser-ed").each(function(){ var that=$(this); that.css({display: that.data("sfswe-display"), visibility: that.data("sfswe-visibility")}); that.removeClass("Web-Eraser-ed"); }); $(".WebEraserCurtains").remove(); setTimeout(inner_eraseElements,1000,"fromPrompt"); //'cos openCurtains takes time //inner_eraseElements("fromPrompt"); } } catch(e){console.error("eraseElementsCmd,"+e+e.lineNumber+e.stack);} }); //dialog=sprompt(...) var keep_layout=config.keepLayout; dialog.find(".ui-dialog-buttonpane").prepend( "<div class=sfswe-ticks style='width:75%;float:left;font-size:10px;'>" +"<input id=sfswe-checkbox2 type=checkbox style='float:left;"+(!keep_layout?" margin:0 3px;":"")+"' "+keep_layout+"><label>Preserve layout (in general).</label>" +(keep_layout ? "<input id=sfswe-checkbox3 type=checkbox style='margin:0 3px 0 10px;height:12px' "+(config.hideCurtains||"")+"><label>Hide curtains (when preserving layout).</label>" : "") +"<br><input id=sfswe-checkbox type=checkbox style='margin-left:3px;'"+(config.noAnimation||"")+"><label>Disable animation (in general).</label>" +"<br><input id=sfswe-checkbox4 type=checkbox style='margin-left:3px;'><label>Set your own curtains' image.</label>" +"<input id=sfswe-checkbox5 type=checkbox style='margin-left:55px;'"+(config.monitor[website]||"")+"><label>Monitor for new elements on this website.</label>" +"</div>" ); dialog.find("input:checkbox").css({"-moz-appearance":"none",height:12}); dialog.find(".ui-dialog-content").attr("title","Current element matches at this webpage:\n"+bodymsg()); } catch(e){console.error("eraseElementsCmd,"+e+e.lineNumber+e.stack);} } //eraseElementsCmd() function inner_eraseElements(from) { try{ // // Called at page load and when user sets selector(s) for erasure. // 1. Go through uncurtained elements for erasure and do curtainClose (or css display to none) on each. // 2. Class each as "Web-Eraser-ed" and backup css values that might get changed. // 3. If changes were made log details to console and to body attribute. // var erasedElems=getHidElems(), len=erasedElems.length, erasedElems_ar=erasedElems.split(/,/), count=0, nomatch=[]; if (erasedElems_ar[0]=="") erasedElems_ar.shift(); //fix split's creation of array length one for empty string. var theErased=$(".Web-Eraser-ed"); theErased.removeClass("Web-Eraser-ed"); erasedElems_ar.forEach(function(sel,i){ erasedElems=$(sel); //Array.from(document.querySelectorAll(sel)); //$(sel), jQ cannot find duplicate ids. erasedElems.each(function() { var eld=this,el=$(eld); // 40msecs per 'each' loop. markForTheCurtains(el,eld,sel); var no_anima=config.noAnimation, keep_layout=config.keepLayout; if (no_anima && !keep_layout) eld.style.setProperty("display","none","important"); else if (el.css("display")!="none") closeCurtains(el, no_anima, measureForCurtains); count++; }); //erasedElems.each() if (erasedElems.length==0) nomatch.push(sel); }); //forEach() theErased=$(".Web-Eraser-ed"); if (len && config.monitor[website]) observeThings(); else observeThings("off"); if (theErased.length==0) { if (len) console.info("WebEraser msg: "+webpage.truncate(20)+" has no match for selectors:",getHidElems()); return; } //////////////////// if (nomatch.length) console.info("No match for some selectors:",nomatch,"at",webpage); var ieemsg="GM script WebEraser is using selectors to hide "+count+(count==1 ? " element that was":" elements that were")+" present on this webpage html: "+webpage +".\nSee GM menu command Erase Web Elements to check and edit selector list. " +(config.keepLayout ? "" : "Keep layout is not ticked.") +(config.noAnimation ? "Animation is off." : "") +(config.hideCurtains ? "Hide curtains is ticked." : ""); theErased.each(function(i){ var that=$(this); var sel=that.attr("selmatch-sfswe"); var onzaplist=zaplists.which(sel); // 10 msecs to here from prev in closeCurtains() above. ieemsg+="\n"+(i+1)+":"+sel; ieemsg+=".\t\t" +(onzaplist.zap ? " => not displaying." : onzaplist.keep_layout ? " => hidden." : "" ); }); count=0; console.info(ieemsg); bodymsg(ieemsg.replace(/(.*\n){2}/,""),"init"); } catch(e){console.info("Error during inner_eraseElements(),"+e+", line:"+e.lineNumber+"\n\t\tStack:\n"+e.stack+" "+erasedElems_ar);} } function closeCurtains(el, noAnimKeepLayout, finishedCB=x=>x) { // called from inner_eraseElements() var that=closeCurtains; if (!that.final_curtain) that.final_curtain=0; var hide_curtains=config.hideCurtains, keep_layout=config.keepLayout; var old_curtained=el.prev().data("covered-el"); if ( ! old_curtained || ! old_curtained.is(el)) var [curtainRod,lrcurtains]=createCurtains(el,noAnimKeepLayout); else { var curtainRod=el.prev(), lrcurtains=curtainRod.children().children(); } var onzaplist=zaplists.which(el); // 20 msecs from prev if (noAnimKeepLayout) { lrcurtains.css({width:"50%"}); if (onzaplist.zap) { curtainRod.css({display:"none"}); el[0].style.setProperty("display","none","important");} // "none" triggers monitor if on. else if (onzaplist.keep_layout||hide_curtains||curtainRod.hasClass("sfsweOverlay")){ curtainRod.css({visibility:"hidden",display:""}); el[0].style.setProperty("visibility","hidden","important"); } measureForCurtains(); } else { // Do animated curtain closing, then, perhaps, fade out. that.final_curtain++; manimate(lrcurtains,["width",50,"%"],2500,6,function(){ ///////////////////////Animation el=$(this).closest(".WebEraserCurtains").data("covered-el"); if (!keep_layout || curtainRod.hasClass("sfsweOverlay")||onzaplist.zap) { el.add(curtainRod).delay(200).fadeOut( 500, function(){ this.style.setProperty("display","none","important"); // triggers monitor if on. if (el[0]==this && --that.final_curtain==0) finishedCB(); }); } else if (hide_curtains||onzaplist.keep_layout) { el.add(curtainRod).delay(200).fadeOut( 1000, function(){ this.style.setProperty("visibility","hidden","important"); this.style.setProperty("display",$(this).data("sfswe-display"),"important"); //triggers monitor. //curtainRod.css({visibility:"hidden",display:""}); curtainRod.remove(); if (el[0]==this && --that.final_curtain==0) finishedCB(); }); } else if (--that.final_curtain==0) finishedCB(); }); //animate() } } //closeCurtains() function getSelectorWithNearestId(target,exclude_classes) { var sel, nearestNonNumericId=target.closest(":regexp(id,^\\D+$)").attr("id"), nnmi=nearestNonNumericId; //closest also checks target if (nnmi) nnmi=$("#"+nnmi).prop("tagName")+"#"+nnmi; //cos of jQ & multiple ids. if ($(nnmi).is(target)) sel=nnmi; else { sel=selector(target,$(nnmi),true,0,exclude_classes); //ok if nnmi is undefined id. if (!sel) sel=nnmi; //both target and $(nnmi) are same element. else if(nnmi) sel=nnmi+sel; } return sel; } function getHidElems(withsite, justpels_ar){ var els, pels=getValue(webpage+":erasedElems","").trim(), sels=getValue(website+":erasedElems","").trim(); if (withsite && sels) { sels=sels.replace(/,/g," site,")+" site"; // see reverse of this in addToHidElements() and eraseElementsCmd(). } if (justpels_ar) return pels.split(","); return pels + (sels && pels ? "," : "") + sels; } function rmFromHidElements(str) { console.log("rmFromHidElements",str); addToHidElements(str,"rm"); } function addToHidElements(str,rm) { // called from checkIfPermanentRemoval() in handleClick on ctrl-click, "cut item" and 'x' del element. var page_erasedElems=getValue(webpage+":erasedElems","").trim(), site_erasedElems=getValue(website+":erasedElems","").trim(), sitewide; console.log("mathc ",page_erasedElems.match(str)); if (!rm) { if (/\ssite$/.test(str)) { sitewide=true; str=str.replace(/\s+site$/,""); } if (sitewide) site_erasedElems += site_erasedElems ? ","+str : str; else page_erasedElems += page_erasedElems ? ","+str : str; } else { if (page_erasedElems.includes(str)) page_erasedElems=$.map(page_erasedElems.split(/,/),el=>el.includes(str)?null:el.trim()).join(","); else if (site_erasedElems.includes(str)) site_erasedElems=$.map(site_erasedElems.split(/,/),el=>el.includes(str)?null:el.trim()).join(","); } console.log("page_erasedElems",page_erasedElems); setValue(website+":erasedElems",site_erasedElems); setValue(webpage+":erasedElems",page_erasedElems); zaplists.update(); } //Blinks are double, one for selected elements, other is only when at top/bottom of narrow/widen chosen. function highlightElement(elem, off, restore, merehl) { //also updates prompt with elem's selector. if (!off) { // on elem=$(elem); if (elem.length==0) return; gpre_elem=gelem; gelem=$(elem); if (!merehl) { var seltext=$("#sfswe-seledel"); //sfs_pesel"); var newsel=getSelectorWithNearestId(gelem,tbcl+" "+rbcl+" Web-Eraser-ed"); gelems=$(newsel).not(gelem); seltext.val(newsel); //+"<pre style='font-size:14.4px;'>\n\tHTML in pre</pre>"); } $("#fsfpe-tagel").text(gelem.prop("tagName").toLowerCase()); gelem.parents().addBack().addClass(tbcl); gelem.find(">:only-child").addClass(tbcl); gelem.add(gelems).toggleClass(rbcl); bblinker=setInterval(function(){ // normal "selected" blink. if (gelems.length) gelems.toggleClass(rbcl); else gelem.toggleClass(rbcl); //.css({borderColor:"red",borderWidth:"9px",borderStyle:"double"}); },1200); gelem.data("pewiden-trace","true"); // if (!gelem.hasClass("pewiden-trace")) //gelem[0].scrollIntoView(); } else { clearInterval(bblinker); gelem.removeClass(rbcl); if (restore) { $("."+tbcl).removeClass(tbcl); return; } return; } } function widen() { // .html() return > encodings, .text() does not. tab as @emsp must be set with html() not text() var seltext=$("#sfswe-seledel"); if (/[:.][^>]+$/.test(seltext.val())) { var newsel=seltext.val().trim().replace(/[:.][^:.]+$/,""); seltext.val(newsel); gelems=$(newsel); gelems.addClass(rbcl); return; } if (gelems.length) { gelems.removeClass(rbcl);gelems=$();} var p=gelem.parent(); if (p.is("html")) { blinkBorders(gelem); //blink double indicates top of hierarchy. return; } highlightElement(0,"off"); highlightElement(p); } function narrow() { if (gelems.length) { widen();narrow(); // Follow trace back to el. return; } var trace=gelem.find(":data(pewiden-trace):first"); // trace left by highlightElement() if(trace.length==0) trace=gelem.find(">:only-child"); if (trace.length==0) { blinkBorders(gelem); return; } highlightElement(0,"off"); highlightElement(trace); } function blinkBorders(elem, interval=150, times=4) { // borders must already be set. times*=2; var cnt=0,i=setInterval(function(){ cnt++; elem.toggleClass(rbcl); //!! elem.toggleClass(tbcl); if (cnt==times) {clearInterval(i);elem.removeClass(rbcl);}// interference so rm class. },interval); } function init_jquery() { $.fn.reverse = Array.prototype.reverse; $.fn.swap = function(to) { var a=this.eq(0), b=$(to).eq(0); var tmp = $('<span>').hide(); a.before(tmp); b.before(a); tmp.replaceWith(b); return; }; $.easing["stepper"] = function (x, t, b, c, maxt) { // eg, see, console.log($.easing) for other funcs. // var y=c*(t/=maxt)*t + b; // if (x<0.4) y=0.1; //console.log(x); //return y; return x; }; $.extend($.expr[':'], { regexp: function(currentobj, i, params, d) { //filter type function. params=params[3].split(/,/); //eg, [ 'regexp', 'regexp', '', 'className,promo$' ] var attr=params[0], re=params[1]; //eg, className, promo$ if (attr=="class") attr="className"; var val=currentobj[attr]+""||""; if (attr=="className") return val.split(/\s/).some(function(cl){return cl.match(re);}); else return val.match(re); }}); //usage eg: $(“div:regexp(className,promo$)”); (function($){ $.event.special.destroyed = { remove: function(o) { if (o.handler) { o.handler(); } } }; })(jQuery); //Usage: $("#anid").bind('destroyed', function() {// do stuff}) // only for is jQ removed el. } //init_jquery() function selector(desc,anc,no_numerals,recursed,exclude_classes) { // descendent, ancestor, such that ancestor.find(ret.val) would return descendant. If no ancestor given it gives it relative to body's parent node. // See example usage in checkIfPermanentRemoval(). Numeraled classes/ids are excluded. anc=$(anc).eq(0); //apply only to first ancestor. if (anc.length==0) anc=$(document.body.parentNode); // !anc wouldnt work for a jq obj. desc=$(desc); if ( (desc.closest(anc).length==0 || desc.length!=1) && !recursed) { console.info("Too many elements or descendant may not related to ancestor:"); console.info("Descendant is:"+selector(desc,0,0,true)); console.info("Ancestor is:"+selector(anc,0,0,true)+"."); return; } // Last element is highest in node tree for .parentsUntil(); var sel= desc.add(desc.parentsUntil(anc)) // up to but not including. .reverse() // see above, needs: $.fn.reverse = Array.prototype.reverse; .map(function() { // works from bottom up to ancestor, hence need for reverse(). var t=$(this), tag=this.tagName.toLowerCase(), nth=t.prevAll(tag).length+1, id, cl, nthcl; id=this.id ? "#"+ this.id : ""; cl=(this.className? "." + $.trim(this.className).replace(/\s/gi, ".") : ""); if (exclude_classes) cl=cl.replace(RegExp(".("+exclude_classes.replace(/ /g,"|")+")","g"),""); if (no_numerals && /\d/.test(id)) id=""; if (no_numerals && /\d/.test(cl)) cl=""; if ( (cl && t.siblings(tag+cl).length==0) || id || t.siblings(tag).length==0) nth=0; else if (cl && t.siblings(tag+cl).length!=0) { cl+=":eq("+t.prevAll(tag+cl).length+")"; //jQuery only has :eq() nth=0; } return tag+(nth?":nth-of-type("+nth+")":"")+id+cl; ////////////////////nth-of-type is One-indexed. }) //map() .get() // .reverse() .join(">"); if (desc.is(anc.find(">"+sel))) { if (anc.is(document.body.parentNode)) return "html>" + sel; return ">"+sel; } else { console.info("Selector result:\n\t"+sel+" Not findable in ancestor, nor in body's parent."); if ($(sel).length) return sel; //Its the very top element, <HTML>. } } function markForTheCurtains(el,eld,sel) { el.css({overflow:"hidden"}).addClass("Web-Eraser-ed").attr("selmatch-sfswe",sel) .data({sfsweDisplay: eld.style.display, sfsweVisibility:eld.style.visibility, sfsweOverflow: eld.style.overflow}); // needed in case zero height element with floating contents. // To make it have dims, in case of zero height with sized contents. } function reattachTornCurtains(curtains=$(".WebEraserCurtains")) { var torn=false; curtains.each(function(){ var that=$(this), el=that.data("covered-el"); if (el.parent().length==0 || !el.hasClass("Web-Eraser-ed")) { torn=true; that.addClass("sfswe-delete","true"); //that.remove(); } }); $(".sfswe-delete").remove(); if (torn) inner_eraseElements(); } function measureForCurtains(curtains=$(".WebEraserCurtains")) { curtains.each(function(){ var that=$(this), el=that.data("covered-el"); //that.next(); // next is the covered elem. var w=el.outerWidth(), h=el.outerHeight(); // Includes padding & border, margin included if 'true' passed. jQuery sets and unsets margin-left during this, provoking attrModifiedListener. if (!el.hasClass("Web-Eraser-ed")) { el.addClass("Web-Eraser-ed"); el.css({overflow:"hidden"}); } var off=moffset(el); that.css(off).css({height:h,width:w}); zoomToShape(that.children()); }); } function bodymsg(str,init) { var b=$("body"); var msg=b.attr("sfswe-message2")||""; if (msg.length>1300) msg=bodymsg.init; if (str) if (init) { b.attr("sfswe-message",str);bodymsg.init=str;} else { b.attr("sfswe-message2",msg+(msg?" ":"")+str);console.info("WebEraser Monitor: "+str); } return b.attr("sfswe-message"); } function observeThings(off) { var that=arguments.callee; that.off=[]; if (that.obs1) { that.obs1.disconnect(); that.obs2.disconnect(); } if (off) return; var sels=getHidElems(), nomonitor=set=>{ if (set==1) { that.off.push(true); that.obs1.takeRecords();} // jquery get causes set, hence inf.loop. if (set==0) { that.off.pop(); that.obs1.takeRecords();} return that.off.slice(-1)[0]; }; var parseCssText=str=>JSON.parse("{" + (str||"").replace(/[\w-]+(?=:)/g,'"$&"').replace(/:\s*(.+?)(?=;)/g,':"$1"').replace(/;/g,",").slice(0,-1) + "}"); console.info("WebEraser msg: Monitoring for creation and appearance of elements to be erased:"+sels); obs1_connect(sels); var cnt=[0,0,0]; function obs1_connect(selectors) { that.obs1=attrModifiedListener(document,selectors,["style"],function(mutrecs,b) { if (nomonitor()) return; nomonitor(1); mutrecs.forEach( mutrec=>{ var target=$(mutrec.target), t=mutrec.target,oldCssDisplay=mutrec.oldValue?mutrec.oldValue.match(/(display:)\s*(\w*);?/):null; var currentValue=target.css("display"); cnt[0]++; var oldval=parseCssText(mutrec.oldValue), currval=parseCssText(t.style.cssText); //console.log("Prev Changes:",csscmp(target.data("olderval"), oldval)+". Compared to current:",csscmp(oldval,currval)); target.data("olderval",oldval); if (currval.display=="none" && oldval.display!="none") { bodymsg("change-nodisplay:"+target.attr("selmatch-sfswe")); target.prev().css("display","none"); measureForCurtains(); } else if (currval.display!="none" && oldval.display=="none" ) { bodymsg("change-display:"+target.attr("selmatch-sfswe")); target.prev().css("display",""); closeCurtains(target,true); } if (parseInt(currval.height||0)- parseInt(oldval.height||0)) { bodymsg("change-height:"+nodeInfo(target)); measureForCurtains(); } }); //forEach nomonitor(0); }); // obs1_connect() } that.obs2=nodeMutationListener(document,sels,function(foundArrayOfNodes, ancestorOfMutation,removed) { if (nomonitor()) return; nomonitor(1); foundArrayOfNodes.forEach(node=>{ var jQnode=$(node); cnt[1]++; if (!removed) { // node inserted. var foundsel; sels.split(/,/).forEach(sel=>{if($(sel).is(jQnode)) foundsel=sel;}); bodymsg("new-node:"+foundsel); markForTheCurtains(jQnode,node,foundsel); setTimeout(x=>{nomonitor(1);closeCurtains(jQnode,false,measureForCurtains);nomonitor(0);},300); } else { // node removed cnt[2]++; //if(jQnode.attr("cc")) { bodymsg("node-delete:"+jQnode.attr("selmatch-sfswe")); $(".WebEraserCurtains[cc='"+jQnode.attr("cc")+"']").remove(); //.filter(function(){return $(this).data()}) measureForCurtains(); //} } });//forEach nomonitor(0); },true);//nodeMutationListener() } function zoomToShape(z,slope=5) { var zoom_scale; z.each(function(i,z){ z=$(z); var sfsdiv=z.parent(), w=sfsdiv.outerWidth(), h=sfsdiv.outerHeight(); zoom_scale=((x,s)=>10 + s*(1000-x)/90|0)(w,slope)/10; //(x=>(2900-2*x)/90|0)(w)/10; zoom_scale*=((x,s)=>5 + s*0.025*(x-20)|0)(h,2)/10; var img=z.children()[0]; z.attr("zoomed-w-h-z",w+"-"+h+"-"+zoom_scale+"-slope-"+slope); zoom_scale = w>1000 ? [1,1] : [zoom_scale,1]; if (GM_getValue("ownImageAddr","")) { var nratio=img.naturalWidth/img.naturalHeight, maxRatio=10, iratio=w/2/h, asp_ratio=iratio/nratio; zoom_scale=[1,Math.min(asp_ratio,maxRatio)]; if (asp_ratio<1) zoom_scale=[Math.min(1/asp_ratio,maxRatio),1]; } z.css("transform","scale("+zoom_scale+")"); }); return zoom_scale; } function openCurtains(zap_or_keep="",curtains=$(".WebEraserCurtain")) { // called from ctrl-click with curtains, eraseElementsCmd() w/o curtains, and lrcurtains.click sets "keep" console.log("openCurtains",zap_or_keep); setTimeout(function() { manimate(curtains,["width",0,"%"],500,3,function() { var that=$(this), erased_el=that.parent().parent().next(); var sel=erased_el.attr("selmatch-sfswe"); switch(zap_or_keep[0]) { case "z": zaplists.add(sel);erased_el.css("display","none");measureForCurtains();break; case "k": zaplists.add(sel,"keep");erased_el[0].style.setProperty("visibility","hidden","important");break; case "t": that.parent().parent().css("display","none"); console.log(that.css("display"),that);break; case "a": console.log("altzap");that.parent().parent().remove();rmFromHidElements(sel);break; } //erased_el.prev().css({display:"none"}); }); },1000); } function createCurtains(el, noAnimKeepLayout) { var h=el.outerHeight()|0,w=el.outerWidth()|0, area=h*w, iw=w/2, pos= moffset(el), warea=window.innerHeight*window.innerWidth, csspos=el.css("position"); // 9 msecs to here from function start. //console.log("closeCurtains h/w",h,w,"pos",pos); var lcurtain=$("<img class='WebEraserCurtain pwe-left' style='left:0;position:relative;' src="+curtain_icon.split(/\s+/)[0]+"></img>"), rcurtain=$("<img class='WebEraserCurtain pwe-right' style='right:0;position:relative;' src="+curtain_icon.split(/\s+/).slice(-1)+"></img>"), curtainRod=$("<sfswediv class=WebEraserCurtains cc="+(++curtain_cnt)+" style='z-index:2147483647; position:absolute; display:block; overflow:hidden;opacity:0.94;'></sfswediv>"), //inline is default here, 'd take full width of parent. zoomer=$("<div class='sfswe-zoomer' style=' height:100%; '></div>"), lrcurtains=lcurtain.add(rcurtain), sel=el.attr("selmatch-sfswe"); el.attr("cc",curtain_cnt); zoomer.append(lcurtain,rcurtain); curtainRod.append(zoomer); lrcurtains.click(function({ctrlKey:ctrl,shiftKey:shift,altKey:alt}) { if (ctrl) return; if (shift) openCurtains("keep_layout",lrcurtains); else if (alt) openCurtains("azap",lrcurtains); else openCurtains("tzap",lrcurtains); return false;}); curtainRod[0].title="Shift-Click here to persistently hide whilst keeping page layout.\nCtrl-click to persistently delete from layout.\nClick to reveal hidden area." +"\nSelector: "+sel; curtainRod.css({height:h,width:w}).css(pos).data({coveredEl:el,selmatchSfswe:sel}); lrcurtains.css({ width: (!noAnimKeepLayout ? 0 : "50%" )}); // Initial width of each curtain. curtainRod.data("zoom",zoomToShape(zoomer)); var scale=curtainRod.data("zoom")[0], calc=50-50/scale; // 50% is fully closed. lrcurtains.width(calc+"%").height("100%"); lrcurtains.data("init-width",calc|0); var portions=area/warea*100|0; //curtainRod.attr("init-calc",(calc|0)+" "+portions); if (portions>=60) { //>75% of window is covered. var visible_area; with (Math) {visible_area=min(w,window.innerWidth)*min(h,window.innerHeight);} if (visible_area>=warea*0.6) { lcurtain.css({left:"10%"}); curtainRod.css({width:"80%",top:"10%"}).addClass("sfsweOverlay"); lrcurtains.css({height:h*0.8}); setTimeout(x=>$("html, body").css("overflow",(i,v) => v=="hidden" ? "auto": null).css("position",(i,v) => v=="fixed" ? "static": null),4000); overlay=true; //First event listener can stop prop to ones added later, ideally would be added at doc-start. console.info("This is an Overlay (>2/3 covered, "+portions+"%): ",sel);}} el.before(curtainRod); return [curtainRod,lrcurtains]; } function toggleCurtains() { var that=arguments.callee; $(".WebEraserCurtains").each(function(){ if (!that.xor) {manimate($(".WebEraserCurtain",this),["width",50,"%"],2000,12);zoomToShape($(".sfswe-zoomer"));} else manimate($(".WebEraserCurtain",this),["width", $(this).data("init-width"),"%"],4000,8); }); } function zaplist_composite() { // composite pattern if (iframe) return; var zlists=[new zaplist(webpage),new zaplist(website),new zaplist(webpage,"kl"),new zaplist(website,"kl")]; this.add=function(sel,keep_layout){ zlists.forEach(function(el) { el.add(sel,keep_layout);}); }; this.contains=function(el){ // may be a dom/jq object or a string selector. return zlists.some(function(list) { return list.contains(el);}); }; this.which=function(el) { if (this.contains(el)) { var has_keep_layout=zlists.map(v => v.contains(el)).includes("kl"); return {keep_layout:has_keep_layout,zap:!has_keep_layout}; } return {keep_layout:false,zap:false}; }; this.update=function(sel){ zlists.forEach(function(el) { el.update();}); }; this.toString=()=>"[object zaplist_composite]"; } function zaplist(key,keytype) { var fullkey=key+":zaplist"+(keytype? ":"+keytype : ""); var savelist=function() { setValue(fullkey,list); }; var readlist=function() { return getValue(fullkey,[]); }; var list=readlist(); //console.log("zaplist created key:",key,", keytype",keytype,", list",list); this.add=function(str,kl) { if (!!kl != !!keytype) return; if(getValue(key+":erasedElems","").split(/,/).includes(str)) { list.push(str); savelist(); } }; this.contains=function(jqobjOrStr){ if (list.length==0) return; if (jqobjOrStr.attr) jqobjOrStr=jqobjOrStr.attr("selmatch-sfswe"); if (list.indexOf(jqobjOrStr) != -1) return keytype||"zap"; }; this.rm=function(str) { var i=list.indexOf(str); if (i!=-1) list.splice(i,1); savelist(); }; this.update=function() { if (list.length==0) return; var strs_ar=getHidElems().split(/,/); list=list.filter(function (lel) { return strs_ar.includes(lel); }); savelist(); }; this.toString=()=>"[object zaplist]"; } function moffset(elem, eld=elem[0]) { if (elem.css("position").includes("fixed")) return Object.assign(elem.position(),{position:"fixed"}); var dominPar=elem.offsetParent()[0]; return left_top(elem); function left_top(elem) { var {left,top}=elem.position(); // jQ sets & unset margintop during this for some reason, margins and floating els may disaffect calc! let margl=parseInt(elem.css('margin-left')), margt=parseInt(elem.css('margin-top')); //let bordl=parseInt(elem.css('border-left-width')), bordt=parseInt(elem.css('border-top-width')); var x = left + margl, y = top + margt; do { //console.log("got y",y," from","top",top,"margt",margt,"bordt",bordt); elem = elem.offsetParent(); if (elem.is(dominPar) || elem.is("html")) break; let {left,top}=elem.position(); // jQ sets & unset margintop during this for some reason, margins and floating els may disaffect calc! console.log(x,nodeInfo(elem),dominPar?nodeInfo(dominPar):""); x += left; y += top; console.log("got y",y," from +",top); } while (true) return { left: x, top: y }; } } // // MutationObserver functions. Eg, var obs=nodeInsertedListener(document,"#results", myCBfunc); function myCBfunc(foundArrayOfNodes, ancestorOfMutation); // Requires jQuery. // See https://www.w3.org/TR/dom/#mutationrecord for details of the object sent to the callback for each change. // Four functions available here: // Parameter, include_subnodes is to check when .innerHTML add subnodes that do not get included in normal mutation lists, these lower nodes are checked when parameeter is true. // Return false from callback to ditch out. function nodeInsertedListener(target, selector, callback, include_subnodes) { return nodeMutation(target,selector,callback,1, include_subnodes); } function nodeRemovedListener(target, selector, callback, include_subnodes) { return nodeMutation(target,selector,callback,2, include_subnodes); } function nodeMutationListener(target, selector, callback, include_subnodes) { //inserted or removed, callback's 3rd parameter is true if nodes were removed. return nodeMutation(target,selector,callback,3, include_subnodes); } function attrModifiedListener(target, selectors, attr, callback) { //attr is array or is not set. var attr_obs=new MutationObserver(attrObserver); var config={ subtree:true, attributes:true, attributeOldValue:true}; if (attr) config.attributeFilter=attr; attr_obs.observe(target, config); function attrObserver(mutations) { var results=mutations.filter(v=>{ return $(v.target).is(selectors);}); if (results.length) callback(results); //console.time("attrObserver"+mutations.length); } return attr_obs; } // // Internal functions: function nodeMutation(target, selectors, callback, type, include_subnodes) { //type new ones, 1, removed, 2 or both, 3. var node_obs=new MutationObserver(mutantNodesObserver); var jQcollection=$(selectors), cnt=0; node_obs.observe(target, { subtree: true, childList: true } ); return node_obs; function mutantNodesObserver(mutations, mu_obs) { var sel_find, muts, node; for(var i=0; i<mutations.length; i++) { if (type!=2) testNodes(mutations[i].addedNodes, mutations[i].target); // target is node whose children changed if (type!=1) testNodes(mutations[i].removedNodes, mutations[i].target,"rmed"); // no longer in DOM. } function testNodes(nodes, ancestor, rmed) { if (nodes.length==0) return; var results=[], subresults=$(); for (var j=0,node; node=nodes[j], j<nodes.length;j++) { if (node.nodeType!=1) continue; if (rmed && jQcollection.is(node)) {results.push(node);jQcollection=jQcollection.not(node);} else if ($(node).is(selectors)) {results.push(node);jQcollection=jQcollection.add(node);} if (include_subnodes) //.innerHTML can add subnodes that do not get included in mutations, these lower nodes are checked here. if (rmed) subresults=$(node).find(jQcollection); else subresults=$(node).find(selectors); } //for results=results.concat(subresults.toArray()); if (results.length) callback(results, ancestor,rmed); } //testNodes() }; } // // End MutationObserver functions. Usage example, var obs=nodeInsertedListener(document,"div.results", myCBfunc); function myCBfunc(foundArrayOfNodes, ancestorOfMutation); // function manimate(objs,[css_attr,target,suffix],interval,noOf_subintervals,CB) { // CB is invoked once, at end. $.animate max-ed out cpu for 30 secs or so. var len=objs.length,cnt=0,i; if (!len) return false; var maxi=objs.length-1, subinterval=interval/noOf_subintervals, init_int=parseInt(objs[0].style[css_attr]), // assume same initital position and same units/suffix for all objs. m=(target-init_int)/noOf_subintervals, linear=(v,i)=>init_int+m*(i+1), // quad=(v,i)=>Math.min(target_int,init_int+(5/3)*Math.pow(i+1,2)-(5/3)*(i+1)), // combo=(v,i)=>quad(v,i)/2+linear(v,i)/2, plotvals=new Uint32Array(noOf_subintervals).map(linear); subinterval+=random(-subinterval/5,subinterval/5), i=setInterval(eppursimuove,subinterval,objs); function eppursimuove(that) { objs.css(css_attr,plotvals[cnt]+suffix); if (++cnt==noOf_subintervals) { clearInterval(i); CB && CB.call(that);}} } function setValue(n,v) { return GM_setValue(n,JSON.stringify(v));} function getValue(n,v) { try { return JSON.parse(GM_getValue(n,JSON.stringify(v)));} catch(e){ var mv=GM_getValue(n,v);setValue(n,mv);return mv;}} // just for migration of verions from non JSON strings. function random(min,max) { return Math.floor(Math.random() * ((max+1) - min)) + min; } function timer() { //console.time() and console.timeEnd() not working at mo. if (window!=window.parent || timer.log) return; var originalLogger = console.log; timer.log=originalLogger; console.log = function () { if (!timer.begin) { timer.begin=Date.now(); originalLogger.call(this,">>>>Init timer "+location+":"); } var args=Array.from(arguments); args.unshift((Date.now()-timer.begin)+"\t"); originalLogger.apply(this, args); }; } function logger() { $(document).dblclick(outputlogger); var originalLogger = console.log; logger.log=originalLogger; console.log = function () { if (!logger.this) logger.this=this; // Do your custom logging logic var argq=$(document).data("loggerq"); var args=Array.from(arguments); if (!argq) argq=[]; if (document.readyState!=logger.state) { argq.push(document.readyState+":"); logger.state=document.readyState; } argq.push(args); $(document).data("loggerq",argq); args.push(document.readyState); originalLogger.apply(this, args); }; } //logger() function csscmp(prevval, newval) { try{ var that=arguments.callee; var covered={}, roll=""; for (let i in prevval) { covered[i]=1; if (newval[i]===undefined) roll+="Removed: "+i+"="+prevval[i]+" "; else if (prevval[i]!=newval[i]) roll+="Changed: "+prevval[i]+" to: "+newval[i]+" "; } for (let i in newval) if (!covered[i]) roll+="Added: "+i+"="+newval[i]+" "; return roll||"Same"; }catch(e) {console.error("csscmp Error",e.lineNumber,e);}} function nodeInfo(node) { return selector(node,node.parentNode,0,0,"Web-Eraser-ed").replace(/^html>body>/,""); } function outputlogger() { var originalLogger=logger.log; var that=logger.this; var argq=$(document).data("loggerq"); originalLogger.call(that,"===============Logger Output=========================="); argq.forEach(function(v){ originalLogger.call(that,v); //this changes in forEach in this case! }); // originalLogger.apply(this,argq); originalLogger.call(that,"===============End Logger Output======================="); return false; }; function logStack(fileToo) { // deepest first. var res="", e=new Error; var s=e.stack.split("\n"); if (fileToo) res="Stack of callers:\n\t\t"; //+s[1].split("@")[0]+"():\n\t\t" for (var i=1;i<s.length-1;i++) res+=s[i].split("@")[0]+"() "+s[i].split(":").slice(-2)+"\n"; return !fileToo ? res : {Stack:s[0]+"\n"+res}; } function Ppositions(el, incl_self,not_pos_break="") { el=$(el); var roll="\n\n"; var els=el.parents(); if (incl_self) els=els.add(el).reverse(); els.each(function(){ var pos=$(this).css("position"); roll+=this.tagName+" "+pos+"\n"; if (! pos.includes(not_pos_break)) return false; // /^((?!relative).)*$/ matches any string, or line w/o \n, not containing the str "relative" }); return roll; } var jqueryui_dialog_css=( "" +".ui-dialog-content,.ui-dialog,.ui-dialog textarea { font-size: 12px; font-family: Arial,Helvetica,sans-serif; border: 1px solid #c5c5c5; " +"background:#fff; color:#333; padding:12px;margin:5px;} " +".ui-dialog-buttonpane { background:whitesmoke; font-size: 10px; cursor:move; border: 1px solid #ddd; overflow:hidden; } " +".ui-dialog-buttonset { float:right; } " +".ui-widget-overlay { background: #aaaaaa none repeat scroll 0 0; opacity: 0.3;height: 100%; left: 0;position: fixed; top: 0; width: 100%;}" +".ui-button,.ui-widget-content { text-align:left; color:#333; border: solid 1px #c5c5c5; padding: 6px 13px;margin: 4px 3px 4px 0;} " +".ui-corner-all,.ui-dialog-buttonpane {border-bottom-left-radius:30px;}" +".ui-button:hover { background-color: #ededed;color:#333; } " +".ui-button { background-color: #f6f6f6;}" +".ui-dialog {position:absolute;padding:3px;outline:none;}" +".ui-resizable-handle { position:absolute; cursor: url(data:image/svg+xml;base64," +"iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAAAAACo4kLRAAAACXBIWXMAAAsTAAALEwEAmpwYAAABAUlEQVQY022RsWrCYACEvz9EK1HQCilYu+jWdNKlj9BNN1/Cp/IBFHTMExihdTCIm0sR26W6KNHkvw6lunjLjffdnXn7fG0/PzzeG0A/m+/Ve/REB3CL/laStn7RBTpOG0iTXgWg0ktSoO20DJDv5gBy3TxgWkQFAG+QSdnAAyhErMtuFSiN0nRUAqpuec2x2V/4YOr7fd2AH/ebR+zhbMOaCWJrF4GphfZ8sEhSNm3EVrJxY5pJkhGAkjtzNRxuyAGws2Ap0DKYWYDbQRek3e6K9A8/TNPhBf5mzbEBvDCTpCz0ADN25gJOkzPAeXICNL85spu8/N0B8LDafK0+ouQXfemVYVtdIewAAAAASUVORK5CYII=" +") 10 10, row-resize; } .ui-resizable-sw {bottom:5px;left:5px;}" +".ui-resizable-w, .ui-resizable-e { width:10px;height:100%;top:-5px;} .ui-resizable-n, .ui-resizable-s { width:100%;height:10px;} .ui-resizable-n {top:-5px; } .ui-resizable-w {left:-5px; } .ui-resizable-e {right:-5px; }" +".ui-tooltip { font-size: 7px; }" +".sfswe-ticks * {font-size:11px;padding:0px;margin:2px;}" +".sfswe-content :-moz-any(div,span,input) { font-size:13px;padding:6px;margin:4px 3px 4px 0;color:#333;}" +".sfswe-content :-moz-any(a,a:visited) { color:#333;text-decoration:underline; padding:0;margin:0;}" +".sfswe-content a:hover {opacity:0.5;}") .replace(/\.ui/g,".sfswe-sprompt .ui"); function chromeInit() { if (!this.GM_getValue || "Barychelidae"!=GM_getValue("arachnoidal","Barychelidae")){ //chromium console.info("WebEraser userscript in non GM_ mode for chrome/safari etc."); this.GM_getValue=function(a,b) { return JSON.parse(localStorage[a]||JSON.stringify(b)); }; this.GM_setValue=function(a,b) { localStorage[a]=JSON.stringify(b);}; this.GM_getResourceURL=function(url) { return "https://github.com/SloaneFox/imgstore/raw/master/whiteCurtains.jpg"; }; this.GM_registerMenuCommand=x=>null; var xhr=new XMLHttpRequest(); xhr.onload = function() { eval(this.response); if (this.responseURL.endsWith("jquery-ui.js")) return; $(main); $(window).click(handleClick); xhr.open('GET', "https://code.jquery.com/ui/1.12.0/jquery-ui.js"); xhr.send(); }; xhr.open('GET', "https://code.jquery.com/jquery-3.1.1.js"); xhr.send(); return true; } else return false; }