|
阅读:537回复:3
快速体验userChromeJS |
|
最新喜欢:
|
|
1楼#
发布于:2025-06-30 21:16
右键菜单管理
// contextMenuManager.uc.js
(function() {
'use strict';
const CONTEXT_MENU_CATEGORIES = {
'页面操作': {
'context-back': '后退',
'context-forward': '前进',
'context-reload': '重新加载',
'context-stop': '停止',
'context-bookmarkpage': '将页面加入书签',
'context-savepage': '保存页面',
'context-viewsource': '查看页面源代码',
'context-inspect': '检查元素',
'context-viewinfo': '查看页面信息'
},
'编辑操作': {
'context-selectall': '全选',
'context-copy': '复制',
'context-paste': '粘贴',
'context-cut': '剪切',
'context-undo': '撤销',
'context-redo': '重做'
},
'链接操作': {
'context-openlink': '打开链接',
'context-openlinkintab': '在新标签页中打开链接',
'context-openlinkprivate': '在新隐私窗口中打开链接',
'context-openlinkinnewwindow': '在新窗口中打开链接',
'context-bookmarklink': '为此链接添加书签',
'context-savelink': '链接另存为',
'context-copylink': '复制链接',
'context-copyemail': '复制邮件地址'
},
'图片操作': {
'context-viewimage': '查看图片',
'context-openimagenewtab': '在新标签页中打开图片',
'context-openimageinnewwindow': '在新窗口中打开图片',
'context-saveimageas': '图片另存为',
'context-copyimage': '复制图片',
'context-copyimagelocation': '复制图片地址',
'context-setDesktopBackground': '设为桌面背景',
'context-viewbgimage': '查看背景图片',
'context-savebgimageas': '背景图片另存为',
'context-shareimage': '分享图片'
},
'媒体操作': {
'context-media-play': '播放',
'context-media-pause': '暂停',
'context-media-mute': '静音',
'context-media-unmute': '取消静音',
'context-savevideo': '视频另存为',
'context-saveaudio': '音频另存为',
'context-copyvideourl': '复制视频地址',
'context-copyaudiourl': '复制音频地址'
},
'文本操作': {
'context-searchselect': '搜索选中文本',
'context-translate': '翻译选中文本',
'context-spell-check-enabled': '启用拼写检查',
'context-spell-add-to-dictionary': '添加到词典'
},
'工具操作': {
'context-print': '打印',
'context-find': '在页面中搜索',
'context-share': '分享',
'context-sendtomobile': '发送到移动设备'
}
};
function createContextMenuItem() {
const contextMenu = document.getElementById('contentAreaContextMenu');
if (!contextMenu) return;
const separator = document.createXULElement('menuseparator');
separator.setAttribute('id', 'context-menu-manager-separator');
// 创建主菜单项(一级菜单)
const managerMenu = document.createXULElement('menu');
managerMenu.setAttribute('id', 'context-menu-manager-menu');
managerMenu.setAttribute('label', '右键菜单管理');
// 创建主菜单的弹出框
const mainPopup = document.createXULElement('menupopup');
mainPopup.setAttribute('id', 'context-menu-manager-main-popup');
// 为每个分类创建二级菜单
Object.entries(CONTEXT_MENU_CATEGORIES).forEach(([categoryName, items]) => {
// 创建分类菜单项(二级菜单)
const categoryMenu = document.createXULElement('menu');
categoryMenu.setAttribute('id', `category-${categoryName}`);
categoryMenu.setAttribute('label', categoryName);
// 创建分类的弹出框(三级菜单容器)
const categoryPopup = document.createXULElement('menupopup');
categoryPopup.setAttribute('id', `category-popup-${categoryName}`);
// 添加该分类下的具体菜单项(三级菜单项)
Object.entries(items).forEach(([itemId, itemLabel]) => {
const menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('id', `toggle-${itemId}`);
menuitem.setAttribute('label', itemLabel);
menuitem.setAttribute('type', 'checkbox');
menuitem.setAttribute('checked', !isMenuItemHidden(itemId));
menuitem.setAttribute('closemenu', 'none');
menuitem.addEventListener('command', () => {
const isChecked = menuitem.getAttribute('checked') === 'true';
toggleMenuItem(itemId, isChecked);
menuitem.setAttribute('checked', isChecked);
});
categoryPopup.appendChild(menuitem);
});
categoryMenu.appendChild(categoryPopup);
mainPopup.appendChild(categoryMenu);
});
// 添加分隔符和全局操作
const globalSeparator = document.createXULElement('menuseparator');
mainPopup.appendChild(globalSeparator);
// 添加重置全部选项
const resetItem = document.createXULElement('menuitem');
resetItem.setAttribute('label', '重置全部');
resetItem.setAttribute('closemenu', 'none');
resetItem.addEventListener('command', () => {
Object.values(CONTEXT_MENU_CATEGORIES).forEach(category => {
Object.keys(category).forEach(itemId => {
Services.prefs.clearUserPref(`userChrome.contextMenu.${itemId}.hidden`);
const toggleItem = document.getElementById(`toggle-${itemId}`);
if (toggleItem) {
toggleItem.setAttribute('checked', 'true');
}
});
});
updateContextMenu();
});
mainPopup.appendChild(resetItem);
// 添加关闭菜单选项
const closeSeparator = document.createXULElement('menuseparator');
mainPopup.appendChild(closeSeparator);
const closeItem = document.createXULElement('menuitem');
closeItem.setAttribute('label', '关闭菜单');
closeItem.addEventListener('command', () => {
contextMenu.hidePopup();
});
mainPopup.appendChild(closeItem);
managerMenu.appendChild(mainPopup);
contextMenu.appendChild(separator);
contextMenu.appendChild(managerMenu);
}
function toggleMenuItem(itemId, show) {
Services.prefs.setBoolPref(`userChrome.contextMenu.${itemId}.hidden`, !show);
// 立即更新当前显示的菜单
const contextMenu = document.getElementById('contentAreaContextMenu');
if (contextMenu && contextMenu.state === 'open') {
const menuItem = document.getElementById(itemId);
if (menuItem) {
if (show && !isMenuItemHidden(itemId)) {
menuItem.hidden = false;
} else if (!show) {
menuItem.hidden = true;
}
}
}
}
function isMenuItemHidden(itemId) {
try {
return Services.prefs.getBoolPref(`userChrome.contextMenu.${itemId}.hidden`, false);
} catch (e) {
return false;
}
}
function updateContextMenu() {
const contextMenu = document.getElementById('contentAreaContextMenu');
if (!contextMenu) return;
// 获取所有菜单项ID
const allItems = Object.values(CONTEXT_MENU_CATEGORIES).reduce((acc, category) => {
return {...acc, ...category};
}, {});
// 只处理当前上下文中实际存在且可见的菜单项
Object.keys(allItems).forEach(itemId => {
const menuItem = document.getElementById(itemId);
if (menuItem && !menuItem.hidden) {
if (isMenuItemHidden(itemId)) {
menuItem.hidden = true;
}
}
});
}
function setupContextMenuListener() {
const contextMenu = document.getElementById('contentAreaContextMenu');
if (contextMenu) {
contextMenu.addEventListener('popupshowing', updateContextMenu);
}
}
function init() {
if (document.readyState === 'complete') {
createContextMenuItem();
setupContextMenuListener();
} else {
document.addEventListener('DOMContentLoaded', () => {
createContextMenuItem();
setupContextMenuListener();
});
}
}
init();
})(); |
|
|
|
2楼#
发布于:2025-06-30 21:15
// ==UserScript==
// [url=home.php?mod=space&uid=467097]@Name[/url] 右键双击工具栏撤销关闭标签页
// @description 右键双击标签栏空白区域撤销最近关闭的标签页
// ==/UserScript==
(function() {
'use strict';
let tabsContainer = gBrowser.tabContainer;
let rightClickCount = 0;
let rightClickTimer = null;
let doubleClickDelay = 400; // 双击间隔时间(毫秒)
function handleMouseDown(event) {
// 只处理右键按下事件
if (event.button !== 2 ||
event.target !== tabsContainer.arrowScrollbox ||
event.composedTarget.localName === "toolbarbutton") {
return;
}
rightClickCount++;
if (rightClickCount === 1) {
// 第一次右键点击,设置定时器
rightClickTimer = setTimeout(() => {
rightClickCount = 0; // 重置计数
}, doubleClickDelay);
} else if (rightClickCount === 2) {
// 第二次右键点击,执行撤销操作
clearTimeout(rightClickTimer);
rightClickCount = 0;
// 阻止上下文菜单显示
event.preventDefault();
event.stopPropagation();
undoCloseTab();
}
}
function handleContextMenu(event) {
// 如果是双击的第二次点击,阻止菜单显示
if (rightClickCount === 0 &&
event.target === tabsContainer.arrowScrollbox &&
event.composedTarget.localName !== "toolbarbutton") {
// 延迟一点再检查,确保mousedown事件已处理
setTimeout(() => {
if (rightClickCount === 0) {
// 不是双击,允许正常的上下文菜单
return;
}
}, 10);
}
}
function undoCloseTab() {
// 使用 Firefox 内置的撤销关闭标签页功能
if (SessionStore.getClosedTabCount(window) > 0) {
SessionStore.undoCloseTab(window, 0);
}
}
// 监听mousedown而不是contextmenu,避免菜单干扰
tabsContainer.addEventListener('mousedown', handleMouseDown, true);
tabsContainer.addEventListener('contextmenu', handleContextMenu, true);
// 清理函数
window.addEventListener('unload', function() {
tabsContainer.removeEventListener('mousedown', handleMouseDown, true);
tabsContainer.removeEventListener('contextmenu', handleContextMenu, true);
if (rightClickTimer) {
clearTimeout(rightClickTimer);
}
});
})(); |
|
|
|
3楼#
发布于:2025-06-30 21:14
用AI写的几个简单的脚本
在标签页显示占用内存 (function() {
'use strict';
let activeTab = null;
async function getTabMemoryInfo(tab) {
try {
const procInfo = await ChromeUtils.requestProcInfo();
const outerWindowId = tab.linkedBrowser.outerWindowID;
for (const childProc of procInfo.children) {
if (childProc.windows) {
for (const win of childProc.windows) {
if (win.outerWindowId === outerWindowId) {
return Math.round(childProc.memory / (1024 * 1024));
}
}
}
}
return null;
} catch (e) {
console.error('获取内存信息失败:', e);
return null;
}
}
async function updateTabWithMemory(tab) {
const memoryMB = await getTabMemoryInfo(tab);
if (memoryMB === null) return;
const currentTitle = tab.getAttribute('label');
if (currentTitle?.startsWith('[') && currentTitle.includes('MB]')) {
return;
}
tab.setAttribute('data-original-label', currentTitle);
tab.setAttribute('label', `[${memoryMB}MB] ${currentTitle}`);
activeTab = tab;
}
function restoreTabLabel(tab) {
const originalTitle = tab.getAttribute('data-original-label');
if (originalTitle) {
tab.setAttribute('label', originalTitle);
tab.removeAttribute('data-original-label');
}
if (activeTab === tab) {
activeTab = null;
}
}
const tabContainer = gBrowser.tabContainer;
tabContainer.addEventListener('TabHoverStart', (event) => {
updateTabWithMemory(event.target);
});
tabContainer.addEventListener('TabHoverEnd', (event) => {
restoreTabLabel(event.target);
});
tabContainer.addEventListener('TabAttrModified', (event) => {
if (event.detail.changed.includes('label') && activeTab === event.target) {
const currentLabel = event.target.getAttribute('label');
const match = currentLabel?.match(/^\[\d+MB\] (.+)$/);
if (match) {
event.target.setAttribute('data-original-label', match[1]);
updateTabWithMemory(event.target);
}
}
});
})(); |
|
|