Links block for Lego.com

Adds a block to each product on Lego.com containing links to external brick websites, including Brickset, Bricklink, Rebrickable, Brickowl, and BrickEconomy

目前为 2024-07-06 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Links block for Lego.com
  3. // @license MIT
  4. // @version 0.1
  5. // @description Adds a block to each product on Lego.com containing links to external brick websites, including Brickset, Bricklink, Rebrickable, Brickowl, and BrickEconomy
  6. // @author azuravian
  7. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
  8. // @match https://www.lego.com/*
  9. // @grant none
  10. // @run-at document-end
  11. // @namespace https://greasyfork.org/users/1025348
  12. // ==/UserScript==
  13.  
  14. waitForKeyElements(
  15. '[data-test*="product-attributes"]',
  16. start);
  17.  
  18. function start() {
  19. const prodattrdiv = document.querySelector('[data-test*="product-attributes"]');
  20. const item = prodattrdiv.querySelector('[data-test*="item-value"]');
  21. const itemnum = item.innerText;
  22. const last_attr = prodattrdiv.lastChild;
  23. const links_list = last_attr.cloneNode(true);
  24. links_list.removeChild(links_list.firstChild);
  25. links_list.removeChild(links_list.firstChild);
  26. const myspan = links_list.getElementsByTagName('span')[0]
  27. const spanclass = myspan.querySelector('span').getAttribute('class');
  28. myspan.removeChild(myspan.firstChild);
  29. myspan.setAttribute('style', 'text-align: left');
  30.  
  31.  
  32. const br1 = document.createElement('br');
  33. const br2 = document.createElement('br');
  34. const br3 = document.createElement('br');
  35. const br4 = document.createElement('br');
  36.  
  37. var brickset = document.createElement('span');
  38.  
  39. brickset.setAttribute('class', spanclass);
  40. var bricksetimg = document.createElement('img');
  41. var bricksetlink = document.createElement('a');
  42. bricksetimg.setAttribute('src', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAA1VBMVEVHcEymLh20giaXhS/AMyUXXSyoOC1QTzp3Vy/AMB3OMyIgXy6Sfy4ljTmXfTDYMCLVMSOkhSXaMB5pVSbxuwvdrBIvYTgmXzI3cj8qcDYyhD4tijsYXS24OCjUphaqLh4rhDmUMSjdrRiaijAgYjDwMCCdLR8tlj7jrhT4wQbxtiDoLyDOMR00tkoxnEHuQSDYoxoxnUI0r0a9mR7/xwLIoByRLR7gOx7hLh4lfTWwKx1GijhWozoohDkkcjMdaC+iiygwoEBxgyMsiDyqjiYQnUGYoyyIwEmGAAAAI3RSTlMA+irxjPs1CBf9uOOXzkXYzdP8+/3JP5kwkIfa7mV74LKCtt0AJoAAAAEQSURBVCiR1c/bTsJAFIXhSSmlAwihLWo0gFqYQ2dKS8+lBxTU938kt7QYxHiv/93Kl9nJIPT/0hVNP1/K2VINIbKx1tLU4tx66p0QZ0II+diMEeNQ3LzVZ30p8XZLFqrWQ8p86sdh+GpP5wqclKmXSoyx9Dy5mDAeMdCYRdyfoP4qM1IPSjEhie8wZvEo4ix8tjuAq5XIDEwSckQH+FOgBiEQYhZFWb4zx/Ftu8HZWLSYUBd6C0/YGSLU01TwLUnM6lBVdXcfO8y2J8NR+1NwswhcesjrOg/ccv8lTVeUvgSQG6zzXfcbAW7WFJzmuyWk/8A1+PJY9wIfKNimxcHFWXR7d0+POLi5vrTWf5G/0ge5ei2NLgiBHwAAAABJRU5ErkJggg==')
  43. bricksetlink.setAttribute('target', '_blank')
  44. bricksetlink.setAttribute('href', `https://brickset.com/sets/${itemnum}`)
  45. brickset.appendChild(bricksetlink)
  46.  
  47. var bricklink = brickset.cloneNode(true)
  48. var rebrickable = brickset.cloneNode(true)
  49. var brickowl = brickset.cloneNode(true)
  50. var brickeconomy = brickset.cloneNode(true)
  51.  
  52. var bricklinkimg = document.createElement('img');
  53. bricklinkimg.setAttribute('style', 'height:26px;width:26px')
  54. bricklinkimg.setAttribute('src', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAe1BMVEVHcEwREREREREREREREREREREICxAREREREREaGBMRERERERERERERERERERERERERERERERH/00wNDhAAAQ3/2VD/zEbvyEr/xUF8Zyz+2nW0lEHjuUf+4oZiVTHt0nv/1WnlwWb/zmA+NRxsWSbDoj2TfDXCqmeCeWF8hizGAAAAEnRSTlMAHo0ILOD97zz+bMhatzHP1ec1JXjSAAABQUlEQVQokW2T67aCIBCFU8tCuxiDkIAKKdr7P+EZsI6X5faH6OfsYTHbw2GhS367H3aV3OMzwDM+7rAoe0CKgjyLtmXXGwHWDRVhcL5dk1UzdGSkclS4Hhh6z62j+AQp65QoUUJ1DKCIJ+8kKwDLhoC8dJUyIHnwvuAeSY9Ia1qWVPtVQwBOxwDTzuHbUg9OCDUISkuquh9kFT6iXN80vcNFKduG/UO08lQrpfFmZL2BSLn/AMvqegODMeecGo/WkH71DmWfcRfKWrb1SLaQh0vK8dO2dm3Lv5JyqKxs5S400lpplbS70Bg7KruAaac4fwUhU8oaMx+fP3g90TfKmPngfyPTP2gXI5uHrT3UYdjneA7SFJPevYTyMQHIlyH7BqzyAcN+8Fgn8IjR9DUYzSyHYhPPOdRJlMXb7C5/h2mnf8FjLS4twHqMAAAAAElFTkSuQmCC')
  55. var bricklinklink = bricklink.getElementsByTagName('a')[0]
  56. bricklinklink.appendChild(bricklinkimg)
  57. bricklinklink.innerHTML = bricklinklink.innerHTML + ' Bricklink'
  58. bricklinklink.setAttribute('href', `https://www.bricklink.com/v2/catalog/catalogitem.page?S=${itemnum}`)
  59.  
  60. var rebrickableimg = document.createElement('img');
  61. rebrickableimg.setAttribute('style', 'height:26px;width:26px')
  62. rebrickableimg.setAttribute('src', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABoVBMVEVHcExKST84PDw5OTk6OjpBSEVwbFJjYkwuLS0pKipAQEAkJCQyMjPbynQcHBs0MzM4OzsVFxopNzccLTUmJSI1P0IAAAELEA5gBgynBgtMEBFzEh81FRQGFBoeHh9vDAvbGSTdKDHJKjI7BAQlAwLEyK0rKiijKC2dFxuSFhsOCwaKBQtwURTy0zLoxyH1zSH01UwVHB7euxrpxh710Rbyzy9PPwichSCzliP93CL41z7BozCLcxsEBAagggXLqR25mhuzlBLWtBDmzFTu2SqcghV5YgLGpA7m2hr/8h5eTAIsIgCOdQqGbQg3KgBMPAB7ZxD++x6ijDNgXUfNrhBIOQA+MQGjiBOEd1ILQbBXRgGsjxuTehQBBBzKqyeGgVKWfyYAECuIiFxmUgKmix4iISCvkx+Mim4aLVlqVwmqjA/EpB7HqCSrmkYxRX6XfAjBoRlxWwRdbH28nyK/nRDSsiPHpiPEpCB3ZhjGqTqWgjrjyG7t1GrlwjPUtkP821sAABAUFBWihxyyp15OQxyQf0RXSSBcTRFoWy9rWhViVB6jt1BHAAAAi3RSTlMANJXOn0IaX///u/+mHP//eP///+z/////////////////////DNP//////9uA484v8P////z///7+WLr+////////Rv////7////////////jvf//////2f///////0K5///////lm//////ja/7////m/P//n9j5////a7D//6Bd2KeLm225s+yihhSvdAAAAulJREFUeAFsTgMWw0AQrTtTxeuNnRr3P1rx1Gjs+ZMeTWfzxXIyQqvZbPp1a0AEHJnYbBG3u8n+YBgAgGa/b+KvDqZpfQcM23Z6EysXvg3b9raEGh4wzsWsM7BEAMPbCqk08e0gjOJYdaG7sPUUD8NIaJrwOCVB0AGa5Wj4QVgIWVooKlbXQk46lLmomooSUimqGkbS4Hg6X67tJ7e0kSRNK6QHVpZNcH88nq99+0adNAErha6JJumHRLJqUBuIovDUhXUJ9Ze6t8F3ieFMgkNSZoI7KQySrLv+7Q7lvJ7v+nV7vA6nz+nbmpu/tr5vb/uZd89evmBm4ty8R3CKki/gDAIQZH1UoXBEisbikOO4LxwjK05HIsmk0rHMIsjmoqwvxDrztGbevbq09OYLU1AD8VhMU+LxH4vgT9GD0hr2hHWdXy1Rf2mJg1BVyuVQqOytAFCt1SPJhkfX9WbA/fpNy2azcbCRRGk/VZt22OnmFNgTcF8yWLjaarVsHIOQDLVmsyn+pcBguEkgEgwsjdjx6xnwhZHlLw2Cm3g0A35NhgQWDEOigFKa+RyXVGVEtCYWp+/phrK5scyNBEkyLb601HrDcUwBqog0MZ5KOzTFTkAbN/CUNiGajtLqEgVUFGmMlXBYk3bfg8oeH3awo2g0zzpc+TmQhA2i9fuSJewugkfFfaLq0ykOK6RH97BqpxlSEPXSzeb44PAIDNbrbCL1RUbJZERBpVU7PXqq4OYjUCeefeMYVLpdxcET3evd3++f2Dk7vUUKqbq3r4mGae6CyrDr95f705PD/f2T0z2GY5gvbreaMMToaCSKXrA4KSpJj8lj18l+OT89O38A7qhQHVuiF+Nm+AKAy24CNQTDsqImzfgQUF2hZE/UtDAhkWu6qWii5zYE05xlnAPgRo2QxN6326v/vz0w0tA0qEtzXswB8G9tHS3sjGA2WEVWoWN0CtDIGJ8EVQZswNouPDzf162zq40NQw4AapnDZhU18fsAAAAASUVORK5CYII=')
  63. var rebrickablelink = rebrickable.getElementsByTagName('a')[0]
  64. rebrickablelink.appendChild(rebrickableimg)
  65. rebrickablelink.innerHTML = rebrickablelink.innerHTML + ' Rebrickable'
  66. rebrickablelink.setAttribute('href', `https://rebrickable.com/search/?show_printed=on&include_accessory=1&include_gear=1&q=${itemnum}`)
  67.  
  68. var brickowlimg = document.createElement('img');
  69. brickowlimg.setAttribute('style', 'height:26px;width:26px')
  70. brickowlimg.setAttribute('src', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAe1BMVEVHcEzX2NjV19fW2NjNz8+dnZ2trq7V1dXW2dnZ29y7urmUlJSYmJjFxcWamZmenp6jo6OamprU1tanp6aurq3UzsqLi4v19vPe4OF7enn/////4bb/05T/3Kj9sCi/gRVkRA3/vlqcahMAAQI8RlD45cwqHATwjw7zkC196lJXAAAAE3RSTlMAMrPJmlCLFf///5T9/9v//zP6OwrJdwAAARlJREFUeAG10NeCgjAQhWF7Jmyy0cikjEi18P5PuGEo2y89Vz9+Ulcv3Hqz3e7208Fuu90cxGIC0mT2xgcbGKa+I+j3T5RqP4oQ6wnFMEYweyESAk9KCRLmhqHl8bSyfNZZ5VayQG6M5jqqAdEp6YNRASCcHfhwjHpGjJYuxZWCC9JoTp90xHNOZVVXpdeZNdRUdVt6VJYRIxVt193uDTnji6rrupRRM+pIzaNLK0k5auopsxn5l7okl7BN+Ug5Irpwfz66x/PqVWbvZfrjs5gvC1mkS1mWBTkIS+Z2RMyjJ0/kNABOaeZXAZtFp5yz/NlcypgjzAjSIoJEngRECzDjPHymIedPZO0B/kNA/IHwzxjX/+50Wr1mH3nDIvGVBEYJAAAAAElFTkSuQmCC')
  71. var brickowllink = brickowl.getElementsByTagName('a')[0]
  72. brickowllink.appendChild(brickowlimg)
  73. brickowllink.innerHTML = brickowllink.innerHTML + ' Brickowl'
  74. brickowllink.setAttribute('href', `https://www.brickowl.com/search/catalog?query=${itemnum}`)
  75.  
  76. var brickeconomyimg = document.createElement('img');
  77. brickeconomyimg.setAttribute('style', 'height:26px;width:26px')
  78. brickeconomyimg.setAttribute('src', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAARVBMVEVHcEzv7/Dv7/Hv7/Dw8PDw8PHw8PH29vTv7/Dv8PHF0/BakOvZ4vXm7PYAZ+cJb+iQse+0yfI8gemhvfAac+j///96pO4XzhHzAAAACnRSTlMAOIbC7P9g/xffFSzsFQAAAVFJREFUeAFdkwGuhCAMRFXpr1JoAVruf9QPmDXLTmIS8mQy0GF7tR+nA3DnsW+/+nPQhTDk/hZ03RN5Cjh/uK8vx4kiMUn/YGhfGCQWzoV8Jfyi19iWRZSllkimGQERHucb0BdW1ZByQcqVKZeE98wJsQ3E0VoOisxYuLaGI7MLLPqB5jWZSTeX4EYazx0JP9B87dA01NozHRNKiSV0GFVSsUym6uHYzgnZbMLmZexPwh7h3NwCU04Vi5lxBHAbDCgfiGyllbGzQ5iQacBo1CwrUVQNVBFg2nobMIlwCTFY6PbG3XYEKtZh0Oe0hGPFSL4HOh7YWB8JJ6stssR+lH3A7qivWHxiDnMwzve1LmKKHMGNi593u0q4w1mWOxL/sgZwP8Oe81xcAwJcb02wvpFkNGEtEUJjeU7yVGitJgZi4Rbfaq6lRk8el1IvzwHX5/APMcQhL8CmHDEAAAAASUVORK5CYII=')
  79. var brickeconomylink = brickeconomy.getElementsByTagName('a')[0]
  80. brickeconomylink.appendChild(brickeconomyimg)
  81. brickeconomylink.innerHTML = brickeconomylink.innerHTML + ' BrickEconomy'
  82. brickeconomylink.setAttribute('href', `https://www.brickeconomy.com/search?query=${itemnum}`)
  83.  
  84. bricksetimg.setAttribute('style', 'height:26px;width:26px')
  85. bricksetlink.appendChild(bricksetimg)
  86. bricksetlink.innerHTML = bricksetlink.innerHTML + ' Brickset';
  87.  
  88. myspan.appendChild(brickset);
  89. myspan.appendChild(br1);
  90. myspan.appendChild(bricklink);
  91. myspan.appendChild(br2);
  92. myspan.appendChild(rebrickable);
  93. myspan.appendChild(br3);
  94. myspan.appendChild(brickowl);
  95. myspan.appendChild(br4);
  96. myspan.appendChild(brickeconomy);
  97. links_list.removeChild(links_list.firstChild);
  98. links_list.appendChild(myspan);
  99. prodattrdiv.appendChild(links_list);
  100. }
  101.  
  102.  
  103. /*--- waitForKeyElements(): A utility function, for Greasemonkey scripts,
  104. that detects and handles AJAXed content.
  105. Usage example:
  106. waitForKeyElements (
  107. "div.comments"
  108. , commentCallbackFunction
  109. );
  110. //--- Page-specific function to do what we want when the node is found.
  111. function commentCallbackFunction (jNode) {
  112. jNode.text ("This comment changed by waitForKeyElements().");
  113. }
  114. IMPORTANT: This function requires your script to have loaded jQuery.
  115. */
  116. function waitForKeyElements (
  117. selectorTxt, /* Required: The jQuery selector string that
  118. specifies the desired element(s).
  119. */
  120. actionFunction, /* Required: The code to run when elements are
  121. found. It is passed a jNode to the matched
  122. element.
  123. */
  124. bWaitOnce, /* Optional: If false, will continue to scan for
  125. new elements even after the first match is
  126. found.
  127. */
  128. iframeSelector /* Optional: If set, identifies the iframe to
  129. search.
  130. */
  131. ) {
  132. var targetNodes, btargetsFound;
  133.  
  134. if (typeof iframeSelector == "undefined")
  135. targetNodes = jQuery(selectorTxt);
  136. else
  137. targetNodes = jQuery(iframeSelector).contents ()
  138. .find (selectorTxt);
  139.  
  140. if (targetNodes && targetNodes.length > 0) {
  141. btargetsFound = true;
  142. /*--- Found target node(s). Go through each and act if they
  143. are new.
  144. */
  145. targetNodes.each ( function () {
  146. var jThis = jQuery(this);
  147. var alreadyFound = jThis.data ('alreadyFound') || false;
  148.  
  149. if (!alreadyFound) {
  150. //--- Call the payload function.
  151. var cancelFound = actionFunction (jThis);
  152. if (cancelFound)
  153. btargetsFound = false;
  154. else
  155. jThis.data ('alreadyFound', true);
  156. }
  157. } );
  158. }
  159. else {
  160. btargetsFound = false;
  161. }
  162.  
  163. //--- Get the timer-control variable for this selector.
  164. var controlObj = waitForKeyElements.controlObj || {};
  165. var controlKey = selectorTxt.replace (/[^\w]/g, "_");
  166. var timeControl = controlObj [controlKey];
  167.  
  168. //--- Now set or clear the timer as appropriate.
  169. if (btargetsFound && bWaitOnce && timeControl) {
  170. //--- The only condition where we need to clear the timer.
  171. clearInterval (timeControl);
  172. delete controlObj [controlKey]
  173. }
  174. else {
  175. //--- Set a timer, if needed.
  176. if ( ! timeControl) {
  177. timeControl = setInterval ( function () {
  178. waitForKeyElements ( selectorTxt,
  179. actionFunction,
  180. bWaitOnce,
  181. iframeSelector
  182. );
  183. },
  184. 300
  185. );
  186. controlObj [controlKey] = timeControl;
  187. }
  188. }
  189. waitForKeyElements.controlObj = controlObj;
  190. }