Thing Remix Attribution Maker

Format the license information from a thing page

当前为 2021-08-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Thing Remix Attribution Maker
  3. // @namespace http://poikilos.org/
  4. // @version 2.1.2
  5. // @description Format the license information from a thing page
  6. // @author Poikilos (Jake Gustafson)
  7. // @include https://www.thingiverse.com/thing:*
  8. // @grant none
  9. // @run-at document-end
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. // formerly @match https://www.thingiverse.com/thing:*
  14. var verbose = false;
  15. var checkTimer = null;
  16. var madeDivClassName = "ThingPage__madeBy";
  17. var licenseClauseImgPrefix = "License__img";
  18. var licenseAnchorPrefix = "License__link"; // INFO: it could be author OR license link
  19. var titlePrefix = "ThingPage__modelName";
  20. var headingCreatedPrefix = "ThingPage__createdBy";
  21. var doneDivPrefixes = [titlePrefix, headingCreatedPrefix];
  22. var clausesContainerPrefix = "License__ccLicense";
  23. var doneDivPrefixesMain = [clausesContainerPrefix];
  24. var urlSmallNames = {
  25. "/by/1.0": "CC BY 1.0",
  26. "/by/2.0": "CC BY 2.0",
  27. "/by/2.5": "CC BY 2.5",
  28. "/by/3.0": "CC BY 3.0",
  29. "/by/4.0": "CC BY 4.0",
  30. "/by-sa/1.0": "CC BY-SA 1.0",
  31. "/by-sa/2.0": "CC BY-SA 2.0",
  32. "/by-sa/2.5": "CC BY-SA 2.5",
  33. "/by-sa/3.0": "CC BY-SA 3.0",
  34. "/by-sa/4.0": "CC BY-SA 4.0",
  35. "/by-nc/1.0": "CC BY-NC 1.0",
  36. "/by-nc/2.0": "CC BY-NC 2.0",
  37. "/by-nc/2.5": "CC BY-NC 2.5",
  38. "/by-nc/3.0": "CC BY-NC 3.0",
  39. "/by-nc/4.0": "CC BY-NC 4.0",
  40. "/by-nc-sa/1.0": "CC BY-NC-SA 1.0",
  41. "/by-nc-sa/2.0": "CC BY-NC-SA 2.0",
  42. "/by-nc-sa/2.5": "CC BY-NC-SA 2.5",
  43. "/by-nc-sa/3.0": "CC BY-NC-SA 3.0",
  44. "/by-nc-sa/4.0": "CC BY-NC-SA 4.0",
  45. "/by-nd/1.0": "CC BY-ND 1.0",
  46. "/by-nd/2.0": "CC BY-ND 2.0",
  47. "/by-nd/2.5": "CC BY-ND 2.5",
  48. "/by-nd/3.0": "CC BY-ND 3.0",
  49. "/by-nd/4.0": "CC BY-ND 4.0",
  50. "/by-nd-nc/1.0": "CC BY-ND-NC 1.0",
  51. "/by-nc-nd/2.0": "CC BY-NC-ND 2.0",
  52. "/by-nc-nd/2.5": "CC BY-NC-ND 2.5",
  53. "/by-nc-nd/3.0": "CC BY-NC-ND 3.0",
  54. "/by-nc-nd/4.0": "CC BY-NC-ND 4.0",
  55. "creativecommons.org/share-your-work/public-domain/cc0": "CC0",
  56. "creativecommons.org/publicdomain/zero/1.0": "CC0 1.0",
  57. };
  58. var bigNames = {
  59. "CC BY 1.0": "Creative Commons Attribution 1.0 Generic",
  60. "CC BY 2.0": "Creative Commons Attribution 2.0 Generic",
  61. "CC BY 2.5": "Creative Commons Attribution 2.5 Generic",
  62. "CC BY 3.0": "Creative Commons Attribution 3.0 Unported",
  63. "CC BY 4.0": "Creative Commons Attribution 4.0 International",
  64. "CC BY-SA 1.0": "Creative Commons Attribution-ShareAlike 1.0 Generic",
  65. "CC BY-SA 2.0": "Creative Commons Attribution-ShareAlike 2.0 Generic",
  66. "CC BY-SA 2.5": "Creative Commons Attribution-ShareAlike 2.5 Generic",
  67. "CC BY-SA 3.0": "Creative Commons Attribution-ShareAlike 3.0 Unported",
  68. "CC BY-SA 4.0": "Creative Commons Attribution-ShareAlike 4.0 International",
  69. "CC BY-NC 1.0": "Creative Commons Attribution-NonCommercial 1.0 Generic",
  70. "CC BY-NC 2.0": "Creative Commons Attribution-NonCommercial 2.0 Generic",
  71. "CC BY-NC 2.5": "Creative Commons Attribution-NonCommercial 2.5 Generic",
  72. "CC BY-NC 3.0": "Creative Commons Attribution-NonCommercial 3.0 Unported",
  73. "CC BY-NC 4.0": "Creative Commons Attribution-NonCommercial 4.0 International",
  74. "CC BY-NC-SA 1.0": "Creative Commons Attribution-NonCommercial-ShareAlike 1.0 Generic",
  75. "CC BY-NC-SA 2.0": "Creative Commons Attribution-NonCommercial-ShareAlike 2.0 Generic",
  76. "CC BY-NC-SA 2.5": "Creative Commons Attribution-NonCommercial-ShareAlike 2.5 Generic",
  77. "CC BY-NC-SA 3.0": "Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported",
  78. "CC BY-NC-SA 4.0": "Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International",
  79. "CC BY-ND 1.0": "Creative Commons Attribution-NoDerivs 1.0 Generic",
  80. "CC BY-ND 2.0": "Creative Commons Attribution-NoDerivs 2.0 Generic",
  81. "CC BY-ND 2.5": "Creative Commons Attribution-NoDerivs 2.5 Generic",
  82. "CC BY-ND 3.0": "Creative Commons Attribution-NoDerivs 3.0 Unported",
  83. "CC BY-ND 4.0": "Creative Commons Attribution-NoDerivatives 4.0 International",
  84. "CC BY-ND-NC 1.0": "Creative Commons Attribution-NoDerivs-NonCommercial 1.0 Generic",
  85. "CC BY-NC-ND 2.0": "Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Generic",
  86. "CC BY-NC-ND 2.5": "Creative Commons Attribution-NonCommercial-NoDerivs 2.5 Generic",
  87. "CC BY-NC-ND 3.0": "Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported",
  88. "CC BY-NC-ND 4.0": "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International",
  89. "CC0": "No Rights Reserved",
  90. "CC0 1.0": "Creative Commons CC0 1.0 Universal",
  91. };
  92. function getElementsWhereClassStartsWith(str) {
  93. if (verbose) {
  94. console.log("");
  95. console.log("getElementsWhereClassStartsWith(\""+str+"\")...");
  96. }
  97. var els = [];
  98. var all = document.getElementsByTagName("*");
  99. for (var i=0, max=all.length; i < max; i++) {
  100. var el = all[i];
  101. if (el.className.startsWith(str)) {
  102. els.push(el);
  103. }
  104. }
  105. if (verbose) {
  106. console.log("- FOUND " + els.length);
  107. }
  108. return els;
  109. }
  110.  
  111. function getElementsWhere(tagName, attributeName, value) {
  112. if (verbose) {
  113. console.log("");
  114. console.log("getSubElementsWhere(\""+tagName+"\", \""+attributeName+"\", \""+value+"\")...");
  115. }
  116. var els = [];
  117. var all = document.getElementsByTagName(tagName);
  118. for (var i=0, max=all.length; i < max; i++) {
  119. var el = all[i];
  120. if (el.getAttribute(attributeName) == value) {
  121. els.push(el);
  122. }
  123. }
  124. if (verbose) {
  125. console.log("- FOUND " + els.length);
  126. }
  127. return els;
  128. }
  129. function getDivsWhereClassStartsWith(str) {
  130. if (verbose) {
  131. console.log("");
  132. console.log("FIND getDivsWhereClassStartsWith(\"" + str + "\")...");
  133. }
  134. var els = [];
  135. var all = document.getElementsByTagName("div");
  136. for (var i=0, max=all.length; i < max; i++) {
  137. var el = all[i];
  138. if (el.className.startsWith(str)) {
  139. els.push(el);
  140. // console.log("- FOUND (" + els.length + ")");
  141. }
  142. else {
  143. // console.log("- " + el.className + " does not start with it.");
  144. }
  145. }
  146. if (verbose) {
  147. // console.log("Div count: " + all.length);
  148. console.log("- FOUND " + els.length);
  149. }
  150. return els;
  151. }
  152. function getWhereClassStartsWithIn(el, str) {
  153. if (el === undefined) {
  154. console.log("[getWhereClassStartsWithIn] Error: el is undefined.");
  155. return [];
  156. }
  157. if (verbose) {
  158. console.log("");
  159. console.log("DETECT getWhereClassStartsWithIn(el, \""+str+"\")...");
  160. // console.log(" el: " + JSON.stringify(el)); // DON'T do (could be circular)
  161. console.log(" el.className: "+el.className);
  162. console.log(" el.childNodes.length:"+el.childNodes.length+"...");
  163. }
  164. var els = [];
  165. var all = el.childNodes;
  166. for (var i=0, max=all.length; i < max; i++) {
  167. var thisEl = all[i];
  168. if (thisEl.className.startsWith(str)) {
  169. els.push(thisEl);
  170. // console.log("- FOUND");
  171. }
  172. else {
  173. // console.log("- "+el.className+" does not start with it.");
  174. }
  175. }
  176. if (verbose) {
  177. console.log("- FOUND " + els.length);
  178. // console.log("- done (div count: " + all.length + ")");
  179. }
  180. return els;
  181. }
  182. function hasAllDivPrefixes(prefixes) {
  183. var found = 0;
  184. for (var i=0, max=prefixes.length; i < max; i++) {
  185. if (getDivsWhereClassStartsWith(prefixes[i]).length > 0) {
  186. found++;
  187. }
  188. }
  189. return found >= prefixes.length;
  190. }
  191. function hasAllClasses(classNames) {
  192. var found = 0;
  193. for (var i=0, max=classNames.length; i < max; i++) {
  194. if (document.getElementsByClassName(classNames[i]).length > 0) {
  195. found++;
  196. }
  197. else {
  198. if (verbose) {
  199. console.error("The className " + classNames[i] + " was not found.")
  200. }
  201. }
  202. }
  203. return found >= classNames.length;
  204. }
  205. function elementHasAllPrefixes(el, prefixes) {
  206. var found = 0;
  207. for (var i=0, max=prefixes.length; i < max; i++) {
  208. if (getWhereClassStartsWithIn(el, prefixes[i]).length > 0) {
  209. found++;
  210. }
  211. }
  212. return found >= prefixes.length;
  213. }
  214. function getImgsWhereClassStartsWith(str) {
  215. var els = [];
  216. var all = document.images; // document.getElementsByTagName("img");
  217. for (var i=0, max=all.length; i < max; i++) {
  218. var el = all[i];
  219. if (el.className.startsWith(str)) {
  220. els.push(el);
  221. }
  222. }
  223. return els;
  224. }
  225. function getAnchorsWhereClassStartsWith(str) {
  226. if (verbose) {
  227. console.log("getAnchorsWhereClassStartsWith(\""+str+"\")...")
  228. }
  229. var els = [];
  230. var all = document.getElementsByTagName("a");
  231. for (var i=0, max=all.length; i < max; i++) {
  232. var el = all[i];
  233. if (el.className.startsWith(str)) {
  234. els.push(el);
  235. }
  236. }
  237. if (verbose) {
  238. console.log("- FOUND " + els.length);
  239. // console.log("- done (div count: " + all.length + ")");
  240. }
  241. return els;
  242. }
  243. function getAnchorsWhereHrefContains(str) {
  244. // Example: str=field_art_tags_tid= finds <a href="/art-search-advanced?field_art_tags_tid=grass">...
  245. if (verbose) {
  246. console.log("getAnchorsWhereHrefContains(\""+str+"\")...")
  247. }
  248. var els = [];
  249. var all = document.getElementsByTagName("a");
  250. for (var i=0, max=all.length; i < max; i++) {
  251. var el = all[i];
  252. if (el.href.includes(str)) {
  253. els.push(el);
  254. }
  255. }
  256. if (verbose) {
  257. console.log("- FOUND " + els.length);
  258. // console.log("- done (div count: " + all.length + ")");
  259. }
  260. return els;
  261. }
  262.  
  263. function elementAToMarkdown(element) {
  264. var ret = null;
  265. if (element.href) {
  266. ret = "[" + element.textContent + "](" + element.href + ")";
  267. }
  268. else {
  269. if (verbose) {
  270. console.warn("- elementAToMarkdown " + element.textContent + " href is blank in elementAToMarkdown: \"" + element.href + "\"")
  271. }
  272. ret = element.textContent;
  273. }
  274. return ret;
  275. }
  276.  
  277. function getMarkdown(info) {
  278. if (verbose) {
  279. console.log("");
  280. console.log("getMarkdown...");
  281. }
  282. var outputStr = "";
  283. outputStr = "## License";
  284. if (info.license) {
  285. outputStr += "\n- ";
  286. if (info.licenseHref) {
  287. outputStr += "[" + info.license + "](" + info.licenseHref + ")";
  288. }
  289. else {
  290. // console.log("* skipping long name detection since a license was detected: \""+info.license+"\"");
  291. outputStr += info.license;
  292. }
  293. if (info.shortLicense > 0) {
  294. outputStr += "\n (" + info.shortLicense + ")";
  295. }
  296. }
  297. else {
  298. outputStr += "\n- LICENSE: [insert license name (&URL unless in each content ZIP) of original thing here]";
  299. }
  300.  
  301. if (info.author) {
  302. outputStr += "\n- by " + info.author + " and <insert remixer's name here>";
  303. }
  304. if (info.title) {
  305. outputStr += "\n- based on";
  306. if (info.titleHref) {
  307. outputStr += " [" + info.title + "](" + info.titleHref + ")";
  308. }
  309. else {
  310. outputStr += " " + info.title;
  311. }
  312. if (info.author) {
  313. if (info.authorHref) {
  314. outputStr += " by [" + info.author + "](" + info.authorHref + ")";
  315. }
  316. else {
  317. outputStr += " by " + info.author;
  318. }
  319. }
  320. if (info.year) {
  321. outputStr += " ";
  322. if (info.month) {
  323. outputStr += info.month + " ";
  324. if (info.day) {
  325. outputStr += info.day + ", "
  326. }
  327. }
  328. outputStr += info.year;
  329. }
  330. }
  331.  
  332. return outputStr;
  333. }
  334.  
  335. function populateCorrespondingLicenseFields(info) {
  336. var licenseShortStr = "";
  337. if (info.license) {
  338. var versionIsFound = false;
  339. var licenseLower = info.license.toLowerCase();
  340. if (info.license.startsWith("Creative Commons") || info.license.startsWith("CC")) {
  341. if (info.license.startsWith("CC0 1.0") || info.license.startsWith("Creative Commons 0 1.0") || info.license.startsWith("Creative Commons Zero 1.0")) {
  342. if (!info.licenseHref) {
  343. info.licenseHref = "https://creativecommons.org/publicdomain/zero/1.0/";
  344. }
  345. licenseShortStr = "CCO 1.0";
  346. }
  347. else if ((info.license == "Creative Commons 0") || (info.license == "Creative Commons Zero")) {
  348. licenseShortStr = "CCO";
  349. }
  350. else {
  351. console.log("Looking for license clauses in license name \""+licenseLower+"\"...");
  352. licenseShortStr = "CC ";
  353. if (licenseLower.includes("attribution")) {
  354. licenseShortStr += "BY";
  355. }
  356. if (licenseLower.includes("non-commercial") || licenseLower.includes("noncommercial") || licenseLower.includes("non commercial")) {
  357. licenseShortStr += "-NC";
  358. }
  359. if (licenseLower.includes("no derivatives") || licenseLower.includes("noderivs") || licenseLower.includes("no-derivatives") || licenseLower.includes("noderivatives")) {
  360. licenseShortStr += "-ND";
  361. }
  362. if (licenseLower.includes("sharealike") || licenseLower.includes("share-alike") || licenseLower.includes("share alike") ) {
  363. licenseShortStr += "-SA";
  364. }
  365.  
  366. if (info.license.includes("1.0")) {
  367. licenseShortStr += " 1.0";
  368. versionIsFound = true;
  369. }
  370. else if (info.license.includes("2.0")) {
  371. licenseShortStr += " 2.0";
  372. versionIsFound = true;
  373. }
  374. else if (info.license.includes("3.0")) {
  375. licenseShortStr += " 3.0";
  376. versionIsFound = true;
  377. }
  378. else if (info.license.includes("4.0")) {
  379. licenseShortStr += " 4.0";
  380. versionIsFound = true;
  381. }
  382. else if (exactLicenseVersion !== null) {
  383. licenseShortStr += " " + exactLicenseVersion;
  384. versionIsFound = true;
  385. }
  386. }
  387. }
  388. console.log("licenseShortStr: " + licenseShortStr);
  389. if (!info.licenseHref) {
  390. var parts = licenseShortStr.split(" ");
  391. if (parts.length == 3) {
  392. var partialHref = null;
  393. // such as ["CC", "BY-SA", "3.0"]
  394. if (parts[1] == "BY") {
  395. partialHref = "http://creativecommons.org/licenses/by/";
  396. }
  397. else if (parts[1] == "BY-SA") {
  398. partialHref = "http://creativecommons.org/licenses/by-sa/";
  399. }
  400. else if (parts[1] == "BY-NC-SA") {
  401. partialHref = "http://creativecommons.org/licenses/by-nc-sa/";
  402. }
  403. else if (parts[1] == "BY-NC-ND") {
  404. partialHref = "http://creativecommons.org/licenses/by-nc-nd/";
  405. }
  406. // NOTE: by-nc-nd-sa is NOT a valid license
  407. if (partialHref != null) {
  408. info.licenseHref = partialHref + parts[2] + "/";
  409. }
  410. }
  411. }
  412. }
  413. else if (info.licenseHref) {
  414. if (!licenseShortStr) {
  415. if (verbose) {
  416. console.log("Generating short license name from URL instead of from clauses...");
  417. }
  418. for (var key in urlSmallNames) {
  419. // Check if the property/key is defined in the object itself, not in parent
  420. if (urlSmallNames.hasOwnProperty(key)) {
  421. if (info.licenseHref.includes(key)) {
  422. licenseShortStr = urlSmallNames[key];
  423. if (verbose) {
  424. console.log("- got \""+licenseShortStr+"\" from \""+key+"\"")
  425. }
  426. break;
  427. }
  428. }
  429. }
  430. }
  431. else {
  432. console.log("* using existing licenseShortStr \""+licenseShortStr+"\"");
  433. }
  434.  
  435. if (!licenseShortStr) {
  436. console.warn("Warning: The URL \""+info.licenseHref+"\" is not recognized (No key in Thing Remix Attribution Maker's urlSmallNames is a partial of the URL), so the long license name could not be generated.");
  437. }
  438. else {
  439. info.shortLicense = licenseShortStr;
  440. if (!info.license) {
  441. if (verbose) {
  442. console.log("Generating long license name from URL instead of from clauses...");
  443. }
  444. if (bigNames.hasOwnProperty(licenseShortStr)) {
  445. // ^ The clauses are only in this order for versions above 1.0!
  446. info.license = bigNames[licenseShortStr];
  447. if (verbose) {
  448. console.log("- got \""+info.license+"\"");
  449. }
  450. }
  451. else {
  452. console.warn("Warning: The short license name \""+licenseShortStr+"\" is not recognized (It is not a key in Thing Remix Attribution Maker's bigNames), so the long license name could not be generated.");
  453. }
  454. }
  455. }
  456. }
  457. if (!info.license) {
  458. console.warn("The license abbreviation cannot be generated because no license text was generated (no license elements were detected).");
  459. }
  460. else {
  461. console.warn("The license abbreviation cannot be generated for an unknown license: " + info.license);
  462. }
  463. }
  464.  
  465. function setClipboardText(text, callbackBtn) {
  466. var msg = "(ERROR: Your browser API is unknown.)";
  467. var okMsg = " &#10003;";
  468. // See https://stackoverflow.com/questions/52177405/clipboard-writetext-doesnt-work-on-mozilla-ie
  469. if (navigator.clipboard != undefined) { // Chrome
  470. navigator.clipboard.writeText(text).then(
  471. function () {
  472. console.log('Async: Copying to clipboard was successful!');
  473. callbackBtn.innerHTML += okMsg;
  474. }, function (err) {
  475. console.error('Async: Could not copy text: ', err);
  476. callbackBtn.innerHTML += '<br/> (ERROR: Accessing the clipboard failed.)';
  477. }
  478. );
  479. msg = null;
  480. }
  481. else if (window.clipboardData) { // Internet Explorer
  482. window.clipboardData.setData("Text", text);
  483. msg = okMsg;
  484. }
  485. if (msg != null) {
  486. callbackBtn.innerHTML += msg;
  487. }
  488. }
  489.  
  490. function getButtonContainer() {
  491. // var pageInfoEs = document.getElementsByClassName("item-page-info");
  492. var pageInfoEs = getElementsWhereClassStartsWith(madeDivClassName);
  493. if (pageInfoEs.length < 1) {
  494. return null;
  495. }
  496. // There should only be one.
  497. return pageInfoEs[0];
  498. }
  499.  
  500. function getInfo() {
  501. 'use strict';
  502. var info = {};
  503. // There should only be one.
  504. // pageInfoE.innerHTML += "<button onclick=\"getRemixLicense()\">Copy Markdown</button>";
  505. // var licenseTextE = document.getElementsByClassName("license-text");
  506. // var licenseTextE = getDivsWhereClassStartsWith(clausesContainerPrefix);
  507. // var pageInfoEs = document.getElementsByClassName("item-page-info");
  508. // var pageInfoEs = getDivsWhereClassStartsWith(madeDivClassName);
  509. // console.log("Checking "+madeDivClassName+"* elements: " + JSON.stringify(pageInfoEs));
  510. var headingParts = getDivsWhereClassStartsWith(titlePrefix);
  511. var headingCreatedParts = getDivsWhereClassStartsWith(headingCreatedPrefix);
  512. if (headingParts.length > 0) {
  513. info.title = headingParts[0].textContent;
  514. }
  515. else {
  516. console.warn("The title is missing. There are no divs with a class starting with " + titlePrefix);
  517. }
  518. var createdStr = null;
  519. if (headingCreatedParts.length > 0) {
  520. createdStr = headingCreatedParts[0].textContent;
  521. }
  522. else {
  523. console.warn("The date is missing. There are no divs with a class starting with " + headingCreatedParts);
  524. }
  525. info.titleHref = window.location.href;
  526. // console.log("info.title: " + info.title);
  527. // console.log("info.titleHref: " + info.titleHref);
  528. console.log("createdStr: " + createdStr);
  529. if (createdStr !== null) {
  530. var createdParts = createdStr.split(" ");
  531. if (createdParts.length >= 3) {
  532. var yI = createdParts.length - 1;
  533. var dI = createdParts.length - 2;
  534. var mI = createdParts.length - 3;
  535. var yStr = createdParts[yI];
  536. var dStr = createdParts[dI];
  537. var mStr = createdParts[mI];
  538. if (dStr.endsWith(",")) {
  539. info.month = mStr;
  540. info.day = dStr.slice(0, -1);
  541. info.year = yStr;
  542. }
  543. else {
  544. console.warn("A date such as MON, D, YYYY was expected at the end of: \""+createdStr+"\"");
  545. }
  546. }
  547. }
  548. var aspects = [];
  549. aspects = getImgsWhereClassStartsWith(licenseClauseImgPrefix);
  550. var ai;
  551. if (aspects.length > 0) {
  552. info.license = "";
  553. }
  554. else {
  555. console.error("The license had zero clauses (img tags with "+licenseClauseImgPrefix+"* class)!")
  556. }
  557. var sep = " - ";
  558. for (ai = 0; ai < aspects.length; ai++) {
  559. var aspectImg = aspects[ai];
  560. if (aspectImg.src == undefined) {
  561. console.error("The license symbol src was undefined.");
  562. }
  563. else if (aspectImg.src == "") {
  564. console.error("The license symbol src was blank.");
  565. }
  566. else if (aspectImg.src.endsWith("cc.svg")) {
  567. info.license += "Creative Commons";
  568. }
  569. else if (aspectImg.src.endsWith("nc.svg")) {
  570. info.license += sep + "Non-Commercial";
  571. }
  572. else if (aspectImg.src.endsWith("nd.svg")) {
  573. info.license += sep + "No Derivatives";
  574. }
  575. else if (aspectImg.src.endsWith("by.svg")) {
  576. info.license += sep + "Attribution";
  577. }
  578. else if (aspectImg.src.endsWith("sa.svg")) {
  579. info.license += sep + "ShareAlike"; // It has a space on ThingiVerse, but that is not correct.
  580. }
  581. else if (aspectImg.src.endsWith("zero.svg")) {
  582. // It is preceded by by.svg on ThingiVerse, but that is not correct.
  583. info.license = "Creative Commons Zero";
  584. }
  585. else {
  586. console.error("The license symbol list has an unknown clause symbol: \"" + aspectImg.src + "\"");
  587. }
  588. }
  589. if (info.license != undefined) {
  590. if (info.license == "") {
  591. console.log("The symbols do not indicate a license (The site layout appears to be broken or changed so the license must be detected from the license URL if possible instead).");
  592. }
  593. else {
  594. console.log("The symbols indicate the following license: " + info.license);
  595. }
  596. }
  597.  
  598.  
  599. var licenseAnchors = getAnchorsWhereClassStartsWith(licenseAnchorPrefix);
  600. var exactLicenseVersion = null;
  601. if (licenseAnchors.length > 0) {
  602. console.log("Checking " + licenseAnchors.length + " license anchors...");
  603. for (var lai=0, max=licenseAnchors.length; lai < max; lai++) {
  604. var licenseA = licenseAnchors[lai];
  605. if (verbose) {
  606. console.log(" checking " + licenseA.className + "...");
  607. // NOTE: .getAttribute("href") gets the raw value, but .href gets the resulting full URL.
  608. console.log(" licenseA.href is a " + typeof licenseA.href);
  609. console.log(" licenseA.href.toString is a " + typeof licenseA.href.toString);
  610. console.log(" licenseA.href.toString().includes is a " + typeof licenseA.href.toString().includes);
  611. }
  612. if (licenseA.href === undefined) {
  613. console.warn("A license a.href is undefined.");
  614. }
  615. // else if (typeof licenseA.href.toString !== 'function') {
  616. // console.warn("A license a.href.toString is not a function.");
  617. // }
  618. else if (typeof licenseA.href.includes !== 'function') {
  619. // NOTE: Firefox 48 removes the "contains" prototype--you must use includes!
  620. // console.warn("A license a.getAttribute(\"href\").includes is not a function.");
  621. console.warn("A license a.href.toString.includes is not a function.");
  622. }
  623. else if (!licenseA.href.includes("thingiverse.com")) {
  624. if (verbose) {
  625. console.log("licenseA.href: ");
  626. console.log("'",licenseA.href, "'");
  627. }
  628. info.licenseHref = licenseA.href;
  629. if (info.licenseHref.slice(-3, -2) == ".") {
  630. exactLicenseVersion = licenseA.href.slice(-4, -1);
  631. }
  632. else {
  633. console.warn("slice at -3 is not .: " + info.licenseHref.slice(-3, -2));
  634. }
  635. }
  636. else {
  637. info.author = licenseA.textContent;
  638. info.authorHref = licenseA.href;
  639. if (verbose) {
  640. console.log("unused[]: " + licenseA.href);
  641. console.log("author: " + info.author);
  642. console.log("authorHref: " + info.authorHref);
  643. }
  644. }
  645. }
  646. }
  647. else {
  648. console.warn("There is no anchor with a class like "+licenseAnchorPrefix+"*");
  649. }
  650. return info;
  651. }
  652.  
  653. function addButton() {
  654. 'use strict';
  655. // This should run when ThingPage_galleryHeader* gets filled in, but only once to prevent an infinite loop.
  656. // var pageInfoEs = document.getElementsByClassName("item-page-info");
  657. // NOTE: now ThingiVerse is a React app, so you must use inspect to see the HTML.
  658. // "ThingPage__madeBy*" includes parts such as:
  659. // - `ThingPage__modelName*`
  660. // - `<div class="ThingPage__createdBy*">by <a ...>UserName</a>MON D, YYYY`
  661. var pageInfoE = getButtonContainer();
  662. if (pageInfoE == null) {
  663. console.log('The '+madeSpanClassName+' class was not found so the button wasn\'t added!');
  664. return;
  665. }
  666. // pageInfoE.innerHTML += "<button onclick=\"getRemixLicense()\">Copy License for Remix</button>";
  667. //or:
  668. // See https://www.w3schools.com/jsref/met_document_createelement.asp
  669. var btn = document.createElement("BUTTON"); // Create a <button> element
  670. btn.setAttribute("class", "button button-secondary");
  671. btn.setAttribute("style", "background-color: rgb(50%, 50%, 50%)");
  672. var btnText = "Copy License for Remix";
  673. btn.innerHTML = btnText; // Insert text
  674. // Any URL starting with a slash comes after: "https://creativecommons.org/licenses"
  675. // otherwise it comes after "https://"
  676. // - A list of CC licenses is at <https://creativecommons.org/about/cclicenses/>.
  677.  
  678. btn.addEventListener("click", function(){
  679. btn.innerHTML = btnText;
  680. var info = getInfo();
  681. populateCorrespondingLicenseFields(info);
  682. var markdownStr = getMarkdown(info);
  683. setClipboardText(markdownStr, btn);
  684. }); // end addEventListener click
  685. pageInfoE.appendChild(btn); // Append <button> for Markdown to whatever element was selected.
  686. }//end addButton
  687. function checkIfComplete() {
  688. // console.log("Monitoring page loading...");
  689. var ready = true;
  690. var containers = getDivsWhereClassStartsWith(madeDivClassName);
  691. // console.log("Checking for completed page content...");
  692. if (containers.length == 1) {
  693. if (!elementHasAllPrefixes(containers[0], doneDivPrefixes)) {
  694. ready = false;
  695. // console.log("The "+containers[0].className+" container is not complete:");
  696. // console.log("The document is not ready yet ("+containers[0].className+" does not contain the classes with the prefixes \""+JSON.stringify(doneDivPrefixes)+"\").");
  697. }
  698. }
  699. else {
  700. ready = false;
  701. // console.log("The page is not formatted as expected:");
  702. // console.log(containers.length + " is an unexpected count for divs with a class named like " + madeDivClassName + "*.");
  703. }
  704. if (!hasAllDivPrefixes(doneDivPrefixesMain)) {
  705. ready = false;
  706. // console.log("The document is not complete:");
  707. // console.log("The document is not ready yet (the document does not contain the class(es) with the prefix(es) \""+JSON.stringify(doneDivPrefixesMain)+"\").");
  708. }
  709. if (ready) {
  710. if (verbose) {
  711. console.log("The page has loaded.");
  712. }
  713. clearInterval(checkTimer);
  714. addButton();
  715. console.log("The license detection will resume after a user clicks the copy license button.");
  716. }
  717. else {
  718. console.log("The document is not ready (or is missing required fields)...");
  719. }
  720. }
  721. checkTimer = setInterval(checkIfComplete, 2000);
  722. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址