// ==UserScript==
// @name Mini Web Tools
// @namespace http://tampermonkey.net/
// @version 2.0
// @description Remove readonly/disabled from fields, toggle page edit mode — draggable & aesthetic
// @author You
// @match *://*/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
// ---- Styles ----
const style = document.createElement('style');
style.textContent = `
#mwt-root {
position: fixed;
bottom: 24px;
left: 24px;
z-index: 2147483647;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
#mwt-root.dragging {
opacity: .93;
}
#mwt-panel {
background: #ffffff;
border: 0.5px solid rgba(0,0,0,0.12);
border-radius: 14px;
padding: 8px;
display: flex;
flex-direction: column;
gap: 3px;
min-width: 216px;
box-shadow: 0 4px 24px rgba(0,0,0,0.10), 0 1px 4px rgba(0,0,0,0.06);
opacity: 0;
transform: translateY(8px) scale(0.96);
pointer-events: none;
transition: opacity .17s ease, transform .17s ease;
}
#mwt-panel.open {
opacity: 1;
transform: translateY(0) scale(1);
pointer-events: all;
}
.mwt-panel-header {
font-size: 11px;
font-weight: 600;
color: #999;
letter-spacing: 0.07em;
text-transform: uppercase;
padding: 4px 8px 8px;
border-bottom: 0.5px solid rgba(0,0,0,0.08);
margin-bottom: 2px;
display: flex;
align-items: center;
justify-content: space-between;
}
.mwt-drag-hint {
font-size: 11px;
color: #bbb;
display: flex;
align-items: center;
gap: 3px;
}
.mwt-drag-hint svg {
width: 12px; height: 12px;
stroke: #bbb;
stroke-width: 1.8;
fill: none;
}
.mwt-tool-btn {
display: flex;
align-items: center;
gap: 10px;
background: transparent;
border: none;
border-radius: 8px;
padding: 9px 10px;
cursor: pointer;
color: #1a1a1a;
font-size: 13.5px;
font-family: inherit;
font-weight: 400;
transition: background .12s;
text-align: left;
width: 100%;
line-height: 1;
}
.mwt-tool-btn:hover {
background: #f4f4f5;
}
.mwt-tool-btn:active {
transform: scale(0.98);
}
.mwt-tool-btn svg {
width: 17px; height: 17px;
stroke: #888;
stroke-width: 1.8;
fill: none;
flex-shrink: 0;
stroke-linecap: round;
stroke-linejoin: round;
}
.mwt-tool-btn.mwt-active-edit {
color: #d63031;
}
.mwt-tool-btn.mwt-active-edit svg {
stroke: #d63031;
}
.mwt-tool-btn.mwt-flash-success {
background: #e8f8f0;
color: #1b8a4a;
}
.mwt-tool-btn.mwt-flash-success svg {
stroke: #1b8a4a;
}
#mwt-fab {
width: 46px;
height: 46px;
border-radius: 50%;
background: #1a1a1a;
border: none;
cursor: grab;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 12px rgba(0,0,0,0.18), 0 1px 3px rgba(0,0,0,0.10);
transition: transform .12s, box-shadow .12s;
flex-shrink: 0;
-webkit-tap-highlight-color: transparent;
}
#mwt-fab:hover {
transform: scale(1.06);
box-shadow: 0 4px 18px rgba(0,0,0,0.22);
}
#mwt-root.dragging #mwt-fab {
cursor: grabbing;
transform: scale(1.08);
}
#mwt-fab svg {
width: 20px; height: 20px;
stroke: #ffffff;
stroke-width: 1.8;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
pointer-events: none;
}
#mwt-toast {
position: fixed;
bottom: 20px;
right: 20px;
background: #1a1a1a;
color: #fff;
font-size: 13px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
padding: 8px 14px;
border-radius: 8px;
z-index: 2147483647;
opacity: 0;
transform: translateY(4px);
transition: opacity .15s, transform .15s;
pointer-events: none;
white-space: nowrap;
}
#mwt-toast.mwt-toast-show {
opacity: 1;
transform: translateY(0);
}
@media (prefers-color-scheme: dark) {
#mwt-panel {
background: #1e1e1e;
border-color: rgba(255,255,255,0.10);
box-shadow: 0 4px 24px rgba(0,0,0,0.40);
}
.mwt-panel-header { color: #666; border-color: rgba(255,255,255,0.08); }
.mwt-drag-hint { color: #555; }
.mwt-drag-hint svg { stroke: #555; }
.mwt-tool-btn { color: #e8e8e8; }
.mwt-tool-btn:hover { background: #2a2a2a; }
.mwt-tool-btn svg { stroke: #666; }
.mwt-tool-btn.mwt-flash-success { background: #0d2e1a; color: #4ade80; }
.mwt-tool-btn.mwt-flash-success svg { stroke: #4ade80; }
#mwt-fab { background: #e8e8e8; box-shadow: 0 2px 12px rgba(0,0,0,0.40); }
#mwt-fab svg { stroke: #1a1a1a; }
#mwt-toast { background: #e8e8e8; color: #1a1a1a; }
}
@media print {
#mwt-root, #mwt-toast { display: none !important; }
}
`;
document.head.appendChild(style);
// ---- SVG Icons ----
const icons = {
tools: `<svg viewBox="0 0 24 24"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>`,
close: `<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`,
lockOpen: `<svg viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/></svg>`,
bolt: `<svg viewBox="0 0 24 24"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`,
pencil: `<svg viewBox="0 0 24 24"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>`,
move: `<svg viewBox="0 0 24 24"><polyline points="5 9 2 12 5 15"/><polyline points="9 5 12 2 15 5"/><polyline points="15 19 12 22 9 19"/><polyline points="19 9 22 12 19 15"/><line x1="2" y1="12" x2="22" y2="12"/><line x1="12" y1="2" x2="12" y2="22"/></svg>`,
};
// ---- Build DOM ----
const root = document.createElement('div');
root.id = 'mwt-root';
const panel = document.createElement('div');
panel.id = 'mwt-panel';
// Panel header
const header = document.createElement('div');
header.className = 'mwt-panel-header';
header.innerHTML = `<span>Web tools</span><span class="mwt-drag-hint">${icons.move} drag to move</span>`;
panel.appendChild(header);
// Helper: create tool button
function makeBtn(icon, label, onClick) {
const btn = document.createElement('button');
btn.className = 'mwt-tool-btn';
btn.innerHTML = `${icons[icon]}<span>${label}</span>`;
btn.addEventListener('click', onClick);
panel.appendChild(btn);
return btn;
}
const btnReadonly = makeBtn('lockOpen', 'Remove readonly', removeReadonly);
const btnDisabled = makeBtn('bolt', 'Remove disabled', removeDisabled);
const btnEdit = makeBtn('pencil', 'Toggle edit page', toggleEditable);
// FAB
const fab = document.createElement('button');
fab.id = 'mwt-fab';
fab.setAttribute('aria-label', 'Open web tools');
fab.innerHTML = icons.tools;
root.appendChild(panel);
root.appendChild(fab);
document.body.appendChild(root);
// Toast
const toast = document.createElement('div');
toast.id = 'mwt-toast';
document.body.appendChild(toast);
// ---- Toast ----
let toastTimer = null;
function showToast(msg) {
toast.textContent = msg;
toast.classList.add('mwt-toast-show');
clearTimeout(toastTimer);
toastTimer = setTimeout(() => toast.classList.remove('mwt-toast-show'), 2200);
}
// ---- Tools ----
function removeReadonly() {
const els = document.querySelectorAll('input[readonly], textarea[readonly]');
els.forEach(el => el.removeAttribute('readonly'));
flashBtn(btnReadonly);
showToast(`Readonly removed from ${els.length} field(s)`);
}
function removeDisabled() {
const els = document.querySelectorAll('[disabled]');
els.forEach(el => el.removeAttribute('disabled'));
flashBtn(btnDisabled);
showToast(`Disabled removed from ${els.length} element(s)`);
}
let pageEditable = false;
function toggleEditable() {
pageEditable = !pageEditable;
document.body.contentEditable = pageEditable ? 'true' : 'false';
document.designMode = pageEditable ? 'on' : 'off';
btnEdit.querySelector('span').textContent = pageEditable ? 'Editing on' : 'Toggle edit page';
btnEdit.classList.toggle('mwt-active-edit', pageEditable);
showToast(pageEditable ? 'Page editing enabled' : 'Page editing disabled');
}
function flashBtn(btn) {
btn.classList.add('mwt-flash-success');
setTimeout(() => btn.classList.remove('mwt-flash-success'), 800);
}
// ---- Panel toggle ----
let panelOpen = false;
function openPanel(state) {
panelOpen = state;
panel.classList.toggle('open', panelOpen);
fab.innerHTML = panelOpen ? icons.close : icons.tools;
fab.setAttribute('aria-label', panelOpen ? 'Close web tools' : 'Open web tools');
}
// Close on outside click
document.addEventListener('mousedown', e => {
if (panelOpen && !root.contains(e.target)) openPanel(false);
});
// ---- Drag logic ----
let dragging = false;
let didDrag = false;
let dragStartX, dragStartY, rootStartX, rootStartY;
function getEventPos(e) {
return e.touches
? { x: e.touches[0].clientX, y: e.touches[0].clientY }
: { x: e.clientX, y: e.clientY };
}
function applyStoredPos() {
try {
const saved = localStorage.getItem('mwt-pos');
if (!saved) return;
const { x, y } = JSON.parse(saved);
root.style.bottom = 'auto';
root.style.right = 'auto';
root.style.left = x + 'px';
root.style.top = y + 'px';
} catch (e) {}
}
function savePos(x, y) {
try { localStorage.setItem('mwt-pos', JSON.stringify({ x, y })); } catch (e) {}
}
function clamp(val, min, max) {
return Math.max(min, Math.min(val, max));
}
fab.addEventListener('mousedown', onDragStart);
fab.addEventListener('touchstart', onDragStart, { passive: true });
function onDragStart(e) {
const pos = getEventPos(e);
const rootRect = root.getBoundingClientRect();
dragStartX = pos.x;
dragStartY = pos.y;
rootStartX = rootRect.left;
rootStartY = rootRect.top;
dragging = true;
didDrag = false;
root.style.transition = 'none';
root.style.bottom = 'auto';
root.style.right = 'auto';
root.style.left = rootStartX + 'px';
root.style.top = rootStartY + 'px';
root.classList.add('dragging');
window.addEventListener('mousemove', onDragMove);
window.addEventListener('touchmove', onDragMove, { passive: false });
window.addEventListener('mouseup', onDragEnd);
window.addEventListener('touchend', onDragEnd);
}
function onDragMove(e) {
if (!dragging) return;
if (e.cancelable) e.preventDefault();
const pos = getEventPos(e);
const dx = pos.x - dragStartX;
const dy = pos.y - dragStartY;
if (Math.abs(dx) > 3 || Math.abs(dy) > 3) didDrag = true;
const rootRect = root.getBoundingClientRect();
const newX = clamp(rootStartX + dx, 0, window.innerWidth - rootRect.width);
const newY = clamp(rootStartY + dy, 0, window.innerHeight - rootRect.height);
root.style.left = newX + 'px';
root.style.top = newY + 'px';
}
function onDragEnd() {
if (!dragging) return;
dragging = false;
root.classList.remove('dragging');
const rootRect = root.getBoundingClientRect();
savePos(rootRect.left, rootRect.top);
window.removeEventListener('mousemove', onDragMove);
window.removeEventListener('touchmove', onDragMove);
window.removeEventListener('mouseup', onDragEnd);
window.removeEventListener('touchend', onDragEnd);
}
fab.addEventListener('click', () => {
if (didDrag) { didDrag = false; return; }
openPanel(!panelOpen);
});
// ---- Window resize: keep in bounds ----
window.addEventListener('resize', () => {
const rootRect = root.getBoundingClientRect();
const newX = clamp(rootRect.left, 0, window.innerWidth - rootRect.width);
const newY = clamp(rootRect.top, 0, window.innerHeight - rootRect.height);
root.style.left = newX + 'px';
root.style.top = newY + 'px';
savePos(newX, newY);
});
// ---- Print ----
window.addEventListener('beforeprint', () => { root.style.display = 'none'; toast.style.display = 'none'; });
window.addEventListener('afterprint', () => { root.style.display = ''; toast.style.display = ''; });
// ---- Init position ----
applyStoredPos();
})();