Firefox: set focus to tab



  • Ich weiß nicht, ob du mich missverstehst oder ich dich.
    Aber ich will letztendlich einfach nur eine WebExtension für Firefox schreiben, mit der ich unter Linux, wo ALT+1-9 zum Wechseln des Tabs verwendet wird statt dem praktischerern CTRL+1-9, diese Shortcuts eben in die CTRL-Variante verändere und CTRL+Q deaktivieren kann. Da ich mich aber mit JavaScript aber nicht so auskenne, muss ich mein gesamtes Wissen im Prinzip aus der Dokumentation ziehen und da konnte ich eben das Ändern des aktiven Tabs (des im Vordergrund geöffneten Tabs) nicht finden.

    Was ich bisher habe:

    "commands": {
    		"first_tab": {
    			"suggested_key": { "default": "Ctrl+1" }
    		}
    		"second_tab": {
    			"suggested_key": { "default": "Ctrl+2" }
    		}
    		"third_tab": {
    			"suggested_key": { "default": "Ctrl+3" }
    		}
    		"fouth_tab": {
    			"suggested_key": { "default": "Ctrl+4" }
    		}
    		"fifth_tab": {
    			"suggested_key": { "default": "Ctrl+5" }
    		}
    		"sixth_tab": {
    			"suggested_key": { "default": "Ctrl+6" }
    		}
    		"seventh_tab": {
    			"suggested_key": { "default": "Ctrl+7" }
    		}
    		"eighth_tab": {
    			"suggested_key": { "default": "Ctrl+8" }
    		}
    		"last_tab": {
    			"suggested_key": { "default": "Ctrl+9" }
    		}
    		"close-q": {
    			"suggested_key": { "default": "Ctrl+q" }
    		}
    	}
    
    	"background": {
    		"scripts": [ "handle-shortcuts.js" ]
    	}
    

    und handle-shortcuts.js:

    browser.commands.onCommand.addListener((command) => {
    
    });
    

    Dort hinein muss jetzt, wenn ich das richtig verstanden habe einfach eine Abfrage des Objekts command, durch welchen Shortcut es ausgelöst wurde und dann will ich eben zu dem entsprechenden Tab wechseln.

    Es geht nicht darum, einen neuen Tab zu erstellen. Oder habe ich deine Antwort missinterpretiert?



  • Ich dachte du wolltest eine extension schreiben, die irgendwelche settings oder sowas im tab anzeigt.

    Als erstes braucht dein manifest die permission fuer tabs , sowie activeTab

    "permissions": [
        "tabs",
        "activeTab"
    ]
    

    Danach kannst du alle tabs via query bekommen:

    const windowTabs = browser.tabs.query({
        "currentWindow": true
    });
    

    Ueber die objects kannst du dann mit for of iterieren, oder den kram weg- if -en.

    Mir will grade auch keine elegante moeglichkeit dazu einfallen.

    Active setzt du den tab (sofern er existiert) einfach wie folgt:

    browser.tabs.update(windowTabs[foo].id, {
        active: true
    });
    


  • Vielen Dank, sieht gut aus.
    Aber leider kann ich das irgendwie nicht laden. Wenn ich in Firefox "\1:debugging" öffne und mein manifest.json laden will, dann kommt:

    There was an error during installation: Extension is invalid

    Hier manifest.json:

    {
    	"manifest-version": "2",
    	"name": "shortcuts",
    	"version": "1.0",
    
    	"description": "sets shortcuts",
    
    	"permissions": [
        	"tabs",
        	"activeTab"
    	],
    
    	"applications": {
    		"gecko": {
    			"id": "my_extension_SHORTCUTS"
    		}
    	},
    
    	"commands": {
    		"first_tab": {
    			"suggested_key": { "default": "Ctrl+1" }
    		},
    		"second_tab": {
    			"suggested_key": { "default": "Ctrl+2" }
    		},
    		"third_tab": {
    			"suggested_key": { "default": "Ctrl+3" }
    		},
    		"fouth_tab": {
    			"suggested_key": { "default": "Ctrl+4" }
    		},
    		"fifth_tab": {
    			"suggested_key": { "default": "Ctrl+5" }
    		},
    		"sixth_tab": {
    			"suggested_key": { "default": "Ctrl+6" }
    		},
    		"seventh_tab": {
    			"suggested_key": { "default": "Ctrl+7" }
    		},
    		"eighth_tab": {
    			"suggested_key": { "default": "Ctrl+8" }
    		},
    		"last_tab": {
    			"suggested_key": { "default": "Ctrl+9" }
    		},
    		"close-q": {
    			"suggested_key": { "default": "Ctrl+q" }
    		}
    	},
    
    	"background": {
    		"scripts": ["shortcuts.js"]
    	}
    }
    

    Und shortcuts.js:

    browser.commands.onCommand.addListener((command) => {
    
    	const windowTabs = browser.tabs.query({
    		"currentWindow": true
    	});
    
    	if(command == "first_tab") {
    		browser.tabs.update(windowTabs[0].id, {
    			active: true
    		});
    	}
    	if(command == "second_tab") {
    		browser.tabs.update(windowTabs[1].id, {
    			active: true
    		});
    	}
    	if(command == "third_tab") {
    		browser.tabs.update(windowTabs[2].id, {
    			active: true
    		});
    	}
    	if(command == "fouth_tab") {
    		browser.tabs.update(windowTabs[3].id, {
    			active: true
    		});
    	}
    	if(command == "fifth_tab") {
    		browser.tabs.update(windowTabs[4].id, {
    			active: true
    		});
    	}
    	if(command == "sixth_tab") {
    		browser.tabs.update(windowTabs[5].id, {
    			active: true
    		});
    	}
    	if(command == "seventh_tab") {
    		browser.tabs.update(windowTabs[6].id, {
    			active: true
    		});
    	}
    	if(command == "eighth_tab") {
    		browser.tabs.update(windowTabs[7].id, {
    			active: true
    		});
    	}
    	if(command == "ninth_tab") {
    		browser.tabs.update(windowTabs[windowTabs.length - 1].id, {
    			active: true
    		});
    	}
    
    	if(command == "close-q") {
    
    	}
    });
    

    Ich habe schon einiges ausprobiert, aber irgendwie funktioniert nichts davon.
    Danke!



  • Wie erstellst du die extension?
    Ausserdem, hast du deine extension signiert? Wenn nicht, musst du in \1:config den key xpinstall.signatures.required auf false setzen.

    Edit: Deine loesung ist nicht sonderlich optimal, wenn nur 3 tabs existieren, bekommst eine IndexOutOfRangeException geschmissen, sobald zb. "CTRL+8" nimmst.

    Als quick'n'dirty solution wuerde ich die ganzen if 's einfach stumpf in try/catch wrappen, indexOutOfRange catchen und windowTabs[windowTabs.length - 1] zurueckgeben...bzw active setzen.

    Edit 2: "last_tab" != "ninth_tab" !



  • Stimmt, es war last_tab und nicht ninth_tab, danke.
    An den Fall habe ich gar nicht gedacht.
    Ich habe jetzt einfach überall if(command == "Xth_tab" && windowsTabs.length > 😵 hinzugefügt.

    Ich erstelle die Extension gar nicht. Ich versuche die manifest.json-Datei in \1:debugging zu öffnen, wie es hier (https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Your_first_WebExtension) in dem Video unten unter Installing gezeigt wird. Bzw. wird da die *.js-Datei geladen, funktioniert bei mir aber auch nicht.
    Das sollte es also eigentlich nicht sein. Die Ordnerstruktur habe ich genauso aufgebaut wie dort.



  • Du hattest einige typos im manifest.

    {
      "applications": {
        "gecko": {
          "id": "addon@example.com",
          "strict_min_version": "55.0"
        }
      },
      "background": {
        "scripts": ["shortcuts.js"]
      },
      "commands": {
    	"one": {
    	  "suggested_key": {
    	    "default": "Alt+1"
    	  }
    	},
    	"two": {
    	  "suggested_key": {
    	    "default": "Alt+2"
    	  }
    	}
      },
      "permissions": [
    	"activeTab",
    	"tabs"
      ],
      "content_scripts": [
        {
          "exclude_matches": [
    	    "*://*/*.xml"
    	  ],
          "matches": [
    	    "<all_urls>"
    	  ],
          "js": [
    	    "shortcuts.js"
    	  ],
    	  "all_frames": true	  
        }
      ],
      "manifest_version": 2,
      "name": "foo",
      "version": "0.1"  
    }
    

    Aber selbst mit dem file ist das noch nicht ganz sauber. Kannst die extension zwar laden, wird aber noch nicht das tun, was du dir erhoffst. Hauptsaechlich, da die commands syncron abgearbeitet werden und der Promise (query nach tabs) asynchron arbeitet.

    Ich schlaf da mal eine nacht drueber, vielleicht habe ich morgen eine saubere loesung.



  • Ich kann irgendwie keine Fehler finden. Das einzige, was ich jetzt nach mehrmaligem durchlesen gefunden habe, ist, dass ich die manifest-version mit "" geschrieben habe. Nach der Korrektur funktionierte es aber immer noch nicht (Extension ließ sich weiterhin nicht laden).

    Kennst du denn sonst eine andere zuverlässige Extension, die das kann? Meine alte Extension Keybinder funktioniert eben nicht mehr. Und ansonsten habe ich keine gute Alternative gefunden.

    Ich danke dir auf jeden Fall für deine Mühe.



  • manifest**_**version, bekommt einen integer, keinen string und wird mit underscore geschrieben.

    strict_min_version ist mandatory.
    Dein ID-string, ist nicht konform.

    Hast du deine fehlenden direktiven hinzugefuegt?

    Bist du sicher das dein manifest file das richtige encoding hat? Steht da vielleicht noch ein BOM am anfang?

    Ich konnte sie mit dem file hinzufuegen und debuggen.
    Generell kann ich dir das node-module web-ext empfehlen. Das startet die extension von CLI und logged besseren error output.



  • Oh, den underscore habe ich übersehen.
    Das komplette "applications" habe ich jetzt testweise einfach 1:1 übernommen. Geht immer noch nicht. Genauso "content_scripts".

    Müsste eigentlich in UTF-8 codiert sein. Ich habe es mit nano erstellt, das ich üblicherweise auch für kleinere C-Programme verwende. Der Compiler müsste sich ja sonst eigentlich auch beschweren. Ich glaube also nicht, dass es daran liegt.

    Die fehlenden Teile habe ich nach bestem Wissen und Gewissen jetzt ergänzt.

    Ich versuche es sonst einmal mit web-ext. Ich habe schon davon gelesen, da ich es aber nicht in dem Repository von Ubuntu gefunden habe, dachte ich, dass es den Zusatzaufwand nicht wert sei. Jetzt installiere ich es aber über npm.
    Bisher immer über \1:debugging im Browser probiert. Müsste aber ja eigentlich gleich funktionieren. Sollte es gleich mit web-ext funktionieren, melde ich mich.

    Ansonsten hier jetzt meine beiden Dateien:

    {
    	"manifest_version": 2,
    	"name": "shortcuts",
    	"version": "1.0",
    
    	"description": "shortcuts",
    
    	"permissions": [
        	"tabs",
        	"activeTab"
    	],
    
    	"icons": {
    		"ico": "icon/icon.png"
    	},
    
    	"applications": {
    		"gecko": {
    			"id": "addon@example.com",
    			"strict_min_version": "55.0"
    		}
    	},
    
    	"content_scripts": [
        {
    		"exclude_matches": [
    			"*://*/*.xml"
    		],
    		"matches": [
    			"<all_urls>"
    		],
    		"js": [
    			"shortcuts.js"
        	],
    		"all_frames": true     
    	}
    	],
    
    	"commands": {
    		"first_tab": {
    			"suggested_key": { "default": "Ctrl+1" }
    		},
    		"second_tab": {
    			"suggested_key": { "default": "Ctrl+2" }
    		},
    		"third_tab": {
    			"suggested_key": { "default": "Ctrl+3" }
    		},
    		"fouth_tab": {
    			"suggested_key": { "default": "Ctrl+4" }
    		},
    		"fifth_tab": {
    			"suggested_key": { "default": "Ctrl+5" }
    		},
    		"sixth_tab": {
    			"suggested_key": { "default": "Ctrl+6" }
    		},
    		"seventh_tab": {
    			"suggested_key": { "default": "Ctrl+7" }
    		},
    		"eighth_tab": {
    			"suggested_key": { "default": "Ctrl+8" }
    		},
    		"last_tab": {
    			"suggested_key": { "default": "Ctrl+9" }
    		},
    		"close-q": {
    			"suggested_key": { "default": "Ctrl+q" }
    		}
    	},
    
    	"background": {
    		"scripts": ["shortcuts.js"]
    	}
    }
    

    und shortcuts.js:

    browser.commands.onCommand.addListener((command) => {
    
    	const windowTabs = browser.tabs.query({
    		"currentWindow": true
    	});
    
    	if(command == "first_tab") {
    		browser.tabs.update(windowTabs[0].id, {
    			active: true
    		});
    	}
    	if(command == "second_tab" && windowsTabs.length > 1) {
    		browser.tabs.update(windowTabs[1].id, {
    			active: true
    		});
    	}
    	if(command == "third_tab" && windowsTabs.length > 2) {
    		browser.tabs.update(windowTabs[2].id, {
    			active: true
    		});
    	}
    	if(command == "fouth_tab" && windowsTabs.length > 3) {
    		browser.tabs.update(windowTabs[3].id, {
    			active: true
    		});
    	}
    	if(command == "fifth_tab" && windowsTabs.length > 4) {
    		browser.tabs.update(windowTabs[4].id, {
    			active: true
    		});
    	}
    	if(command == "sixth_tab" && windowsTabs.length > 5) {
    		browser.tabs.update(windowTabs[5].id, {
    			active: true
    		});
    	}
    	if(command == "seventh_tab" && windowsTabs.length > 6) {
    		browser.tabs.update(windowTabs[6].id, {
    			active: true
    		});
    	}
    	if(command == "eighth_tab" && windowsTabs.length > 7) {
    		browser.tabs.update(windowTabs[7].id, {
    			active: true
    		});
    	}
    	if(command == "last_tab") {
    		browser.tabs.update(windowTabs[windowTabs.length - 1].id, {
    			active: true
    		});
    	}
    
    	if(command == "close-q") {
    
    	}
    });
    

    Aber wenn das sowieso nicht funktioniert, dann ist das eigentlich auch nicht so wichtig.
    Was ich noch gefunden habe, sind folgende Überreste von Keybinder in \1:config:

    {"overlays":[{"_type":"overlay","key":{"_type":"key","id":"key_selectTab1"},"shortcut":{"_type":"shortcut","keycode":"VK_1","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_selectTab2"},"shortcut":{"_type":"shortcut","keycode":"VK_2","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_selectTab3"},"shortcut":{"_type":"shortcut","keycode":"VK_3","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_selectTab4"},"shortcut":{"_type":"shortcut","keycode":"VK_4","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_selectTab5"},"shortcut":{"_type":"shortcut","keycode":"VK_5","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_selectTab6"},"shortcut":{"_type":"shortcut","keycode":"VK_6","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_selectTab7"},"shortcut":{"_type":"shortcut","keycode":"VK_7","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_selectTab8"},"shortcut":{"_type":"shortcut","keycode":"VK_8","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_selectLastTab"},"shortcut":{"_type":"shortcut","keycode":"VK_9","modifiers":{"_type":"modifiers","modifiers":["control"]}}},{"_type":"overlay","key":{"_type":"key","id":"key_quitApplication"},"shortcut":{"disabled":true}}]}
    

    Das sind vermutlich aber nur die Daten von KeyBinder, die es dort gespeichert hat, oder? Damit kann ich dann ja vermutlich nichts anfangen.
    Über \1:config kann man, was Shortcuts angeht, ja nichts machen, oder doch?



  • Gerade noch folgende Fehlermeldung in web-ext bekommen:

    SyntaxError: Unexpected token .
        at exports.runInThisContext (vm.js:53:16)
        at Module._compile (module.js:374:25)
        at Object.Module._extensions..js (module.js:417:10)
        at Module.load (module.js:344:32)
        at Function.Module._load (module.js:301:12)
        at Module.require (module.js:354:17)
        at require (internal/module.js:12:17)
        at Object.<anonymous> (/usr/local/lib/node_modules/web-ext/node_modules/whatwg-url/lib/public-api.js:3:15)
        at Module._compile (module.js:410:26)
        at Object.Module._extensions..js (module.js:417:10)
    

    Ich finde aber keinen Punkt zu viel.



  • Nr 1:

    [firefox/index.js][debug] Firefox stdout: 1511459919791	addons.webextension.<unknown>	
    ERROR	Loading extension 'null': Reading manifest: Error processing icons: Unexpected property "ico"
    

    siehe: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/icons

    Nr 2:

    [firefox/index.js][debug] Firefox stdout: 1511460114570	addons.webextension.<unknown>	
    ERROR	Loading extension 'null': Reading manifest: Error processing commands.close-q.suggested_key.default: Value "Ctrl+q" must either: 
    match the pattern /^\s*(Alt|Ctrl|Command|MacCtrl)\s*\+\s*(Shift\s*\+\s*)?([A-Z0-9]|Comma|Period|Home|End|PageUp|PageDown|Space|Insert|Delete|Up|Down|Left|Right)\s*$/, 
    match the pattern /^\s*((Alt|Ctrl|Command|MacCtrl)\s*\+\s*)?(Shift\s*\+\s*)?(F[1-9]|F1[0-2])\s*$/, 
    or match the pattern /^(MediaNextTrack|MediaPlayPause|MediaPrevTrack|MediaStop)$/
    

    (hint: uppercase)

    --verbose ist dein freund.

    Ich kann dir heute nacht noch den js part schicken.

    Hau mal bitte ein paar linebreaks in dein json, ich muss soweit zum send button scrollen...



  • Ich dachte, dass sei nur ein ganz normaler Variablenname für das Icon. Danke.

    An --verbose habe ich ehrlich gesagt gar nicht gedacht.
    Das waren schon echt zwei dumme Fehler.
    Funktioniert jetzt auch tatsächlich. Also es lädt, die erwünschte Wirkung hat es nicht, ich vermute aufgrund von dem Verhalten der Abfrage, die du anfangs schon erwähnt hast.
    Hast du noch eine Idee, mit der sich das eventuell bewerkstelligen ließe?

    Ich habe jetzt, indem ich in Firefox das Ganze debuggt habe, herausgefunden, dass irgendwie browser.commands nicht erkannt wird. Ich bekomme:

    ReferenceError: commands is not defined
    TypeError: browser.commands is undefined
    TypeError: browser.commands is undefined
    

    Das kann ich mir auch irgendwie nicht erklären.

    Allerdings scheint web-ext bei mir gar nicht zu funktionieren. Da scheint es irgendeinen internen Fehler zu geben. Die Fehlermeldung bezog sich also entsprechend gar nicht auf mein manifest.json.



  • Es funktioniert!
    Ich danke dir.

    Meine Vorgehensweise:
    Erst einmal das Script aus content_script in background. content_script stimmt natürlich nicht.
    Dann nach einer Möglichkeit gesucht, auf Promises zu warten, da dies das Problem zu sein schien. Da "await" nicht funktionierte, stieß ich schließlich auf "then" und es funktioniert.
    Hier der Code, falls es noch jemand braucht:

    manifest.json:

    {
    	"manifest_version": 2,
    	"name": "shortcuts",
    	"version": "1.0",
    
    	"description": "shortcuts",
    
    	"permissions": [
        	"tabs",
        	"activeTab"
    	],
    
    	"icons": {
    		"96": "icon/icon.png"
    	},
    
    	"applications": {
    		"gecko": {
    			"id": "addon@example.com",
    			"strict_min_version": "55.0"
    		}
    	},
    
    	"commands": {
    		"first_tab": {
    			"suggested_key": { "default": "Ctrl+1" }
    		},
    		"second_tab": {
    			"suggested_key": { "default": "Ctrl+2" }
    		},
    		"third_tab": {
    			"suggested_key": { "default": "Ctrl+3" }
    		},
    		"fouth_tab": {
    			"suggested_key": { "default": "Ctrl+4" }
    		},
    		"fifth_tab": {
    			"suggested_key": { "default": "Ctrl+5" }
    		},
    		"sixth_tab": {
    			"suggested_key": { "default": "Ctrl+6" }
    		},
    		"seventh_tab": {
    			"suggested_key": { "default": "Ctrl+7" }
    		},
    		"eighth_tab": {
    			"suggested_key": { "default": "Ctrl+8" }
    		},
    		"last_tab": {
    			"suggested_key": { "default": "Ctrl+9" }
    		},
    		"close-q": {
    			"suggested_key": { "default": "Ctrl+Q" }
    		}
    	},
    
    	"background": {
    		"scripts": ["shortcuts.js"]
    	}
    }
    

    shortcuts.js:

    browser.commands.onCommand.addListener(function(command) {
    
    	const windowTabs = browser.tabs.query({
    		"currentWindow": true
    	});
    
    	windowTabs.then(handle.bind(null, command), error);
    });
    
    function handle(command, windowTabs) {
    	if(command == "first_tab") {
    		browser.tabs.update(windowTabs[0].id, {
    			active: true
    		});
    		console.log("Tab 1!");
    	}
    	if(command == "second_tab" && windowTabs.length > 1) {
    		browser.tabs.update(windowTabs[1].id, {
    			active: true
    		});
    	}
    	if(command == "third_tab" && windowTabs.length > 2) {
    		browser.tabs.update(windowTabs[2].id, {
    			active: true
    		});
    	}
    	if(command == "fouth_tab" && windowTabs.length > 3) {
    		browser.tabs.update(windowTabs[3].id, {
    			active: true
    		});
    	}
    	if(command == "fifth_tab" && windowTabs.length > 4) {
    		browser.tabs.update(windowTabs[4].id, {
    			active: true
    		});
    	}
    	if(command == "sixth_tab" && windowTabs.length > 5) {
    		browser.tabs.update(windowTabs[5].id, {
    			active: true
    		});
    	}
    	if(command == "seventh_tab" && windowTabs.length > 6) {
    		browser.tabs.update(windowTabs[6].id, {
    			active: true
    		});
    	}
    	if(command == "eighth_tab" && windowTabs.length > 7) {
    		browser.tabs.update(windowTabs[7].id, {
    			active: true
    		});
    	}
    	if(command == "last_tab") {
    		browser.tabs.update(windowTabs[windowTabs.length - 1].id, {
    			active: true
    		});
    	}
    
    	if(command == "close-q") {
    
    	}
    }
    
    function error(msg) {
    	console.log("Error: " + msg);
    }
    

    Danke Cardiac für deine ausdauernde Hilfe.
    Falls du noch Verbesserungsvorschläge hast, bin ich aber auch offen dafür.

    Cardiac schrieb:

    Hau mal bitte ein paar linebreaks in dein json, ich muss soweit zum send button scrollen...

    Und hier verstehe ich leider nicht dein Anliegen? Wenn ich mehr Zeilenumbrücke benutze, dann musst du doch noch länger scrollen? Am Anfang der Seite ist doch außerdem auch ein "Beitrag verfassen"-Button?


Anmelden zum Antworten