您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Various tweaks for OnShape, such as remap F2 for rename (SHIFT + N)
// ==UserScript== // @name OnShape helper // @namespace V@no // @version 25.8.1 // @description Various tweaks for OnShape, such as remap F2 for rename (SHIFT + N) // @author V@no // @license MIT // @match https://cad.onshape.com/documents // @match https://cad.onshape.com/documents?* // @match https://cad.onshape.com/documents/* // @icon https://onshape.com/favicon.png // @grant none // ==/UserScript== (CSS => { // eslint-disable-next-line no-unused-expressions "use strict"; /* ^ = CTRL ! = ALT + = SHIFT */ const VERSION = "25.8.1"; const CHANGES = `+ Add configuration btn remembers last used item ! help popup in FS editor with dark mode ! dimension input style affected configurations input`; const map = { "F2": {key: "N", code: "KeyN", keyCode: 78, shiftKey: true} }; const elStyle = document.createElement("style"); elStyle.id = "onShapeHelper"; elStyle.textContent = CSS; document.head.append(elStyle); let mouseEvent = {}; document.addEventListener("mousemove", evt => { mouseEvent = evt; }, false); document.body.addEventListener("keydown", evt => { let modifier = ""; modifier = evt.altKey ? "!" : ""; modifier = evt.shiftKey ? "+" : ""; modifier = evt.ctrlKey || evt.metaKey ? "^" : ""; const key = modifier + evt.code; if (!evt.isTrusted || !(key in map) || evt.altKey || evt.shiftKey || evt.ctrlKey || evt.metaKey) return;// console.log(evt, mouseEvent); if (mouseEvent.target) { evt.target.dispatchEvent(new KeyboardEvent(evt.type, Object.assign({}, evt, {key: " ", code: "space", keyCode: 32}, {bubbles: true}))); mouseEvent.target.dispatchEvent(new PointerEvent("click", mouseEvent)); } evt.target.dispatchEvent(new KeyboardEvent(evt.type, Object.assign({}, evt, map[key], {bubbles: true}))); }, true); const dataValue = (el, value) => { el.dataset.value = value; }; const changeByRegex = /Change by (.+) at (.+)$/; const getChildIndex = child => { let i = 0; while ((child = child.previousElementSibling) !== null) i++; return i; }; // eslint-disable-next-line no-unused-vars const observer = new MutationObserver((mutationList, _observer) => { const types = {}; for (const mutation of mutationList) { for(const node of mutation.addedNodes) { if (node.nodeType !== 1) continue; /* ----------------------------- input boxes ----------------------------- */ if (node.matches("input:not(.OSH)")) { node.classList.add("OSH"); node.parentElement.classList.add("OSH", "input_box"); const eventHandler = () => dataValue(node.parentElement, node.value); node.addEventListener("input", eventHandler); // inserted variables don't trigger input event, so we need to check for changes let previousValue = null; const loop = timestamp => { if (previousValue !== node.value) { previousValue = node.value; eventHandler(); } if (node.isConnected) return requestAnimationFrame(loop); }; requestAnimationFrame(loop); } /* ------------------------- version and history ------------------------- */ if (node.matches(".os-flex-table-row:not(.change, .OSH, .separator)")) { node.classList.add("OSH"); const elDescription = document.createElement("div"); elDescription.classList.add("os-flex-col", "os-item-description", "inside-document", "OSH_description"); elDescription.textContent = node.dataset.bsExpandedContent || ""; node.append(elDescription); if (node.dataset.bsExpandedContent) types.historyDescription = true; } /* --------------------- version and history changes --------------------- */ if (node.matches(".os-flex-table-row.change:not(.OSH)")) { node.classList.add("OSH"); const changeBy = node.dataset.bsOriginalTitle.match(changeByRegex); let parentChangeBy = ""; for(let i = getChildIndex(node); i >= 0; --i) { const elSibling = node.parentElement.children[i].querySelector(".os-item-modified-by"); if (elSibling) { parentChangeBy = elSibling.textContent.trim(); break; } } const elModified = node.querySelector(".os-flex-col.os-item-modified-date.inside-document"); elModified.innerHTML = (parentChangeBy === changeBy[1] ? `` : `${changeBy[1]}\n`) + changeBy[2]; node.classList.toggle("OSH_single_line", parentChangeBy === changeBy[1]); } /* ---------------------------- version graph ---------------------------- */ if (node.matches("line") && !types.versionGraph && node.closest(".os-version-graph")) { types.versionGraph = node.parentElement; } /* ---------------------------- configuration ---------------------------- */ if (!node.classList.contains(".single-table-container.os-virtual-scroll-section:not(.OSH_conf)")) { const nlNodes = node.querySelectorAll(`a:not(.OSH_conf)[ng-click="configurationTable.moveParameterUp()"], a:not(.OSH_conf)[ng-click="configurationTable.moveParameterDown()"`); if (nlNodes.length > 0) { types.configuration = nlNodes.length; node.classList.add("OSH_conf"); } for(let i = 0; i < nlNodes.length; i++) { const elA = nlNodes[i]; elA.classList.add("OSH_conf"); const elParent = elA.closest("div.os-table-header-responsive-last-row>div.d-flex"); elParent.classList.add("OSH_conf_row"); if (elParent.upDown === undefined) elParent.upDown = {}; const type = elA.matches(`[ng-click="configurationTable.moveParameterUp()"]`); if (elParent.upDown[type]) elParent.upDown[type].replaceWith(elA); else elParent.prepend(elA); elParent.upDown[type] = elA; elA.classList.add(type ? "UP" : "DOWN"); elA.title = elA.textContent; elA.textContent = type ? "▲" : "▼"; elA.addEventListener("click", () => moved(elA.parentElement.parentElement.parentElement)); } } /* ----------------------- add configuration button ---------------------- */ if (node.matches("#right-content-pane > div > div > div.content-footer.os-row > div.button-container > div:not(.OSH)")) { node.classList.add("OSH"); const elButton_orig = node.querySelector("button"); //add configuration button const elButton = elButton_orig.cloneNode(true); elButton_orig.parentElement.replaceChild(elButton, elButton_orig); const nlSelectItems = node.querySelectorAll("a.dropdown-item"); const label = elButton_orig.lastChild.textContent.match(/^(.+\s)\S+/)[1]; const elSelectItems = []; for(let i = 0; i < nlSelectItems.length; i++) { const el = nlSelectItems[i].cloneNode(true); elSelectItems.push(el); nlSelectItems[i].parentElement.replaceChild(el, nlSelectItems[i]); const text = el.textContent.match(/\s(\S+?)$/)[1]; el.dataset.text = String(text).charAt(0).toUpperCase() + String(text).slice(1); } const setLabel = index => { if (!elSelectItems[index].dataset.text) return; elButton.dataset.value = index; elButton.replaceChild(elSelectItems[index].firstElementChild.cloneNode(true), elButton.firstElementChild); elButton.lastChild.textContent = label + elSelectItems[index].dataset.text; }; setLabel(~~localStorage.getItem("OSH_confAddButton")); elButton.addEventListener("click", evt => { evt.preventDefault(); evt.stopPropagation(); nlSelectItems[evt.target.dataset.value].click(); }); node.addEventListener("click", evt => { if (!evt.isTrusted) return; // ignore synthetic events /* --------------------------- dropdown item --------------------------- */ if (evt.target.matches("a")) { const index = elSelectItems.indexOf(evt.target); localStorage.setItem("OSH_confAddButton", index); setLabel(index); elButton.click(); } }); } /* ---------------------------- message bubble --------------------------- */ if (node.matches(`div[ng-include="'/project/web/woolsthorpe/app/partials/toolbarMessageBubble.html'"]`) && node.parentElement !== document.body) { document.body.append(node); } if (node.matches(".d-flex.flex-column.ng-star-inserted:not(.OSH)")) { node.classList.add("OSH"); types.documentList = node; } } // for added nodes } // for mutation list if (types.configuration) { if (!document.querySelector("div.single-table-container.os-virtual-scroll-section:first-child .UP")) { const elRow = document.querySelector("div.single-table-container.os-virtual-scroll-section:first-child div.OSH_conf_row"); const elA = elRow.firstChild.cloneNode(true); elA.setAttribute("ng-click", "configurationTable.moveParameterUp()"); elA.classList.remove("DOWN"); elA.title = "Move UP"; elA.classList.add("OSH_conf", "UP"); elA.textContent = "▲"; elRow.prepend(elA); const elParent = elA.closest("div.os-table-header-responsive-last-row>div.d-flex"); elParent.upDown[true] = elA; } if (!document.querySelector("div.single-table-container.os-virtual-scroll-section:last-child .DOWN")) { const elRow = document.querySelector("div.single-table-container.os-virtual-scroll-section:last-child div.OSH_conf_row"); if (elRow) { const elA = elRow.firstChild.cloneNode(true); elA.setAttribute("ng-click", "configurationTable.moveParameterDown()"); elA.classList.remove("UP"); elA.title = "Move DOWN"; elA.classList.add("OSH_conf", "DOWN"); elA.textContent = "▼"; elRow.append(elA); const elParent = elA.closest("div.os-table-header-responsive-last-row>div.d-flex"); elParent.upDown[false] = elA; } } } if (types.versionGraph) { const nlLines = types.versionGraph.querySelectorAll("line"); let max = 0; let min = 1e10; for(let i = 0; i < nlLines.length; i++) { const elLine = nlLines[i]; max = Math.max(max, Number.parseFloat(elLine.getAttribute("x1"))); min = Math.min(min, Number.parseFloat(elLine.getAttribute("x1"))); } const elGraph = types.versionGraph.closest(".document-panel-main-content"); elGraph.style.setProperty("--os-version-graph-width", `${max - min + 28}px`); elGraph.style.setProperty("--os-version-graph-left", `-${min - 14}px`); } if (types.historyDescription) { document.querySelector(".versions-history-table-container").classList.add("OSH_description"); } /* --------------- prevent document folder open in a new tab --------------- */ const elFolder = document.querySelector("a.folder[target='_blank']"); if (elFolder) elFolder.removeAttribute("target"); // if (types.documentList) // { // const node = types.documentList; // const elSplitter = node.querySelector("osx-splitter"); // const saveStyle = () => localStorage.setItem("OSH_splitterStyle", elSplitter.getAttribute("style")); // let timer = null; // const mutationObserver2 = new MutationObserver(mutationList2 => // { // if (!elSplitter.classList.contains("OSH")) // { // elSplitter.classList.add("OSH"); // const savedStyle = localStorage.getItem("OSH_splitterStyle"); // if (savedStyle) // { // elSplitter.setAttribute("style", savedStyle); // elSplitter.querySelector(".cdk-drag.gutter-handle").dispatchEvent(new Event("dragstart", {bubbles: true})); // return; // } // } // clearTimeout(timer); // timer = setTimeout(saveStyle, 500); // console.log("OSH: MutationObserver2", mutationList2); // }); // mutationObserver2.observe(elSplitter, { attributeFilter: ["style"], attributeOldValue: true }); // } }); observer.observe(document.body, { childList: true, subtree: true, }); const moved = el => { moved.clear(); el.classList.add("moved"); moved.el = el; moved.timer = setTimeout(moved.clear, 2000); }; moved.clear = () => { clearTimeout(moved.timer); if (moved.el) { moved.el.classList.remove("moved"); moved.el = null; } }; console.log(`OnShape helper v${VERSION} loaded`, "https://greasyfork.org/en/scripts/522636"); })(` .OSH_hidden { display: none !important; } /* ------------------------ dimension edit input box ------------------------ */ .dimension-edit-container .ns-feature-parameter .bti-numeric-text, .dimension-edit-container os-quantity-parameter input, .dimension-edit { max-width: unset; z-index: 9999; text-align: center; } .dimension-edit-container .input_box.OSH::before, .dimension-edit-container .input_box.OSH::after { box-sizing: border-box; } .dimension-edit-container .input_box.OSH { display: inline-grid; vertical-align: top; align-items: center; position: relative; } .dimension-edit-container .input_box.OSH::after, .dimension-edit-container .input_box.OSH input { width: auto; min-width: 1em; grid-area: 1/2; font: inherit; padding: 0 0.25em 0 0; margin: 0; resize: none; background: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; border: none; } /* --- this will force to extend the width of the input to fit the content -- */ .dimension-edit-container .input_box.OSH::after { content: attr(data-value) " "; visibility: hidden; white-space: pre-wrap; } /* ----------------------- configuration input fields ----------------------- */ .os-select-bootstrap .os-select-match-text span, .os-param-wrapper > .os-param-text { text-align: right; } .open > .dropdown-menu { right: 0; } /* --------------------------- configuration panel -------------------------- */ div.OSH_conf_row > .OSH_conf { font-size: x-large; padding: 0 0.2em; line-height: 1em; } div.OSH_conf_row > .OSH_conf:hover { background-color: var(--os-table-cell-fill--hover); } div.OSH_conf_row > .OSH_conf.UP { order: 1; } div.OSH_conf_row > .OSH_conf.DOWN { order: 2; } div.OSH_conf_row > :not(.OSH_conf) { order: 3; } div.moved { background-color: var(--os-alert-background-success); } div.single-table-container.os-virtual-scroll-section:first-child .UP, div.single-table-container.os-virtual-scroll-section:last-child .DOWN { opacity: 0.5; pointer-events: none; } /* --------------------- Message bubble move to the top --------------------- */ os-message-bubble .os-message-bubble-container.document-message-bubble { top: 5px; } .os-speech-bubble-container { top: 0; } /* ----------------------------- version history ---------------------------- */ .versions-history-table-container .os-flex-col.os-item-workspace-or-version-graph.inside-document { flex: initial !important; } /* -------------------------- version history graph ------------------------- */ .versions-history-table-container .os-flex-col.os-item-workspace-or-version-graph.inside-document { min-width: var(--os-version-graph-width, 140px); } .os-version-graph > svg { margin-left: var(--os-version-graph-left, 0); } /* ------------ version history search result header modified by ------------ */ .versions-history-table-container .os-flex-col.history-search-results-header:last-child, .versions-history-table-container .os-flex-table-row.history-search-result .os-flex-col:not(.os-item-workspace-or-version-actions).os-item-modified-date, /* -------------------------- version history user -------------------------- */ .versions-history-table-container .os-flex-col.os-item-modified-by-and-date.inside-document, /* ---------------------- version history modified date --------------------- */ .os-flex-col.os-item-modified-date.inside-document, /* ----------------------- version history description ---------------------- */ .versions-history-table-container.OSH_description .os-flex-col.history-search-results-header, .versions-history-table-container.OSH_description .os-flex-col.os-item-description{ flex: none; } /* ----------------------- version history description ---------------------- */ .versions-history-table-container .os-flex-col.os-item-modified-date.inside-document, .versions-history-table-container .os-flex-col.os-item-workspace-or-version-name.inside-document, .versions-history-table-container .os-flex-col.os-item-workspace-or-version-description.inside-document { max-width: unset; } /* ----------------------- version history change time ---------------------- */ .os-flex-col.os-item-modified-date.inside-document { font-size: 0.8em; white-space: pre; line-height: 1em; text-align: end; max-width: 10em !important; text-overflow: ellipsis; overflow: hidden; padding-top: 0.3em; } .OSH_single_line > .os-flex-col.os-item-modified-date.inside-document { padding-top: 0.9em; } /* ------------------- version history description column ------------------- */ .versions-history-table-container:not(.OSH_description) .OSH_description { display: none !important; } .versions-history-table-container.OSH_description .os-flex-col.os-item-modified-by-and-date.inside-document + .ng-hide, .versions-history-table-container.OSH_description .os-flex-col.os-item-description { display: block !important; order: 3; } .versions-history-table-container.OSH_description .os-item-modified-by-and-date { order: 4; } .versions-history-table-container.OSH_description .os-item-workspace-or-version-name { order: 2; } .versions-history-table-container.OSH_description .os-item-workspace-or-version-graph:not(.change-item) { order: 1; } /* just a visual indicator that script is running - a green dot on the logo */ osx-navbar-logo-component > a { position: relative; } osx-navbar-logo-component > a::before { content: ""; position: absolute; background-color: green; left: 12px; top: 18px; font-size: 2em; width: 5px; height: 5px; border-radius: 100%; } /* ---------------------------- dark mode tweaks ---------------------------- */ [data-os-theme=dark] .fs-doc-body a, [data-os-theme=dark] .fs-doc-body a code { color: var(--bs-link-color); } [data-os-theme=dark] .fs-doc-body .fs-parameter-name { color: var(--os-text-tertiary--static); } `);