Tampermonkey Support Library

to reduce repetition in creating scripts for Tampermonkey support

当前为 2019-08-11 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/23115/724072/Tampermonkey%20Support%20Library.js

  1. var tm = {
  2. addGlobalStyle: function(css) {
  3. var head, style;
  4. head = document.getElementsByTagName('head')[0];
  5. if (!head) { return; }
  6. style = document.createElement('style');
  7. style.type = 'text/css';
  8. style.innerHTML = css;
  9. head.appendChild(style);
  10. },
  11. log: function(msg) {
  12. console.log('Tampermonkey: ' + msg);
  13. },
  14. selectText: function (targetClass) {
  15. var textToCopy, range;
  16. try {
  17. if (document.selection) {
  18. range = document.body.createTextRange();
  19. range.moveToElementText(document.getElementsByClassName(targetClass)[0]);
  20. range.select();
  21. } else if (window.getSelection) {
  22. var selection = window.getSelection();
  23. range = document.createRange();
  24. range.selectNode(document.getElementsByClassName(targetClass)[0]);
  25. selection.removeAllRanges();
  26. selection.addRange(range);
  27. }
  28. } catch (err) {
  29. tm.log('Failed to select text');
  30. }
  31. },
  32. sysFriendly: function(el) {
  33. var text = $(el).text();
  34. $(el).text(text.replace(/\/|\:|\<|\>|\\|\||\*|\?/g, '-'));
  35. },
  36. ping: function (ip, callback) { // via http://jsfiddle.net/GSSCD/203/
  37. if (!this.inUse) {
  38. this.status = 'unchecked';
  39. this.inUse = true;
  40. this.callback = callback;
  41. this.ip = ip;
  42. var _that = this;
  43. this.img = new Image();
  44.  
  45. this.img.onload = function () {
  46. _that.inUse = false;
  47. _that.callback('responded');
  48. };
  49.  
  50. this.img.onerror = function (e) {
  51. if (_that.inUse) {
  52. _that.inUse = false;
  53. _that.callback('error', e);
  54. }
  55. };
  56.  
  57. this.start = new Date().getTime();
  58. this.img.src = "http://" + this.ip;
  59. this.timer = setTimeout(function () {
  60. if (_that.inUse) {
  61. _that.inUse = false;
  62. _that.callback('timeout');
  63. }
  64. }, 1500);
  65. }
  66. },
  67. isTagIn: function (targetString, tags) {
  68. var isFound = false;
  69. _.each(tags, function scanTarget (tag) {
  70. if (targetString.toLowerCase().indexOf(tag.toLowerCase()) > -1) {
  71. isFound = true;
  72. }
  73. });
  74. return isFound;
  75. },
  76. copyTextToClipboard: function (text) {
  77. var copyFrom = document.createElement("textarea");
  78. copyFrom.textContent = text;
  79. var body = document.getElementsByTagName('body')[0];
  80. body.appendChild(copyFrom);
  81. copyFrom.select();
  82. document.execCommand('copy');
  83. body.removeChild(copyFrom);
  84. },
  85. showModal: function(modalId, modalBody) {
  86. if ($('#' + modalId).is(":visible")) {
  87. $('#' + modalId).remove();
  88. } else {
  89. $('body').append('<div role="dialog" aria-label="modal for ' + modalId + '" class="popupDetailWindow" id="' + modalId + '">' +
  90. ' <div class="popupDetailTitle">&nbsp;</div>' +
  91. ' <div class="popupDetailContent fingery tamperModalClose" style="text-align:right;" onclick="$(this).parent().remove()">[CLOSE]</div>' +
  92. ' ' + modalBody +
  93. '</div>');
  94. }
  95. },
  96. waitTimers: [],
  97. getContainer: function (opts) {
  98. var options = {
  99. id: opts.id ? opts.id : opts.el.replace(/[ (:)]/g, ''),
  100. el: opts.el,
  101. try: 0,
  102. max: opts.max ? opts.max : 20,
  103. spd: opts.spd ? opts.spd : 500
  104. };
  105. clearTimeout(tm.waitTimers[options.id]);
  106. return new Promise(function (resolve, reject) {
  107. tm.waitForContainerElement(resolve, options);
  108. });
  109. },
  110. waitForContainerElement: function (resolve, options) {
  111. var $configElement = $(options.el);
  112. if ($configElement.length === 0) {
  113. options.try++;
  114. if (options.try < options.max) {
  115. tm.waitTimers[options.id] = setTimeout(tm.waitForContainerElement.bind(this, resolve, options), options.spd);
  116. } else {
  117. $('#output').val($('#output').val() + 'Maximum searches reached\n');
  118. }
  119. } else {
  120. resolve($configElement);
  121. }
  122. },
  123. savePreferences: function (name, value) {
  124. GM_setValue(name, JSON.stringify(value));
  125. },
  126. erasePreferences: function(name) {
  127. GM_setValue(name, JSON.stringify({}));
  128. },
  129. setTamperIcon: function (global) {
  130. var scriptName = global.ids != null ? global.ids.scriptName : global.scriptName,
  131. prefsName = global.ids != null ? global.ids.prefsName : global.prefsName,
  132. memsName = global.ids != null ? global.ids.memsName : global.memsName,
  133. mems = global.mems,
  134. prefs = global.prefs,
  135. notes = global.notes;
  136. if (!scriptName || !prefsName || !prefs) {
  137. tm.log('setTamperIcon not properly configured; please send entire global object');
  138. return;
  139. }
  140. // Add Tampermonkey Icon with label to identify this script
  141. if($('.tamperlabel').length > 0) {
  142. if ($('.tamperlabel').prop('title').indexOf(scriptName) === -1) {
  143. $('.tamperlabel').prop('title', $('.tamperlabel').prop('title') + ' | ' + scriptName);
  144. }
  145. } else {
  146. $('body').append('<span class="tamperlabel" title="Tampermonkey scripts: ' + scriptName + '"></span>');
  147. }
  148. if (prefsName != null && prefs != null && !global.handlePrefsLocally) {
  149. var tamperAction = function () {
  150. var modalId = scriptName.replace(/\s/g, '') + 'Options',
  151. modalBody = '',
  152. notesInsert = '';
  153. modalBody += '<div class="popupDetailTitle">' + modalId + '</div><div class="popupDetailContent">&nbsp;</div>';
  154. _.each(prefs, function (value, key) {
  155. if (Array.isArray(value) || typeof value === 'string' || typeof value === 'number') {
  156. var thisVal = typeof value === 'object' ? JSON.stringify(value) : value;
  157. modalBody +=
  158. '<div class="popupDetailTitle">' + key + '</div>' +
  159. '<div class="popupDetailContent">' +
  160. ' <textarea style="width:100%" id="' + key + '" type="text">' + thisVal + '</textarea>' +
  161. '</div>';
  162. } else {
  163. _.each(value, function (value2, key2) {
  164. var thisVal2 = typeof value2 === 'object' ? JSON.stringify(value2) : value2;
  165. modalBody +=
  166. '<div class="popupDetailTitle">' + key2 + '</div>' +
  167. '<div class="popupDetailContent">' +
  168. ' <textarea style="width:100%" id="' + key2 + '" type="text">' + thisVal2 + '</textarea>' +
  169. '</div>';
  170. });
  171. }
  172. });
  173. if (notes != null) {
  174. modalBody += ' <div class="popupDetailTitle">&nbsp;</div><div class="popupDetailContent" style="margin-top:20px;">&nbsp;</div>';
  175. _.each(notes.messages, function(note) {
  176. modalBody += ' <div class="popupDetailTitle tmNote">NOTE:</div><div class="popupDetailContent tmNote">' + note + '</div>';
  177. });
  178. notesInsert = ' <button aria-label="Erase Tampermonkey Session Notes" class="notery tBtn">Erase Notes</button>';
  179. }
  180. modalBody += '<div class="popupDetailTitle">&nbsp;</div><div class="popupDetailContent" style="text-align:right;">' +
  181. notesInsert +
  182. ' <button aria-label="Reset Plugin Memory" class="memery tBtn">Reset Memory</button>' +
  183. ' <button aria-label="Reset Plugin Preferences" class="resetery tBtn tBtnMain">Reset Preferences</button>' +
  184. ' <button aria-label="Save Plugin Preferences" class="savery tBtn tBtnMain">Save</button>' +
  185. ' <button aria-label="Close Preference Window" class="uiClosify tBtn">Close</button>' +
  186. '</div>';
  187.  
  188. tm.showModal(modalId, modalBody);
  189.  
  190. // hide the default popup Close because for some weird reason it's not working
  191. $('.popupDetailContent.fingery').hide();
  192.  
  193. $('.savery').on('click', function() {
  194. _.each(prefs, function(value, key) {
  195. prefs[key] = $('#' + key).val();
  196. });
  197. tm.savePreferences(prefsName, prefs);
  198. alert('Prefernces saved. You may need to refresh.');
  199. });
  200. $('.resetery').on('click', function() {
  201. tm.erasePreferences(prefsName);
  202. alert('Preferences erased. You may need to refresh.');
  203. });
  204. $('.memery').on('click', function() {
  205. tm.erasePreferences(memsName);
  206. alert('Page memory erased.');
  207. });
  208. $('.uiClosify').on('click', function() {
  209. $('#' + modalId).remove();
  210. });
  211. $('.notery').on('click', function() {
  212. $('.tmNote').remove();
  213. global.notes = null;
  214. tm.initNotes(global);
  215. });
  216.  
  217. return false;
  218. };
  219. $('.tamperlabel').unbind('click').click(tamperAction);
  220. }
  221. },
  222. initNotes: function(global) {
  223. if (global.notes == null) {
  224. global.notes = {
  225. messages: [],
  226. notifiedCount: 0
  227. };
  228. }
  229. },
  230. checkNotes: function(global) {
  231. tm.initNotes(global);
  232. if (global.notes.messages.length !== global.notes.notifiedCount) {
  233. global.notes.notifiedCount = global.notes.messages.length;
  234. var blinkNotify = function() {
  235. if ($('.tamperlabel').css('background-color') === 'rgb(255, 0, 0)') {
  236. $('.tamperlabel').css('background-color', 'transparent');
  237. } else {
  238. $('.tamperlabel').css('background-color', 'rgb(255, 0, 0)');
  239. }
  240. }
  241. setTimeout(function() {
  242. for (var intI = 0; intI < 4; intI ++) {
  243. setTimeout(blinkNotify, 1000 * intI);
  244. };
  245. }, 3000);
  246. }
  247. },
  248. addNote: function(global, theNote) {
  249. var theType,
  250. typeAddedIndex = -1,
  251. compiledNote = function() {
  252. var returnNote = global.scriptName + ': ';
  253. returnNote += theType.length > 0 ? theType + ': ' : '';
  254. returnNote += theNote;
  255. return returnNote;
  256. };
  257. tm.initNotes(global);
  258. if (typeof theNote === 'object') {
  259. theType = theNote.type;
  260. theNote = theNote.note;
  261. for (var intI = 0; intI < global.notes.messages.length; intI++) {
  262. if (global.notes.messages[intI].indexOf(theType) > -1) {
  263. typeAddedIndex = intI;
  264. }
  265. }
  266. if (typeAddedIndex > -1 && global.notes.messages[typeAddedIndex] !== compiledNote()) {
  267. global.notes.messages.splice(typeAddedIndex, 1);
  268. global.notes.notifiedCount--;
  269. }
  270. }
  271. if (global.notes.messages.indexOf(compiledNote()) === -1) {
  272. global.notes.messages.push(compiledNote());
  273. }
  274. }
  275. };