utils.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. var scriptUtils = {
  2. isRemote: function (url) {
  3. return url && !(/^(file|data):/.test(url));
  4. },
  5. fetch: function (url, type, headers) {
  6. var xhr = new XMLHttpRequest;
  7. xhr.open('GET', url, true);
  8. if (type) xhr.responseType = type;
  9. if (headers) for (var k in headers)
  10. xhr.setRequestHeader(k, headers[k]);
  11. return new Promise(function (resolve, reject) {
  12. xhr.onload = function () {
  13. resolve(this);
  14. };
  15. xhr.onerror = function () {
  16. reject(this);
  17. };
  18. xhr.send();
  19. });
  20. },
  21. parseMeta: function (code) {
  22. // initialize meta, specify those with multiple values allowed
  23. var meta = {
  24. include: [],
  25. exclude: [],
  26. match: [],
  27. require: [],
  28. resource: [],
  29. grant: [],
  30. };
  31. var flag = -1;
  32. code.replace(/(?:^|\n)\/\/\s*([@=]\S+)(.*)/g, function(m, group1, group2) {
  33. if (flag < 0 && group1 == '==UserScript==')
  34. // start meta
  35. flag = 1;
  36. else if(flag > 0 && group1 == '==/UserScript==')
  37. // end meta
  38. flag = 0;
  39. if (flag == 1 && group1[0] == '@') {
  40. var key = group1.slice(1);
  41. var val = group2.replace(/^\s+|\s+$/g, '');
  42. var value = meta[key];
  43. // multiple values allowed
  44. if (value && value.push) value.push(val);
  45. // only first value will be stored
  46. else if (!(key in meta)) meta[key] = val;
  47. }
  48. });
  49. meta.resources = {};
  50. meta.resource.forEach(function(line) {
  51. var pair = line.match(/^(\w\S*)\s+(.*)/);
  52. if (pair) meta.resources[pair[1]] = pair[2];
  53. });
  54. delete meta.resource;
  55. // @homepageURL: compatible with @homepage
  56. if (!meta.homepageURL && meta.homepage) meta.homepageURL = meta.homepage;
  57. return meta;
  58. },
  59. newScript: function () {
  60. var script = {
  61. custom: {},
  62. enabled: 1,
  63. update: 1,
  64. code: '// ==UserScript==\n// @name New Script\n// @namespace Violentmonkey Scripts\n// @grant none\n// ==/UserScript==\n',
  65. };
  66. script.meta = scriptUtils.parseMeta(script.code);
  67. return script;
  68. },
  69. getScriptInfo: function (script) {
  70. return {
  71. id: script.id,
  72. custom: script.custom,
  73. meta: script.meta,
  74. enabled: script.enabled,
  75. update: script.update,
  76. };
  77. },
  78. getNameURI: function (script) {
  79. var ns = script.meta.namespace || '';
  80. var name = script.meta.name || '';
  81. var nameURI = escape(ns) + ':' + escape(name) + ':';
  82. if (!ns && !name) nameURI += script.id || '';
  83. return nameURI;
  84. },
  85. compareVersion: function (ver1, ver2) {
  86. ver1 = (ver1 || '').split('.');
  87. ver2 = (ver2 || '').split('.');
  88. var len1 = ver1.length, len2 = ver2.length;
  89. for (var i = 0; i < len1 || i < len2; i ++) {
  90. var delta = (parseInt(ver1[i], 10) || 0) - (parseInt(ver2[i], 10) || 0);
  91. if (delta) return delta < 0 ? -1 : 1;
  92. }
  93. return 0;
  94. },
  95. };
  96. var tester = function () {
  97. function testURL(url, script) {
  98. var custom = script.custom;
  99. var meta = script.meta;
  100. var inc = [], exc = [], mat = [];
  101. if (custom._match !== false && meta.match) mat = mat.concat(meta.match);
  102. if (custom.match) mat = mat.concat(custom.match);
  103. if (custom._include !== false && meta.include) inc = inc.concat(meta.include);
  104. if (custom.include) inc = inc.concat(custom.include);
  105. if (custom._exclude !== false && meta.exclude) exc = exc.concat(meta.exclude);
  106. if (custom.exclude) exc = exc.concat(custom.exclude);
  107. var ok = !mat.length && !inc.length;
  108. // @match
  109. ok = ok || mat.length && function (urlParts) {
  110. return mat.some(function (str) {
  111. return matchTest(str, urlParts);
  112. });
  113. }(url.match(match_reg));
  114. // @include
  115. ok = ok || inc.some(function (str) {
  116. return autoReg(str).test(url);
  117. });
  118. // exclude
  119. ok = ok && !exc.some(function (str) {
  120. return autoReg(str).test(url);
  121. });
  122. return ok;
  123. }
  124. function str2RE(str) {
  125. return RegExp('^' + str.replace(/([.?\/])/g, '\\$1').replace(/\*/g, '.*?') + '$');
  126. }
  127. function autoReg(str) {
  128. if (/^\/.*\/$/.test(str))
  129. return RegExp(str.slice(1, -1)); // Regular-expression
  130. else
  131. return str2RE(str); // String with wildcards
  132. }
  133. var match_reg = /(.*?):\/\/([^\/]*)\/(.*)/;
  134. function matchTest(str, urlParts) {
  135. if (str == '<all_urls>') return true;
  136. var parts = str.match(match_reg);
  137. var ok = !!parts;
  138. // scheme
  139. ok = ok && (
  140. // exact match
  141. parts[1] == urlParts[1]
  142. // * = http | https
  143. || parts[1] == '*' && /^https?$/i.test(urlParts[1])
  144. );
  145. // host
  146. ok = ok && (
  147. // * matches all
  148. parts[2] == '*'
  149. // exact match
  150. || parts[2] == urlParts[2]
  151. // *.example.com
  152. || /^\*\.[^*]*$/.test(parts[2]) && str2RE(parts[2]).test(urlParts[2])
  153. );
  154. // pathname
  155. ok = ok && str2RE(parts[3]).test(urlParts[3]);
  156. return ok;
  157. }
  158. return {
  159. testURL: testURL,
  160. };
  161. }();
  162. var searchParams = {
  163. load: function (string) {
  164. return string.split('&').reduce(function (data, piece) {
  165. parts = piece.split('=');
  166. data[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
  167. return data;
  168. }, {});
  169. },
  170. dump: function (dict) {
  171. var qs = [];
  172. for (var k in dict) {
  173. qs.push(encodeURIComponent(k) + '=' + encodeURIComponent(dict[k]));
  174. }
  175. return qs.join('&');
  176. },
  177. };
  178. _.broadcast = function (data) {
  179. chrome.tabs.query({}, function (tabs) {
  180. _.forEach(tabs, function (tab) {
  181. chrome.tabs.sendMessage(tab.id, data);
  182. });
  183. });
  184. };