-
Notifications
You must be signed in to change notification settings - Fork 2
/
ThingiversePlus.user.js
59 lines (59 loc) · 31.4 KB
/
ThingiversePlus.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// ==UserScript==
// @name Thingiverse Plus
// @namespace https://thingiverse.com/
// @version 3.0.0
// @description Thingiverse with extra features
// @author adripo
// @homepage https://github.com/adripo/thingiverse-plus
// @icon https://www.thingiverse.com/favicon.ico
// @updateURL https://raw.githubusercontent.com/adripo/thingiverse-plus/main/ThingiversePlus.meta.js
// @downloadURL https://raw.githubusercontent.com/adripo/thingiverse-plus/main/ThingiversePlus.user.js
// @supportURL https://github.com/adripo/thingiverse-plus/issues
// @match https://www.thingiverse.com/*
// @require https://cdn.jsdelivr.net/gh/CoeJoder/GM_wrench@v1.3/dist/GM_wrench.min.js
// @require https://raw.githubusercontent.com/eligrey/FileSaver.js/master/src/FileSaver.js
// @require https://raw.githubusercontent.com/Stuk/jszip/master/dist/jszip.min.js
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
!function(){"use strict";let e,n,t,i,a;const l="download-all-files",o="images",s="elements-per-page",c="position-right",d=[{id:l,description:"Download All Files As Zip",enableFunction:function(){const e='a[class^="SidebarMenu__download--"]';let n=document.querySelector(e);n?x(n):GM_wrench.waitForKeyElements(e,(e=>{x(e)}))},disableFunction:function(){const e='a[class^="SidebarMenu__download--"]';let n=document.querySelector(e);n?y(n):GM_wrench.waitForKeyElements(e,(e=>{y(e)}))},options:[{id:o,description:"include images",type:"checkbox",enableFunction:u,disableFunction:u}]},{id:"advanced-collections",description:"Advanced Collections",enableFunction:function(){document.querySelectorAll('div[class^="CollectThingWindow__closeImageWrapper--"]').forEach((e=>e.click())),function(){const e={attributes:!1,childList:!0,subtree:!0};a=new MutationObserver((e=>{for(const n of e)"childList"===n.type&&n.addedNodes.forEach((e=>{e.classList.forEach((n=>{n.startsWith("CollectThingWindow__collectWindowContainer--")&&v(e)}))}))})),a.observe(document.body,e)}()},disableFunction:function(){document.querySelectorAll('div[class^="CollectThingWindow__closeImageWrapper--"]').forEach((e=>e.click())),void 0!==a&&(a.disconnect(),a=void 0)}},{id:s,description:"Elements Per Page Selector",enableFunction:g,disableFunction:m,options:[{id:c,description:"Position",type:"toggle",left:"Left",right:"Right",enableFunction:h,disableFunction:h}]},{id:"hide-banners",description:"Hide Banners",enableFunction:function(){if(!n){n=GM_addStyle("div[class^='HomePageBanner__'] {\n display: none !important;\n }\n\n div[class^='SiteWideNotification__'] {\n display: none !important;\n }")}},disableFunction:function(){n&&(n.remove(),n=void 0)}},{id:"hide-ads",description:"Hide Ads",enableFunction:function(){if(!t){t=GM_addStyle("div[class^='ItemCardContainer__']:has(> div[class^='ItemCardHeader__'][title='Advertisement']) {\n display: none !important;\n }")}window.location.pathname.startsWith("/thing:")&&b(6)},disableFunction:function(){t&&(t.remove(),t=void 0)}}];
/**
* Retrieves the status of a feature or option from the configuration.
* @param {string} featureId - The ID of the feature.
* @param {string} [optionId] - The ID of the option (optional).
* @returns {boolean} - The status of the feature or option.
*/
function r(e,n){return void 0===n?GM_getValue("settings_"+e,!1):GM_getValue("settings_"+e+"_"+n,!1)}
/**
* Updates the configuration status based on the state of the target checkbox.
* If the checkbox corresponds to a feature, it updates the feature's configuration.
* If the checkbox corresponds to an option within a feature, it updates the option's configuration.
*
* @param {HTMLElement} targetCheckbox - The checkbox element whose state triggers the update.
*/function p(e){const n=e.dataset.feature,t=e.dataset.option,i=d.find((e=>e.id===n));if(!i)return void console.error("Feature not found:",n);let a,l;if(void 0===t)GM_setValue("settings_"+i.id,e.checked),a=i.enableFunction,l=i.disableFunction,
/**
* Updates the visibility and enables/disables the option checkboxes based on the state of the feature checkbox.
* @param {HTMLElement} featureCheckbox - The feature checkbox whose state determines the visibility and enablement of option checkboxes.
*/
function(e){const n=e.closest(".plus-settings-feature-container");if(!n)return void console.error("Feature container not found");n.querySelectorAll(".plus-subsettings-element").forEach((n=>{const t=n.querySelector('input[type="checkbox"]');t&&(n.classList.toggle("hidden",!e.checked),t.disabled=!e.checked)}))}(e,e.checked);else{const n=i.options.find((e=>e.id===t));if(!n)return void console.error("Option not found:",t);GM_setValue("settings_"+i.id+"_"+n.id,e.checked),a=n.enableFunction,l=n.disableFunction}e.checked&&"function"==typeof a?a():e.checked||"function"!=typeof l||l()}function u(){let e=document.getElementById("plus-checkbox-"+elNameDownloadAllFilesImages);GM_setValue("subsettings_"+elNameDownloadAllFilesImages,e.checked)}function h(){m(),g()}function m(){document.querySelectorAll(".plus-elements-per-page").forEach((e=>{e.remove()})),i&&(i.remove(),i=void 0),e&&(e.remove(),e=void 0),f()}function g(){const n=window.location.pathname;if("/"===n||"/search"===n){const n=r(s,c);e||(e=GM_addStyle("/* Graphical Improvements Style */\n \n div[class^='HomePage__homePage--'] {\n transition: all 0.3s ease;\n }\n \n div[class^='PageHeader__headerPlaceholder--'],\n div[class^='PageHeader__headerWrapper'] {\n min-width: 348px;\n }\n \n @media (max-width: 620px) {\n div[class^='ItemCardGrid__itemCardGrid--'] {\n grid-template-columns: repeat(auto-fit,minmax(300px,1fr));\n }\n }\n \n @media (min-width: 1025px) and (max-width: 1043px) {\n div[class^='PageHeader__headerPlaceholder--'],\n div[class^='PageHeader__headerWrapper--'] {\n height: 85px;\n }\n \n div[class^='PageHeader__headerPlaceholder--'][class*='PageHeader__siteNotification--'],\n div[class^='PageHeader__headerWrapper--'][class*='PageHeader__siteNotification--'] {\n height: 125px;\n }\n \n div[class^='PageHeader__header--'] {\n -ms-flex-wrap:wrap;\n flex-wrap: wrap;\n gap: normal;\n padding: 0 5px 5px;\n }\n \n div[class^='PageHeader__header--'] div[class^='PageHeader__navBar--'] {\n -webkit-box-ordinal-group: 3;\n -ms-flex-order: 2;\n order: 2;\n }\n \n div[class^='PageHeader__header--'] div[class*='PageHeader__searchBar--'] {\n -webkit-box-ordinal-group: 4;\n -ms-flex-order: 3;\n order: 3;\n }\n \n div[class*='PageHeader__searchBar--'] {\n max-width: none;\n }\n }\n \n div[class^='SearchFilterBar__searchFilterBar--'] {\n grid-template-columns: repeat(auto-fit,minmax(300px,1fr));\n display: grid;\n row-gap: 18px;\n column-gap: 24px;\n }\n \n div[class^='SearchFilterBar__searchFilterBar--'] > * {\n width: 100% !important;\n }\n \n div[class^='SearchFilterBar__searchFilterBar--'] > :last-child:nth-child(3n-1),\n div[class^='SearchFilterBar__searchFilterBar--'] > :nth-last-child(2):nth-child(3n+1) {\n grid-column-end: auto;\n }\n \n @media (max-width: 720px) {\n .SearchFilterBar__searchFilterBar--RIie5 {\n column-gap: 24px;\n }\n }")),function(e=!1){const n=[20,30,60,100,200],t=GM_getValue("elements_per_page",n[0]);b(t);const a="/* Elements Per Page Style */\n \n .plus-elements-per-page {\n position: relative;\n width: 100%;\n }\n\n .plus-elements-per-page > label {\n opacity: 1;\n -webkit-box-align: center;\n -ms-flex-align: center;\n -webkit-box-pack: justify;\n -ms-flex-pack: justify;\n align-items: center;\n background-color: #fff;\n border: 1px solid #d4d4d4;\n border-radius: 12px;\n color: #6c6c6c;\n cursor: pointer;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n font-family: Noto Sans Mono,Arial,Helvetica;\n font-size: 12px;\n font-weight: 400;\n gap: 12px;\n justify-content: space-between;\n line-height: 16px;\n min-height: 34px;\n outline: none;\n width: calc(100% - 2px);\n }\n\n .plus-elements-per-page > label > span {\n font-family: Noto Sans Mono,Arial,Helvetica;\n font-size: 12px;\n line-height: 16px;\n padding-left: 12px;\n }\n\n .plus-elements-per-page > label > select {\n min-width: 80px;\n height: 30px;\n cursor: pointer;\n border: 0;\n border-left: 1px solid #d4d4d4;\n color: #6c6c6c;\n font-family: Noto Sans Mono,Arial,Helvetica;\n font-size: 12px;\n font-weight: 400;\n padding-left: 12px;\n margin-right: 12px;\n }\n\n .plus-hidden-left,\n .plus-hidden-right {\n visibility: hidden;\n }\n\n @media (max-width: 1691px) {\n .plus-hidden-left {\n display: none;\n }\n .plus-hidden-right {\n display: none;\n }\n }\n\n @media (max-width: 2015px) {\n .plus-hidden-d-none {\n display: none;\n }\n }";let l=[];n.forEach((e=>{let n=document.createElement("option");n.value=e.toString(),n.selected=t===e,n.innerHTML=e.toString(),l.push(n)}));let o=document.createElement("div");o.classList.add("plus-elements-per-page","plus-hidden-left");let s=document.createElement("div");s.classList.add("plus-elements-per-page","plus-hidden-right");let c=document.createElement("div");c.className="plus-elements-per-page";let d=document.createElement("span");d.innerHTML="Elements per page";let r=document.createElement("select");r.id="plus-elements-per-page-select",l.forEach((e=>{r.add(e)})),r.onchange=function(){const e=parseInt(this.value);n.includes(e)&&(GM_setValue("elements_per_page",e),b(e))};let p=document.createElement("label");p.htmlFor=r.id,p.appendChild(d),p.appendChild(r),c.appendChild(p),i=GM_addStyle(a);const u='div[class^="SearchFilterBar__"]',h=document.querySelector(u),m=(e,n)=>{n?(s.classList.add("plus-hidden-d-none"),e.prepend(o),e.append(c,s)):(o.classList.add("plus-hidden-d-none"),e.prepend(o,c),e.append(s))};h?m(h,e):GM_wrench.waitForKeyElements(u,(n=>{m(n,e)}))}(n)}}function b(e){URLSearchParams.prototype._append&&f(),URLSearchParams.prototype._append=URLSearchParams.prototype.append,URLSearchParams.prototype.append=function(n,t){return"per_page"===n&&(t=e),this._append(n,t)}}function f(){URLSearchParams.prototype.append=URLSearchParams.prototype._append}function v(e){!function(e){let n=document.createElement("div");n.className="plus-spinner-wrapper";let t=document.createElement("i");t.className="plus-spinner-loading",n.appendChild(t),e.prepend(n)}(e);const n=function(){try{return JSON.parse(window.localStorage["user-data"]).user}catch(e){return null}}();if(n){(async function(e="",n=""){const t="https://api.thingiverse.com/users/"+e+"/collections/true",i=await fetch(t,{method:"GET",headers:{Authorization:"Bearer "+n}});return i.json()})(function(){try{return JSON.parse(window.localStorage["user-data"]).data.name}catch(e){return null}}(),n).then((n=>{let t=function(e){if(0===e.length)return null;let n=new Date(e[0].modified),t=0;for(let i=1;i<e.length;i++)new Date(e[i].modified)>n&&(t=i,n=new Date(e[i].modified));return t}(n);t&&n.unshift(n.splice(t,1)[0]);let i=[];n.forEach((e=>{let n=document.createElement("option");n.value=e.id,n.text=e.name+" ("+e.count+")",i.push(n)}));let a=document.createElement("option");a.style.cssText="display: none;",a.value="-1",a.text="Create a new Collection",i.push(a);let l=Array.from(document.querySelectorAll('a[class^="SideMenuItem__textWrapper"]')).filter((e=>"Collect Thing"===e.innerHTML)).map((e=>e.parentNode)),o=Array.from(document.querySelectorAll('div[class^="CardActionItem__textWrapper--"]')).filter((e=>"Collect Thing"===e.innerHTML)).map((e=>e.parentNode.parentNode.parentNode));l.concat(o).forEach((e=>{e.onclick=async function(){var e;await(e=0,new Promise((n=>setTimeout(n,e)))),s.selectedIndex=0}})),e.querySelector('div[class^="CollectThingWindow__collectWindowBody"]').style.cssText="flex-flow: row wrap;",e.querySelector('span[class^="CollectThingWindow__bodyTextWrapper"]').style.cssText="width: 100%;";let s=e.querySelector('select[class^="CollectThingWindow__selectWrapper"]');s.style.cssText="max-width: calc(100% - 30px - 10px );flex-grow: 1;";const c=i.map((e=>e.cloneNode(!0)));s.replaceChildren(...c),s.selectedIndex=0;let d=document.createElement("button");d.style.cssText="width: 30px; height: 30px;",d.textContent="+",d.onclick=function(){s.value="-1";const e=new Event("change",{bubbles:!0});s.dispatchEvent(e)};let r=function(e=null){let n=document.createElement("span");e&&n.appendChild(e);return n}(d);s.after(r)})).catch((e=>{console.error("Error:",e)})).finally((()=>{!function(e){e.querySelector("div.plus-spinner-wrapper").remove()}(e)}))}}function x(e){e.onclick=async function(){!function(){document.body.classList.add("wait");let e=new JSZip;console.log(w().stripSlashes());let n=JSON.parse(w().stripSlashes()).thing;if(n.files.forEach((n=>{let t=M(n.public_url);e.file(n.name,t)})),r(l,o)){let t=e.folder("images");n.images.forEach((e=>{let n=M(e.sizes.filter((e=>"display"===e.type&&"large"===e.size))[0].url);t.file(e.name,n)}))}let t=n.id+" - "+n.name;t=function(e,{replacement:n="�"}={}){const t=e;return(e=(e=(e=e.split(/[\r\n]/).map((e=>e.trim())).filter((e=>e.length)).join(" ")).replaceAll(/[<>:"\/\\|?*\x00-\x1F]/g,n)).replace(/\.$/,"")).length||(e="_"),e.match(/^(CON|PRN|AUX|NUL|COM1|COM2|COM3|COM4|COM5|COM6|COM7|COM8|COM9|LPT1|LPT2|LPT3|LPT4|LPT5|LPT6|LPT7|LPT8|LPT9)(\..+)?$/)&&(e=`_${e}`),{fname:e,isOriginal:e===t}}(t).fname,e.generateAsync({type:"blob"}).then((function(e){saveAs(e,t),document.body.classList.remove("wait")}))}()}}function y(e){e.onclick=null}function w(){try{return JSON.parse(window.localStorage["persist:root"]).currentThing}catch(e){return null}}async function M(e){return(await fetch(e,{method:"GET"}).catch((e=>{console.error("Error:",e)}))).arrayBuffer()}GM_addStyle(".wait {\n cursor: wait;\n }\n\n .plus-settings-button {\n position: fixed;\n z-index: 500;\n bottom: 10px;\n right: 10px;\n border-radius: 3px;\n padding: 5px;\n background-color: #fff;\n }\n\n .plus-settings-button img {\n box-sizing: content-box;\n max-width: 20px;\n padding: 10px;\n border-radius: 3px;\n vertical-align: middle;\n background-color: #248bfb;\n cursor: pointer;\n }\n\n .plus-settings-container {\n position: fixed;\n transition: max-height 0.3s, max-width 0.3s, visibility 0.3s, opacity 0.3s linear;\n z-index: 500;\n bottom: 70px;\n right: 10px;\n max-height: 100%;\n max-width: 100%;\n visibility: visible;\n opacity: 1;\n background-color: #248bfb;\n overflow: hidden;\n padding: 5px;\n border-radius: 3px;\n box-sizing: content-box;\n }\n\n .plus-settings-container.hidden {\n max-width: 0;\n max-height: 0;\n visibility: hidden;\n opacity: 0;\n }\n\n .plus-settings-container > div {\n background-color: #f5f5f5;\n padding: 8px;\n border-radius: 3px;\n }\n\n .plus-settings-container > div:not(:last-child) {\n margin-bottom: 5px;\n }\n\n .plus-settings-checkbox {\n vertical-align: middle;\n width: 30px;\n height: 30px;\n margin: 0;\n cursor: pointer;\n }\n\n .plus-settings-checkbox + label {\n display: inline-block;\n vertical-align: middle;\n color: #555;\n opacity: 1;\n margin: 0 10px 0 10px;\n cursor: pointer;\n font-family: Noto Sans Mono,Arial,Helvetica;\n font-size: 16px;\n line-height: 30px;\n }\n\n .plus-subsettings-element {\n --height: 30px;\n\n transition: max-height 0.3s, visibility 0.3s, opacity 0.3s linear;\n max-height: var(--height);\n visibility: visible;\n opacity: 1;\n overflow: hidden;\n }\n\n .plus-subsettings-element.hidden {\n max-height: 0;\n visibility: hidden;\n opacity: 0;\n }\n\n .plus-subsettings-element label,\n .plus-subsettings-element span {\n color: #555;\n opacity: 1;\n font-size: 14px;\n margin: auto;\n }\n\n .plus-settings-pipe {\n --width: 30px;\n --top-gap: 2px;\n\n display: inline-block;\n vertical-align: middle;\n width: calc(var(--width) / 2);\n height: calc(var(--height) / 2 - var(--top-gap));\n margin: var(--top-gap) 0 calc(var(--height) / 2 - var(--top-gap)) calc(var(--width) / 2);\n color: #555;\n opacity: .8;\n border-left: 1px dashed;\n border-bottom: 1px dashed;\n }\n\n .plus-settings-pipe + span,\n .plus-settings-pipe + input {\n margin: 0 10px 0 10px;\n }\n\n .plus-subsettings-element > .plus-settings-checkbox {\n width: 24px;\n height: 24px;\n }"),GM_addStyle('/* Toggle Style */\n\n .plus-toggle {\n --width: 120px;\n --height: calc(var(--width) / 6);\n\n position: relative;\n display: inline-block;\n opacity: 1;\n width: var(--width);\n height: var(--height);\n vertical-align: middle;\n margin: auto;\n background-color: rgba(0,0,0,.1);\n cursor: pointer;\n }\n\n .plus-toggle, .plus-toggle .slider {\n height: var(--height);\n border-radius: calc( var(--height) / 2);\n }\n\n .plus-toggle .slider {\n position: absolute;\n width: 50%;\n background-color: #248bfb;\n box-shadow: 0 2px 15px rgba(0,0,0,.15);\n transition: transform .2s cubic-bezier(0.25, 0.46, 0.45, 0.94);\n }\n .plus-toggle .labels {\n width: 50%;\n height: 100%;\n position: absolute;\n display: flex;\n opacity: 1;\n justify-content: center;\n align-items: center;\n font-family: Noto Sans Mono,Arial,Helvetica;\n font-size: 0.75rem;\n color: #555;\n transition: color .2s cubic-bezier(0.25, 0.46, 0.45, 0.94);\n }\n\n .plus-toggle .labels.right {\n right: 0;\n }\n\n /* Toggle */\n .plus-toggle input[type="checkbox"] {\n display: none;\n }\n\n .plus-toggle input[type="checkbox"]:checked + .slider {\n transform: translateX(100%);\n }\n\n .plus-toggle input[type="checkbox"]:checked ~ .labels.right,\n .plus-toggle input[type="checkbox"]:not(:checked) ~ .labels:not(.right) {\n color: white;\n }'),GM_addStyle("/* Spinner Loading */\n\n .plus-spinner-wrapper {\n display: flex;\n position: absolute;\n background: rgba(0,0,0,0.6);\n left: 0;\n top: 0;\n height: 100%;\n width: 100%;\n align-items: center;\n justify-content: center;\n z-index: 1;\n }\n\n .plus-spinner-loading {\n background-image: url(https://cdn.thingiverse.com/site/assets/inline-icons/19420d877d0e95abb31b.svg);\n background-repeat: no-repeat;\n background-position: 50%;\n height: 117px;\n width: 117px;\n animation: plus-spin 7s linear infinite;\n }\n @keyframes plus-spin {\n 100% {\n transform:rotate(360deg);\n }\n }"),function(){const e="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEMAAABCCAYAAAAMlmvWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAG2GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNy4xLWMwMDAgNzkuZWRhMmIzZiwgMjAyMS8xMS8xNC0xMjozMDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIzLjEgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyMi0wMS0wM1QwMzoxMzoyNCswMTowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjItMDEtMDNUMDM6MjM6MDErMDE6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjItMDEtMDNUMDM6MjM6MDErMDE6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N2YzMWI3NWQtMDZiYy1jMzRhLWIyOGYtZTdlODA2NDc4YjRlIiB4bXBNTTpEb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6MmE0NjVlNzAtZDg4Ni04MTQzLThmYjItNTcyMWYxZjcyOTM0IiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6NWNmYjU5ODctOTJjMi0xODQ4LWI4MzktNGU2YTEzMDA0M2I3Ij4gPHBob3Rvc2hvcDpUZXh0TGF5ZXJzPiA8cmRmOkJhZz4gPHJkZjpsaSBwaG90b3Nob3A6TGF5ZXJOYW1lPSIrIiBwaG90b3Nob3A6TGF5ZXJUZXh0PSIrIi8+IDwvcmRmOkJhZz4gPC9waG90b3Nob3A6VGV4dExheWVycz4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo1Y2ZiNTk4Ny05MmMyLTE4NDgtYjgzOS00ZTZhMTMwMDQzYjciIHN0RXZ0OndoZW49IjIwMjItMDEtMDNUMDM6MTM6MjQrMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMy4xIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo3ZjMxYjc1ZC0wNmJjLWMzNGEtYjI4Zi1lN2U4MDY0NzhiNGUiIHN0RXZ0OndoZW49IjIwMjItMDEtMDNUMDM6MjM6MDErMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMy4xIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBh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";let n=document.createElement("div");n.className="plus-settings-button";let t=document.createElement("img");t.src=e,t.alt="ThingiversePlus-logo",t.onclick=function(){document.querySelector(".plus-settings-container").classList.toggle("hidden")},n.appendChild(t),document.body.appendChild(n)}(),function(){let e=document.createElement("div");e.classList.add("plus-settings-container"),e.classList.add("hidden"),d.forEach((n=>{e.appendChild(function(e){let n=document.createElement("div");n.className="plus-settings-feature-container";let t=document.createElement("div");t.className="plus-settings-feature-config";let i=document.createElement("input");i.type="checkbox",i.id="plus-checkbox-"+e.id,i.className="plus-settings-checkbox",i.dataset.feature=e.id,i.onchange=function(){p(this)};const a=r(e.id);i.checked=!!a;let l=document.createElement("label");return l.htmlFor=i.id,l.innerHTML=e.description,t.appendChild(i),t.appendChild(l),n.appendChild(t),void 0!==e.options&&e.options.forEach((t=>{let i=
/**
* Creates a subconfiguration element for a feature option based on its type.
* @param {string} featureId - The ID of the feature containing the option.
* @param {string} optionId - The ID of the option.
* @returns {HTMLElement} - The created subconfiguration element.
*/
function(e,n){const t=d.find((n=>n.id===e));if(!t)return console.error("Feature not found:",e),null;const i=t.options.find((e=>e.id===n));if(!i)return console.error("Option not found:",n),null;let a;switch(i.type){case"checkbox":a=
/**
* Creates a subconfiguration checkbox element for a feature option.
* @param {string} featureId - The ID of the feature containing the option.
* @param {string} optionId - The ID of the option.
* @returns {HTMLElement} - The created subconfiguration checkbox element.
*/
function(e,n){const t=d.find((n=>n.id===e));if(!t)return console.error("Feature not found:",e),null;const i=t.options.find((e=>e.id===n));if(!i)return console.error("Option not found:",n),null;const a=r(t.id);let l=document.createElement("div");l.id="plus-settings-"+i.id,l.className="plus-subsettings-element",a||l.classList.add("hidden");let o=document.createElement("div");o.className="plus-settings-pipe",l.appendChild(o);const s=r(t.id,i.id);let c=document.createElement("input");c.type="checkbox",c.id="plus-checkbox-"+t.id+"-"+i.id,c.className="plus-settings-checkbox",c.checked=!!s,c.disabled=!a,c.dataset.feature=t.id,c.dataset.option=i.id,c.onchange=function(){p(this)},l.appendChild(c);let u=document.createElement("label");return u.htmlFor=c.id,u.innerHTML=i.description,l.appendChild(u),l}
/**
* Creates a subconfiguration toggle element for a feature option.
* @param {string} featureId - The ID of the feature containing the option.
* @param {string} optionId - The ID of the option.
* @returns {HTMLElement} - The created subconfiguration toggle element.
*/(t.id,i.id);break;case"toggle":a=function(e,n){const t=d.find((n=>n.id===e));if(!t)return console.error("Feature not found:",e),null;const i=t.options.find((e=>e.id===n));if(!i)return console.error("Option not found:",n),null;const a=r(t.id);let l=document.createElement("div");l.id="plus-settings-"+i.id,l.className="plus-subsettings-element",a||l.classList.add("hidden");let o=document.createElement("div");o.className="plus-settings-pipe",l.appendChild(o);let s=document.createElement("span");s.innerHTML=i.description+":",l.appendChild(s);const c=r(t.id,i.id);let u=document.createElement("label");u.className="plus-toggle";let h=document.createElement("input");h.type="checkbox",h.id="plus-toggle-"+i.id,h.checked=!!c,h.disabled=!a,h.dataset.feature=t.id,h.dataset.option=i.id,h.onchange=function(){p(this)},u.appendChild(h);let m=document.createElement("div");m.className="slider",u.appendChild(m);let g=document.createElement("span");g.className="labels",g.innerHTML=i.left.toUpperCase(),u.appendChild(g);let b=document.createElement("span");return b.className="labels right",b.innerHTML=i.right.toUpperCase(),u.appendChild(b),l.appendChild(u),l}(t.id,i.id)}return a||(console.error("Failed to create subconfiguration for:",n),null)}(e.id,t.id);n.appendChild(i)})),n}(n))})),document.body.appendChild(e),window.addEventListener("click",(function(e){let n=document.querySelector(".plus-settings-container");const t=document.querySelector(".plus-settings-button");n.classList.contains("hidden")||t.contains(e.target)||n.contains(e.target)||n.classList.add("hidden")}))}(),d.forEach((e=>function(e){const n=r(e.id);n?e.enableFunction():e.disableFunction()}(e))),String.prototype.stripSlashes=function(){return this.replace(/\\(.)/gm,"$1")}}();