But if you just want to toggle items while keeping the menu open, you can simply middle-click (press the wheel) them:
Aber das ist ja das Problem, das Menü schließt oftmals vorzeitig, bevor ich etwas auswählen konnte.
Daher mein Fix.
But if you just want to toggle items while keeping the menu open, you can simply middle-click (press the wheel) them:
Aber das ist ja das Problem, das Menü schließt oftmals vorzeitig, bevor ich etwas auswählen konnte.
Daher mein Fix.
The problem was that the menu would often close before I could select a script.
I was able to fix this with two small changes.
before:
menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('label','Alle UserScripte aktivieren/deaktivieren');
// menuitem.setAttribute('label','userCrome.js \u306e \u6709\u52b9/\u7121\u52b9');
menuitem.setAttribute('type','checkbox');
menuitem.toggleAttribute('checked', !userChrome_js.dirDisable['*']);
menuitem.dirName = '*';
menupopup.appendChild(menuitem);
menuitem.addEventListener('command', () => userChromejs.chgDirStat("*"));
menuitem.addEventListener('click', (event) => userChromejs.clickDirMenuitem(event,true));
menuitem.addEventListener('mouseup', (event) => {if(event.button == 1) event.preventDefault()});
after:
menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('label','Alle UserScripte aktivieren/deaktivieren');
// menuitem.setAttribute('label','userCrome.js \u306e \u6709\u52b9/\u7121\u52b9');
menuitem.setAttribute('type','checkbox');
menuitem.setAttribute('closemenu','none');
menuitem.toggleAttribute('checked', !userChrome_js.dirDisable['*']);
menuitem.dirName = '*';
menupopup.appendChild(menuitem);
menuitem.addEventListener('command', () => userChromejs.chgDirStat("*"));
menuitem.addEventListener('click', (event) => userChromejs.clickDirMenuitem(event,true));
menuitem.addEventListener('mousedown', (event) => {if(event.button == 1) event.preventDefault()});
menuitem.addEventListener('mouseup', (event) => {if(event.button == 1) event.preventDefault()});
Alles anzeigen
I'd appreciate your help—could you maybe get in touch with Alice0775 somehow?
Unfortunately, Yahoo is no longer accessible from Europe,
and I didn't want to go to the trouble of creating a GitHub account just for that.
If there really isn't any other way, I guess I'll have to do it after all.
Why did I come up with this bold idea?
You live somewhere way out in East Asia,
and you might have other options or even be in direct contact with Alice0775.
It’s certainly possible.
I definitely don’t mean any harm by this.
And sorry for my poor English, but DeepL and Google don't do any better.
Fixing "rebuild_userChrome.uc.js"
fix menu auto-close: closemenu="none" on checkbox items, update checked state in command handler, harden middleclick protection (mousedown/mouseup/click)
This is my version of the script, but—and this is important—it includes the fixes!
// ==UserScript==
// @name rebuild_userChrome.uc.js
// @namespace http://space.geocities.yahoo.co.jp/gl/alice0775
// @description userChrome.js Clear script cache, open new window, and go to Script Management.
// @description Comment from Mira: Open new window is hidden by CSS
// @charset utf-8
// @include main
// @compatibility Firefox 149
// @author Alice0775
// @version 2026/10/13 Modified by Mira Bellenbaum
// @version 2026/10/13 keep script menu open on click: set closemenu="none" and toggle checked state in command handler
// @version 2026/10/13 harden middleclick protection: prevent default on mousedown/mouseup/click instead of mouseup only
// @version 2026/03/26 fix menu click handler
// @version 2026/01/13 00:00 compatibility 149 from 148
// @version 2026/01/12 Modified by Mira Bellenbaum
// @version 2026/01/07 Bug 2008041 - Make XUL disabled / checked attributes html-style boolean attributes.
// @version 2024/12/22 fix Bug 1936336 - Disallow inline event handlers
// @version 2023/09/07 remove to use nsIScriptableUnicodeConverter
// @version 2023/06/20 remove Bug 1780695 - Remove Services.jsm
// @version 2022/04/01 23:00 Convert Components.utils.import to ChromeUtils.import
// @version 2022/04/01 remove nsIIOService
// @version 2020/04/25 14:00 prevent close menu when middleclick
// Date 2019/05/21 08:30 fix 69.0a1 Bug 1534407 - Enable browser.xhtml by default, Bug 1551320 - Replace all CreateElement calls in XUL documents with CreateXULElement
// @version 2019/04/19 14:00 Fixed 68a1 due to Bug 1519502 - Convert menu bindings to a Custom Element
// ==/UserScript==
// @Note Make sure your editor is set up correctly.
// @Note Required Sub-Script/Overlay Loader v3.0.38mod( https://github.com/alice0775/userChrome.js/blob/master/userChrome.js )
// @Source https://github.com/alice0775/userChrome.js/blob/master/149/rebuild_userChrome.uc.js
var userChromejs = {
// --- config ---
editor: (AppConstants.platform == "win")
? "C:\\Program Files\\hidemaru\\hidemaru.exe"
: ((AppConstants.platform == "linux")
?"/usr/bin/gedit" /*"/usr/bin/xed"*/ /*"/usr/bin/featherpad"*/
: ""),
// --- config ---
_statusDisplay: null,
get statusDisplay() {
if (!this._statusDisplay)
this._statusDisplay = document.getElementById('status-bar') ||
document.getElementById('statusbar-display');
return this._statusDisplay;
},
_addonbar: null,
get addonbar() {
if (!this._addonbar)
this._addonbar = document.getElementById('addon-bar');
return this._addonbar;
},
handleEvent: function(event) {
switch(event.type) {
case 'dragover':
this.dragover(event);
break;
case 'drop':
this.drop(event);
break;
case 'unload':
this.uninit();
break;
}
},
createElement: function(localName, arryAttribute) {
let elm = document.createXULElement(localName);
for(let i = 0; i < arryAttribute.length; i++) {
elm.setAttribute(arryAttribute[i].attr, arryAttribute[i].value);
}
return elm;
},
init: function(){
window.addEventListener("unload",this , false);
let ref = document.getElementById("menu_preferences");
let menu = ref.parentNode.insertBefore(
this.createElement("menu",
[{attr: "id", value:"userChrome.js_menu"},
{attr: "label", value:"JavaScript-Loader-Menü"},
]), ref);
let popup = menu.appendChild(this.createElement("menupopup",
[{attr: "id", value:"userChromejs_options"},
{attr: "context", value:""}
]));
popup.appendChild(this.createElement("menuitem",
[{attr: "id", value:"userChrome_setting"},
{attr: "label", value:"Skript für jedes Fenster neuladen"},
{attr: "accesskey", value:"u"},
{attr: "type", value:"checkbox"}
]));
popup.appendChild(this.createElement("menuitem",
[{attr: "id", value:"userChrome_rebuild"},
{attr: "label", value:"Neues Fenster öffnen"},
]));
popup.appendChild(this.createElement("menuitem",
[{attr: "id", value:"userChrome_restartApp"},
{attr: "label", value:"Neustart (inkl. Script Cache leeren)"},
]));
popup.appendChild(this.createElement("menuitem",
[{attr: "id", value:"userChrome_openChrome"},
{attr: "label", value:"Chrome-Ordner öffnen"},
]));
/* menu = ref.parentNode.insertBefore(
this.createElement("menu",
[{attr: "id", value:"userChromejs_script_options_Menu"},
{attr: "label", value:"userChrome.js Scripte"},
]), ref);
popup = menu.appendChild(this.createElement("menupopup",
[{attr: "id", value:"userChromejs_script_options"}
]));
*/
document.getElementById('userChrome_setting').addEventListener("command", () => userChromejs.setting());
document.getElementById('userChrome_rebuild').addEventListener("command", () => userChromejs.rebuild());
document.getElementById('userChrome_restartApp').addEventListener("command", () => userChromejs.restartApp());
document.getElementById('userChrome_openChrome').addEventListener("command", () => {new Components.Constructor("@mozilla.org/file/local;1","nsIFile", "initWithPath")(Services.dirsvc.get("UChrm", Components.interfaces.nsIFile).path).reveal()});
if (AppConstants.platform == "linux")
userChromejs.onpopup();
if ("nsDragAndDrop" in window && this.statusDisplay) {
this.statusDisplay.addEventListener('dragover',function(event){nsDragAndDrop.dragOver(event,userChromejs.dndObserver);},true);
this.statusDisplay.addEventListener('dragdrop',function(event){nsDragAndDrop.drop(event,userChromejs.dndObserver);},true);
} else if(this.addonbar) {
this.addonbar.addEventListener('dragover', this ,true);
this.addonbar.addEventListener('drop', this ,true);
}
this.addPrefListener(userChromejs.readLaterPrefListener); // 登録処理
document.getElementById("menu_ToolsPopup").addEventListener("popupshowing", function(event) {if (event.target == this) userChromejs.onpopup(event);}, false);
},
uninit: function(){
if ("nsDragAndDrop" in window && this.statusDisplay) {
this.statusDisplay.removeEventListener('dragover',function(event){nsDragAndDrop.dragOver(event,userChromejs.dndObserver);},true);
this.statusDisplay.removeEventListener('dragdrop',function(event){nsDragAndDrop.drop(event,userChromejs.dndObserver);},true);
} else if(this.addonbar) {
this.addonbar.removeEventListener('dragover', this ,true);
this.addonbar.removeEventListener('drop', this ,true);
}
this.removePrefListener(userChromejs.readLaterPrefListener); // 登録解除
},
dragover: function(event) {
var dragService = Cc["@mozilla.org/widget/dragservice;1"]
.getService(Ci.nsIDragService);
var dragSession = dragService.getCurrentSession();
var supportedTypes = ["text/x-moz-url", "text/unicode", "application/x-moz-file"];
for (let type of supportedTypes) {
if (event.dataTransfer.types.contains(type)) {
var data = event.dataTransfer.getData(type);
var url = (/^\s*(.*?)\s*$/m.test(data))
? RegExp.$1 : null;
if (/(\.uc\.js|\.uc\.xul|\.uc\.xul\.txt)$/.test(url)) {
dragSession.canDrop = true;
event.preventDefault();
return;
}
}
}
},
drop: function(event) {
var dragService = Cc["@mozilla.org/widget/dragservice;1"]
.getService(Ci.nsIDragService);
var dragSession = dragService.getCurrentSession();
var supportedTypes = ["text/x-moz-url", "text/unicode", "application/x-moz-file"];
for (let type of supportedTypes) {
if (event.dataTransfer.types.contains(type)) {
var data = event.dataTransfer.getData(type);
this.dndObserver.onDrop(event, {data: data}, dragSession);
return;
}
}
},
dragDropSecurityCheck: function dragDropSecurityCheck(event, dragSession, url) {
if (!url)
return false;
// need to do a security check to make
// sure the source document can load the dropped URI.
url = url.replace(/^\s*|\s*$/g, '');
if (url.indexOf('chrome://') == 0 || url.indexOf('file://') == 0)
return url;
// urlSecurityCheck
try {
urlSecurityCheck(url, gBrowser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
}
catch(e) {
event.stopPropagation();
//throw 'Drop of ' + url + ' denied.';
return false;
}
return url;
},
dndObserver: {
getSupportedFlavours : function () {
var flavours = new FlavourSet();
flavours.appendFlavour("text/x-moz-url");
flavours.appendFlavour("text/unicode");
flavours.appendFlavour("application/x-moz-file");
return flavours;
},
onDragOver: function (evt,flavour,session){},
onDrop: function (evt,dropdata,session){
var fname;
evt.stopPropagation();
evt.preventDefault();
if (dropdata.data!=""){
//ステータスバーの左1/3にドロップしたか
var target = evt.target;
while(target){
if(target == userChromejs.statusDisplay ||
target == userChromejs.addonbar)
break;
target = target.parentNode;
}
if(!target) return;
if(evt.screenX > target.boxObject.screenX + target.boxObject.width/3) return;
//saveFolderModokiが必要
if(!saveFolderModoki) return;
//ドロップしたurl
var url = (/^\s*(.*?)\s*$/m.test(dropdata.data))?RegExp.$1:null;
//保存ホルダ nsIFile
var folder = Services.dirsvc.get("UChrm", Components.interfaces.nsIFile);
//デフォルトのファイル名
if(/(.*)\n?(.*)?/m.test(dropdata.data) )
fname = RegExp.$2?RegExp.$2:"";
//データスキームか
if(/(^data:text\/javascript(;.*)?,?)|(^data:application\/x-javascript(;.*)?,?)/.test(url)){
// urlSecurityCheck は saveFolderModoki.directSaveLinkで実施している
saveScript(url, fname, folder);
}else{
//リンクか
if(!/(^h?ttps?:\/\/)|(^ftp:\/\/)/.test(url)) return;
if (/^h?.?.p(s?):(.+)$/i.test(url)){
url = "http" + RegExp.$1 + ':' + RegExp.$2;
if(!RegExp.$2) return null;
fname = url.match(/.+\/(.+)$/)[1];
}
fname = fname.replace(/\.uc\.xul\.txt$/,'.uc.xul');
//スクリプトファイルか?
if(/(\.uc\.js|\.uc\.xul|\.uc\.xul\.txt)$/.test(url)){
if (typeof gBrowser.dragDropSecurityCheck == 'function')
gBrowser.dragDropSecurityCheck(evt, session, url);
else {
userChromejs.dragDropSecurityCheck(evt, session, url)
}
saveScript(url, fname, folder);
}
}
}
function saveScript(url, fname, folder){
//ファイルピッカによりnsIFile決定
var aFile = getFolderPath(fname, folder)
if(!aFile) return;
//フォルダパス
folder = aFile.path.replace(aFile.leafName,'');
//nsILocalFileのフォルダ
var aFolder = saveFolderModoki.initFileWithPath(folder);
if(!aFolder) return;
//リンクを保存
saveFolderModoki.directSaveLink(null, url, aFile.leafName, gBrowser.currentURI, aFolder);
}
function getFolderPath(fname, folder){
//ファイルピッカにより保存先決定
var fp = Components.classes['@mozilla.org/filepicker;1']
.createInstance(Components.interfaces.nsIFilePicker);
fp.init(window, "Save script As", fp.modeSave);
fp.appendFilter("Script Files","*.uc.js; *.uc.xul");
if(/\.uc\.js$/.test(fname)){
fp.defaultExtension = "uc.js";
fp.defaultString = fname;
}else if(/\.uc\.xul$/.test(fname)){
fp.defaultExtension = "uc.xul";
fp.defaultString = fname;
}else{
fp.defaultExtension = "uc.js";
fp.defaultString = fname + ".uc.js";
}
fp.displayDirectory = folder;
if ( fp.show() == fp.returnCancel || !fp.file ) return;
//nsIFile
return fp.file;
}
}
},
rebuild: function(){
var flag = this.getPref("userChrome.enable.reuse",'bool',true);
this.setPref("userChrome.enable.reuse",'bool',false);
setTimeout(function(){OpenBrowserWindow();}, 0);
setTimeout(function(self,flag){self.setPref("userChrome.enable.reuse",'bool',flag);},2000,this,flag);
},
setting: function(){
var flag = this.getPref("userChrome.enable.reuse",'bool',true);
this.setPref("userChrome.enable.reuse",'bool',!flag);
},
onpopup: function(event){
var menu;
var flag = this.getPref("userChrome.enable.reuse",'bool',true);
var menuitem = document.getElementById('userChrome_setting');
menuitem.toggleAttribute('checked', !flag);
var menupopup = document.getElementById("userChromejs_options");
for(var i = 4, len = menupopup.childNodes.length; i < len; i++){
menupopup.removeChild(menupopup.lastChild);
}
var menuseparator = document.createXULElement('menuseparator');
menupopup.appendChild(menuseparator);
/*
menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('label','Alle UserScripte aktivieren/deaktivieren');
menuitem.setAttribute('type','checkbox');
menuitem.setAttribute('closemenu','none');
menuitem.toggleAttribute('checked', !userChrome_js.dirDisable['*']);
menuitem.dirName = '*';
menupopup.appendChild(menuitem);
menuitem.addEventListener('command', () => userChromejs.chgDirStat("*"));
menuitem.addEventListener('click', (event) => userChromejs.clickDirMenuitem(event,true));
menuitem.addEventListener('mousedown', (event) => {if(event.button == 1) event.preventDefault()});
menuitem.addEventListener('mouseup', (event) => {if(event.button == 1) event.preventDefault()});
*/
for(var j = 0, lenj = userChrome_js.arrSubdir.length; j < lenj; j++){
var dirName = userChrome_js.arrSubdir[j] == "" ? "root" : userChrome_js.arrSubdir[j];
var flg = false;
for(var i = 0, len = userChrome_js.scripts.length; i < len; i++){
var script = userChrome_js.scripts[i];
if(script.dir != dirName) continue;
flg = true;
break;
}
if(!flg){
for(var i = 0, len = userChrome_js.overlays.length; i < len; i++){
var script = userChrome_js.overlays[i];
if(script.dir != dirName) continue;
flg = true;
break;
}
}
if(!flg) continue;
menu = document.createXULElement('menu');
menu.setAttribute('label','Alle UserScripte in ' +'"'+ (dirName=="root"?"":dirName) +'"');
menu.addEventListener('click', (event) => userChromejs.clickDirMenu(event));
if(userChrome_js.dirDisable[dirName])
menu.setAttribute('style', 'font-style:italic;');
menu.dirName = dirName;
menupopup = document.createXULElement('menupopup');
menupopup.setAttribute('style', 'max-height: 1000px;'); // Neu bestimmt die Höhe des Menüs
/*
menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('label','Alle UserScripte in ' +'"'+ (dirName=="root"?"":dirName) +'"' + ' aktivieren/deaktivieren');
menuitem.setAttribute('type', 'checkbox');
menuitem.setAttribute('closemenu', 'none');
menuitem.toggleAttribute('checked', !userChrome_js.dirDisable[dirName]);
menuitem.dirName = dirName;
menupopup.appendChild(menuitem);
menuitem.addEventListener('command', (event) => userChromejs.chgDirStat(event.target.dirName));
menuitem.addEventListener('click', (event) => userChromejs.clickDirMenuitem(event));
menuitem.addEventListener('mousedown', (event) => {if(event.button == 1) event.preventDefault()});
menuitem.addEventListener('mouseup', (event) => {if(event.button == 1) event.preventDefault()});
menuseparator = document.createXULElement('menuseparator');
menupopup.appendChild(menuseparator);
*/
var flg = false;
for(var i = 0, len = userChrome_js.scripts.length; i < len; i++){
var script = userChrome_js.scripts[i];
if(script.dir != dirName) continue;
flg = true;
menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('label',script.filename);
menuitem.setAttribute('type','checkbox');
menuitem.setAttribute('autocheck','false');
menuitem.setAttribute('closemenu','none');
menuitem.toggleAttribute('checked',!userChrome_js.scriptDisable[script.filename] );
if(script.description)
menuitem.setAttribute('tooltiptext',script.description);
menuitem.script = script;
menupopup.appendChild(menuitem);
menuitem.addEventListener('command', (event) => {
userChromejs.chgScriptStat(event.target.script.filename);
event.target.toggleAttribute('checked',!userChrome_js.scriptDisable[event.target.script.filename]);
});
menuitem.addEventListener('click', (event) => userChromejs.clickScriptMenu(event));
menuitem.addEventListener('mousedown', (event) => {if(event.button == 1) event.preventDefault()});
menuitem.addEventListener('mouseup', (event) => {if(event.button == 1) event.preventDefault()});
}
for(var i = 0, len = userChrome_js.overlays.length; i < len; i++){
var script = userChrome_js.overlays[i];
if(script.dir != dirName) continue;
if(flg){
menuseparator = document.createXULElement('menuseparator');
menupopup.appendChild(menuseparator);
}
flg = false;
menuitem = document.createXULElement('menuitem');
menuitem.setAttribute('label',script.filename);
menuitem.setAttribute('type','checkbox');
menuitem.setAttribute('autocheck','false');
menuitem.setAttribute('closemenu','none');
menuitem.toggleAttribute('checked',!userChrome_js.scriptDisable[script.filename] );
if(script.description)
menuitem.setAttribute('tooltiptext',script.description);
menuitem.script = script;
menupopup.appendChild(menuitem);
menuitem.addEventListener('command', (event) => {
userChromejs.chgScriptStat(event.target.script.filename);
event.target.toggleAttribute('checked',!userChrome_js.scriptDisable[event.target.script.filename]);
});
menuitem.addEventListener('click', (event) => userChromejs.clickScriptMenu(event));
menuitem.addEventListener('mousedown', (event) => {if(event.button == 1) event.preventDefault()});
menuitem.addEventListener('mouseup', (event) => {if(event.button == 1) event.preventDefault()});
}
menu.appendChild(menupopup);
menupopup = document.getElementById("userChromejs_options");
menupopup.appendChild(menu);
}
},
clickDirMenu: function(event){
if(event.button == 1 || event.button == 2){
event.stopPropagation();
event.preventDefault();
userChromejs.chgDirStat(event.target.dirName);
if(event.target.firstChild && event.target.firstChild.firstChild)
event.target.firstChild.firstChild.toggleAttribute('checked',!userChrome_js.dirDisable[event.target.dirName] );
if(!!userChrome_js.dirDisable[event.target.dirName])
event.target.setAttribute('style', 'font-style:italic;');
else
event.target.removeAttribute('style');
}
},
clickDirMenuitem: function(event,stop){
if(event.button == 1 || event.button == 2){
event.stopPropagation();
event.preventDefault();
userChromejs.chgDirStat(event.target.dirName);
event.target.toggleAttribute('checked',!userChrome_js.dirDisable[event.target.dirName] );
if(!stop && !!userChrome_js.dirDisable[event.target.dirName])
event.target.parentNode.parentNode.setAttribute('style', 'font-style:italic;');
else
event.target.parentNode.parentNode.removeAttribute('style');
}
},
clickScriptMenu: function(event){
if(event.button==1){
event.stopPropagation();
event.preventDefault();
userChromejs.chgScriptStat(event.target.script.filename);
event.target.toggleAttribute('checked',!userChrome_js.scriptDisable[event.target.script.filename] );
}else if(event.button==2){
event.stopPropagation();
event.preventDefault();
this.launchEditor(event.target.script);
}
},
launchEditor: function(aScript){
var editor = this.editor;
var path = Services.io.newURI(aScript.url)
.QueryInterface(Ci.nsIFileURL).file.path;
var appfile = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsIFile);
appfile.initWithPath(editor);
var process = Components.classes['@mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
process.init(appfile);
process.runw(false, [path], 1, {});
},
chgDirStat: function(adirName){
var s = userChromejs.getPref("userChrome.disable.directory", "str", "");
if(!userChrome_js.dirDisable[adirName]){
s = (s+',').replace(adirName+',','') + adirName+',';
}else{
s = (s+',').replace(adirName+',','');
}
s = s.replace(/,,/g,',').replace(/^,/,'');
userChromejs.setPref("userChrome.disable.directory", "str", s);
userChrome_js.dirDisable = this.restoreState(s.split(','));
},
chgScriptStat: function(afilename){
var s = userChromejs.getPref("userChrome.disable.script", "str", "");
if(!userChrome_js.scriptDisable[afilename]){
s = (s+',').replace(afilename+',','') + afilename+',';
}else{
s = (s+',').replace(afilename+',','');
}
s = s.replace(/,,/g,',').replace(/^,/,'');
userChromejs.setPref("userChrome.disable.script", "str", s);
userChrome_js.scriptDisable = this.restoreState(s.split(','));
},
restoreState: function (arr){
var disable = [];
for(var i = 0,len = arr.length; i < len; i++)
disable[arr[i]] = true;
return disable;
},
//prefを読み込み
getPref: function(aPrefString, aPrefType, aDefault){
var xpPref = Services.prefs;
try {
switch (aPrefType){
case 'complex':
return xpPref.getComplexValue(aPrefString, Components.interfaces.nsIFile); break;
case 'str':
return unescape(xpPref.getCharPref(aPrefString).toString()); break;
case 'int':
return xpPref.getIntPref(aPrefString); break;
case 'bool':
default:
return xpPref.getBoolPref(aPrefString); break;
}
} catch(e) {}
return aDefault;
},
//prefを書き込み
setPref: function(aPrefString, aPrefType, aValue){
var xpPref = Services.prefs;
try {
switch (aPrefType){
case 'complex':
return xpPref.setComplexValue(aPrefString, Components.interfaces.nsIFile, aValue); break;
case 'str':
return xpPref.setCharPref(aPrefString, escape(aValue)); break;
case 'int':
aValue = parseInt(aValue);
return xpPref.setIntPref(aPrefString, aValue); break;
case 'bool':
default:
return xpPref.setBoolPref(aPrefString, aValue); break;
}
} catch(e) {}
return null;
},
// 監視を開始する
addPrefListener: function(aObserver) {
try {
var pbi = Services.prefs;
pbi.addObserver(aObserver.domain, aObserver, false);
} catch(e) {}
},
// 監視を終了する
removePrefListener: function(aObserver) {
try {
var pbi = Services.prefs;
pbi.removeObserver(aObserver.domain, aObserver);
} catch(e) {}
},
readLaterPrefListener:{
domain : 'userChrome.disable',
//"userChrome.disable"という名前の設定が変更された場合全てで処理を行う
observe : function(aSubject, aTopic, aPrefstring) {
if (aTopic == 'nsPref:changed') {
// 設定が変更された時の処理
setTimeout(function(){
var s = userChromejs.getPref("userChrome.disable.directory", "str", "");
userChrome_js.dirDisable = userChromejs.restoreState(s.split(','));
s = userChromejs.getPref("userChrome.disable.script", "str", "");
userChrome_js.scriptDisable = userChromejs.restoreState(s.split(','));
}, 0);
}
}
},
restartApp: function() {
if ("BrowserUtils" in window && typeof BrowserUtils.restartApplication == "function") {
Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULRuntime).invalidateCachesOnRestart();
BrowserUtils.restartApplication();
return;
}
const appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
.getService(Components.interfaces.nsIAppStartup);
// Notify all windows that an application quit has been requested.
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
.createInstance(Components.interfaces.nsISupportsPRBool);
os.notifyObservers(cancelQuit, "quit-application-requested", null);
// Something aborted the quit process.
if (cancelQuit.data)
return;
// Notify all windows that an application quit has been granted.
os.notifyObservers(null, "quit-application-granted", null);
// Enumerate all windows and call shutdown handlers
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var windows = wm.getEnumerator(null);
var win;
while (windows.hasMoreElements()) {
win = windows.getNext();
if (("tryToClose" in win) && !win.tryToClose())
return;
}
let XRE = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
if (typeof XRE.invalidateCachesOnRestart == "function")
XRE.invalidateCachesOnRestart();
appStartup.quit(appStartup.eRestart | appStartup.eAttemptQuit);
}
}
userChromejs.init();
//メニューが長くなりすぎるので, あまり使わないメニューを"userChrome.jsの各スクリプトの設定"の下に移動させる
var userChromejsScriptOptionsMenu = {
//あまり使わないメニューのリスト
/* menues: [
"GrabScroll_optionsMenu",
"Patch_XULrubySupportMenu",
"menutabTooltip",
"PipeliningToggle",
"linkInNewTabForSpecifiedPageToolMenu",
"ieviewModokiTool",
"linkloadInBackgroundToolMenu",
"SaveFolderToolsMenu",
"ucjs_copysysinfo-menu"
],
*/
interval: 500, //0.5秒間隔
maxcount: 50, //最大50回までトライ
count: 0,
timer: null,
run: function() {
//DOMの構築が完了するのを待ってからメニューを移動させる(5秒間隔で最大50回までトライ)
this.timer = setInterval(function(self){
if (++self.count > self.maxcount || self.moveMenu())
clearInterval(self.timer);
}, this.interval, this);
},
moveMenu: function(){
var menupopup = document.getElementById('userChromejs_script_options');
if (!menupopup)
return false;
var i = 0;
while (i < this.menues.length) {
var menu = document.getElementById(this.menues[i])
if (menu) {
setTimeout(function(menupopup, menu){menupopup.appendChild(menu);}, 100, menupopup, menu);
this.menues.splice(i, 1);
continue;
}
i++;
}
return this.menues.length == 0 ? true : false;
},
}
userChromejsScriptOptionsMenu.run();
Alles anzeigen
Eventuell findet das ja auch so den Weg!
Merci chao Please.
Ich würde sagen, erstelle dir hier ein neues Issue, oben rechts auf den grünen Button New issue klicken.
Daran hatte ich auch schon gedacht, aber dazu muss ich erst einen neuen Account anlegen!
Wenn's nicht anders geht, ist das Plan B.
Weiß irgendwer, ob Alice0775 hier mitliest?
Denn ich hätte da einen Fix für sein "rebuild_userChrome.uc.js"!
Das Menü schließt manchmal bevor man ein Skript auswählen kann.
mr.b. Aber das was Du da an Anforderung beschreibst, kannst Du doch lösen,
wenn Du z.B. bei Gemini, oder auch bei Mistral einen Account anlegst!
Du musst die KI nur noch anweisen auch die Alten Chats in neue "Anfragen" mit einzubeziehen!
Dann "erinnert" sich die KI auch an "Altes"!
Der Punkt ist, Du musst angemeldet sein, damit das funktioniert![]()
Du musst nichts herunterladen und lokal speichern!
Genau so mache ich es auch, damit ich nicht jedes mal der KI mitteilen muss,
dass sie z,B. auf searchfox recherchieren soll.
Sie "weiß" das jetzt!
Und auch fragen zu älteren Chats kann sie mir in einem neuen Chat beantworten,
da sie sich ja "erinnert".
Das ist doch genau DAS, was Du willst.
Findbar-Quicksearch.uc.js
Was meinst Du ... ?
![]()
geldhuegel Das geht doch![]()
Schau bitte hier nach =>
Endor Es gibt ein Update!
Habe noch zwei Funktionen auf vielfachen Wunsch zweier Personen hinzugefügt!
1. Man kann nun, solange der Fokus auf der Suchleiste liegt, mit den Pfeilen der Tastatur navigieren.
2. Ja und auch mit der Entertaste kann man die Treffer nach unten abklappern!
BONUS. Und per Shift+Enter geht es auch wieder hoch. ![]()
Wer all so viel Funktionen nicht mag,
es gibt einen KONFIGURATIONBEREICH.
Da kann man auch einzelne Funktionen konfigurieren!
Das ist da erklärt!
Standard ist alles "Eingeschaltet"!
// ==UserScript==
// @name Schnell-Suche mit Auto-Close.uc.js
// @description Tippe irgendwo einen Buchstaben – die VOLLSTÄNDIGE Firefox-Suchleiste
// (mit Pfeilen, Groß-/Kleinschreibung, Hervorheben usw.) öffnet sich,
// der Buchstabe steht bereits im Suchfeld, du tippst einfach weiter.
// Geschlossen wird nur noch per Klick auf die Seite (oder Escape/X).
// @compatibility Firefox 157+
// @author Mira Bellenbaum mit Hilfe von Mistral (KI)
// @version 2026.10.12
// ==/UserScript==
//
// =====================================================================
// WIE ES FUNKTIONIERT (Quellcode: toolkit/content/widgets/findbar.js)
// =====================================================================
//
// 1. „Beim Tippen automatisch im Seitentext suchen“
// (accessibility.typeaheadfind) lässt beim Tippen die Quick-Find-Leiste
// aufgehen – der Buchstabe steht sofort im Suchfeld.
//
// 2. Die Quick-Find-Leiste sieht minimal aus, weil _updateFindUI() bei
// findMode != FIND_NORMAL alle Elemente außer Textfeld und Trefferzähler
// auf hidden setzt.
// → Zwei unabhängige Mechanismen blenden alles wieder ein:
// a) Prototyp-Patch: nach jedem Original-_updateFindUI
// b) findbaropen-Event: direkt an der geöffneten Instanz
//
// 3. Navigation durch die Treffer (solange die Leiste geöffnet ist),
// einzeln schaltbar über die KONFIGURATION unten:
// - Scrollrad über der Leiste (scrollNavigation)
// - Enter = weiter / Shift+Enter = zurück (enterNavigation)
// - Pfeiltasten ↑/↓ = zurück/weiter (arrowKeyNavigation)
// Alle Varianten nutzen die FindBar-Methode
// onFindAgainCommand(true = zurück / false = weiter).
//
// 4. Schließen bei Klick auf die Seite – nativ in Firefox enthalten
// (findbar.js: onMouseUp schließt die Quick-Find-Leiste selbst).
//
// FEHLERSUCHE: Alle Meldungen erscheinen IMMER in der Browser-Konsole
// (Strg+Umschalt+J), gefiltert nach „Schnell-Suche“.
//
// =====================================================================
'use strict';
// =====================================================================
// KONFIGURATION
// =====================================================================
const CONFIG = {
// Beim Tippen im Seitentext suchen (Type-Ahead-Find) aktiviert lassen?
enableTypeAhead: true, /* false => die Leiste muss manuell aktiviert werden */
// Auto-Close-Timer abschalten? (true = Leiste bleibt offen bis Klick)
disableAutoClose: true, /* false => die Leiste schließt nach vorgegebener Zeit */
// Nur relevant, falls disableAutoClose = false:
autoCloseTimeoutMs: 5000,
// Navigation durch die Treffer – einzeln schaltbar:
// Scrollrad über der Leiste: runter = weiter, hoch = zurück
scrollNavigation: true, /* true => ON, false => OFF */
// Enter = nächster Treffer, Shift+Enter = vorheriger Treffer
enterNavigation: true, /* true => ON, false => OFF */
// Pfeiltasten: ↓ = nächster Treffer, ↑ = vorheriger Treffer
arrowKeyNavigation: true, /* true => ON, false => OFF */
};
// =====================================================================
// AB HIER NICHTS MEHR ÄNDERN
// =====================================================================
(function SchnellSucheVollstaendigeLeiste() {
const LOG = '[Schnell-Suche] ';
const CE_NAME = 'findbar';
const MAX_TRIES = 60; // 60 × 500 ms = max. 30 Sekunden warten
// In allen Fenstern ausführen
if (window.gBrowser && !CustomizableUI.getWidget("ExtraConfigMenu-button"))
return;
console.log(LOG + '2026.10.10 geladen, Initialisierung läuft …');
function fail(aMsg, aErr) {
console.error(LOG + aMsg, aErr);
}
// -----------------------------------------------------------------
// Kernroutine: an einer konkreten FindBar-Instanz alles einblenden
// -----------------------------------------------------------------
function showFullUI(aFb) {
if (!aFb)
return false;
let ok = true;
// a) Alle Kinder des Containers sichtbar schalten
try {
let container = aFb.getElement
? aFb.getElement('findbar-container')
: aFb.querySelector('.findbar-container');
if (!container) {
fail('findbar-container nicht gefunden! Verfügbare Struktur:', aFb.outerHTML.slice(0, 600));
ok = false;
} else {
for (let node of container.children) {
node.hidden = false;
}
}
} catch (err) {
fail('Fehler beim Einblenden der Container-Kinder: ', err);
ok = false;
}
// b) Pfeile „Weiter“ / „Zurück“
try {
let next = aFb.getElement ? aFb.getElement('find-next')
: aFb.querySelector('[anonid="find-next"], .findbar-find-next');
let prev = aFb.getElement ? aFb.getElement('find-previous')
: aFb.querySelector('[anonid="find-previous"], .findbar-find-previous');
if (next) next.hidden = false;
if (prev) prev.hidden = false;
} catch (err) {
fail('Fehler beim Einblenden der Pfeile: ', err);
ok = false;
}
// c) Die drei Options-Checkboxen werden NICHT vom Container-Durchlauf
// erfasst, weil _updateCaseSensitivity(), _updateDiacriticMatching()
// und _setEntireWord() sie im Quick-Find-Modus explizit auf
// hidden = true setzen (findbar.js: „Show the checkbox on the full
// Find bar in non-auto mode“). Deshalb hier einzeln einblenden:
try {
const TOGGLES = ['find-case-sensitive', 'find-match-diacritics',
'find-entire-word'];
for (let id of TOGGLES) {
let cb = aFb.getElement ? aFb.getElement(id)
: aFb.querySelector('[anonid="' + id + '"]');
if (cb) cb.hidden = false;
}
} catch (err) {
fail('Fehler beim Einblenden der Options-Checkboxen: ', err);
ok = false;
}
// d) Schmalen Quick-Find-Look des Textfeldes zurücknehmen
try {
if (aFb._findField)
aFb._findField.classList.remove('minimal');
} catch (err) {
fail('Fehler beim Zurücksetzen des Textfeld-Looks: ', err);
ok = false;
}
// e) Leeren Trefferzähler nicht als leeres Element zeigen
try {
let fm = aFb._foundMatches;
if (fm && !fm.value)
fm.hidden = true;
} catch (err) { /* unkritisch */ }
return ok;
}
// -----------------------------------------------------------------
// 1) Prefs setzen (User-Zweig – gewinnt immer)
// -----------------------------------------------------------------
try {
Services.prefs.setBoolPref('accessibility.typeaheadfind',
CONFIG.enableTypeAhead);
Services.prefs.setIntPref('accessibility.typeaheadfind.timeout',
CONFIG.disableAutoClose ? 0 : CONFIG.autoCloseTimeoutMs);
Services.prefs.setBoolPref('accessibility.typeaheadfind.enablesound',
false);
console.log(LOG + 'Prefs gesetzt: typeaheadfind=' +
Services.prefs.getBoolPref('accessibility.typeaheadfind') +
', timeout=' + Services.prefs.getIntPref('accessibility.typeaheadfind.timeout') + 'ms');
} catch (err) {
fail('Konnte Prefs nicht setzen: ', err);
}
// -----------------------------------------------------------------
// 2a) Mechanismus 1: Prototyp-Patch auf _updateFindUI
// -----------------------------------------------------------------
let patched = false;
function patchFindbarClass() {
let findbarClass = customElements.get(CE_NAME);
if (!findbarClass)
return false;
const origUpdateFindUI = findbarClass.prototype._updateFindUI;
if (typeof origUpdateFindUI !== 'function') {
fail('findbar-Klasse gefunden, aber _updateFindUI fehlt – ' +
'Firefox-Update mit umbenannter Methode?');
return true; // nicht endlos weiterversuchen
}
findbarClass.prototype._updateFindUI = function (...aArgs) {
try {
origUpdateFindUI.apply(this, aArgs);
} catch (err) {
fail('Original-_updateFindUI warf einen Fehler: ', err);
}
showFullUI(this);
};
// Die drei Checkboxen werden bei JEDEM Such-Update (also jedem
// getippten Zeichen) durch updateControlState erneut versteckt.
// Deshalb zusätzlich diese drei Methoden patchen – nach dem
// Original-Aufruf die Checkbox immer wieder einblenden:
const TOGGLE_METHODS = {
_updateCaseSensitivity: 'find-case-sensitive',
_updateDiacriticMatching: 'find-match-diacritics',
_setEntireWord: 'find-entire-word',
};
for (let [methodName, anonId] of Object.entries(TOGGLE_METHODS)) {
let orig = findbarClass.prototype[methodName];
if (typeof orig !== 'function') {
fail('Methode ' + methodName + ' nicht gefunden – umbenannt?');
continue;
}
findbarClass.prototype[methodName] = function (...aArgs) {
try {
orig.apply(this, aArgs);
} catch (err) {
fail('Original-' + methodName + ' warf einen Fehler: ', err);
}
try {
let cb = this.getElement ? this.getElement(anonId)
: this.querySelector('[anonid="' + anonId + '"]');
if (cb) cb.hidden = false;
// zugehöriges Status-Label bleibt unsichtbar (nur für die
// vollständige Leiste ohne Checkbox vorgesehen)
} catch (err) { /* unkritisch */ }
};
}
patched = true;
console.log(LOG + 'Mechanismus 1 aktiv: _updateFindUI gepatcht.');
return true;
}
function waitForFindbar(aTries) {
if (patched)
return;
if (patchFindbarClass())
return;
if (aTries >= MAX_TRIES) {
fail('findbar-Custom-Element wurde nach 30 Sekunden nicht registriert.');
return;
}
setTimeout(() => waitForFindbar(aTries + 1), 500);
}
waitForFindbar(0);
// -----------------------------------------------------------------
// 2b) Mechanismus 2: findbaropen-Event direkt abfangen.
// Das Event wird beim Öffnen auf der FindBar dispatched
// (findbar.js: event.initEvent("findbaropen", true, false)).
// -----------------------------------------------------------------
document.addEventListener('findbaropen', function (aEvent) {
let fb = aEvent.target;
console.log(LOG + 'findbaropen erkannt, blende vollständige Leiste ein …');
showFullUI(fb);
enableWheelScrolling(fb); // 3) Scrollrad-Blättern aktivieren /* Mira */
// Sicherheitsnetz: nochmals nach einem kurzen Moment, falls
// interne Aufrufe die Elemente nach dem Öffnen erneut verstecken.
setTimeout(() => showFullUI(fb), 100);
setTimeout(() => showFullUI(fb), 400);
}, true);
// -----------------------------------------------------------------
// 3) Navigation: Scrollrad / Enter / Pfeiltasten
// Gemeinsame FindBar-API: onFindAgainCommand(true = zurück,
// false = weiter) – das ist der interne Command-Handler der
// Pfeil-Buttons (findbar.js).
// -----------------------------------------------------------------
// 3a) Scrollrad über der Leiste: runter = weiter, hoch = zurück
const WHEEL_FLAG = '_schnellSucheWheel';
function enableWheelScrolling(aFb) {
if (!CONFIG.scrollNavigation)
return;
if (!aFb || aFb[WHEEL_FLAG])
return; // Listener schon angehängt
aFb[WHEEL_FLAG] = true;
aFb.addEventListener('wheel', function (aEvent) {
// Nur bei vorhandenem Suchbegriff blättern
if (!aFb._findField || !aFb._findField.value)
return;
aEvent.preventDefault();
aEvent.stopPropagation();
if (aEvent.deltaY > 0) {
// Rad nach unten → nächster Treffer
try { aFb.onFindAgainCommand(false); } catch (e) {
let btn = aFb.getElement && aFb.getElement('find-next');
if (btn) btn.click();
}
} else {
// Rad nach oben → vorheriger Treffer
try { aFb.onFindAgainCommand(true); } catch (e) {
let btn = aFb.getElement && aFb.getElement('find-previous');
if (btn) btn.click();
}
}
}, { passive: false });
}
// 3b) Enter = nächster Treffer, Shift+Enter = vorheriger Treffer,
// Pfeiltasten ↑/↓ = zurück/weiter – nur bei offener Leiste.
if (CONFIG.enterNavigation || CONFIG.arrowKeyNavigation) {
window.addEventListener('keydown', function (aEvent) {
if (aEvent.ctrlKey || aEvent.altKey || aEvent.metaKey)
return;
let fb = window.gFindBar || window.gBrowser.getCachedFindBar();
if (!fb || fb.hidden)
return;
if (!fb._findField || !fb._findField.value)
return;
// Shift+Enter → vorheriger Treffer
if (CONFIG.enterNavigation &&
aEvent.key === 'Enter' && aEvent.shiftKey) {
aEvent.preventDefault();
fb.onFindAgainCommand(true);
return;
}
switch (aEvent.key) {
case 'Enter':
case 'ArrowDown':
if ((aEvent.key === 'Enter' && !CONFIG.enterNavigation) ||
(aEvent.key === 'ArrowDown' && !CONFIG.arrowKeyNavigation))
return;
aEvent.preventDefault();
fb.onFindAgainCommand(false); // nächster Treffer
break;
case 'ArrowUp':
if (!CONFIG.arrowKeyNavigation)
return;
aEvent.preventDefault();
fb.onFindAgainCommand(true); // vorheriger Treffer
break;
}
}, true);
}
// -----------------------------------------------------------------
// 4) Schließen bei Klick auf die Seite: NICHT nötig!
// Firefox erledigt das nativ selbst – findbar.js schließt die
// Quick-Find-Leiste bei Mouse-up im Seiteninhalt:
// onMouseUp() { if (!this.hidden &&
// this.findMode != this.FIND_NORMAL) this.close(); }
// Die normale Strg+F-Leiste bleibt bei Klick geöffnet (nativ).
// -----------------------------------------------------------------
console.log(LOG + 'Initialisierung abgeschlossen. Navigation: Scrollrad=' +
CONFIG.scrollNavigation + ', Enter=' + CONFIG.enterNavigation +
', Pfeiltasten=' + CONFIG.arrowKeyNavigation);
})();
Alles anzeigen
captain chaos Bitte schön, mit der Entertaste.
geldhuegel Funktioniert auch mit den Pfeiltasten.
Und lest bitte die Beschreibung und passt das Skript Euren Wünschen im Konfigurationsbereich an.
Mit den TASTEN?
Die sind aber doch schon mit dem Scrollen belegt!
Das wird schwierig, denn es muss die bisherige Belegung mit dem Aktivieren der Suchleiste "unterbrochen" werden
und dann muss den Pfeilen neue Funktionen zugewiesen werden, die,
sobald die Leiste wieder "weg" ist, wieder ihre normalen Funktionen erhalten!
Da bin ich mir gar nicht so sicher, ob das wirklich geht.
Super![]()
In zweien Füchsen getestet, klappt! ![]()
2002Andreas Mit diesem Skript kann man aber nur über den Stern in der Adresszeile Lesezeichen bearbeiten!
Wenn Du direkt über die Lesezeichen gehst, Rechtsklick Menü "Lesezeichen bearbeiten ...",
und so schaut das Popup von Son Goku aus, ist da kein Notizfeld!
Ich arbeite da gerade drann, ob's was wird, weiß ich noch nicht!
Danke für die ausführliche Anleitung, mit der ich gepflegt überfordert bin 😗
Hey, ich bin blond und helfe nur in der Gastro aus!
Und ich habe das auch hinbekommen, zugegeben, auch erst nach mehreren Anläufen!
Mache zu aller erst ein Backup des Profils, und dann mach dich ans Werk!
Du machst mit Linux rum! Damit bin ich überfordert!
Warum ... ?
Ja, Mozilla macht schon verdammt viel möglich, aber auch alles und jeden einzugehen, ...?
Das wäre dann doch etwas zu viel des Guten, findest Du nicht?
Immerhin ermöglichen sie es dem User per CSS den Firefox so anpassbar wie nur was zu machen.
Versuche DAS mal bei irgendeiner anderen Software!
Da wirst Du lange suchen (müssen).
Kann man das zusätzlich auch mit der Enter-Taste realisieren?
Dafür gibt es doch die F3 - Taste!
Das mit der Entertaste halte ich für keine gute Idee!
Diese Taste ist für das Bestätigen von Eingaben und so etwas gedacht!
Die möchte ich nur ungerne vergewaltigen!
Moin. ubuntu-novize
Du nutzt noch gar kein CSS um Dir den Firefox an zu passen?
Dann musst Du erst einmal ein paar Vorbereitungen treffen.
Die ausführliche Anleitung:
Dann müsste jeder User sich erst alle Beiträge nachträglich ansehen, bzw. erstmal darauf kommen, dass da so ein Like angeklickt wurde. Wenn du das nicht extra gesagt hättest, wäre mir das auch nicht aufgefallen.
Und eine kurze Rückmeldung wie: danke funktioniert...oder ähnlich sollte doch wohl sein dann
So hätte es sein sollen.
Aber weil der captain nichts geschrieben hatte, machte ich halt eine "Meldung".
Frage, darf ich das bei Github hochladen?
Aber natürlich.
Wenn ja wie soll ich es nennen?
QuickSearchAutoClose.uc.js oder FindBarExtrau.c.js ?
Keine Ahnung was da am besten passt.
Eine kurze Rückmeldung wäre dann ja auch nicht schlecht gewesen
Das war jetzt aber nicht an mich gerichtet, oder?
Ich habe das auch nur angenommen, weil captain chaos den Beitrag #27 mit "Gefällt mir" markiert hat.
Thema scheint erledigt zu sein!
2002Andreas Das ist in der Tat sehr merkwürdig, da das Skript aus #23
nur um folgendes ergänzt wurde:
// -----------------------------------------------------------------
// 3) Scrollrad über der Leiste = Treffer vor-/zurückblättern
// Verharrt der Mauszeiger auf der Suchleiste, springt
// Mausrad-runter zum nächsten und Mausrad-hoch zum vorherigen
// Treffer. Wird an jede geöffnete FindBar einmalig angehängt.
// -----------------------------------------------------------------
const WHEEL_FLAG = '_schnellSucheWheel';
function enableWheelScrolling(aFb) {
if (!aFb || aFb[WHEEL_FLAG])
return; // Listener schon angehängt
aFb[WHEEL_FLAG] = true;
aFb.addEventListener('wheel', function (aEvent) {
// Nur bei vorhandenem Suchbegriff blättern
if (!aFb._findField || !aFb._findField.value)
return;
// Nicht blättern, wenn der Nutzer gerade im Textfeld markiert/
// scrollt? Das Textfeld scrollt nicht – also einfach weiter:
aEvent.preventDefault();
aEvent.stopPropagation();
if (aEvent.deltaY > 0) {
// Rad nach unten → nächster Treffer
try { aFb.findNext(); } catch (e) {
let btn = aFb.getElement && aFb.getElement('find-next');
if (btn) btn.click();
}
} else {
// Rad nach oben → vorheriger Treffer
try { aFb.findPrevious(); } catch (e) {
let btn = aFb.getElement && aFb.getElement('find-previous');
if (btn) btn.click();
}
}
}, { passive: false });
}
Alles anzeigen
Der übrige Code aber gar nicht angefasst oder verändert wurde.
OK, die kleine Korrektur aus #26, aber DAS kann es nicht sein!
Jetzt habe ich mir extra eine neue, "nackte" Portable 157.0.1 gebaut!
Ok, die kann ich ja für andere Tests nutzen.
Und, was war das Ergebnis, auch da funktionierte das Skript.
Aber lieber zwei, drein Mal getestet, als einfach so da hingeklatscht!