[AMD] Auto Expand Option(s)

Automatically opens the first option.

  1. // ==UserScript==
  2. // @name [AMD] Auto Expand Option(s)
  3. // @description Automatically opens the first option.
  4. // @author Magic of Lolis <magicoflolis@tuta.io>
  5. // @icon https://www.amd.com/themes/custom/amd/favicon.ico
  6. // @version 1.0.5
  7. // @supportURL https://github.com/magicoflolis/userscriptrepo/issues/new
  8. // @namespace https://github.com/magicoflolis/userscriptrepo/tree/master/AMDAutoOpen#amd-auto-expand
  9. // @homepageURL https://github.com/magicoflolis/userscriptrepo/tree/master/AMDAutoOpen#amd-auto-expand
  10. // @match https://www.amd.com/*/support/*
  11. // @grant navigator.userAgent
  12. // @compatible chrome
  13. // @compatible firefox
  14. // @compatible edge
  15. // @compatible opera
  16. // @run-at document-end
  17. // @noframes
  18. // ==/UserScript==
  19.  
  20. 'use strict';
  21. (() => {
  22. //#region Config
  23. /** Choice Options:
  24. * @param {string} choice - first | all | none | windows or Windows 11 - 64-Bit Edition...etc */
  25. let choice = 'first';
  26. /** Enable/disable Reduce Clutter:
  27. * @param {boolean} reduce_clutter - Removes some clutter */
  28. let reduce_clutter = true;
  29. /** Auto Scroll Amount:
  30. * @param {number} scroll_amount - Set to 0 disables auto scroll AND 'Top' button */
  31. let scroll_amount = 110;
  32. /** Top Button CSS:
  33. * @param {string} css - You can customize the look here */
  34. let css = `.aeo-top-btn {
  35. bottom: 1rem;
  36. right: 1rem;
  37. color: #000;
  38. border: 2px solid #000;
  39. font-size: 14px;
  40. font-weight: bold;
  41. width: auto;
  42. min-height: 5px;
  43. margin: 0 3px;
  44. padding: 10px 15px;
  45. cursor: pointer;
  46. text-transform: uppercase;
  47. text-align: center;
  48. white-space: normal;
  49. position:fixed;
  50. }
  51. .os-group summary .summary {
  52. margin-left: .5em;
  53. }
  54. /** Removes more clutter */
  55. [id="colorbox"],
  56. [id="cboxOverlay"],
  57. .PPLightBox {
  58. display: none !important;
  59. z-index: -1 !important;
  60. visibility: hidden !important;
  61. }`;
  62. //#endregion
  63.  
  64. const err = (...msg) =>
  65. console.error(
  66. '[%cAMD%c] %cERROR',
  67. 'color: rgb(237, 28, 36);',
  68. '',
  69. 'color: rgb(249, 24, 128);',
  70. ...msg
  71. );
  72. // const log = (...msg) =>
  73. // console.log(
  74. // '[%cAMD%c] %cDBG',
  75. // 'color: rgb(237, 28, 36);',
  76. // '',
  77. // 'color: rgb(255, 212, 0);',
  78. // ...msg
  79. // );
  80. // const info = (...msg) => console.info('[%cAMD%c] %cINF', 'color: rgb(237, 28, 36);', '', 'color: rgb(0, 186, 124);', ...msg);
  81.  
  82. /**
  83. * Object is Null
  84. * @param {Object} obj - Object
  85. * @returns {boolean} Returns if statement true or false
  86. */
  87. const isNull = (obj) => {
  88. return Object.is(obj, null) || Object.is(obj, undefined);
  89. };
  90. /**
  91. * Object is Blank
  92. * @param {(Object|Object[]|string)} obj - Array, Set, Object or String
  93. * @returns {boolean} Returns if statement true or false
  94. */
  95. const isBlank = (obj) => {
  96. return (
  97. (typeof obj === 'string' && Object.is(obj.trim(), '')) ||
  98. (obj instanceof Set && Object.is(obj.size, 0)) ||
  99. (Array.isArray(obj) && Object.is(obj.length, 0)) ||
  100. (obj instanceof Object &&
  101. typeof obj.entries !== 'function' &&
  102. Object.is(Object.keys(obj).length, 0))
  103. );
  104. };
  105. /**
  106. * Object is Empty
  107. * @param {(Object|Object[]|string)} obj - Array, object or string
  108. * @returns {boolean} Returns if statement true or false
  109. */
  110. const isEmpty = (obj) => {
  111. return isNull(obj) || isBlank(obj);
  112. };
  113. /**
  114. * Add Event Listener
  115. * @param {Object} root - Selected Element
  116. * @param {string} type - root Event Listener
  117. * @param {Function} callback - Callback function
  118. * @param {Object} [options={}] - (Optional) Options
  119. * @returns {Object} Returns selected Element
  120. */
  121. const ael = (root, type, callback, options = {}) => {
  122. try {
  123. root = root || document || document.documentElement;
  124. if (/Mobi/.test(navigator.userAgent) && type === 'click') {
  125. type = 'mouseup';
  126. root.addEventListener('touchstart', callback);
  127. root.addEventListener('touchend', callback);
  128. }
  129. if (type === 'fclick') {
  130. type = 'click';
  131. }
  132. return root.addEventListener(type, callback, options);
  133. } catch (ex) {
  134. return err(ex);
  135. }
  136. };
  137. /**
  138. * Form Attributes of Element
  139. * @param {Object} elt - Element
  140. * @param {string} cname - (Optional) Element class name
  141. * @param {Object} [attrs={}] - (Optional) Element attributes
  142. * @returns {Object} Returns created Element
  143. */
  144. const formAttrs = (el, cname, attrs = {}) => {
  145. try {
  146. if (!isEmpty(cname)) {
  147. el.className = cname;
  148. }
  149. if (!isEmpty(attrs)) {
  150. for (const key in attrs) {
  151. if (key === 'dataset') {
  152. for (const key2 in attrs[key]) {
  153. el[key][key2] = attrs[key][key2];
  154. }
  155. } else if (key === 'click') {
  156. ael(el, 'click', attrs[key]);
  157. } else if (key === 'container') {
  158. if (typeof key === 'function') {
  159. key();
  160. }
  161. } else {
  162. el[key] = attrs[key];
  163. }
  164. }
  165. }
  166. return el;
  167. } catch (ex) {
  168. err(ex);
  169. return el;
  170. }
  171. };
  172. const make = (element, cname, attrs = {}) => {
  173. let el;
  174. try {
  175. el = document.createElement(element);
  176. return formAttrs(el, cname, attrs);
  177. } catch (ex) {
  178. err(ex);
  179. return el;
  180. }
  181. };
  182. const loadCSS = (css, name = 'common') => {
  183. const s = make('style', `aeo-${name}`, {
  184. innerHTML: css,
  185. });
  186. return !document.head.contains(s) ? document.head.appendChild(s) : false;
  187. };
  188. /**
  189. * Prefix for document.querySelector()
  190. * @param {Object} element - Element for query selection
  191. * @param {Object} [root=document] - Root selector Element
  192. * @returns {Object} Returns root.querySelector(element)
  193. */
  194. const qs = (element, root) => {
  195. root = root ?? document ?? document.body;
  196. return root.querySelector(element);
  197. };
  198. /**
  199. * Prefix for document.querySelectorAll()
  200. * @param {Object} element - Elements for query selection
  201. * @param {Object} [root=document] - Root selector Element
  202. * @returns {Object} Returns root.querySelectorAll(element)
  203. */
  204. const qsA = (element, root) => {
  205. root = root ?? document ?? document.body;
  206. return root.querySelectorAll(element);
  207. };
  208. /**
  209. * Prefix for document.querySelector() w/ Promise
  210. * @param {Object} element - Element for query selection
  211. * @param {Object} [root=document] - Root selector Element
  212. * @returns {Object} Returns root.querySelector(element)
  213. */
  214. const query = async (element, root) => {
  215. root = root ?? document ?? document.body;
  216. while (root.querySelector(element) === null) {
  217. await new Promise((resolve) => requestAnimationFrame(resolve));
  218. }
  219. return root.querySelector(element);
  220. };
  221. const top_btn = make('input', 'aeo-top-btn', {
  222. value: 'Top',
  223. type: 'button',
  224. onclick: () => {
  225. return window.scroll(0, scroll_amount);
  226. },
  227. });
  228. const initScript = async () => {
  229. try {
  230. loadCSS(css);
  231. if (scroll_amount > 0) {
  232. document.body.append(top_btn);
  233. window.scroll(0, scroll_amount);
  234. window.onscroll = () => {
  235. document.documentElement.scrollTop > scroll_amount
  236. ? top_btn.setAttribute('style', 'display: inline-block !important')
  237. : top_btn.setAttribute('style', 'display: none !important');
  238. };
  239. }
  240. if (reduce_clutter) {
  241. if (qs('[id="scrollspy"]')) {
  242. qs('[id="scrollspy"]').setAttribute(
  243. 'style',
  244. 'padding: 0px !important'
  245. );
  246. }
  247. const ads = [
  248. qs('.panel'),
  249. qs('[role="banner"]'),
  250. qs('[role="contentinfo"]'),
  251. ];
  252. for (const ad of ads) {
  253. if (isEmpty(ad)) continue;
  254. ad.remove();
  255. }
  256. }
  257. if (!isEmpty(choice) && !choice.match(/none/gi)) {
  258. if (choice === 'first') {
  259. qs('details.os-group').setAttribute('open', '');
  260. } else {
  261. for (const details of qsA('details.os-group')) {
  262. if (choice === 'all') {
  263. details.setAttribute('open', '');
  264. } else {
  265. const re = new RegExp(`${choice}+`, 'gi');
  266. const txt = details.children[0].textContent;
  267. if (!isEmpty(txt)) {
  268. const find = txt.match(re) ?? [];
  269. if (!isEmpty(find)) {
  270. details.setAttribute('open', '');
  271. }
  272. }
  273. }
  274. }
  275. }
  276. }
  277. await query('details.os-group .os-row a');
  278. await query('details.os-group summary .summary');
  279. for (const details of qsA('details.os-group')) {
  280. const summary = qs('summary > span.summary', details);
  281. // for(const driver of qsA('.driver .field--type-uri > a[href]', details)) { };
  282. const driver = qs('.driver-metadata a', details);
  283. summary.textContent = driver.href;
  284. summary.onclick = (e) => {
  285. e.preventDefault();
  286. const dlBtn = make('a', 'amd_Downloader');
  287. dlBtn.href = driver.href;
  288. dlBtn.click();
  289. dlBtn.remove();
  290. };
  291. }
  292. } catch (ex) {
  293. err(ex);
  294. }
  295. };
  296. initScript();
  297. })();
  298. /**
  299. * Defaults:
  300. *
  301. * choice = 'first'
  302. * reduce_clutter = true
  303. * scroll_amount = 110
  304. * css = `.aeo-top-btn {
  305. bottom: 1rem;
  306. right: 1rem;
  307. color: #000;
  308. border: 2px solid #000;
  309. font-size: 14px;
  310. font-weight: bold;
  311. width: auto;
  312. min-height: 5px;
  313. margin: 0 3px;
  314. padding: 10px 15px;
  315. cursor: pointer;
  316. text-transform: uppercase;
  317. text-align: center;
  318. white-space: normal;
  319. position:fixed;
  320. }
  321. ...`
  322. */