Greasyfork - 為腳本新增備註(別名/標籤)

為腳本新增備註(別名/標籤)功能,以幫助識別和搜尋

目前為 2021-08-04 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Greasyfork - Add notes to the script
  3. // @name:en Greasyfork - Add notes(aliases/tags) to the script
  4. // @name:zh-CN Greasyfork - 为脚本添加备注(别名/标签)
  5. // @name:zh-TW Greasyfork - 為腳本新增備註(別名/標籤)
  6. // @name:ja Greasyfork - スクリプトにメモを追加する(エイリアス/タグ)
  7. // @name:ko Greasyfork - 스크립트에 메모 추가 (별칭/태그)
  8. // @name:fr Greasyfork - Ajouter des notes (alias/tag) au script
  9. // @namespace https://greasyfork.org/zh-CN/users/193133-pana
  10. // @homepage https://greasyfork.org/zh-CN/users/193133-pana
  11. // @icon data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2JhKDI5LDE2MSwyNDIsMS4wMCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYmEoMjksMTYxLDI0MiwxLjAwKSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+
  12. // @version 2.1.4
  13. // @description Add a note(alias/tag) for scripts to help identify and search
  14. // @description:en Add a note(alias/tag) for scripts to help identify and search
  15. // @description:zh-CN 为脚本添加备注(别名/标签)功能,以帮助识别和搜索
  16. // @description:zh-TW 為腳本新增備註(別名/標籤)功能,以幫助識別和搜尋
  17. // @description:ja 識別と検索に役立つコメント(エイリアス/タグ)関数をスクリプトに追加
  18. // @description:ko 식별 및 검색을 돕기 위해 스크립트에 주석 (별칭/태그) 기능 추가
  19. // @description:fr Ajouter une fonction de commentaire (alias/tag) au script pour aider à identifier et rechercher
  20. // @author pana
  21. // @license GNU General Public License v3.0 or later
  22. // @compatible chrome
  23. // @compatible firefox
  24. // @include http*://*greasyfork.org/*
  25. // @include http*://*sleazyfork.org/*
  26. // @require https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js
  27. // @require https://cdn.jsdelivr.net/gh/LightAPIs/greasy-fork-library@8505bfa589b6b7bd3ec9f33bdf350f7cd607cf69/Note_Obj.js
  28. // @grant GM_info
  29. // @grant GM.info
  30. // @grant GM_getValue
  31. // @grant GM.getValue
  32. // @grant GM_setValue
  33. // @grant GM.setValue
  34. // @grant GM_deleteValue
  35. // @grant GM.deleteValue
  36. // @grant GM_listValues
  37. // @grant GM.listValues
  38. // @grant GM_openInTab
  39. // @grant GM.openInTab
  40. // @grant GM_registerMenuCommand
  41. // @grant GM_unregisterMenuCommand
  42. // @grant GM_addValueChangeListener
  43. // @grant GM_removeValueChangeListener
  44. // ==/UserScript==
  45.  
  46. (async function () {
  47. 'use strict';
  48. if (typeof Note_Obj !== 'function') {
  49. alert('Note_Obj.js was not loaded successfully!');
  50. }
  51. const updated = '2021-08-04';
  52. const GF_ICON = {
  53. NOTE_BLACK:
  54. 'url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2IoMzgsIDM4LCAzOCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYigzOCwgMzgsIDM4KSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)',
  55. };
  56. const GF_STYLE = `
  57. .note-obj-gf-note-btn {
  58. background-image: ${GF_ICON.NOTE_BLACK};
  59. background-repeat: no-repeat;
  60. background-position: center;
  61. cursor: pointer;
  62. vertical-align: top;
  63. }
  64. .note-obj-gf-info-note-btn {
  65. background-size: 32px auto;
  66. width: 32px;
  67. height: 32px;
  68. margin-left: 20px;
  69. display: inline-block;
  70. }
  71. .note-obj-gf-library-note-btn {
  72. background-size: 24px auto;
  73. width: 24px;
  74. height: 24px;
  75. margin-left: 20px;
  76. display: inline-block;
  77. }
  78. .note-obj-gf-list-note-btn {
  79. background-size: 24px auto;
  80. width: 24px;
  81. height: 24px;
  82. margin-left: 10px;
  83. display: none;
  84. }
  85. .note-obj-gf-ts-note-btn {
  86. background-size: 16px auto;
  87. width: 16px;
  88. height: 16px;
  89. margin-left: 10px;
  90. display: none;
  91. vertical-align: sub;
  92. }
  93. ol.script-list li:hover .note-obj-gf-list-note-btn,
  94. #script-table tbody tr:hover .note-obj-gf-ts-note-btn {
  95. display: inline-block;
  96. }
  97. .note-obj-gf-note-tag,
  98. .note-obj-gf-ts-note-tag {
  99. background-color: #3c81df;
  100. color: #fff;
  101. display: inline-block;
  102. align-items: center;
  103. white-space: nowrap;
  104. border-radius: 50px;
  105. padding: 1px 10px;
  106. line-height: 1em;
  107. }
  108. .note-obj-gf-list-note-tag {
  109. text-decoration: none;
  110. }
  111. `;
  112. function change_Event(note_obj, id = null) {
  113. let pathname = location.pathname;
  114. if (/^\/[\w-]+\/scripts\/\d+-/i.test(pathname)) {
  115. let script_id = /^\/[\w-]+\/scripts\/(\d+)-/i.exec(pathname)[1];
  116. let ele = document.querySelector('#script-info h2');
  117. ele &&
  118. (!id || id == script_id) &&
  119. note_obj.handler(script_id, ele, null, {
  120. add: 'span',
  121. class: 'note-obj-gf-note-tag',
  122. });
  123. } else if (/^\/[\w-]+\/scripts/i.test(pathname) || /^\/[\w-]+\/users\/\d+/i.test(pathname)) {
  124. let browse_list = document.querySelectorAll('ol.script-list li');
  125. for (let ele of browse_list) {
  126. let script_id = ele.getAttribute('data-script-id');
  127. if (script_id) {
  128. let header = ele.querySelector('article > h2 > a');
  129. header &&
  130. (!id || id == script_id) &&
  131. note_obj.handler(script_id, header, null, {
  132. add: 'span',
  133. class: ['note-obj-gf-note-tag', 'note-obj-gf-list-note-tag'],
  134. });
  135. }
  136. }
  137. document.querySelectorAll('#script-table tbody tr').forEach(item => {
  138. let script_title = item.querySelector('.thetitle a');
  139. if (script_title) {
  140. let script_id = script_title.href.match(/\d+$/) && script_title.href.match(/\d+$/)[0];
  141. (!id || id == script_id) &&
  142. note_obj.handler(script_id, script_title, null, {
  143. add: 'span',
  144. class: 'note-obj-gf-ts-note-tag',
  145. });
  146. }
  147. });
  148. }
  149. }
  150. function init_Script(note_obj) {
  151. let browse_list = document.querySelectorAll('ol.script-list li');
  152. for (let ele of browse_list) {
  153. let script_id = ele.getAttribute('data-script-id');
  154. if (script_id) {
  155. let description = ele.querySelector('.description');
  156. let script_name = (ele.querySelector('article > h2 > a') && ele.querySelector('article > h2 > a').textContent) || '';
  157. description &&
  158. !description.parentNode.querySelector('.note-obj-add-note-btn') &&
  159. description.before(note_obj.createNoteBtn(script_id, script_name, ['note-obj-gf-note-btn', 'note-obj-gf-list-note-btn']));
  160. let header = ele.querySelector('article > h2 > a');
  161. header &&
  162. note_obj.judgeUsers(script_id) &&
  163. note_obj.handler(
  164. script_id,
  165. header,
  166. null,
  167. {
  168. add: 'span',
  169. class: ['note-obj-gf-note-tag', 'note-obj-gf-list-note-tag'],
  170. },
  171. script_name
  172. );
  173. }
  174. }
  175. }
  176. function init_TS(note_obj) {
  177. document.querySelectorAll('#script-table tbody tr').forEach(item => {
  178. let script_title = item.querySelector('.thetitle a');
  179. if (script_title) {
  180. let script_id = script_title.href.match(/\d+$/) && script_title.href.match(/\d+$/)[0];
  181. let thetitle = item.querySelector('.thetitle');
  182. script_id &&
  183. thetitle.appendChild(
  184. note_obj.createNoteBtn(script_id, script_title.textContent, ['note-obj-gf-note-btn', 'note-obj-gf-ts-note-btn'])
  185. );
  186. note_obj.judgeUsers(script_id) &&
  187. note_obj.handler(
  188. script_id,
  189. script_title,
  190. null,
  191. {
  192. add: 'span',
  193. class: 'note-obj-gf-ts-note-tag',
  194. },
  195. script_title.textContent
  196. );
  197. }
  198. });
  199. }
  200. async function init() {
  201. let old_config = await Note_Obj.GM.getValue('greasyfork_config', null);
  202. if (old_config && old_config.scripts_array) {
  203. for (let item of old_config.scripts_array) {
  204. Note_Obj.GM.setValue(item.id, {
  205. tag: item.tag,
  206. });
  207. }
  208. await Note_Obj.GM.deleteValue('greasyfork_config');
  209. }
  210. let note_obj = new Note_Obj('myGreasyForkNote');
  211. await note_obj.init({
  212. style: GF_STYLE,
  213. changeEvent: change_Event,
  214. script: {
  215. author: {
  216. name: 'pana',
  217. homepage: 'https://greasyfork.org/zh-CN/users/193133-pana',
  218. },
  219. address: 'https://greasyfork.org/scripts/404275',
  220. updated: updated,
  221. },
  222. itemClick: key => 'https://greasyfork.org/scripts/' + key,
  223. type: 'script',
  224. });
  225. let pathname = location.pathname;
  226. if (/^\/[\w-]+\/scripts\/\d+-/i.test(pathname)) {
  227. let script_id = /^\/[\w-]+\/scripts\/(\d+)-/i.exec(pathname)[1];
  228. let install_help_link = document.querySelector('#install-area .install-help-link:last-child');
  229. let suggestion = document.querySelector('#script-feedback-suggestion');
  230. let script_name = (document.querySelector('header h2') && document.querySelector('header h2').textContent) || '';
  231. if (install_help_link) {
  232. install_help_link.after(note_obj.createNoteBtn(script_id, script_name, ['note-obj-gf-note-btn', 'note-obj-gf-info-note-btn']));
  233. } else if (suggestion) {
  234. suggestion.appendChild(note_obj.createNoteBtn(script_id, script_name, ['note-obj-gf-note-btn', 'note-obj-gf-library-note-btn']));
  235. }
  236. let ele = document.querySelector('#script-info h2');
  237. ele &&
  238. note_obj.judgeUsers(script_id) &&
  239. note_obj.handler(
  240. script_id,
  241. ele,
  242. null,
  243. {
  244. add: 'span',
  245. class: 'note-obj-gf-note-tag',
  246. },
  247. script_name
  248. );
  249. } else if (/^\/[\w-]+\/scripts/i.test(pathname) || /^\/[\w-]+\/users\/\d+/i.test(pathname)) {
  250. init_Script(note_obj);
  251. let browse_script_list = document.querySelector('#browse-script-list');
  252. if (browse_script_list) {
  253. let script_observer = new MutationObserver(() => {
  254. init_Script(note_obj);
  255. });
  256. script_observer.observe(browse_script_list, {
  257. childList: true,
  258. });
  259. }
  260. init_TS(note_obj);
  261. let ts_tbody = document.querySelector('#script-table tbody');
  262. if (ts_tbody) {
  263. let observer = new MutationObserver(() => {
  264. init_TS(note_obj);
  265. });
  266. observer.observe(ts_tbody, {
  267. childList: true,
  268. });
  269. }
  270. }
  271. }
  272. init();
  273. })();