frisch's UserScript Extender

Extends the document with a new namespace for user script crosswide functions to utilize. Has no use alone but can be accessed by other scripts using document.fExt

当前为 2016-12-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name frisch's UserScript Extender
  3. // @namespace http://null.frisch-live.de/
  4. // @version 0.60
  5. // @description Extends the document with a new namespace for user script crosswide functions to utilize. Has no use alone but can be accessed by other scripts using document.fExt
  6. // @author frisch
  7. // @include *
  8. // @require http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
  9. // @grant GM_setClipboard
  10. // ==/UserScript==
  11. if(document.fExt === undefined) {
  12. console.log("Initializing frisch's UserScript Extender...");
  13.  
  14. // Initialization
  15. fExt = {};
  16. fExt.jq = $;
  17. // Overwrites the contains expression to be case-insensitive
  18. fExt.jq.expr[':'].contains = function(a, i, m) {
  19. return fExt.jq(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
  20. };
  21. fExt.settings = {
  22. minShowTime: 3000, // in milliseconds
  23. maxShowTime: 9000, // in milliseconds
  24. position: "BottomRight", // Position for the popup menu: TopRight, TopLeft, BottomRight, BottomLeft
  25. animationType: "fade", // Animation for the popup menu: slide, fade, none
  26. animationSpeed: 500,
  27. customContextMenu: true,
  28. hideContextMenuOnLeave: true, // automatically fades out the custom context menu when it loses focus, otherwhise only hides when you click somewhere
  29. progressType: "progressbar", //Possible values: hourglass, progressbar
  30. toleranceX: 20, // pixels as tolerance for the context menu, adjust the position slightly
  31. toleranceY: 20, // pixels as tolerance for the context menu, adjust the position slightly
  32. };
  33. fExt.popupQueue = [];
  34. fExt.popping = false;
  35.  
  36. var hourGlass0 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICgkAYfvBAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAKpJREFUSMetlcEOwyAMQ+39/z97h0nrOkjihPZAAYlXVPALcPgQgE7WEzhA8LODKYLfZoTg7dVGcOm0ENx2bQTDgYVgOiwRLCdSBK2pEEHAB6wI2pvaIgj0AReC87SpOtbXEz5Ivq97Zrs/UWvsO8eovTnci6RYPs5VVu6vKkyqFZjFWZ5FI6EYOkiEIlNIgdLUUOJGqmpK+U/rGpSFn8KiYWHiA8X1NM14AxEBKx1JZtGVAAAAAElFTkSuQmCC";
  37. var hourGlass25 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICgR+0Id8AAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAKhJREFUSMetlUkOxCAMBLv4/589h5koG3hjckgAydVtR8bS5oMk24lH+iKsoSx+3zqC++tA1C1cAQ0LT0AewXSZRrDcpBC42xBBeOAiSB0tEUh5wBtB2tQUgVQHnAj63WbRbx3/uA8cfbv3bLWIlxJQT+FQDy4LInUFLkYUHl1ZI6PuIciGrxIZidxdF+TV5y6GH05YC2rqbxc0p8JjsFi/k7aH62436wPGSjUSU11z+AAAAABJRU5ErkJggg==";
  38. var hourGlass50 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICTqUnMkUAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAKpJREFUSMe1lMsOgzAMBHfy///sHopEQsGv0BxAMtpZJ8ErbS4k2Y4e6YuwhrM43nUE66OKmJVM9SRiNWb5lkBc+r4ACi08AZIteAAfQVhwEaRKjwikPOAXQbqpWwRSHXAi6E+bRdc63sgDx9/Wma0e4nQE1LdwyAlmjMhdQRcjkkeRRcbd62L48jhvRuzupx7lPHIizTo/IC35Taxbdwxoy6d7tb8NY2Z9AJxfMxVU9/UgAAAAAElFTkSuQmCC";
  39. var hourGlass75 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICTPtQHGwAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAK1JREFUSMetlUkSgzAMBKf5/5/FIUnFG9ZiOEAVaHqE8Qjp8ECSneiRPggrOIvvNY+gP2URrZLmfhDRG9M9CyCGvgeAi2DSMNVsECwULOoeECzrWVptW4gANi1EATOCcFNLBFIe8EdQT5t5O+t6Yx5s/K3PbHYRmyUg/wo/dycgeO5yurh8+b4LEkkIhsly342k3Bkolt89FOQPQ9Vqe5iifJhxVk/S8c/1NM26AScHLxnJI48dAAAAAElFTkSuQmCC";
  40. var hourGlass100 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICSxgSHxFAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAKpJREFUSMetlUsShDAIBem5/52ZxbhIIhA+40Kr9L0GCSEiwwsR0YkfkR9CG5GF51lHsN+qiNXJ8j6J2AOzfUsgjrwPwBXBy8NLEyAwHBg6B4GpxwxlIHDUONkeCFwtbr0WBIGSoOQPglBHuOiaUl0Ql876/GMejH6BhL1ZRM0pSdqLjaT5fCnYk5tJa+tG0X4ZKFrvHhp2Z6hqr4dp2o8xof2dND5cp7tZvgvYKh27llJDAAAAAElFTkSuQmCC";
  41.  
  42. var pbar0 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCSsaEe8UvgAAALZJREFUSMfdll0OxCAIhAfDjfT+J5Az0adumo1FUXSTnacmVj8ZflpSVQAAEaGlnPPnWUTg1X0+v73wBFjro/C0AvGIIwAj0bF1yHNjD+KKqAWZsam1h98gMwDrYrya7BF7Tes8kJGLpRMQACBVBREpNkpVKeGQvhuWIqtQRHQ5R16FgXrDNQzUs/aYdf9X3nR/akspZqJnh2yt9UflPfPj4Sl59vTCSl/xzii29ZHlSIoaMb31C3teW2ty8diEAAAAAElFTkSuQmCC";
  43. var pbar25 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCSsrQDEUhAAAALZJREFUSMfdlssNxCAMRMfIHUH/FcQ1zZ6yyoEYzG+lnVMkAg+PP4mQBACICGrKOX+fzQxR3efr2wtPgLfeC08zkIh0BaAnOvUOeW5sQUIR1SAjNtX26BtkBOBdTGeT3WOva10E0nOxdAICAEISIkJsFElJOCTtqCIZrUIz43SOoloGag3XZaCWtces+7/ylvtTW0pxEz06ZK/r+lF5j/x4REpeI70w01e6M4ptfeQ5klaNmNb6B29WW2uHr2HMAAAAAElFTkSuQmCC";
  44. var pbar50 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCSs7XYYE4AAAALVJREFUSMfdlssNxCAMRMfIHZn+Kwg1zZ6yyoEYzG+lnVMkAg+PP4mQBACICGoys+9zKQVR3efr2wtPgLfeC08zkIh0BaAnOvUOeW5sQUIR1SAjNtX26BtkBOBdTGeT3WOva10E0nOxdAICAEISIkJsFElJOKThHJmZdNjL6RxFtQzUGq7LQK3qO2bd/5W33J/anLOb6NEhe13Xj8p75McjUvIa6YWZvtKdUWzrI8+RtGrEtNY/mktYa4XsqhcAAAAASUVORK5CYII=";
  45. var pbar75 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCSwJ2hDDpwAAAK1JREFUSMftllEOAyEIRAfDjfD+J9AzsV/bbBpFQWuTpvNlgvJwNCipKgCAiNCSiLzGtVZ4defn3oQnwIrPwtMKxCPeAZjZHVtJngtHENeOWpCITa013INEAFZhvHrYM/aa1nkgM4WlExAAIFUFESk+KFWlhEPinclEhN7s1eUz8uoPCuv3rjfdT23O2ewC0SZbSvnSZYh8PDydnXuBnZDtLcgqNp2AuEAjW0fxC+YyVWuwau4lAAAAAElFTkSuQmCC";
  46. var pbar100 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCTAYVte+CAAAAKJJREFUSMftllEOxCAIRAfDjfT+J9AzzX510w+loLabbDpfJigPR4MKSQCAiKCnnPN33FpDVEd+HU04A6y4F55WIBHpDoBnd2olOS+8goR21IPM2NRboyPIDMAqTFcP22OvaV0E4iksPQEBACEJESFuFElJeEgv6AX9MUiOp7aUYnaB2SZba/2RdTMfj0hn11FgJ2T5mfAAbrl1liNpRxJP/APHYkptRNVvhwAAAABJRU5ErkJggg==";
  47.  
  48. var loader0, loader25, loader50, loader75, loader100;
  49.  
  50. switch(fExt.settings.progressType){
  51. case "progressbar":
  52. loader0 = pbar0;
  53. loader25 = pbar25;
  54. loader50 = pbar50;
  55. loader75 = pbar75;
  56. loader100 = pbar100;
  57. break;
  58. case "hourglass":
  59. loader0 = hourGlass0;
  60. loader25 = hourGlass25;
  61. loader50 = hourGlass50;
  62. loader75 = hourGlass75;
  63. loader100 = hourGlass100;
  64. break;
  65. default:
  66. loader0 = hourGlass0;
  67. loader25 = hourGlass25;
  68. loader50 = hourGlass50;
  69. loader75 = hourGlass75;
  70. loader100 = hourGlass100;
  71. break;
  72. }
  73.  
  74. // Custom Elements
  75. fExt.fExtPopup = $('<div id="fExtPopup" class="fExtElement" style="display:none; position:fixed; width:auto; height:auto; background-color:#545454; padding:10px; border-color:white; border-style:groove; color:white; z-index:10000; text-align:center; font-size:12px;"></div>');
  76. $("body").append(fExt.fExtPopup);
  77.  
  78. fExt.fExtMessage = $('<div id="fExtMessage" class="fExtElement" style="display:none; position:fixed; width:auto; height:auto; background-color:#545454; padding:25px; border-color:white; border-style:groove; color:white; z-index:10000; text-align:center; font-size:large; padding:20px;"></div>');
  79. fExt.fExtMessageText = $('<span style="display: inline-block;"></span>');
  80. fExt.fExtMessageText.appendTo(fExt.fExtMessage);
  81. fExt.fExtMessage.appendTo("body");
  82.  
  83. // Functions
  84. fExt.setLoading = function(percentage){
  85. if(percentage >= 100){
  86. $("link[rel='icon']").attr("href", loader100);
  87. $("link[rel='shortcut icon']").attr("href", loader100);
  88.  
  89. setTimeout(function(){ fExt.setLoading(-1); },fExt.settings.minShowTime);
  90. }
  91. else if(percentage >= 75){
  92. $("link[rel='icon']").attr("href", loader75);
  93. $("link[rel='shortcut icon']").attr("href", loader75);
  94. }
  95. else if(percentage >= 50){
  96. $("link[rel='icon']").attr("href", loader50);
  97. $("link[rel='shortcut icon']").attr("href", loader50);
  98. }
  99. else if(percentage >= 25){
  100. $("link[rel='icon']").attr("href", loader25);
  101. $("link[rel='shortcut icon']").attr("href", loader25);
  102. }
  103. else if(percentage >= 0){
  104. $("link[rel='icon']").attr("href", loader0);
  105. $("link[rel='shortcut icon']").attr("href", loader0);
  106. }
  107. else {
  108. $("link[rel='icon']").attr("href", siteFavIconHref);
  109. $("link[rel='shortcut icon']").attr("href", siteFavIconHref);
  110. }
  111. };
  112.  
  113. fExt.enqueuePopup = function(msg) {
  114. fExt.popupQueue.push(msg);
  115. };
  116.  
  117. fExt.dequeuePopup = function() {
  118. var rv;
  119. if(fExt.popupQueue.length > 0){
  120. rv = fExt.popupQueue[0];
  121. fExt.popupQueue.splice(0, 1);
  122. }
  123. return rv;
  124. };
  125.  
  126. fExt.createStyle = function(newClass) {
  127. $( "<style>" + newClass + "</style>" ).appendTo("head");
  128. };
  129.  
  130. fExt.center = function (element,w) {
  131. if(w !== undefined)
  132. element.width(w);
  133.  
  134. element.css("position", "fixed")
  135. .css("top", (($(window).height() - $(element).outerHeight()) / 2) + "px")
  136. .css("left", (($(window).width() - $(element).outerWidth()) / 2) + "px");
  137. };
  138.  
  139. fExt.popup = function(msg) {
  140. if(msg !== undefined){
  141. if(fExt.popping){
  142. fExt.enqueuePopup(msg);
  143. return;
  144. }
  145. fExt.popping = true;
  146. fExt.fExtPopup.text(msg);
  147.  
  148. fExt.show(fExt.fExtPopup);
  149.  
  150. var showTime = msg.length * 50;
  151.  
  152. if(showTime < fExt.settings.minShowTime)
  153. showTime = fExt.settings.minShowTime;
  154. else if(showTime > fExt.settings.maxShowTime)
  155. shotTime = fExt.settings.maxShowTime;
  156.  
  157. setTimeout(function(){
  158. fExt.hide(fExt.fExtPopup);
  159. setTimeout(function(){
  160. fExt.fExtPopup.text('');
  161. fExt.popping = false;
  162. fExt.popup(fExt.dequeuePopup());
  163. },fExt.settings.animationSpeed);
  164. },showTime);
  165. }
  166. };
  167.  
  168. fExt.clipboard = function(action, text) {
  169. var clipboardCopy, retVal;
  170. action = action.toLowerCase();
  171.  
  172. clipboardCopy = document.createElement('textarea');
  173. var jqClipboardCopy = $(clipboardCopy);
  174. document.body.appendChild(clipboardCopy);
  175. clipboardCopy.value = text;
  176. clipboardCopy.select();
  177.  
  178. var msg;
  179. try {
  180. var successful = document.execCommand(action);
  181. if(successful)
  182. msg = action + " successful";
  183. else
  184. msg = "Could not perform Clipboard-Action " + action;
  185.  
  186. if(clipboardCopy.value.length <= 50)
  187. msg += " (" + clipboardCopy.value + ")";
  188.  
  189. document.fExt.popup(msg);
  190. }
  191. catch (err) {
  192. document.fExt.popup("Error on Clipboard-Action " + action +": " + err);
  193. }
  194.  
  195. if(clipboardCopy)
  196. clipboardCopy.remove();
  197. };
  198.  
  199. fExt.message = function(msg) {
  200. if(msg !== undefined && msg.length > 0){
  201. fExt.fExtMessageText.text(msg);
  202.  
  203. if(!fExt.fExtMessage.is(":visible"))
  204. fExt.show(fExt.fExtMessage);
  205.  
  206. fExt.center($("div#fExtMessage"));
  207. }
  208. else {
  209. fExt.hide(fExt.fExtMessage);
  210. setTimeout(function(){
  211. fExt.fExtMessageText.text('');
  212. },fExt.settings.animationSpeed);
  213. }
  214. };
  215.  
  216. fExt.rotate = function(element, rotation) {
  217. var jqEl = $(element);
  218. var degree = jqEl.data('rotation');
  219.  
  220. if (!degree)
  221. degree = 0;
  222.  
  223. degree += rotation;
  224.  
  225. jqEl.css('-webkit-transform','rotate(' + degree + 'deg)');
  226. jqEl.data('rotation',degree);
  227. };
  228.  
  229. fExt.zoom = function(element, zoom){
  230. var jqEl = $(element);
  231. var zValue = parseFloat(jqEl.css('zoom'));
  232. var zAdd = parseFloat(zoom) / 100;
  233.  
  234. if(!zValue)
  235. zValue = 1.0;
  236.  
  237. var zNew = zValue + zAdd;
  238. jqEl.css('zoom', zNew);
  239. };
  240.  
  241. fExt.zoomIn = function(element, zoom){
  242. fExt.zoom(element, zoom);
  243. };
  244.  
  245. fExt.zoomOut = function(element, zoom){
  246. fExt.zoom(element, zoom * -1);
  247. };
  248.  
  249. switch(fExt.settings.animationType) {
  250. case "fade":
  251. fExt.show = function(element, speed) {
  252. if(speed === undefined)
  253. speed = fExt.settings.animationSpeed;
  254. $(element).fadeIn(speed);
  255. };
  256. fExt.hide = function(element, speed) {
  257. if(speed === undefined)
  258. speed = fExt.settings.animationSpeed;
  259. $(element).fadeOut(speed);
  260. };
  261. break;
  262. case "slide":
  263. fExt.show = function(element, speed) {
  264. if(speed === undefined)
  265. speed = fExt.settings.animationSpeed;
  266. $(element).slideDown(speed);
  267. };
  268. fExt.hide = function(element, speed) {
  269. if(speed === undefined)
  270. speed = fExt.settings.animationSpeed;
  271. $(element).slideUp(speed);
  272. };
  273. break;
  274. //case "none":
  275. default:
  276. fExt.show = function(element, speed) {
  277. if(speed === undefined)
  278. speed = fExt.settings.animationSpeed;
  279. $(element).show(speed);
  280. };
  281. fExt.hide = function(element, speed) {
  282. if(speed === undefined)
  283. speed = fExt.settings.animationSpeed;
  284. $(element).hide(speed);
  285. };
  286. break;
  287. }
  288.  
  289. switch(fExt.settings.position) {
  290. case "TopRight":
  291. fExt.fExtPopup.attr("style", fExt.fExtPopup.attr("style") + "top:50px; right:50px;");
  292. break;
  293. case "TopLeft":
  294. fExt.fExtPopup.attr("style", fExt.fExtPopup.attr("style") + "top:50px; left:50px;");
  295. break;
  296. case "BottomRight":
  297. fExt.fExtPopup.attr("style", fExt.fExtPopup.attr("style") + "bottom:50px; right:50px;");
  298. break;
  299. case "BottomLeft":
  300. fExt.fExtPopup.attr("style", fExt.fExtPopup.attr("style") + "bottom:50px; left:50px;");
  301. break;
  302. default:
  303. break;
  304. }
  305.  
  306. var siteFavIcon = $("link[rel='icon']");
  307. if(siteFavIcon === undefined) {
  308. $("head").append('<link id="favIcon" rel="icon" href="');
  309. siteFavIcon = $("link[rel='icon']");
  310. }
  311. else {
  312. siteFavIcon.attr("id","favIcon");
  313. }
  314. var siteFavIconHref = siteFavIcon.attr("href");
  315.  
  316. fExt.getSelection = function() {
  317. return window.getSelection().toString();
  318. };
  319.  
  320. fExt.getSource = function(element) {
  321. var retVal;
  322.  
  323. var jqTarget = $(element);
  324. var ucTagName = element.tagName.toUpperCase();
  325.  
  326. switch(ucTagName) {
  327. case "IMG":
  328. retVal = element.src;
  329. break;
  330. case "A":
  331. retVal = element.href;
  332. break;
  333. case "VIDEO":
  334. var videoSource = jqTarget.find("source");
  335. retVal = (videoSource !== undefined) ? videoSource.get(0).src : undefined;
  336. break;
  337. case "INPUT":
  338. return jqTarget.val();
  339. default:
  340. jqTarget = $(element).closest("a");
  341. if(jqTarget.length > 0)
  342. retVal = jqTarget.attr("href");
  343. break;
  344. }
  345.  
  346. if(retVal) {
  347. if(!retVal.match("http.*")) {
  348. retVal = window.location.origin + retVal;
  349. }
  350. }
  351. else {
  352. retVal = $(element).text();
  353. }
  354.  
  355. return retVal;
  356. };
  357.  
  358. fExt.createStyle(".fExtLoader { background:url('" + loader50 + "') #EFF7FF no-repeat top center; }");
  359.  
  360. // ContextMenu
  361. fExt.ctxMenu = [];
  362.  
  363. // Styles
  364. fExt.createStyle("#fExtContextMenu,#fExtContextMenu * { text-align: left !important; text-decoration: none !important; color: #fff; }");
  365. fExt.createStyle("#fExtContextMenu { position: fixed; z-index: 10000; }");
  366. fExt.createStyle("#fExtContextMenu,.ctxSubList { font-size: 14px; background-color: #263238; width: 300px; height: auto; padding: 0;}");
  367. fExt.createStyle("#fExtContextMenu a,#fExtContextMenu hr,#fExtContextMenu li { width: 100%;}");
  368. fExt.createStyle("#fExtContextMenu .ctxElement { float: left; clear: left;}");
  369. fExt.createStyle("#fExtContextMenu li>a,#fExtContextMenu li>div,.ctxSubList li>a,.ctxSubList li>div { padding: 8px;}");
  370. fExt.createStyle("#fExtContextMenu li hr { margin: 0; border-style: solid; border-color: #666; border-width: 1px 0 0 0;}");
  371. fExt.createStyle("#fExtContextMenu li.ctxSub { cursor: default; font-weight: bold;}");
  372. fExt.createStyle("#fExtContextMenu li.ctxSub * { cursor: pointer; font-weight: normal;}");
  373. fExt.createStyle("#fExtContextMenu li { list-style-type: none; margin: 0 !important;}");
  374. fExt.createStyle("#fExtContextMenu li.ctxSub:hover>div.ctxSubLabel,");
  375. fExt.createStyle("#fExtContextMenu li.ctxSub:hover>div.ctxArrow {}");
  376. fExt.createStyle("#fExtContextMenu li.ctxItem { padding-left: 5px;}");
  377. fExt.createStyle("#fExtContextMenu li.ctxItem { border: none; position: initial; box-sizing: border-box; transition: all 250ms ease; }");
  378. fExt.createStyle("#fExtContextMenu li.ctxItem:hover { background: #3a7999; color: #3a7999; box-shadow: inset 0 0 0 3px #3a7999; }");
  379. fExt.createStyle("#fExtContextMenu li.ctxSub.disabled div.ctxSubLabel:hover,");
  380. fExt.createStyle("#fExtContextMenu li.ctxItem.disabled:hover a,#fExtContextMenu li.disabled div.ctxSubLabel,#fExtContextMenu li.disabled a { opacity: 0.70; font-style: italic; padding-left: 7px !important;}");
  381. fExt.createStyle("#fExtContextMenu li.ctxSeparator { display: inline-block;}");
  382. fExt.createStyle("#fExtContextMenu li.ctxSub div.ctxSubLabel { padding-left: 10px !important; float: left; clear: left;}");
  383. fExt.createStyle("#fExtContextMenu li.ctxSub div.ctxArrow { float: right; clear: right;}");
  384. fExt.createStyle("#fExtContextMenu li.ctxSub ul.ctxSubList { position: absolute; height: auto;}");
  385.  
  386. // Default variables
  387. fExt.ctxMenu.uniqueID = 1;
  388. fExt.ctxMenu.allItems = [];
  389. fExt.ctxMenu.actor = undefined;
  390. fExt.ctxMenu.html = $('<ul id="fExtContextMenu" class="ctxElement" style="display: none;"></ul>');
  391. fExt.ctxMenu.html.appendTo("body");
  392.  
  393. // Private Methods
  394. ctxCtor = function(ret, sub) {
  395. ret.ItemText = function(value){
  396. if(value === undefined)
  397. return this.item.text();
  398.  
  399. this.item.text(value);
  400. };
  401. ret.Attribute = function(attribute, value){
  402. if(value === undefined)
  403. return this.item.attr(attribute);
  404. else
  405. this.item.attr(attribute, value);
  406. };
  407. ret.Toggle = function(enabled){
  408. if(enabled === true || (enabled === undefined && this.hasClass("disabled")))
  409. this.removeClass("disabled");
  410. else
  411. this.addClass("disabled");
  412. };
  413. ret.IsDisabled = function(){
  414. return this.hasClass("disabled");
  415. };
  416. ret.ID = function() {
  417. return this.data("Item-ID");
  418. };
  419. };
  420.  
  421. getParentFrom = function(sub){
  422. if(sub !== undefined)
  423. return $(sub).find("ul:first");
  424. else
  425. return fExt.ctxMenu.html;
  426. };
  427.  
  428. setZIndex = function(item, parent){
  429. var parentzIndex = parent.css("z-index");
  430. parentzIndex++;
  431. item.css("z-index", parentzIndex);
  432. item.children().each(function(){ $(this).css("z-index", parentzIndex); });
  433. };
  434.  
  435. // Public Methods
  436. fExt.ctxMenu.addItem = function(label, unused, sub){
  437. var ret = $('<li class="ctxItem ctxElement"></li>');
  438. var retObj = $('<a href="#" class="ctxElement"></a>');
  439. retObj.appendTo(ret);
  440. ret.item = retObj;
  441.  
  442. var parentMenu = getParentFrom(sub);
  443. ret.appendTo(parentMenu);
  444. setZIndex(ret, parentMenu);
  445.  
  446. ctxCtor(ret, sub);
  447.  
  448. ret.Action = undefined;
  449. ret.ItemText(label);
  450. fExt.ctxMenu.assignID(ret);
  451. return ret;
  452. };
  453.  
  454. fExt.ctxMenu.addSub = function(label, orientation, sub){
  455. var ret = $('<li class="ctxElement ctxSub"><div class="ctxElement ctxArrow">&gt;</div><ul class="ctxElement ctxSubList" style="display: none"></ul></li>');
  456. var item = $('<div class="ctxElement ctxSubLabel">' + label + ' </div>');
  457. item.appendTo(ret);
  458.  
  459. ctxCtor(ret, sub);
  460.  
  461. var parentMenu = getParentFrom(sub);
  462.  
  463. if(orientation === 'bottom' || orientation === undefined || $(parentMenu).children().length === 0) {
  464. ret.appendTo(parentMenu);
  465. }
  466. else {
  467. ret.insertBefore($(parentMenu).children("li:first"));
  468. }
  469.  
  470. setZIndex(ret, parentMenu);
  471.  
  472. return ret;
  473. };
  474.  
  475. fExt.ctxMenu.addSeparator = function(sub){
  476. var ret = $('<li class="ctxElement ctxSeparator"><hr/></li>');
  477.  
  478. var parentMenu = getParentFrom(sub);
  479.  
  480. ret.appendTo(parentMenu);
  481. setZIndex(ret, parentMenu);
  482.  
  483. return ret;
  484. };
  485.  
  486. fExt.ctxMenu.assignID = function(item){
  487. if(item.ID() !== undefined)
  488. console.log("Item already has an ID: " + item.ID());
  489.  
  490. item.data("Item-ID", fExt.ctxMenu.uniqueID);
  491. fExt.ctxMenu.uniqueID++;
  492. fExt.ctxMenu.allItems.push(item);
  493. };
  494.  
  495. fExt.ctxMenu.getItem = function(id) {
  496. if(id !== undefined) {
  497. for(i = 0;i < fExt.ctxMenu.allItems.length; i++){
  498. var item = fExt.ctxMenu.allItems[i];
  499. if(id === item.ID())
  500. return item;
  501. }
  502. }
  503.  
  504. return undefined;
  505. };
  506.  
  507. // Events
  508. $("#fExtContextMenu").on("click", "li", function( event ) {
  509. var sender = fExt.ctxMenu.getItem($(this).data("Item-ID"));
  510. if(sender === undefined || sender.Action === undefined)
  511. return true;
  512.  
  513. event.preventDefault();
  514. if(!sender.IsDisabled())
  515. sender.Action(event, sender, fExt.ctxMenu.actor);
  516.  
  517. fExt.hide(fExt.ctxMenu.html);
  518. return false;
  519. });
  520.  
  521. $("#fExtContextMenu").on("mouseenter", "li.ctxSub", function(event){
  522. var sub = $(this);
  523. var subOffs = sub.offset();
  524. var ul = sub.children("ul.ctxSubList:first");
  525.  
  526. if(ul.children("li.ctxItem, li.ctxSub").length === 0)
  527. return;
  528.  
  529. fExt.show(ul, 0);
  530.  
  531. var height = ul.height();
  532. var width = ul.width();
  533. var y = subOffs.top;
  534. var x = subOffs.left + sub.width();
  535. if ((x + width) >= window.screen.availWidth)
  536. x = subOffs.left - ul.width();
  537. if ((y + height + 100 - window.scrollY) >= window.screen.availHeight)
  538. y = y - height;
  539.  
  540. if ((y - window.scrollY) < 0)
  541. y = window.scrollY;
  542. if ((x - window.scrollX) < 0)
  543. x = window.scrollX;
  544.  
  545. ul.offset({ top: y, left: x});
  546. });
  547.  
  548. $("#fExtContextMenu").on("mouseleave", "li.ctxSub", function(event){
  549. var ul = $(this).children("ul.ctxSubList:first");
  550. fExt.hide(ul);
  551. });
  552.  
  553. $("#fExtContextMenu").on("mouseenter", "li.ctxSub", function(event){
  554. var ul = $(this).children("ul.ctxSubList:first");
  555. ul.stop();
  556. if($(this).find("li.ctxItem").length > 0)
  557. ul.show(0);
  558. });
  559.  
  560. fExt.customContextMenuHandler = function (event){
  561. event.preventDefault();
  562.  
  563. fExt.ctxMenu.actor = $(event.target);
  564.  
  565. var y = event.clientY - fExt.settings.toleranceY,
  566. x = event.clientX - fExt.settings.toleranceX;
  567. if ((x + fExt.ctxMenu.html.width()) >= window.screen.availWidth)
  568. x = x - fExt.ctxMenu.html.width() + (fExt.settings.toleranceX * 1.5);
  569. if ((y + fExt.ctxMenu.html.height() + 100) >= window.screen.availHeight)
  570. y = y - fExt.ctxMenu.html.height() + (fExt.settings.toleranceY * 1.5);
  571.  
  572. if (y < 0)
  573. y = 0;
  574. if (x < 0)
  575. x = 0;
  576.  
  577. fExt.ctxMenu.html.css({
  578. top: y,
  579. left: x
  580. });
  581.  
  582. $("#fExtContextMenu").trigger("fExtContextMenuOpening", [fExt.ctxMenu.actor]);
  583.  
  584. fExt.show(fExt.ctxMenu.html, 0);
  585.  
  586. return false;
  587. };
  588.  
  589. $("#fExtContextMenu").on("fExtContextMenuOpening", function(event, actor){
  590. });
  591.  
  592. if(fExt.settings.hideContextMenuOnLeave) {
  593. $("#fExtContextMenu").mouseleave(function(){
  594. fExt.hide(fExt.ctxMenu.html);
  595. });
  596. $("#fExtContextMenu").mouseenter(function(){
  597. fExt.ctxMenu.html.stop();
  598. fExt.ctxMenu.html.show(0);
  599. });
  600. }
  601. else {
  602. $("body").click(function(e){
  603. if(!$(this).hasClass("ctxElement") && fExt.ctxMenu.html.is(":visible"))
  604. fExt.hide(fExt.ctxMenu.html,0);
  605. });
  606. }
  607.  
  608. $(document).on('contextmenu', function(event){
  609. if(fExt.settings.customContextMenu) {
  610. if(!$(event.target).hasClass("ctxElement"))
  611. fExt.customContextMenuHandler(event);
  612. else
  613. fExt.ctxMenu.html.hide();
  614. }
  615. });
  616.  
  617. $(document).on('keyup', function(event){
  618. if((event.which === 17 && event.altKey) || (event.which === 18 && event.ctrlKey)) {
  619. fExt.settings.customContextMenu = !fExt.settings.customContextMenu;
  620. fExt.popup("Context-Menu has been toggled " + (fExt.settings.customContextMenu ? "on" : "off"));
  621. }
  622. });
  623.  
  624. // Finalize
  625. document.fExt = fExt;
  626.  
  627. fExt.fExtPopup.click(function(e){
  628. fExt.popupQueue = [];
  629. fExt.hide($(this));
  630. });
  631.  
  632. fExt.fExtMessage.click(function(e){
  633. fExt.hide($(this));
  634. });
  635.  
  636. console.log("frisch's UserScript Extender initialized!");
  637. }

QingJ © 2025

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