您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allows to add line breaks in the description textarea of the Moco booking tool
// ==UserScript== // @name Mocoapp Textarea Fix // @namespace http://tampermonkey.net/ // @version 2025-04-08-03 // @description Allows to add line breaks in the description textarea of the Moco booking tool // @author opctim // @license MIT // @match https://*.mocoapp.com/* // @icon data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI3LjguMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxvZ29fUkdCIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIKCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6I0ZGRkZGRjt9Cgkuc3Qxe2ZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO2ZpbGw6IzM4QjVFQjt9Cgkuc3Qye2ZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO30KCS5zdDN7ZmlsbDpub25lO30KPC9zdHlsZT4KPGc+Cgk8Zz4KCQk8Y2lyY2xlIGNsYXNzPSJzdDAiIGN4PSIxNiIgY3k9IjE2IiByPSIxMS44Ii8+CgkJPGc+CgkJCTxnPgoJCQkJPHBhdGggY2xhc3M9InN0MSIgZD0iTTE2LjEsOS45Yy0yLDAtMy45LDAuOC01LjMsMi4xYzAuMy0wLjEsMC42LTAuMSwwLjktMC4xYzEuNiwwLDMsMS4zLDMsM2MwLDEuNi0xLjMsMy0zLDMKCQkJCQljLTEuNSwwLTIuNy0xLjEtMi45LTIuNmMtMC4yLDAuNy0wLjQsMS41LTAuNCwyLjNjMCw0LjIsMy40LDcuNyw3LjcsNy43YzQuMiwwLDcuNy0zLjQsNy43LTcuN0MyMy44LDEzLjQsMjAuNCw5LjksMTYuMSw5Ljl6IgoJCQkJCS8+CgkJCQk8Zz4KCQkJCQk8Zz4KCQkJCQkJPHBhdGggZD0iTTE2LDMxLjljLTIuMiwwLTQuMy0wLjQtNi4yLTEuM2MtMS45LTAuOC0zLjYtMi01LTMuNGMtMS40LTEuNC0yLjYtMy4xLTMuNC01Yy0wLjgtMS45LTEuMy00LTEuMy02LjIKCQkJCQkJCWMwLTIuMiwwLjQtNC4zLDEuMy02LjJjMC44LTEuOSwyLTMuNiwzLjQtNWMxLjQtMS40LDMuMS0yLjYsNS0zLjRjMS45LTAuOCw0LTEuMyw2LjItMS4zYzIuMiwwLDQuMywwLjQsNi4yLDEuMwoJCQkJCQkJYzEuOSwwLjgsMy42LDIsNSwzLjRjMS40LDEuNCwyLjYsMy4xLDMuNCw1YzAuOCwxLjksMS4zLDQsMS4zLDYuMmMwLDIuMi0wLjQsNC4zLTEuMyw2LjJjLTAuOCwxLjktMiwzLjYtMy40LDUKCQkJCQkJCWMtMS40LDEuNC0zLjEsMi42LTUsMy40QzIwLjMsMzEuNSwxOC4yLDMxLjksMTYsMzEuOXogTTE2LDQuNmMtMS42LDAtMy4xLDAuMy00LjUsMC45Yy0xLjQsMC42LTIuNiwxLjQtMy42LDIuNAoJCQkJCQkJYy0xLDEtMS45LDIuMi0yLjUsMy42QzQuOCwxMyw0LjUsMTQuNCw0LjUsMTZjMCwxLjYsMC4zLDMuMSwwLjksNC41YzAuNiwxLjQsMS40LDIuNiwyLjUsMy42YzEsMSwyLjMsMS45LDMuNiwyLjQKCQkJCQkJCWMxLjQsMC42LDIuOSwwLjksNC41LDAuOWMxLjYsMCwzLTAuMyw0LjQtMC45YzEuNC0wLjYsMi42LTEuNCwzLjYtMi40YzEtMSwxLjgtMi4zLDIuNC0zLjZjMC42LTEuNCwwLjktMi45LDAuOS00LjUKCQkJCQkJCWMwLTEuNi0wLjMtMy0wLjktNC40Yy0wLjYtMS40LTEuNC0yLjYtMi40LTMuNmMtMS0xLTIuMi0xLjgtMy42LTIuNEMxOSw0LjksMTcuNiw0LjYsMTYsNC42eiIvPgoJCQkJCTwvZz4KCQkJCTwvZz4KCQkJCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xNi4xLDEyLjljLTAuNywwLTEuMywwLjEtMS45LDAuNGMwLjMsMC41LDAuNSwxLDAuNSwxLjZjMCwxLjYtMS4zLDMtMywzYy0wLjEsMC0wLjIsMC0wLjMsMAoJCQkJCWMwLjEsMi41LDIuMiw0LjUsNC43LDQuNWMyLjYsMCw0LjctMi4xLDQuNy00LjdTMTguNywxMi45LDE2LjEsMTIuOXoiLz4KCQkJPC9nPgoJCTwvZz4KCTwvZz4KCTxyZWN0IGNsYXNzPSJzdDMiIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIvPgo8L2c+Cjwvc3ZnPgo= // @grant none // ==/UserScript== (function() { 'use strict'; window.addEventListener('load', function () { const style = document.createElement('style'); style.innerHTML = '.activity-row .third > .flex > div, .tst-timesheet-activity span[title] { white-space: pre-wrap }'; document.head.appendChild(style); const attachListener = (textarea) => { // Avoid attaching the listener multiple times if (textarea._shiftEnterHandled) return; textarea._shiftEnterHandled = true; textarea.addEventListener('keydown', function (event) { if (event.key === 'Enter' && event.shiftKey) { event.stopPropagation(); console.log('Shift + Enter stopped on:', textarea); } }); }; // Attach to existing elements document.querySelectorAll('textarea[name="description"]').forEach(attachListener); // Observe DOM changes to catch newly added textareas const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.nodeType !== Node.ELEMENT_NODE) continue; if (node.matches?.('textarea[name="description"]')) { attachListener(node); } node.querySelectorAll?.('textarea[name="description"]').forEach(attachListener); } } }); observer.observe(document.body, { childList: true, subtree: true, }); }); })();