1. Greasemonkey Emulation

Emulate the Greasemonkey GM_* functions for other browsers.

目前为 2015-02-14 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/8068/36731/1%20Greasemonkey%20Emulation.js

  1. // ==UserScript==
  2. // @run-at document-start
  3. // @name 1. Greasemonkey Emulation
  4. // @description Emulate the Greasemonkey GM_* functions for other browsers.
  5. // @version 2.0.1c
  6. // @author Lil Devil
  7. // @attribution based on version 1.4.5 by ale5000 http://userscripts-mirror.org/scripts/show/88932
  8. // @namespace http://www.lildevil.org/greasemonkey/
  9. // @include http://*
  10. // @include https://*
  11. // @filename aab-greasemonkey-emulation.user.js
  12. // @filename-IE aab-greasemonkey-emulation.ieuser.js
  13. // @filename-opera aab-greasemonkey-emulation.js
  14. // @uniquescriptname greasemonkey_emulation
  15. // @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
  16. // ==/UserScript==
  17.  
  18. (function()
  19. {
  20. // Settings, can be changed
  21. var enable_GM_registerMenuCommand = true,
  22. override_GM_registerMenuCommand = false,
  23. show_global_config_menu_item = false,
  24. enable_opera_scriptStorage = true,
  25. use_alert_as_fallback = true;
  26.  
  27. // Internal variables, do not change
  28. var version = "2.0";
  29. var unique_script_name = "greasemonkey_emulation";
  30.  
  31. var opera_obj = window.opera, hostname = location.hostname;
  32. var rnd = ( Math.floor(Math.random() * 100) + 1 );
  33. var chrome = (navigator.userAgent.indexOf("Chrome") != -1), midori = (navigator.userAgent.indexOf("Midori") != -1);
  34. var unsfw = null, storage = null, storage_used = false, cross_domain_values = false, opera_script_storage_active = false;
  35. if(opera_obj && enable_opera_scriptStorage) // http://www.opera.com/docs/userjs/specs/#scriptstorage
  36. {
  37. try { storage = opera_obj.scriptStorage; opera_script_storage_active = true; } catch(e) {}
  38. }
  39. if(!storage)
  40. {
  41. opera_script_storage_active = false;
  42.  
  43. if(window.localStorage)
  44. {
  45. storage = localStorage;
  46. if(opera_obj) opera_obj.postError("Go on \"opera:config#PersistentStorage|UserJSStorageQuota\" and set a quota different from 0 like for example 5120 to enable window.opera.scriptStorage");
  47. }
  48. else if(window.globalStorage)
  49. storage = globalStorage[hostname];
  50. }
  51. if((typeof unsafeWindow) != "undefined") unsfw = unsafeWindow; else { unsfw = window; unsafeWindow = unsfw; }
  52.  
  53. var base_obj, userscripts;
  54. var default_toString = function(){ return undefined; };
  55. if(opera_obj) base_obj = opera_obj; else base_obj = window;
  56.  
  57. if((typeof base_obj.userscripts) == "undefined")
  58. {
  59. userscripts = new Object();
  60. userscripts.toString = default_toString;
  61. base_obj.userscripts = userscripts;
  62. if(!opera_obj && !unsfw.userscripts) unsfw.userscripts = userscripts;
  63. }
  64. else
  65. userscripts = base_obj.userscripts;
  66.  
  67. if(userscripts.GME) { userscripts.GME.GM_log("Double execution. Browser bug!!!"); return; }
  68. // https://bugs.launchpad.net/midori/+bug/707166
  69.  
  70. userscripts.GME = new Object();
  71. var gm_extensions = userscripts.GME;
  72.  
  73. if((typeof GM_log) != "undefined") // Firefox
  74. gm_extensions.GM_log = GM_log;
  75. else
  76. {
  77. var opera_postError = null, pro_log_present = false, console_enabled = false;
  78. if(opera_obj) opera_postError = opera_obj.postError;
  79. else if((typeof PRO_log) != "undefined") pro_log_present = true;
  80. else if((typeof console) == "object") console_enabled = true;
  81.  
  82. gm_extensions.GM_log = function(message, displayed_script_name)
  83. {
  84. if(displayed_script_name != undefined) message = displayed_script_name + ":\n" + message;
  85.  
  86. if(opera_postError) // Opera
  87. opera_postError(message);
  88. else if(pro_log_present) // Internet Explorer
  89. PRO_log(message);
  90. else if(console_enabled) // Google Chrome - Midori
  91. try{ console.log(message); } catch(e){ if(use_alert_as_fallback) alert(message); }
  92. else if(use_alert_as_fallback) // Fallback to an alert if other methods fail
  93. alert(message);
  94. };
  95. }
  96.  
  97. var native_getsetvalues_functions = false, is_GM_deleteValue_bultin = false, is_GM_listValues_bultin = false;
  98. gm_extensions.GM_deleteValue = function(name, unique_script_name) { if(!name) return false; if(gm_extensions.GM_getValue(name, undefined, unique_script_name) === undefined) return; gm_extensions.GM_setValue(name, "", unique_script_name); try{ gm_extensions.GM_setValue(name, undefined, unique_script_name); } catch(e){} };
  99. gm_extensions.GM_listValues = function() { return []; }; // Dummy
  100. var get_full_name = function(name, unique_script_name) // unique_script_name is optional but recommended
  101. {
  102. if(unique_script_name != undefined)
  103. return "UserJS_" + unique_script_name + "_" + name;
  104. else
  105. return "UserJS__" + name;
  106. };
  107. if((typeof GM_setValue) != "undefined" && GM_setValue.toString().indexOf("not supported") == -1) // Firefox
  108. {
  109. cross_domain_values = true;
  110. native_getsetvalues_functions = true;
  111. var _GM_getValue = GM_getValue, _GM_setValue = GM_setValue, _GM_deleteValue = null, _GM_listValues = null;
  112. gm_extensions.GM_getValue = function(name, default_value, unique_script_name)
  113. {
  114. if(!name) return; return _GM_getValue(get_full_name(name, unique_script_name), default_value);
  115. };
  116. gm_extensions.GM_setValue = function(name, value, unique_script_name)
  117. {
  118. if(!name) return false; _GM_setValue(get_full_name(name, unique_script_name), value);
  119. };
  120. if((typeof GM_deleteValue) != "undefined")
  121. {
  122. is_GM_deleteValue_bultin = true;
  123. _GM_deleteValue = GM_deleteValue;
  124. gm_extensions.GM_deleteValue = function(name, unique_script_name)
  125. {
  126. if(!name) return false; _GM_deleteValue(get_full_name(name, unique_script_name));
  127. };
  128. }
  129. if((typeof GM_listValues) != "undefined")
  130. {
  131. is_GM_listValues_bultin = true;
  132. _GM_listValues = GM_listValues;
  133. gm_extensions.GM_listValues = _GM_listValues; // ToDO
  134. }
  135. }
  136. else
  137. {
  138. var get_recoverable_string = function(value)
  139. {
  140. var type = (typeof value);
  141. if(type == "boolean")
  142. return "" + value;
  143. if(type == "number")
  144. {
  145. if(isNaN(value)) return "Number.NaN";
  146. if(value == Number.POSITIVE_INFINITY) return "Number.POSITIVE_INFINITY";
  147. if(value == Number.NEGATIVE_INFINITY) return "Number.NEGATIVE_INFINITY";
  148. return "" + value;
  149. }
  150. if(type == "string")
  151. {
  152. var tmp = escape(value);
  153. if(value == tmp) return "'" + value + "'";
  154. return "unescape('" + tmp + "')";
  155. }
  156. if(type == "null" || (type == "object" && value == null))
  157. return "null";
  158. if(type == "date")
  159. return "new Date(" + value.getTime() + ")";
  160.  
  161. alert("Unsupported value in GM_set: " + value);
  162. return "{error: 'Unsupported value.'}";
  163. };
  164.  
  165. if((typeof PRO_setValue) != "undefined") // Internet Explorer
  166. {
  167. cross_domain_values = true;
  168. gm_extensions.GM_getValue = function(name, default_value, unique_script_name)
  169. {
  170. if(!name) return;
  171. var value = PRO_getValue(get_full_name(name, unique_script_name), default_value);
  172. if(value == default_value) return default_value;
  173.  
  174. try { eval("value = " + unescape(value)); } catch(e) { return default_value; }
  175.  
  176. // If the value is equal to default, delete it so it won't waste space
  177. if(value == default_value) gm_extensions.GM_deleteValue(name, unique_script_name);
  178.  
  179. return value;
  180. };
  181. gm_extensions.GM_setValue = function(name, value, unique_script_name)
  182. {
  183. if(!name) return false;
  184. PRO_setValue(get_full_name(name, unique_script_name), escape(get_recoverable_string(value)));
  185. };
  186. gm_extensions.GM_deleteValue = function(name, unique_script_name)
  187. {
  188. if(!name) return false;
  189. if((typeof PRO_deleteValue) != "undefined")
  190. PRO_deleteValue(get_full_name(name, unique_script_name));
  191. else
  192. PRO_setValue(get_full_name(name, unique_script_name), "");
  193. };
  194. if((typeof PRO_listValues) != "undefined") gm_extensions.GM_listValues = PRO_listValues; // ToDO
  195. }
  196. else if(storage)
  197. {
  198. storage_used = true;
  199. if(opera_script_storage_active) cross_domain_values = true;
  200. gm_extensions.GM_getValue = function(name, default_value, unique_script_name)
  201. {
  202. if(!name) return;
  203. var value = storage.getItem(get_full_name(name, unique_script_name));
  204. if(value == null) return default_value;
  205.  
  206. try { eval("value = " + unescape(value)); } catch(e) { return default_value; }
  207.  
  208. // If the value is equal to default, delete it so it won't waste space
  209. if(value == default_value) gm_extensions.GM_deleteValue(name, unique_script_name);
  210.  
  211. return value;
  212. };
  213. gm_extensions.GM_setValue = function(name, value, unique_script_name)
  214. {
  215. if(!name) return false;
  216. storage.setItem(get_full_name(name, unique_script_name), escape(get_recoverable_string(value)));
  217. };
  218. gm_extensions.GM_deleteValue = function(name, unique_script_name)
  219. {
  220. if(!name) return false;
  221. storage.removeItem(get_full_name(name, unique_script_name));
  222. };
  223. gm_extensions.GM_listValues = function(unique_script_name)
  224. {
  225. var list = [], count = 0, storage_length = storage.length, search = null, skip_length = 0; if(storage_length == undefined) return [];
  226.  
  227. if(unique_script_name != undefined) search = "UserJS_" + unique_script_name + "_";
  228. else { search = "UserJS__"; gm_extensions.GM_log("You should avoid using GM_listValues without unique_script_name."); }
  229. skip_length = search.length;
  230.  
  231. for(var i = 0; i < storage_length; i++)
  232. {
  233. name = storage.key(i);
  234. if(name.indexOf(search) == 0) { list[count] = name.substring(skip_length); count++; }
  235. }
  236.  
  237. return list;
  238. };
  239. }
  240. /*else if(window.google && google.gears){ google.gears.factory.create('beta.database'); }*/
  241. else
  242. {
  243. gm_extensions.GM_getValue = function(name, default_value, unique_script_name)
  244. {
  245. if(!name) return;
  246. var full_name = escape(get_full_name(name, unique_script_name));
  247. var cookies = document.cookie.split("; ");
  248. var cookies_length = cookies.length, one_cookie;
  249. for(var i = 0; i < cookies_length; i++)
  250. {
  251. one_cookie = cookies[i].split("=");
  252. if(one_cookie[0] == full_name)
  253. {
  254. var value;
  255. try { eval("value = "+unescape(one_cookie[1])); } catch(e) { return default_value; }
  256.  
  257. // If the value is equal to default, delete it so it won't waste space
  258. if(value == default_value) gm_extensions.GM_deleteValue(name, unique_script_name);
  259.  
  260. return value;
  261. }
  262. }
  263. return default_value;
  264. };
  265. var life_time = 157680000000; // 31536000 * 5 * 1000
  266. gm_extensions.GM_setValue = function(name, value, unique_script_name, action)
  267. {
  268. if(!name) return false;
  269. if(action == "delete") action = -10; else action = life_time;
  270. document.cookie = escape(get_full_name(name, unique_script_name))+"="+escape(get_recoverable_string(value))+";expires="+( new Date( (new Date()).getTime() + action ) ).toGMTString()+";path=/";
  271. };
  272. gm_extensions.GM_deleteValue = function(name, unique_script_name) { return gm_extensions.GM_setValue(name, "", unique_script_name, "delete"); };
  273. gm_extensions.GM_listValues = function() { return []; }; // ToDO
  274. }
  275. }
  276. gm_extensions.GM_areStoredValuesCrossDomain = function()
  277. {
  278. return cross_domain_values;
  279. };
  280.  
  281. if((typeof GM_addStyle) != "undefined") // Firefox
  282. gm_extensions.GM_addStyle = GM_addStyle;
  283. else if((typeof PRO_addStyle) != "undefined") // Internet Explorer
  284. gm_extensions.GM_addStyle = PRO_addStyle;
  285. else
  286. {
  287. gm_extensions.GM_addStyle = function(css_string)
  288. {
  289. var head = document.getElementsByTagName("head"),
  290. stylesheet = document.createElement("style");
  291. stylesheet.type = "text/css";
  292. stylesheet.appendChild(document.createTextNode(css_string));
  293. if(head)
  294. head[0].appendChild(stylesheet);
  295. else
  296. document.documentElement.insertBefore(stylesheet, document.documentElement.firstChild);
  297. };
  298. }
  299.  
  300. gm_extensions.GM_renameMenuCommand = function(){}; // Dummy
  301. if((typeof GM_registerMenuCommand) != "undefined" && GM_registerMenuCommand.toString().indexOf("not supported") == -1 && !override_GM_registerMenuCommand) // Firefox
  302. gm_extensions.GM_registerMenuCommand = GM_registerMenuCommand;
  303. else if((typeof PRO_registerMenuCommand) != "undefined" && !override_GM_registerMenuCommand) // Internet Explorer
  304. gm_extensions.GM_registerMenuCommand = PRO_registerMenuCommand;
  305. else if(!enable_GM_registerMenuCommand)
  306. gm_extensions.GM_registerMenuCommand = function(){}; // Dummy
  307. else
  308. {
  309. gm_extensions.GM_registerMenuCommand = function(caption, command_func, access_key)
  310. {
  311. if (arguments.length === 5) {
  312. // GM 0.9.1 & earlier - http://wiki.greasespot.net/GM_registerMenuCommand
  313. access_key = arguments[4];
  314. }
  315. gm_menu.add_item(caption, command_func, access_key);
  316. };
  317. gm_extensions.GM_renameMenuCommand = function(old_caption, new_caption, new_access_key) {
  318. var gm_menu_list = document.getElementById("gme_menu"),
  319. matching_menu_item,
  320. re = new RegExp("^" + old_caption + "(\\s\\(.\\))?$", "i");
  321.  
  322. // find menu item with old_caption
  323. for (var i=0, len=gm_menu_list.childNodes.length; i<len; i++) {
  324. var this_caption = gm_menu_list.childNodes[i].textContent || gm_menu_list.childNodes[i].innerText;
  325. if (re.test(this_caption)) {
  326. matching_menu_item = gm_menu_list.childNodes[i];
  327. break;
  328. }
  329. }
  330. if (matching_menu_item) {
  331. gm_menu.add_access_key(matching_menu_item, new_caption, new_access_key, i);
  332. return true;
  333. } else {
  334. gm_extensions.GM_log('caption: "' + old_caption +'" not found in GM_renameMenuCommand.');
  335. return false;
  336. }
  337. };
  338.  
  339. var gm_menu = {};
  340. gm_menu.add_access_key = function(obj, menu_text, access_char, skip) {
  341. var menu_updated = false;
  342. if ((typeof access_char == "string") && (access_char.length > 0)) {
  343. access_char = access_char.substr(0,1).toUpperCase();
  344. var gm_menu_list = obj.parentNode,
  345. keycode = access_char.charCodeAt(0),
  346. keycode_in_use = false,
  347. menu_label = menu_text;
  348.  
  349. // see if another menu item uses the same keycode
  350. for (var i=0, len=gm_menu_list.childNodes.length; i<len; i++) {
  351. if ((i !== skip) &&
  352. (gm_menu_list.childNodes[i].getAttribute("accesskeycode") == keycode)) {
  353. keycode_in_use = true;
  354. break;
  355. }
  356. }
  357.  
  358. if (!keycode_in_use) {
  359. var reg_exp = new RegExp("(" + access_char + ")", "i");
  360. menu_label = menu_text.replace(reg_exp, "<u>$1</u>");
  361. if (menu_label == menu_text) {
  362. menu_label += " (<u>" + access_char + "</u>)";
  363. }
  364. obj.innerHTML = menu_label;
  365. obj.setAttribute("accesskeycode", keycode);
  366. menu_updated = true;
  367. }
  368. }
  369. if (!menu_updated) {
  370. obj.innerHTML = menu_text;
  371. obj.removeAttribute("accesskeycode");
  372. }
  373. };
  374.  
  375. var node_contains = function(outer, innie) {
  376. if (outer.contains) {
  377. return outer.contains(innie); // a node is considered to contain itself
  378. } else if (outer.compareDocumentPosition) {
  379. var bitmask = outer.compareDocumentPosition(innie);
  380. return ((bitmask === 0) || // innie "is equal to" outer
  381. !!(bitmask & 16)); // innie "is contained by" outer
  382. }
  383. return false; // unknown
  384. };
  385. gm_menu.create = function() {
  386. gm_menu.icon = document.getElementById("gme_menu_icon");
  387. if (gm_menu.icon) return; // another extension has already created the menu
  388.  
  389. var menu_icon = 'data:image/png;base64,' +
  390. 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/o' +
  391. 'L2nkwAAARNJREFUOMut07ErxGEcx/HXzyFlkIUYDCKTRVZksjIRmWQwMFqfe64MJoPBKINNMd5gNOgMsi' +
  392. 'gr+QOU6EJneU7X5Y6Obz09Pd+e7/v7/Xzqm+Xz+Yo/RDuEELJWimOMlba/dP+aoI7aiW0sYQQ5POIchRD' +
  393. 'CfVMADrGMV0ym3B7WMIWxhoAYY2/qDF0JUkyTwNtPEgZR9SXDDmYxgA5c1wPqTbzDGcrpvYgHlHCBmxjj' +
  394. 'RMMJQgjvWKiRlMNq8iXDKDaw3siDeRQwjGecYBO76EvfPppJOMI4utGPuRBCJUmoRqkZoJjuFxxgOsbYg' +
  395. '6GUv8RxM8AKtnCVZJziFk8pPxNCKNcWfGfifjq/iv/ZhRhjyyv9CYEvRESFg9k9AAAAAElFTkSuQmCC';
  396. // http://webdesign.about.com/od/colorcharts/l/blsystemcolors.htm
  397. gm_extensions.GM_addStyle(
  398. "#gme_menu_icon { z-index:900000;" +
  399. " height:16px; width:16px; position:fixed; right:0; bottom:0;" +
  400. " background-color:transparent; }" +
  401.  
  402. "#gme_menu_icon { cursor:pointer; }" +
  403. "#gme_menu_icon.open, #gme_menu_icon.closed {" +
  404. " background:url('" + menu_icon + "') no-repeat center center; }" +
  405. "#gme_menu_icon.open { background-color:Highlight; }" +
  406. "#gme_menu_icon.closed:hover { background-color:Highlight; }" +
  407. "#gme_menu_icon.open ul { display:block; }" +
  408.  
  409. "#gme_menu { display:none; width:auto; padding:2px; margin:0; position:fixed;" +
  410. " background-color:Menu; right:0; bottom:15px; border:1px solid ThreeDShadow;" +
  411. " -moz-box-shadow:0px 2px 4px rgba(0,0,0,0.5);" +
  412. " -webkit-box-shadow:0px 2px 4px rgba(0,0,0,0.5);" +
  413. " box-shadow:0px 2px 4px rgba(0,0,0,0.5); }" +
  414.  
  415. ".gme_menu_item { background-color:Menu; color:MenuText;" +
  416. " list-style-type:none; padding:0 10px; white-space:pre;" +
  417. " font:11px sans-serif; text-align:left; }" +
  418.  
  419. "#gme_menu li.hover { background-color:Highlight; color:HighlightText; }");
  420.  
  421. gm_menu.icon = document.createElement("div");
  422. gm_menu.icon.id = "gme_menu_icon";
  423.  
  424. var gm_menu_list = document.createElement("ul");
  425. gm_menu_list.id = "gme_menu";
  426. gm_menu.icon.appendChild(gm_menu_list);
  427. var doc_body = document.body || document.documentElement.lastChild || document.documentElement; // HTML.body || HTML.body || HTML
  428. doc_body.appendChild(gm_menu.icon);
  429.  
  430. var is_open_query = function() {
  431. return (gm_menu.icon.className == "open");
  432. };
  433. var simulate_click = function(obj) {
  434. // the menu item may have been added by another invocation of this script
  435. // so when an access_key or enter is pressed, the only way to call the
  436. // command_func is to trigger the click event on the menu item.
  437. if (obj.dispatchEvent) {
  438. var evt = document.createEvent("MouseEvents");
  439. evt.initMouseEvent("click", true, true, window,
  440. 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  441. obj.dispatchEvent(evt);
  442. } else if (obj.fireEvent) {
  443. obj.fireEvent("onclick");
  444. }
  445. };
  446. var window_mousedown_event = function(e) {
  447. if (!e) e = window.event;
  448. var targ = (e.target || e.srcElement);
  449. if (targ.nodeType == 3) targ = targ.parentNode; // Safari
  450.  
  451. if (!node_contains(gm_menu.icon, targ)) {
  452. // not over menu
  453. if (is_open_query()) gm_menu.close();
  454. } else //if (targ.className.indexOf("gme_menu_item") >= 0) {
  455. if (targ.nodeName == "LI") {
  456. // over a menu item - prevent text selection within menu
  457. if (e.preventDefault) e.preventDefault();
  458. e.returnValue = false;
  459. } else {
  460. // over some other part of the menu
  461. if (e.stopPropagation) e.stopPropagation();
  462. e.cancelBubble = true;
  463. if (is_open_query()) gm_menu.close();
  464. else gm_menu.open();
  465. }
  466. };
  467. var window_blur_event = function() {
  468. if (is_open_query()) gm_menu.close();
  469. };
  470. /*
  471. http://asquare.net/javascript/tests/KeyCode.html
  472. http://www.quirksmode.org/js/keys.html
  473. http://unixpapa.com/js/key.html
  474. */
  475. var window_key_event = function(e) {
  476. // Note: In the keydown and keyup events you will get the keycode of the letters
  477. // always in uppercase
  478. // but in the keypress events you will get them in the same case the user typed them.
  479. if (!e) e = window.event;
  480. var keyCode = e.keyCode || e.which;
  481. if (keyCode == 0) return; // Unknown key
  482.  
  483. if (is_open_query()) {
  484. // while the menu is open, prevent all keypresses from doing anything else
  485. if (e.preventDefault) e.preventDefault();
  486. e.returnValue = false;
  487.  
  488. var gm_menu_list = document.getElementById("gme_menu"),
  489. numItems = gm_menu_list.childNodes.length,
  490. menu_item;
  491. if (keyCode == 38) { // up arrow
  492. // find which item is currently highlighted
  493. menu_item = gm_menu.highlighted_item_query();
  494.  
  495. // un-highlight the item
  496. gm_menu.highlight_item(menu_item, false);
  497.  
  498. // get the next item up
  499. if (menu_item && menu_item.previousSibling) {
  500. menu_item = menu_item.previousSibling;
  501. } else {
  502. menu_item = gm_menu_list.lastChild;
  503. }
  504.  
  505. // highlight the new item
  506. gm_menu.highlight_item(menu_item, true);
  507.  
  508. } else if (keyCode == 40) { // down arrow
  509. // find which item is currently highlighted
  510. menu_item = gm_menu.highlighted_item_query();
  511.  
  512. // un-highlight the item
  513. gm_menu.highlight_item(menu_item, false);
  514.  
  515. // get the next item down
  516. if (menu_item && menu_item.nextSibling) {
  517. menu_item = menu_item.nextSibling;
  518. } else {
  519. menu_item = gm_menu_list.firstChild;
  520. }
  521.  
  522. // highlight the new item
  523. gm_menu.highlight_item(menu_item, true);
  524.  
  525. } else if (keyCode == 27) { // esc
  526. gm_menu.close();
  527. } else if (keyCode == 13) { // enter
  528. menu_item = gm_menu.highlighted_item_query();
  529. gm_menu.close();
  530. simulate_click(menu_item);
  531. } else {
  532. // see if one of the menu items uses this keycode
  533. var menu_item_to_handle;
  534. for (var i=0; i<numItems; i++) {
  535. if (gm_menu_list.childNodes[i].hasAttribute("accesskeycode") &&
  536. gm_menu_list.childNodes[i].getAttribute("accesskeycode") == keyCode) {
  537. menu_item_to_handle = gm_menu_list.childNodes[i];
  538. break;
  539. }
  540. }
  541. if (menu_item_to_handle) {
  542. gm_menu.highlight_item(gm_menu.highlighted_item_query(), false);
  543. gm_menu.highlight_item(menu_item_to_handle, true);
  544. window.setTimeout(function() {
  545. gm_menu.close();
  546. simulate_click(menu_item_to_handle);
  547. }, 100);
  548. }
  549. }
  550. } else { // menu is not open
  551. if ((keyCode == 220) && e.ctrlKey) { // ctrl+\
  552. gm_menu.open();
  553. if (e.preventDefault) e.preventDefault();
  554. else e.returnValue = false;
  555. }
  556. }
  557. };
  558. var prevent_selection = function(e) {
  559. if (!e) e = window.event;
  560. if (e.preventDefault) e.preventDefault();
  561. e.returnValue = false;
  562. };
  563. if (document.addEventListener) {
  564. document.addEventListener("mousedown", window_mousedown_event, false);
  565. document.addEventListener("keydown", window_key_event, false);
  566. window.addEventListener ("blur", window_blur_event, false);
  567. } else {
  568. gm_menu.icon.attachEvent("onselectstart", gm_menu.prevent_selection);
  569. document.attachEvent ("onmousedown", window_mousedown_event);
  570. document.attachEvent ("onkeydown", window_key_event);
  571. window.attachEvent ("onblur", window_blur_event);
  572. }
  573. };
  574.  
  575. /*
  576. http://www.quirksmode.org/dom/events/index.html
  577. http://www.quirksmode.org/js/events_properties.html
  578. */
  579. gm_menu.add_item = function(caption, command_func, access_key) {
  580. gm_menu.create();
  581. var gm_menu_list = document.getElementById("gme_menu"),
  582. gm_menu_item = document.createElement("li");
  583. gm_menu_item.innerHTML = caption;
  584. gm_menu_item.className = "gme_menu_item";
  585. gm_menu_list.appendChild(gm_menu_item);
  586. gm_menu.add_access_key(gm_menu_item, caption, access_key);
  587.  
  588. var click_event = function(e) {
  589. if (!e) e = window.event;
  590. if (e.stopPropagation) e.stopPropagation();
  591. e.cancelBubble = true;
  592.  
  593. gm_menu.close();
  594. if ("function" == typeof command_func) command_func();
  595. };
  596. var mouseover_event = function(e) {
  597. // find which item is currently highlighted (in case highlighted via keyboard)
  598. var item = gm_menu.highlighted_item_query();
  599.  
  600. // un-highlight that item
  601. gm_menu.highlight_item(item, false);
  602.  
  603. // highlight this item
  604. if (!e) e = window.event;
  605. var targ = (e.target || e.srcElement);
  606. if (targ.nodeType == 3) targ = targ.parentNode; // Safari
  607. if (targ.nodeName != "LI") targ = targ.parentNode; // underlined access_key
  608. gm_menu.highlight_item(targ, true);
  609.  
  610. };
  611. var mouseout_event = function(e) {
  612. if (!e) e = window.event;
  613. var targ = (e.target || e.srcElement);
  614. if (targ.nodeType == 3) targ = targ.parentNode; // Safari
  615. if (targ.nodeName != "LI") targ = targ.parentNode; // underlined access_key
  616. gm_menu.highlight_item(targ, false);
  617. };
  618.  
  619. if (document.addEventListener) {
  620. gm_menu_item.addEventListener("mouseover", mouseover_event, false);
  621. gm_menu_item.addEventListener("mouseout", mouseout_event, false);
  622. gm_menu_item.addEventListener("click", click_event, false);
  623. } else {
  624. gm_menu_item.attachEvent("onmouseenter", mouseover_event);
  625. gm_menu_item.attachEvent("onmouseleave", mouseout_event);
  626. gm_menu_item.attachEvent("onclick", click_event);
  627. }
  628. };
  629. gm_menu.close = function(e) {
  630. // find which item is currently highlighted
  631. var obj = gm_menu.highlighted_item_query();
  632.  
  633. // close the menu
  634. var gm_menu_icon = document.getElementById("gme_menu_icon");
  635. if (gm_menu_icon) {
  636. gm_menu_icon.className = "closed";
  637. }
  638.  
  639. // un-highlight the item
  640. gm_menu.highlight_item(obj, false);
  641.  
  642. return obj;
  643. };
  644. gm_menu.open = function(e) {
  645. var gm_menu_icon = document.getElementById("gme_menu_icon");
  646. if (gm_menu_icon) {
  647. gm_menu_icon.className = "open";
  648. }
  649. };
  650. gm_menu.highlight_item = function(obj, state) {
  651. if (obj) {
  652. obj.className = (state ? "gme_menu_item hover" : "gme_menu_item");
  653. }
  654. };
  655. gm_menu.highlighted_item_query = function() {
  656. var gm_menu_list = document.getElementById("gme_menu");
  657. for (var i=0, len=gm_menu_list.childNodes.length; i<len; i++) {
  658. if (gm_menu_list.childNodes[i].className.indexOf(" hover") > 0) {
  659. return gm_menu_list.childNodes[i];
  660. }
  661. }
  662. };
  663. }
  664. var GlobalConfiguration = function()
  665. {
  666. var global_variables = {"Script managment":[], "Unknown script":[], "Web page":[]};
  667. var output = "";
  668.  
  669. if(storage_used)
  670. {
  671. var storage_length = storage.length, name, value, pos;
  672. if(storage_length != undefined)
  673. for(var i = 0; i < storage_length; i++)
  674. {
  675. name = storage.key(i);
  676. value = storage.getItem(name);
  677. if(name.indexOf("UserJS_") != 0)
  678. global_variables["Web page"][(global_variables["Web page"].length)] = [name, value];
  679. else
  680. {
  681. name = name.substring(7);
  682. if(name.indexOf("Script_managment-") == 0)
  683. global_variables["Script managment"][(global_variables["Script managment"].length)] = [name.substring(17), value];
  684. else
  685. {
  686. pos = name.indexOf("_");
  687. if(pos == 0)
  688. global_variables["Unknown script"][(global_variables["Unknown script"].length)] = [name.substring(1), value];
  689. else
  690. {
  691. var temp = name.substring(0, pos);
  692. if(!global_variables[temp]) global_variables[temp] = [];
  693. global_variables[temp][(global_variables[temp].length)] = [name.substring(pos+1), value];
  694. }
  695. }
  696. }
  697. }
  698.  
  699. output += "Cross-domain values => " + cross_domain_values + "<br>";
  700. output += "opera.scriptStorage active => " + opera_script_storage_active + "<br>";
  701. output += "window.localStorage => " + (!!window.localStorage) + "<br><br>";
  702. if(storage_length == undefined) output += "Warning: Missing length property in the storage array.<br><br>";
  703. var value, i, global_variables_script_length;
  704. for(var script_name in global_variables)
  705. {
  706. if(script_name == "Script managment") continue;
  707. for(i = 0, global_variables_script_length = global_variables[script_name].length; i < global_variables_script_length; i++)
  708. {
  709. if(script_name != "Web page")
  710. try { eval("value = " + unescape(global_variables[script_name][i][1])); } catch(e) { value = {error: "Failed."}; }
  711. else
  712. value = global_variables[script_name][i][1];
  713. output += script_name + " => " + global_variables[script_name][i][0] + " = " + value + "<br>";
  714. }
  715. if(global_variables_script_length > 0) output += "<br>";
  716. }
  717. global_variables = null;
  718. document.write(output);
  719. output = null;
  720. }
  721. else
  722. alert("Not yet implemented.");
  723. };
  724.  
  725. if (show_global_config_menu_item && storage_used) {
  726. // In Opera, this script runs at document-start, before the DOM is fully created.
  727. // Attempting to add the GM_menu to the DOM would fail.
  728. // This delays the menu creation until the DOM is loaded.
  729. if (opera_obj && document.addEventListener) {
  730. document.addEventListener("DOMContentLoaded", function() {
  731. gm_extensions.GM_registerMenuCommand("Global configuration", GlobalConfiguration, "G");
  732. }, false);
  733. } else {
  734. gm_extensions.GM_registerMenuCommand("Global configuration", GlobalConfiguration, "G");
  735. }
  736. }
  737.  
  738. gm_extensions.unsafeWindow = unsfw;
  739. if(!window.wrappedJSObject) window.wrappedJSObject = unsfw;
  740. if(!window.content) window.content = window.top; // https://developer.mozilla.org/en/DOM/window.content
  741. if(!unsfw.content) unsfw.content = unsfw.top;
  742. if(!unsfw._content) unsfw._content = unsfw.content;
  743.  
  744. if((typeof GM_xmlhttpRequest) != "undefined") // Firefox
  745. gm_extensions.GM_xmlhttpRequest = GM_xmlhttpRequest;
  746. else
  747. {
  748. var error_text = "GM_xmlhttpRequest failed, URL: ";
  749. var cross_domain_note = "\nNote: Cross-domain GM_xmlhttpRequest is disabled, if you are using Opera you must install the \"Cross-domain XMLHttpRequest\" userscript to enable it.";
  750. var cross_domain_opera_xmlhttprequest = (opera_obj ? opera_obj.XMLHttpRequest : null);
  751. var iepro_xmlhttprequest_exist = ((typeof PRO_xmlhttpRequest) != "undefined" ? true : false);
  752. var is_cross_domain_http_request = function(url_req)
  753. {
  754. //gm_extensions.GM_log("is_cross_domain_http_request(" + url_req + ");");
  755. var pos = url_req.indexOf("://");
  756. if( url_req.substring(0, pos + 1) != location.protocol ) return true;
  757.  
  758. url_req = url_req.substring(pos + 3);
  759. pos = url_req.indexOf("/");
  760. if(pos != -1) url_req = url_req.substring(0, pos);
  761. if( url_req != location.host ) return true;
  762.  
  763. return false;
  764. };
  765.  
  766. gm_extensions.GM_xmlhttpRequest = function(details) // http://www.w3.org/Protocols/HTTP/HTRESP.html
  767. {
  768. //gm_extensions.GM_log("XMLHttpRequest of: " + details.url);
  769. var xml_http = null, cross_domain_used = true, cross_domain_req = is_cross_domain_http_request(details.url);
  770. //gm_extensions.GM_log("cross_domain_req => " + cross_domain_req);
  771.  
  772. if(cross_domain_req && cross_domain_opera_xmlhttprequest) // Opera (cross-domain requests only)
  773. xml_http = new cross_domain_opera_xmlhttprequest();
  774. else if(iepro_xmlhttprequest_exist) // Internet Explorer + IEPro
  775. xml_http = PRO_xmlhttpRequest();
  776. else
  777. {
  778. cross_domain_used = false;
  779. if(window.XMLHttpRequest) // The standard
  780. xml_http = new XMLHttpRequest();
  781. else if(window.createRequest) // IceBrowser
  782. xml_http = window.createRequest();
  783. }
  784. if(!xml_http)
  785. { // Simulate a real error
  786. if(details.onerror) details.onerror({ responseText: "", readyState: 4, responseHeaders: "", status: 0, statusText: "GM_xmlhttpRequest failed (missing xml_http object)", finalUrl: details.url });
  787. else gm_extensions.GM_log("GM_xmlhttpRequest failed (missing xml_http object), URL: " + details.url);
  788. return;
  789. }
  790.  
  791. xml_http.onreadystatechange = function()
  792. {
  793. var ready_state = xml_http.readyState;
  794. var status3or4 = (ready_state == 3 || ready_state == 4);
  795. var response =
  796. {
  797. responseText: (status3or4 ? xml_http.responseText : ""),
  798. readyState: ready_state,
  799. responseHeaders: (status3or4 ? xml_http.getAllResponseHeaders() : null),
  800. status: (status3or4 ? xml_http.status : null),
  801. statusText: (status3or4 ? xml_http.statusText : null),
  802. finalUrl: (ready_state == 4 ? details.url : null)
  803. };
  804.  
  805. if(details.onreadystatechange) details.onreadystatechange(response);
  806. if(ready_state == 4)
  807. {
  808. if(xml_http.status >= 200 && xml_http.status < 300) { if(details.onload) details.onload(response); }
  809. else { if(details.onerror) details.onerror(response); }
  810. }
  811. };
  812.  
  813. xml_http.open(details.method, details.url, true);
  814. if(details.headers)
  815. for(var this_header in details.headers) xml_http.setRequestHeader(this_header, details.headers[this_header]);
  816.  
  817. try { xml_http.send(details.data); }
  818. catch(e)
  819. { // Simulate a real error
  820. if(details.onerror) details.onerror({ responseText: "", readyState: 4, responseHeaders: "", status: 403, statusText: "Forbidden", finalUrl: details.url });
  821. else gm_extensions.GM_log(error_text + details.url + (opera_obj && !cross_domain_used && cross_domain_req ? cross_domain_note : ""));
  822. }
  823. };
  824. }
  825.  
  826. if((typeof GM_openInTab) != "undefined") // Firefox
  827. gm_extensions.GM_openInTab = GM_openInTab;
  828. else if((typeof PRO_openInTab) != "undefined") // Internet Explorer
  829. gm_extensions.GM_openInTab = PRO_openInTab;
  830. else
  831. gm_extensions.GM_openInTab = function(url) { return window.open(url, "_blank"); };
  832.  
  833. var gm_emulation_enhanced_scripts = [];
  834. gm_extensions.GM_announcePresence = function(unique_script_name, displayed_name, version)
  835. {
  836. if(unique_script_name.length <= 4) { alert("GM_announcePresence => The \"unique_script_name\" is missing or too short."); return false; }
  837. gm_emulation_enhanced_scripts[gm_emulation_enhanced_scripts.length] = [unique_script_name, displayed_name, version];
  838. return gm_extensions.GM_getValue("is_enabled", true, "Script_managment-" + unique_script_name);
  839. };
  840. gm_extensions.GM_updateCheck = function(update_check_url, installed_version, update_check_every, handle_update_function, unique_script_name)
  841. {
  842. if(!cross_domain_values) return null;
  843. var now = Math.round( ( (new Date()).getTime() ) / 60000 ); // 60000 (1000 * 60) From milliseconds to minutes
  844.  
  845. var last_update_check_global = gm_extensions.GM_getValue("last_update_check", 0, "Script_managment-GLOBAL_SHARED");
  846. if(now - last_update_check_global < 3) return false; // Only one time every 3 minutes maximum
  847.  
  848. if(unique_script_name.length <= 4) { alert("GM_updateCheck => The \"unique_script_name\" is missing or too short."); return false; }
  849.  
  850. var last_update_check = gm_extensions.GM_getValue("last_update_check", 0, "Script_managment-" + unique_script_name);
  851. if(now - last_update_check < update_check_every * 1440) return false; // 1440 (60 * 24) From days to minutes - Only one time every X days maximum
  852.  
  853. gm_extensions.GM_setValue("last_update_check", now, "Script_managment-GLOBAL_SHARED");
  854. gm_extensions.GM_setValue("last_update_check", now, "Script_managment-" + unique_script_name);
  855. gm_extensions.GM_xmlhttpRequest(
  856. {
  857. method: "GET", url: update_check_url, onload: function(result)
  858. {
  859. //gm_extensions.GM_log(result.responseText);
  860. var new_version = /\/\/\s*@version[\t\s]+([^\s\t\r\n]+)\s*\r?\n/i.exec(result.responseText);
  861. var new_unique_script_name = /\/\/\s*@uniquescriptname[\t\s]+([^\s\t\r\n]+)\s*\r?\n/i.exec(result.responseText);
  862.  
  863. if(new_version == null)
  864. {
  865. var error = unique_script_name + " => Failed checking the new version, URL: " + update_check_url;
  866. gm_extensions.GM_log(error);
  867. alert(error);
  868. return null;
  869. }
  870. new_version = new_version[1];
  871. if(new_unique_script_name == null)
  872. gm_extensions.GM_log(unique_script_name + " => The \"uniquescriptname\" is missing on the update server, URL: " + update_check_url);
  873. else if(new_unique_script_name[1] != unique_script_name)
  874. {
  875. var error = unique_script_name + " => The unique script name passed doesn't match the unique script name on the update server, maybe the update_check_url is wrong, URL: " + update_check_url;
  876. gm_extensions.GM_log(error);
  877. alert(error);
  878. return null;
  879. }
  880. gm_extensions.GM_setValue("last_new_version", new_version, "Script_managment-" + unique_script_name);
  881. if(new_version == installed_version) handle_update_function(false);
  882. else handle_update_function(new_version);
  883. }
  884. });
  885.  
  886. return true;
  887. };
  888. gm_extensions.GM_getEmulationVersion = function()
  889. {
  890. return version;
  891. };
  892.  
  893. // 2.0.1: added GM_setClipboard stub
  894. if((typeof GM_setClipboard) != "undefined")
  895. gm_extensions.GM_setClipboard = GM_setClipboard;
  896. else
  897. {
  898. gm_extensions.GM_setClipboard = function(clipAttempt){
  899. console.log("script attempted to use GM_setClipboard, only functional in Greasemonkey or Tampermonkey. Clipped value was:");
  900. console.log(clipAttempt);
  901. };
  902. }
  903.  
  904. // 2.0.1: added GM_getResourceText stub
  905. if((typeof GM_getResourceText) != "undefined")
  906. gm_extensions.GM_getResourceText = GM_getResourceText;
  907. else
  908. {
  909. gm_extensions.GM_getResourceText = function(resTxtAttempt){
  910. console.log("script attempted to use GM_getResourceText, only functional in Greasemonkey or Tampermonkey. Requested value was:");
  911. console.log(resTxtAttempt);
  912. };
  913. }
  914.  
  915. // 2.0.1: added GM_getResourceURL stub
  916. if((typeof GM_getResourceURL) != "undefined")
  917. gm_extensions.GM_getResourceURL = GM_getResourceURL;
  918. else
  919. {
  920. gm_extensions.GM_getResourceURL = function(resUrlAttempt){
  921. console.log("script attempted to use GM_getResourceURL, only functional in Greasemonkey or Tampermonkey. Requested value was:");
  922. console.log(resUrlAttempt);
  923. };
  924. }
  925.  
  926. gm_extensions.GM_exposeAPIs = function()
  927. {
  928. GM_log = gm_extensions.GM_log;
  929. if(!native_getsetvalues_functions)
  930. {
  931. GM_getValue = gm_extensions.GM_getValue;
  932. GM_setValue = gm_extensions.GM_setValue;
  933. }
  934. if(!is_GM_deleteValue_bultin) GM_deleteValue = gm_extensions.GM_deleteValue;
  935. if(!is_GM_listValues_bultin) GM_listValues = gm_extensions.GM_listValues;
  936. GM_areStoredValuesCrossDomain = gm_extensions.GM_areStoredValuesCrossDomain;
  937. GM_addStyle = gm_extensions.GM_addStyle;
  938. GM_registerMenuCommand = gm_extensions.GM_registerMenuCommand;
  939. GM_renameMenuCommand = gm_extensions.GM_renameMenuCommand;
  940. GM_xmlhttpRequest = gm_extensions.GM_xmlhttpRequest;
  941. GM_openInTab = gm_extensions.GM_openInTab;
  942. GM_setClipboard = gm_extensions.GM_setClipboard; // 2.0.1 addition
  943. GM_getResourceText = gm_extensions.GM_getResourceText; // 2.0.1 addition
  944. GM_getResourceURL = gm_extensions.GM_getResourceURL; // 2.0.1 addition
  945. };
  946. gm_extensions.GM_exposeAPIs();
  947. if (window == window.top)
  948. window.setTimeout(function() {
  949. var TarquinWJ = (typeof doGMMeenoo != "undefined"),
  950. ale5000 = ( (typeof window.opera != "undefined") &&
  951. (typeof window.opera.userscripts != "undefined") &&
  952. (typeof window.opera.userscripts.GM != "undefined") ) // version 1.4.5 on Opera
  953. ||
  954. ( (typeof window.userscripts != "undefined") &&
  955. (typeof window.userscripts.GM != "undefined") ) // version 1.4.5
  956. ||
  957. ( (typeof window.userjs != "undefined") &&
  958. (typeof window.userjs.GM != "undefined") ), // versions 1.3.7 through 1.4.4
  959. str = '';
  960. if (TarquinWJ) str += '"Emulate GM functions" by TarquinWJ\n';
  961. if (ale5000) str += '"Greasemonkey Emulation" by ale5000\n';
  962. if (str) alert("You have multiple Greasemonkey emulation scripts installed:\n\n" + str + '"Greasemonkey Emulation" by Lil Devil\n\nOnly the one by Lil Devil should be installed for proper operation.');
  963. }, 5000);
  964.  
  965. var compat_array_indexof = false, compat_array_foreach = false;
  966. gm_extensions.BrowserCompat_Add = function()
  967. {
  968. var result = false;
  969. if(!Array.prototype.indexOf)
  970. {
  971. result = true;
  972. compat_array_indexof = true;
  973. Array.prototype.indexOf = function(find, i /*opt*/)
  974. {
  975. var array_length = this.length;
  976. if(!i) i = 0; else { if(i < 0) i+= array_length; if(i < 0) i= 0; }
  977.  
  978. for(; i < array_length; i++) if(this[i] == find) return i;
  979. return -1;
  980. };
  981. }
  982. if(!Array.prototype.forEach)
  983. {
  984. result = true;
  985. compat_array_foreach = true;
  986. Array.prototype.forEach = function(callback, thisObject /*opt*/)
  987. {
  988. if(!thisObject)
  989. {
  990. for(var i = 0, array_length = this.length; i < array_length; i++) if (i in this) callback(this[i]);
  991. }
  992. else
  993. {
  994. for(var i = 0, array_length = this.length; i < array_length; i++) if (i in this) callback.call(thisObject, this[i]);
  995. }
  996. };
  997. }
  998. return result;
  999. };
  1000.  
  1001. gm_extensions.BrowserCompat_Restore = function()
  1002. {
  1003. if(compat_array_indexof) { delete Array.prototype.indexOf; compat_array_indexof = false; }
  1004. if(compat_array_foreach) { delete Array.prototype.forEach; compat_array_foreach = false; }
  1005. };
  1006.  
  1007. /* var handle_update_function = function(new_version)
  1008. {
  1009. if(new_version != null && new_version != false)
  1010. {
  1011. GM_log("Greasemonkey Emulation => New version detected: " + new_version);
  1012. var result = confirm("A new version of the \"Greasemonkey Emulation\" userscript is available.\nCurrent version: " + version + "\nNew version: " + new_version + "\n\nDo you want to update it now?\nThe update check will run again in 10 days.");
  1013. if(result)
  1014. try { location.href = "http://userscripts.org/scripts/source/105153.user.js"; } catch(e) {}
  1015. }
  1016. };
  1017.  
  1018. // this will only run in Firefox, IE and Opera (with scriptStorage active)
  1019. gm_extensions.GM_updateCheck("http://userscripts.org/scripts/source/105153.meta.js", version, 10, handle_update_function, unique_script_name);
  1020. */
  1021.  
  1022. })();