GC - Universal Userscripts Settings

Library for adding a user interface to manage settings for grundos.cafe userscripts

目前为 2024-10-28 提交的版本。查看 最新版本

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

  1. function _addSettingsLink() {
  2. const existingNav = document.querySelector('nav.center.margin-1');
  3. if (existingNav) {
  4. const newNav = document.createElement('nav');
  5. newNav.classList.add('center', 'margin-1');
  6. newNav.id = 'userscript-navigation';
  7. const newLink = document.createElement('a');
  8. newLink.href = '/help/userscripts/';
  9. newLink.textContent = 'Userscript Preferences';
  10. newNav.appendChild(newLink);
  11. existingNav.after(newNav);
  12. } else {
  13. console.error('Existing navigation element not found.');
  14. }
  15. }
  16.  
  17. function _createLabel(labelText) {
  18. const labelContainer = document.createElement('div');
  19. labelContainer.classList.add('data', 'left');
  20.  
  21. const label = document.createElement('span');
  22. label.textContent = labelText;
  23. labelContainer.appendChild(label);
  24. return labelContainer;
  25. }
  26.  
  27. function _createInput(input) {
  28. const inputContainer = document.createElement('div');
  29. inputContainer.classList.add('data', 'flex-column', 'right');
  30. inputContainer.appendChild(input);
  31. return inputContainer;
  32. }
  33.  
  34. function _addCallback(callbackFunction) {
  35. document.getElementById('userscript-update').addEventListener('click', callbackFunction);
  36. }
  37.  
  38. async function _addCategoryHeader(categoryName) {
  39. if (!window.location.href.includes('/help/userscripts/')) return;
  40. await _checkSettingsSetup();
  41. const settings = document.querySelector('.market_grid.profile.prefs.margin-auto');
  42. const footer = document.querySelector('#userscript-preferences>.market_grid.profile.prefs.margin-auto>.footer.small-gap');
  43. if (!settings) {
  44. console.error('Settings not found.');
  45. return;
  46. }
  47.  
  48. const headers = Array.from(settings.querySelectorAll('.header'));
  49. let header = headers.find(header => header.textContent.trim() === categoryName);
  50.  
  51. if (!header) {
  52. header = document.createElement('div');
  53. header.classList.add('header');
  54. header.innerHTML = `<strong>${categoryName}</strong>`;
  55. const insertionPoint = headers.find(existingHeader => existingHeader.textContent.trim().localeCompare(categoryName) > 0);
  56. if (insertionPoint) {
  57. insertionPoint.insertAdjacentElement('beforebegin', header);
  58. } else {
  59. footer.insertAdjacentElement('beforebegin', header);
  60. }
  61. }
  62.  
  63. return header;
  64. }
  65.  
  66. async function addTextInput(categoryName, settingName, labelText, currentSetting = undefined, callbackFunction = undefined) {
  67. if (!window.location.href.includes('/help/userscripts/')) throw Error('Attempted to add setting outside of settings page.'); const header = await _addCategoryHeader(categoryName);
  68.  
  69. if (currentSetting === undefined) {
  70. currentSetting = await GM.getValue(settingName, '');
  71. }
  72.  
  73. const textInput = document.createElement('input');
  74. textInput.type = 'text';
  75. textInput.name = settingName;
  76. textInput.value = currentSetting;
  77. const label = _createLabel(labelText);
  78. header.insertAdjacentElement('afterend', label);
  79.  
  80. const inputElement = _createInput(textInput);
  81. label.insertAdjacentElement('afterend', inputElement);
  82.  
  83. if (callbackFunction) {
  84. _addCallback(() => callbackFunction(settingName, textInput.value));
  85. } else {
  86. _addCallback(async () => await GM.setValue(settingName, checkbox.checked));
  87. }
  88. }
  89.  
  90. async function addNumberInput(categoryName, settingName, labelText, min = 0, max = 100, step = 1, currentSetting = undefined, callbackFunction = undefined) {
  91. if (!window.location.href.includes('/help/userscripts/')) throw Error('Attempted to add setting outside of settings page.'); const header = await _addCategoryHeader(categoryName);
  92. if (currentSetting === undefined) {
  93. currentSetting = await GM.getValue(settingName, min);
  94. }
  95.  
  96. const numberInput = document.createElement('input');
  97. numberInput.type = 'number';
  98. numberInput.name = settingName;
  99. numberInput.value = currentSetting;
  100. numberInput.min = min;
  101. numberInput.max = max;
  102. numberInput.step = step;
  103. const label = _createLabel(labelText);
  104. header.insertAdjacentElement('afterend', label);
  105.  
  106. const inputElement = _createInput(numberInput);
  107. label.insertAdjacentElement('afterend', inputElement);
  108.  
  109. if (callbackFunction) {
  110. _addCallback(() => callbackFunction(settingName, numberInput.value));
  111. } else {
  112. _addCallback(async () => await GM.setValue(settingName, checkbox.checked));
  113. }
  114. }
  115.  
  116. async function addCheckboxInput(categoryName, settingName, labelText, currentSetting = undefined, callbackFunction = undefined) {
  117. if (!window.location.href.includes('/help/userscripts/')) throw Error('Attempted to add setting outside of settings page.'); const header = await _addCategoryHeader(categoryName);
  118. if (currentSetting === undefined) {
  119. currentSetting = await GM.getValue(settingName, false);
  120. }
  121.  
  122. const checkbox = document.createElement('input');
  123. checkbox.type = 'checkbox';
  124. checkbox.name = settingName;
  125. checkbox.checked = currentSetting;
  126. const label = _createLabel(labelText);
  127. header.insertAdjacentElement('afterend', label);
  128.  
  129. const inputElement = _createInput(checkbox);
  130. label.insertAdjacentElement('afterend', inputElement);
  131.  
  132. if (callbackFunction) {
  133. _addCallback(() => callbackFunction(settingName, checkbox.checked));
  134. } else {
  135. _addCallback(async () => await GM.setValue(settingName, checkbox.checked));
  136. }
  137. }
  138.  
  139. async function addDropdown(categoryName, settingName, labelText, options, currentSetting = undefined, callbackFunction = undefined) {
  140. if (!window.location.href.includes('/help/userscripts/')) throw Error('Attempted to add setting outside of settings page.');
  141. const header = await _addCategoryHeader(categoryName);
  142. if (currentSetting === undefined) {
  143. currentSetting = await GM.getValue(settingName, options[0].value);
  144. }
  145.  
  146. const select = document.createElement('select');
  147. select.name = settingName;
  148. select.classList.add('form-control');
  149.  
  150. options.forEach(option => {
  151. const optionElement = document.createElement('option');
  152. optionElement.value = option.value;
  153. optionElement.textContent = option.text;
  154. if (option.value === currentSetting) {
  155. optionElement.selected = true;
  156. }
  157. select.appendChild(optionElement);
  158. });
  159. const label = _createLabel(labelText);
  160. header.insertAdjacentElement('afterend', label);
  161.  
  162. const inputElement = _createInput(select);
  163. label.insertAdjacentElement('afterend', inputElement);
  164.  
  165. if (callbackFunction) {
  166. _addCallback(() => callbackFunction(settingName, select.value));
  167. } else {
  168. _addCallback(async () => await GM.setValue(settingName, checkbox.checked));
  169. }
  170. }
  171.  
  172. function _replaceBannerImage() {
  173. const bannerImage = document.getElementById('top-header-image');
  174. if (bannerImage) {
  175. bannerImage.src = 'https://grundoscafe.b-cdn.net/misc/banners/userinfo.gif';
  176. } else {
  177. console.error('Banner image not found.');
  178. }
  179. }
  180.  
  181. function _setupShareSettings() {
  182. const urlPattern = /\/help\/(?:profile|siteprefs|sidebar|randomevents)\/|\/discord\//;
  183. const settings = window.location.href.includes('/help/userscripts/');
  184. const help = urlPattern.test(window.location.href) && !settings;
  185. if (help) {
  186. _addSettingsLink();
  187. } else if (settings) {
  188. _replaceBannerImage();
  189. const element = document.querySelector('main');
  190. if (element) {
  191. element.id = 'userscript-preferences';
  192. element.innerHTML = `
  193. <h1>Userscript Preferences</h1>
  194. <nav class="center margin-1">
  195. <a href="/help/profile/">Edit Profile</a> |
  196. <a href="/help/siteprefs/">Site Preferences</a> |
  197. <a href="/help/sidebar/">Edit Sidebar</a> |
  198. <a href="/discord/">Discord</a> |
  199. <a href="/help/randomevents/">Random Event Log</a>
  200. </nav>
  201. <nav class="center margin-1" id="userscript-navigation"><a href="/help/userscripts/">Userscript Preferences</a></nav>
  202. <p>Here you can adjust settings for participating userscripts.</p>
  203. <div class="market_grid profile prefs margin-auto">
  204. <div class="footer small-gap">
  205. <input class="form-control half-width" type="submit" value="Update Preferences" id="userscript-update">
  206. </div>
  207. </div>
  208. `;
  209. }
  210. }
  211. }
  212.  
  213. async function _checkSettingsSetup() {
  214. return new Promise((resolve, reject) => {
  215. const interval = setInterval(() => {
  216. if (document.getElementById('userscript-preferences') !== null) {
  217. clearInterval(interval);
  218. clearTimeout(timeout);
  219. resolve(true);
  220. }
  221. }, 50);
  222.  
  223. const timeout = setTimeout(() => {
  224. clearInterval(interval);
  225. reject(new Error('Timeout: userscript-preferences element not found within 10 seconds'));
  226. }, 10000);
  227. });
  228. }
  229.  
  230. if (!document.getElementById('userscript-navigation')) {
  231. console.log("settings running");
  232. _setupShareSettings();
  233. }