GM 2 port - Function Override Helper

Not yet.

当前为 2014-06-18 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/2599/7130/GM%202%20port%20-%20Function%20Override%20Helper.js

  1. // ==UserScript==
  2. // @name GM 2 port - Function Override Helper
  3. // @Description Not yet.
  4. // @namespace org.jixun.gm2.port
  5. // @version 1.0.1
  6.  
  7. // unsafeWindow required to use `exportFunction`.
  8. // @grant unsafeWindow
  9.  
  10. // @run-at document-start
  11. // ==/UserScript==
  12.  
  13. // Check if is GM 2.x
  14. if (typeof exportFunction == 'undefined') {
  15. // For GM 1.x backward compatibility, should work.
  16. var exportFunction = (function (foo, scope, defAs) {
  17. scope[defAs.defineAs] = foo;
  18. }).bind(unsafeWindow);
  19.  
  20. // Well.. It's not going to do anything.
  21. var cloneInto = (function (obj, scope, opt) {
  22. return obj;
  23. }).bind(unsafeWindow);
  24. }
  25.  
  26. /**
  27. * unsafeObject:
  28. * Basically cloneInto but could without scope (Default: unsafeWindow)
  29. *
  30. * @param {Object} obj Object to pass through
  31. * @param {Object} scope Scope where object is going to be applied.
  32. * @param {Object} opt Options
  33. * @return {Object} A reference to the cloned object.
  34. */
  35. var unsafeObject = function (obj, scope, opt) {
  36. return cloneInto (obj, scope || unsafeWindow, opt || {});
  37. };
  38.  
  39. /**
  40. * unsafeDefineFunction
  41. * @param {String} fooName Target name
  42. * @param {Function} foo The function to override
  43. * @param {Object} scope unsafeWindow
  44. * @return {Function} The placeholder function which has been created in the target context.
  45. */
  46. var unsafeDefineFunction = function (fooName, foo, scope) {
  47. // @throw TypeError: can't redefine non-configurable property
  48. // @throw Error: First argument must be a function
  49. return exportFunction (foo, scope || unsafeWindow, {defineAs: fooName});
  50. };
  51.  
  52. /**
  53. * unsafeOverwriteFunction
  54. * @param {Object} fooMapping {name: foo}
  55. * @param {Object} scope unsafeWindow
  56. * @param {String} scopeName Optional, required if target is not `window`.
  57. * e.g. The target is window.api.xxx, '.api' would
  58. * be the scopeName.
  59. * @return {HTML Element} Script Tag
  60. */
  61. var unsafeOverwriteFunction = function (fooMapping, scope, scopeName) {
  62. var argMapping = {}, tmpName;
  63.  
  64. // Mapping new random names.
  65. for (var x in fooMapping) {
  66. if (fooMapping.hasOwnProperty(x)) {
  67. try {
  68. tmpName = 'u_w_f_' + Math.random().toString().slice(2) + +new Date();
  69. // Export function
  70. // unsafeDefineFunction will take care of null values.
  71. unsafeDefineFunction (tmpName, fooMapping[x], scope);
  72. argMapping[x] = tmpName;
  73. } catch (e) {
  74. console.error ('Error at `unsafeOverwrite`:', e);
  75. }
  76. }
  77. }
  78.  
  79. var tmpScript = document.createElement ('script');
  80. tmpScript.textContent = ';('+ (function (j, x) {
  81. for (x in j)
  82. if (j.hasOwnProperty(x))
  83. // Map everything.
  84. // If Object with custom function / Function
  85. // passed in it will throw CloneNonReflectorsWrite.
  86. // Use unsafeOverwriteFunctionSafeProxy if you need to bypass that.
  87. // However, it's going to be slower.
  88. window/**/[x] = window/**/[j[x]];
  89. // TODO: Maybe remove this script tag after finish?
  90. }).toString().replace(/\/\*\*\//g, scopeName ? scopeName : '') +')(' + JSON.stringify(argMapping) + ');';
  91. document.head.appendChild (tmpScript);
  92.  
  93. return tmpScript;
  94. };
  95.  
  96. /**
  97. * ErrorUnsafe:
  98. * An error class for unsafeOverwriteFunctionSafeProxy.
  99. *
  100. * @param {String} name Error Name
  101. * @param {String} message Error Message
  102. */
  103. var ErrorUnsafe = function (name, message) {
  104. return cloneInto ({
  105. name: name || 'ErrorUnsafe',
  106. message: message || 'Unknown error.'
  107. }, scope || unsafeWindow);
  108. };
  109.  
  110. /**
  111. * ErrorUnsafeSuccess:
  112. * An Error Class for unsafeOverwriteFunctionSafeProxy.
  113. * Inform proxy to execute origional function with its full arguments.
  114. *
  115. * @param {[type]} message [description]
  116. * @param {[type]} scope [description]
  117. */
  118. var ErrorUnsafeSuccess = function (message, scope) {
  119. return cloneInto ({
  120. name: 'ErrorUnsafeSuccess: ProxyFinish',
  121. success: true,
  122. message: message || ''
  123. }, scope || unsafeWindow);
  124. };
  125.  
  126. /**
  127. * unsafeOverwriteFunctionSafeProxy
  128. * Similar to unsafeOverwriteFunction, but its a proxy instead.
  129. * It will strip all functions before pass in to sandboxed function.
  130. * So, it can prevent CloneNonReflectorsWrite error.
  131. *
  132. * @param {[type]} fooMapping [description]
  133. * @param {[type]} scope [description]
  134. * @param {[type]} scopeName [description]
  135. * @return {[type]} [description]
  136. */
  137. var unsafeOverwriteFunctionSafeProxy = function (fooMapping, scope, scopeName) {
  138. var argMapping = {}, tmpName;
  139.  
  140. // Mapping new random names.
  141. for (var x in fooMapping) {
  142. if (fooMapping.hasOwnProperty(x)) {
  143. try {
  144. tmpName = 'u_w_f_' + Math.random().toString().slice(2) + +new Date();
  145. // Export function
  146. // unsafeDefineFunction will take care of null values.
  147. unsafeDefineFunction (tmpName, fooMapping[x], scope);
  148. argMapping[x] = tmpName;
  149. } catch (e) {
  150. console.error ('Error at `unsafeOverwrite`:', e);
  151. alert (e);
  152. }
  153. }
  154. }
  155.  
  156. var tmpScript = document.createElement ('script');
  157. tmpScript.textContent = ';('+ (function (j, x) {
  158. for (x in j)
  159. if (j.hasOwnProperty(x)) {
  160. (function (x, bak, foo) {
  161. // Assign variable to our proxy function.
  162. window/**/[x] = function () {
  163. // console.info (arguments);
  164. for (var i = 0, y, args = []; i < arguments.length; i++) {
  165. // Array - Sure we can handle this right?
  166. if (arguments[i] instanceof Array) {
  167. args.push (arguments[i].slice());
  168. } else if (arguments[i] instanceof Object) {
  169. // Strip off all prototype functions, if possible.
  170. // TODO: maybe try-catch the following line?
  171. args.push (JSON.parse(JSON.stringify (arguments[i])));
  172. } else if ('function' == typeof arguments[i]) {
  173. // Function can't be sandboxied :<
  174. args.push (null);
  175. } else {
  176. // idk... should be safe to pass through?
  177. args.push (arguments[i]);
  178. }
  179. }
  180.  
  181. try {
  182. // Try to call our function!
  183. return foo.apply({}, args);
  184. } catch (err) {
  185. // We throw this error on purpose,
  186. // if we need to do the complete callback.
  187. // If the error don'e have success flag, we'll
  188. // throw the error to console.
  189.  
  190. if (!err.success) console.error (err);
  191. return bak.apply ({}, arguments);
  192. }
  193. };
  194. }) (x, window/**/[x], window/**/[j[x]]);
  195. }
  196.  
  197. // TODO: Maybe remove this script tag after finish?
  198. }).toString().replace(/\/\*\*\//g, scopeName ? scopeName : '') +')(' + JSON.stringify(argMapping) + ');';
  199. document.head.appendChild (tmpScript);
  200.  
  201. return tmpScript;
  202. };