Repository: andy-portmen/open-in
Branch: master
Commit: b1981c98d2d5
Files: 19
Total size: 29.3 KB
Directory structure:
gitextract_pmrctrx2/
├── README.md
├── brave/
│ ├── config.js
│ └── manifest.json
├── chrome/
│ └── README
├── chromium/
│ └── README
├── common/
│ ├── common.js
│ ├── data/
│ │ ├── inject.js
│ │ └── options/
│ │ ├── index.html
│ │ └── index.js
│ └── schema.json
├── edge/
│ └── README
├── palemoon/
│ ├── config.js
│ └── manifest.json
├── vivaldi/
│ ├── config.js
│ └── manifest.json
├── waterfox/
│ ├── config.js
│ └── manifest.json
└── yandex/
├── config.js
└── manifest.json
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
# open-in
Send URLs from one browser to another one
## browser-specific projects
* [open-in-chromium](https://github.com/andy-portmen/open-in-chromium)
* [open-in-edge](https://github.com/andy-portmen/open-in-edge)
* [open-in-ie](https://github.com/andy-portmen/open-in-ie)
* [open-in-opera](https://github.com/andy-portmen/open-in-opera)
* [open-in-firefox](https://github.com/andy-portmen/open-in-firefox)
## general-purpose connector
* https://github.com/andy-portmen/native-client
================================================
FILE: brave/config.js
================================================
'use strict';
var app = {
id: 'com.add0n.node',
tag: 'brave',
multiple: true
};
app.locale = {
name: 'brave',
current: 'Open Link in Brave Browser',
all: 'Open all Tabs in Brave Browser',
call: 'Open all Tabs in Brave Browser (Current window)',
example: 'example D:\\Brave\\Application\\Brave.exe'
};
app.runtime = {
mac: {
args: ['-a', 'Brave Browser']
},
linux: {
name: 'brave-browser'
},
windows: {
name: 'cmd',
args: ['/s/c', 'start', 'brave "%url;"'],
prgfiles: '%ProgramFiles(x86)%\\BraveSoftware\\Brave-Browser\\Application\\brave.exe'
}
};
================================================
FILE: brave/manifest.json
================================================
{
"name": "Open in Brave Browser",
"description": "Open current page, link, or all tabs in the Brave browser",
"version": "0.1.3",
"manifest_version": 2,
"permissions": [
"storage",
"tabs",
"contextMenus",
"nativeMessaging"
],
"optional_permissions": [
"downloads"
],
"background": {
"persistent": false,
"scripts": [
"config.js",
"common.js"
]
},
"storage": {
"managed_schema": "schema.json"
},
"homepage_url": "https://add0n.com/open-in.html?from=brave",
"icons": {
"16": "data/icons/16.png",
"32": "data/icons/32.png",
"48": "data/icons/48.png",
"64": "data/icons/64.png",
"128": "data/icons/128.png",
"256": "data/icons/256.png",
"512": "data/icons/512.png"
},
"browser_action": {},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["data/inject.js"],
"run_at": "document_start",
"all_frames": true,
"match_about_blank": true
}],
"options_ui": {
"page": "data/options/index.html",
"chrome_style": true,
"open_in_tab": true
}
}
================================================
FILE: chrome/README
================================================
moved to https://github.com/andy-portmen/open-in-chrome/
================================================
FILE: chromium/README
================================================
moved to https://github.com/andy-portmen/open-in-chromium/
================================================
FILE: common/common.js
================================================
/* globals app */
'use strict';
const os = {
mac: navigator.userAgent.indexOf('Mac') !== -1,
linux: navigator.userAgent.indexOf('Linux') !== -1
};
const isFirefox = navigator.userAgent.indexOf('Firefox') !== -1;
function error(response) {
window.alert(`Something went wrong!
-----
Code: ${response.code}
Output: ${response.stdout}
Error: ${response.stderr}`);
}
function response(res, success = () => {}) {
// windows batch file returns 1
if (res && (res.code !== 0 && (res.code !== 1 || res.stderr !== ''))) {
error(res);
}
else if (!res) {
chrome.tabs.query({
url: chrome.runtime.getURL('data/helper/index.html')
}, tabs => {
if (tabs && tabs.length) {
chrome.tabs.update(tabs[0].id, {
active: true
}, () => {
chrome.windows.update(tabs[0].windowId, {
focused: true
});
});
}
else {
chrome.tabs.create({
url: 'data/helper/index.html'
});
}
});
}
else {
success();
}
}
function exec(command, args, callback, properties = {}) {
if (command) {
chrome.runtime.sendNativeMessage(app.id, {
cmd: 'exec',
command,
arguments: args,
properties
}, res => (callback || response)(res));
}
else {
window.alert(`Please set the "${app.locale.name}" executable path in the options page`);
chrome.runtime.openOptionsPage();
}
}
function find(callback) {
chrome.runtime.sendNativeMessage(app.id, {
cmd: 'env'
}, res => {
if (res && res.env && res.env.ProgramFiles) {
chrome.storage.local.set({
path: app.runtime.windows.prgfiles
.replace('%LOCALAPPDATA%', res.env.LOCALAPPDATA)
.replace('%ProgramFiles(x86)%', res.env['ProgramFiles(x86)'])
.replace('%ProgramFiles%', res.env.ProgramFiles)
}, callback);
}
else {
response(res);
}
});
}
const open = (urls, closeIDs = []) => {
chrome.storage.local.get({
path: null,
closeme: false
}, prefs => {
const close = () => {
if (prefs.closeme && closeIDs.length) {
chrome.tabs.remove(closeIDs);
}
};
if (os.mac) {
if (prefs.path) {
const length = app.runtime.mac.args.length;
app.runtime.mac.args[length - 1] = prefs.path;
}
exec('open', [...app.runtime.mac.args, ...urls], r => response(r, close));
}
else if (os.linux) {
exec(prefs.path || app.runtime.linux.name, urls, r => response(r, close));
}
else {
if (prefs.path) {
exec(prefs.path, [...(app.runtime.windows.args2 || []), ...urls], r => response(r, close));
}
else {
const args = app.runtime.windows.args
.map(a => a.replace('%url;', urls.join(' ')))
// Firefox is not detaching the process on Windows
.map(s => s.replace('start', isFirefox ? 'start /WAIT' : 'start'));
exec(app.runtime.windows.name, args, res => {
// use old method
if (res && res.code !== 0) {
find(() => open(urls, closeIDs));
}
else {
response(res, close);
}
}, {windowsVerbatimArguments: true});
}
}
});
};
function delayOpen(tabs) {
chrome.storage.local.get({
multiple: app.multiple
}, prefs => {
if (prefs.multiple) {
return open(tabs.map(t => t.url), tabs.map(t => t.id));
}
const tab = tabs.shift();
if (tab) {
open([tab.url], [tab.id]);
window.setTimeout(delayOpen, 1000, tabs);
}
});
}
chrome.browserAction.onClicked.addListener(() => {
chrome.tabs.query({
active: true,
currentWindow: true
}, tabs => open(tabs.map(t => t.url), tabs.map(t => t.id)));
});
// context menu
{
const callback = () => {
chrome.contextMenus.create({
id: 'open-current',
title: app.locale.current,
contexts: ['link'],
documentUrlPatterns: ['*://*/*']
});
chrome.contextMenus.create({
id: 'open-all',
title: app.locale.all,
contexts: ['browser_action']
});
chrome.contextMenus.create({
id: 'open-call',
title: app.locale.call,
contexts: ['browser_action']
});
};
chrome.runtime.onInstalled.addListener(callback);
chrome.runtime.onStartup.addListener(callback);
}
chrome.contextMenus.onClicked.addListener(info => {
if (info.menuItemId === 'open-current') {
open([info.linkUrl || info.pageUrl], []);
}
else if (info.menuItemId === 'open-all') {
chrome.tabs.query({
url: ['*://*/*']
}, delayOpen);
}
else if (info.menuItemId === 'open-call') {
chrome.tabs.query({
url: ['*://*/*'],
currentWindow: true
}, delayOpen);
}
});
chrome.runtime.onMessage.addListener((request, sender) => {
if (request.cmd === 'open-in') {
open([request.url], [sender.tab.id]);
}
});
// FAQs & Feedback/* FAQs & Feedback */
{
const {management, runtime: {onInstalled, setUninstallURL, getManifest}, storage, tabs} = chrome;
if (navigator.webdriver !== true) {
const page = getManifest().homepage_url;
const {name, version} = getManifest();
onInstalled.addListener(({reason, previousVersion}) => {
management.getSelf(({installType}) => installType === 'normal' && storage.local.get({
'faqs': true,
'last-update': 0
}, prefs => {
if (reason === 'install' || (prefs.faqs && reason === 'update')) {
const doUpdate = (Date.now() - prefs['last-update']) / 1000 / 60 / 60 / 24 > 45;
if (doUpdate && previousVersion !== version) {
tabs.create({
url: page + '&version=' + version + (previousVersion ? '&p=' + previousVersion : '') + '&type=' + reason,
active: reason === 'install'
});
storage.local.set({'last-update': Date.now()});
}
}
}));
});
setUninstallURL(page + '&rd=feedback&name=' + encodeURIComponent(name) + '&version=' + version);
}
}
================================================
FILE: common/data/inject.js
================================================
'use strict';
const config = {
button: 0,
altKey: true,
ctrlKey: false,
shiftKey: true,
metaKey: false,
enabled: false,
hosts: [],
urls: [],
reverse: false,
topRedict: false
};
const validate = (a, callback, isTop = false) => {
if (config.hosts.length) {
const host = a.hostname;
if (host) {
if (config.hosts.some(h => h.endsWith(host) || host.endsWith(h))) {
return config.reverse ? '' : callback(a.href);
}
}
}
else {
const href = a.href;
if (href) {
if (config.urls.some(h => href.startsWith(h))) {
return config.reverse ? '' : callback(a.href);
}
}
}
// reverse mode
if (config.reverse && a.href && (a.href.indexOf('#') === -1 || isTop)) {
if (a.href.startsWith('http') || a.href.startsWith('file')) {
return callback(a.href);
}
}
};
chrome.storage.local.get(config, prefs => {
Object.assign(config, prefs);
// managed
chrome.storage.managed.get({
hosts: [],
urls: [],
reverse: false
}, prefs => {
if (!chrome.runtime.lastError) {
config.hosts.push(...prefs.hosts);
config.urls.push(...prefs.urls);
config.reverse = config.reverse || prefs.reverse;
}
// top level redirect
if (window.top === window && config.topRedict) {
validate(location, url => {
if (history.length) {
history.back();
}
else {
window.stop();
}
chrome.runtime.sendMessage({
cmd: 'open-in',
url
});
}, true);
}
// Gmail attachments
// https://github.com/andy-portmen/open-in/issues/42
if (window.top === window && location.hostname === 'mail.google.com') {
validate(location, () => {
const script = document.createElement('script');
script.textContent = `{
const script = document.currentScript;
const hps = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, 'src');
Object.defineProperty(HTMLIFrameElement.prototype, 'src', {
set(v) {
if (v && v.indexOf('&view=att&') !== -1) {
script.dispatchEvent(new CustomEvent('open-request', {
detail: v
}));
}
else {
hps.set.call(this, v);
}
}
});
}`;
script.addEventListener('open-request', e => {
e.stopPropagation();
chrome.runtime.sendMessage({
cmd: 'open-in',
url: e.detail
});
});
document.documentElement.appendChild(script);
script.remove();
}, true);
}
});
});
chrome.storage.onChanged.addListener(e => {
Object.keys(e).forEach(n => {
config[n] = e[n].newValue;
});
});
document.addEventListener('click', e => {
const redirect = url => {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
chrome.runtime.sendMessage({
cmd: 'open-in',
url
});
return false;
};
// hostname on left-click
if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
if (config.hosts.length || config.urls.length || config.reverse) {
let a = e.target.closest('a');
if (a) {
if (a.href.startsWith('https://www.google') && a.href.indexOf('&url=') !== -1) {
const link = decodeURIComponent(a.href.split('&url=')[1].split('&')[0]);
a = new URL(link);
}
validate(a, redirect);
}
}
}
// click + modifier
if (
config.enabled &&
e.button === config.button &&
e.altKey === config.altKey &&
e.ctrlKey === config.ctrlKey &&
e.metaKey === config.metaKey &&
e.shiftKey === config.shiftKey
) {
const a = e.target.closest('a');
if (a && a.href) {
return redirect(a.href);
}
}
}, true);
================================================
FILE: common/data/options/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>Open In Options</title>
<meta charset="UTF-8">
<style>
@supports (-moz-appearance:none) {
body {
font-size: 13px;
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
margin: 10px;
min-width: unset;
color: #424242;
background-color: #fff;
}
textarea {
padding: 5px;
}
button,
input[type=submit],
input[type=button] {
height: 24px;
color: #444;
background-image: linear-gradient(rgb(237, 237, 237), rgb(237, 237, 237) 38%, rgb(222, 222, 222));
box-shadow: rgba(0, 0, 0, 0.08) 0 1px 0, rgba(255, 255, 255, 0.75) 0 1px 2px inset;
text-shadow: rgb(240, 240, 240) 0 1px 0;
border: solid 1px rgba(0, 0, 0, 0.25);
}
input[type=button]:disabled {
opacity: 0.5;
}
h2 {
font-size: 110%;
font-weight: normal;
}
}
table.tbl {
width: 100%;
}
.tbl td:first-child {
width: 1px;
white-space: nowrap;
}
.tbl td:last-child {
text-align: right;
}
.admin {
background-color: #ffffed;
border: solid 1px #e8ec3a;
padding: 10px;
margin: 15px 0;
}
code {
background-color: rgba(0, 0, 0, 0.05);
padding: 0 3px;
}
code:empty::after {
content: 'not defined';
font-family: italic;
}
hr {
border: none;
border-top: dashed 1px #ccc;
}
h2 {
background-color: #e6e6e6;
padding: 5px;
}
ol {
padding-left: 1.8em;
}
li {
margin-bottom: 5px;
}
.grid {
display: grid;
grid-template-columns: 1fr min-content;
grid-gap: 5px;
}
</style>
</head>
<body>
<h2>Open With Keyboard-Mouse-Click Combinations</h2>
<table class="tbl">
<tr>
<td><label for="enabled">Enabled</label></td>
<td><input id="enabled" type="checkbox"></td>
</tr>
<tr>
<td>Mouse click<sup>4</sup></td>
<td>
<label>Ctrl <input id="ctrlKey" type="checkbox"></label> +
<label>Alt <input id="altKey" type="checkbox"></label> +
<label>Shift <input id="shiftKey" type="checkbox"></label> +
<label>Meta <input id="metaKey" type="checkbox"></label> +
<select id="button">
<option value=0>Left Click</option>
<option value=1 disabled="true">Middle Click</option>
<option value=2 disabled="true">Right Click</option>
</select>
</td>
</tr>
</table>
<h2>Open with Left-Click</h2>
<table class="tbl">
<tr>
<td colspan="2" style="text-align: left; white-space: normal;">Comma-separated list of domains to open with the external browser when the link is opened with left-click<sup>1</sup></td>
</tr>
<tr>
<td colspan="2"><textarea id="hosts" style="width: 100%" rows="3" placeholder="e.g.: www.google.com, bing.com"></textarea></td>
</tr>
<tr>
<td colspan="2" style="text-align: left; white-space: normal;">Comma-separated list of URLs to open with the external browser when the link is opened with left-click<sup>1</sup></td>
</tr>
<tr>
<td colspan="2"><textarea id="urls" style="width: 100%" rows="3" placeholder="e.g.: https://www.google.com/, https://bing.com/"></textarea></td>
</tr>
</table>
<div class="grid">
<label for="reverse">Reverse Mode<sup>5</sup></label>
<input type="checkbox" id="reverse">
<label for="topRedict">Consider even top-level navigation<sup>6</sup></label>
<input type="checkbox" id="topRedict">
</div>
<h2>Misc</h2>
<div class="grid">
<label for="closeme">Close the source tab when link is pushed</label>
<input type="checkbox" id="closeme">
<label for="multiple">Open multiple links at once<sup>3</sup></label>
<input type="checkbox" id="multiple">
<label for="faqs">Open FAQs page on updates</label>
<input type="checkbox" id="faqs">
</div>
<div>
<span style="margin-top: 10px; margin-bottom: 5px; display: block">Path to the executable<sup>2</sup>:</span>
<div style="display: flex;">
<input type="text" id="path" style="flex: 1;">
</div>
</div>
<div class="admin">This extension supports managed storage. Some of the preferences can be pre-configured by <a href="https://add0n.com/open-in.html#faq17">the domain administrator</a></div>
<div id="explore" data-inc=50></div>
<p>
<button id="reset">Reset Settings</button>
<button id="support">Support Development</button> - <button id="save">Save Options</button>
<span id="status"></span>
</p>
<hr style="margin: 10px 0">
<ol>
<li>It is possible to use "managed storage" to set the default host and URL list. This is useful for administrators to force opening a set of URLs or hostnames in another browser. Instruction on how to setup the managed storage can be found in the FAQs page.</li>
<li>On Windows, if the path to the executable is not provided (is empty) <code id="l2"></code> is used. On Linux, if the path is not set, it is assumed <code id="l3"></code> binary can be found in the global PATH environment. On Mac OS, <code>open -a</code> command is used (with <code id="l4"></code> as the application or whatever is in the input).</li>
<li>By activating this option all the requested URLs are sent to the external executable at once. Only activate this option if the external executable is capable of handling this type of requests.</li>
<li>Not all key combinations are allowed in all operating systems.</li>
<li>When enabled, all left-click links except the ones that match with at least one condition will be sent to the external executable.</li>
<li>If checked, the extension validates top-level navigation with the list of left-click hostnames and URLs. If matched, the URL is sent to the external executable, and the navigation is blocked.</li>
</ol style="padding-left: 1.8em;">
<script src="../../config.js"></script>
<script src="index.js"></script>
<script async src="matched.js"></script>
</body>
</html>
================================================
FILE: common/data/options/index.js
================================================
/* globals app */
'use strict';
document.title = 'Open In ' + app.locale.name + ' :: Options';
document.getElementById('path').placeholder = app.locale.example;
document.getElementById('l2').textContent = app.runtime.windows.prgfiles;
document.getElementById('l3').textContent = app.runtime.linux.name;
document.getElementById('l4').textContent = app.runtime.mac.args[1];
function restore() {
// Use default value color = 'red' and likesColor = true.
chrome.storage.local.get({
path: '',
enabled: false,
altKey: true,
shiftKey: true,
ctrlKey: false,
metaKey: false,
button: 0,
faqs: true,
closeme: false,
multiple: app.multiple,
hosts: [],
urls: [],
reverse: false,
topRedict: false
}, prefs => {
document.getElementById('path').value = prefs.path;
document.getElementById('enabled').checked = prefs.enabled;
document.getElementById('altKey').checked = prefs.altKey;
document.getElementById('shiftKey').checked = prefs.shiftKey;
document.getElementById('ctrlKey').checked = prefs.ctrlKey;
document.getElementById('metaKey').checked = prefs.metaKey;
document.getElementById('button').selectedIndex = prefs.button;
document.getElementById('faqs').checked = prefs.faqs;
document.getElementById('closeme').checked = prefs.closeme;
document.getElementById('multiple').checked = prefs.multiple;
document.getElementById('hosts').value = prefs.hosts.join(', ');
document.getElementById('urls').value = prefs.urls.join(', ');
document.getElementById('reverse').checked = prefs.reverse;
document.getElementById('topRedict').checked = prefs.topRedict;
});
}
function save() {
const path = document.getElementById('path').value;
const enabled = document.getElementById('enabled').checked;
const altKey = document.getElementById('altKey').checked;
const shiftKey = document.getElementById('shiftKey').checked;
const ctrlKey = document.getElementById('ctrlKey').checked;
const metaKey = document.getElementById('metaKey').checked;
const button = document.getElementById('button').selectedIndex;
const faqs = document.getElementById('faqs').checked;
const closeme = document.getElementById('closeme').checked;
const multiple = document.getElementById('multiple').checked;
const hosts = document.getElementById('hosts').value;
const urls = document.getElementById('urls').value;
const reverse = document.getElementById('reverse').checked;
const topRedict = document.getElementById('topRedict').checked;
chrome.storage.local.set({
path,
enabled,
altKey,
shiftKey,
ctrlKey,
metaKey,
button,
faqs,
closeme,
multiple,
hosts: hosts.split(/\s*,\s*/).map(s => s.replace('http://', '')
.replace('https://', '')
.split('/')[0].trim())
.filter((h, i, l) => h && l.indexOf(h) === i),
urls: urls.split(/\s*,\s*/).filter(s => s.startsWith('http') || s.startsWith('file'))
.filter((h, i, l) => h && l.indexOf(h) === i),
reverse,
topRedict
}, () => {
restore();
const status = document.getElementById('status');
status.textContent = 'Options saved.';
setTimeout(() => status.textContent = '', 750);
});
}
document.addEventListener('DOMContentLoaded', restore);
document.getElementById('save').addEventListener('click', save);
document.getElementById('support').addEventListener('click', () => chrome.tabs.create({
url: chrome.runtime.getManifest().homepage_url + '&rd=donate'
}));
document.getElementById('save').addEventListener('click', save);
document.getElementById('reset').addEventListener('click', e => {
if (e.detail === 1) {
const status = document.getElementById('status');
window.setTimeout(() => status.textContent = '', 750);
status.textContent = 'Double-click to reset!';
}
else {
localStorage.clear();
chrome.storage.local.clear(() => {
chrome.runtime.reload();
window.close();
});
}
});
================================================
FILE: common/schema.json
================================================
{
"type": "object",
"properties": {
"hosts": {
"title": "List of hosts",
"description": "List of domains to open with the external browser when the link is opened with left-click",
"type": "array",
"items": {
"type": "string"
}
},
"urls": {
"title": "List of URLs",
"description": "List of URLs to open with the external browser when the link is opened with left-click",
"type": "array",
"items": {
"type": "string"
}
},
"faqs": {
"title": "Open FAQs page on updates",
"type": "boolean"
},
"reverse": {
"title": "Enable reversed left-click mode",
"type": "boolean"
}
}
}
================================================
FILE: edge/README
================================================
moved to https://github.com/Rynu/open-in-edge/tree/master
================================================
FILE: palemoon/config.js
================================================
'use strict';
var app = {
id: 'com.add0n.node',
tag: 'palemoon',
multiple: true
};
app.locale = {
name: 'Pale Moon',
current: 'Open Link in Pale Moon Browser',
all: 'Open all Tabs in Pale Moon Browser',
call: 'Open all Tabs in Pale Moon Browser (Current window)',
example: 'example D:\\Pale Moon\\browser.exe'
};
app.runtime = {
mac: {
args: ['-a', 'Palemoon']
},
linux: {
name: 'palemoon'
},
windows: {
name: 'cmd',
args: ['/s/c', 'start', 'palemoon "%url;"'],
prgfiles: '%ProgramFiles(x86)%\\Pale Moon\\palemoon.exe'
}
};
================================================
FILE: palemoon/manifest.json
================================================
{
"name": "Open in Pale Moon",
"description": "Open current page, link, or all tabs in the Pale Moon browser.",
"version": "0.1.1",
"manifest_version": 2,
"permissions": [
"storage",
"tabs",
"contextMenus",
"nativeMessaging"
],
"optional_permissions": [
"downloads"
],
"background": {
"persistent": false,
"scripts": [
"config.js",
"common.js"
]
},
"storage": {
"managed_schema": "schema.json"
},
"homepage_url": "https://add0n.com/open-in.html?from=palemoon",
"icons": {
"16": "data/icons/16.png",
"32": "data/icons/32.png",
"48": "data/icons/48.png",
"64": "data/icons/64.png",
"128": "data/icons/128.png",
"256": "data/icons/256.png",
"512": "data/icons/512.png"
},
"browser_action": {},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["data/inject.js"],
"run_at": "document_start",
"all_frames": true,
"match_about_blank": true
}],
"options_ui": {
"page": "data/options/index.html",
"chrome_style": true,
"open_in_tab": true
}
}
================================================
FILE: vivaldi/config.js
================================================
'use strict';
var app = {
id: 'com.add0n.node',
tag: 'vivaldi',
multiple: true
};
app.locale = {
name: 'Vivaldi',
current: 'Open Link in Vivaldi Browser',
all: 'Open all Tabs in Vivaldi Browser',
call: 'Open all Tabs in Vivaldi Browser (Current window)',
example: 'example D:\\Vivaldi\\vivaldi.exe'
};
app.runtime = {
mac: {
args: ['-a', 'vivaldi']
},
linux: {
name: 'vivaldi'
},
windows: {
name: 'cmd',
args: ['/s/c', 'start', 'vivaldi "%url;"'],
prgfiles: '%LOCALAPPDATA%\\Vivaldi\\Application\\vivaldi.exe'
}
};
================================================
FILE: vivaldi/manifest.json
================================================
{
"name": "Open in Vivaldi",
"description": "Open current page, link, or all tabs in the Vivaldi browser.",
"version": "0.2.0",
"manifest_version": 2,
"permissions": [
"storage",
"tabs",
"contextMenus",
"nativeMessaging"
],
"optional_permissions": [
"downloads"
],
"background": {
"persistent": false,
"scripts": [
"config.js",
"common.js"
]
},
"storage": {
"managed_schema": "schema.json"
},
"homepage_url": "https://add0n.com/open-in.html?from=vivaldi",
"icons": {
"16": "data/icons/16.png",
"32": "data/icons/32.png",
"48": "data/icons/48.png",
"64": "data/icons/64.png",
"128": "data/icons/128.png",
"256": "data/icons/256.png",
"512": "data/icons/512.png"
},
"browser_action": {},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["data/inject.js"],
"run_at": "document_start",
"all_frames": true,
"match_about_blank": true
}],
"options_ui": {
"page": "data/options/index.html",
"chrome_style": true,
"open_in_tab": true
}
}
================================================
FILE: waterfox/config.js
================================================
'use strict';
var app = {
id: 'com.add0n.node',
tag: 'waterfox',
multiple: true
};
app.locale = {
name: 'Waterfox',
current: 'Open Link in Waterfox Browser',
all: 'Open all Tabs in Waterfox Browser',
call: 'Open all Tabs in Waterfox Browser (Current window)',
example: 'example D:\\Waterfox\\browser.exe'
};
app.runtime = {
mac: {
args: ['-a', 'Waterfox']
},
linux: {
name: 'waterfox'
},
windows: {
name: 'cmd',
args: ['/s/c', 'start', 'waterfox "%url;"'],
prgfiles: '%ProgramFiles(x86)%\\Waterfox\\waterfox.exe'
}
};
================================================
FILE: waterfox/manifest.json
================================================
{
"name": "Open in Waterfox",
"description": "Open current page, link, or all tabs in the Waterfox browser.",
"version": "0.1.1",
"manifest_version": 2,
"permissions": [
"storage",
"tabs",
"contextMenus",
"nativeMessaging"
],
"optional_permissions": [
"downloads"
],
"background": {
"persistent": false,
"scripts": [
"config.js",
"common.js"
]
},
"storage": {
"managed_schema": "schema.json"
},
"homepage_url": "https://add0n.com/open-in.html?from=waterfox",
"icons": {
"16": "data/icons/16.png",
"32": "data/icons/32.png",
"48": "data/icons/48.png",
"64": "data/icons/64.png",
"128": "data/icons/128.png",
"256": "data/icons/256.png",
"512": "data/icons/512.png"
},
"browser_action": {},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["data/inject.js"],
"run_at": "document_start",
"all_frames": true,
"match_about_blank": true
}],
"options_ui": {
"page": "data/options/index.html",
"chrome_style": true,
"open_in_tab": true
}
}
================================================
FILE: yandex/config.js
================================================
'use strict';
var app = {
id: 'com.add0n.node',
tag: 'yandex',
multiple: true
};
app.locale = {
name: 'Yandex',
current: 'Open Link in Yandex Browser',
all: 'Open all Tabs in Yandex Browser',
call: 'Open all Tabs in Yandex Browser (Current window)',
example: 'example D:\\Yandex\\browser.exe'
};
app.runtime = {
mac: {
args: ['-a', 'yandex']
},
linux: {
name: 'yandex'
},
windows: {
name: 'cmd',
args: ['/s/c', 'start', 'yandex "%url;"'],
prgfiles: '%LOCALAPPDATA%\\Yandex\\YandexBrowser\\Application\\browser.exe'
}
};
================================================
FILE: yandex/manifest.json
================================================
{
"name": "Open in Yandex browser",
"description": "Open current page, link, or all tabs in the Yandex browser.",
"version": "0.1.6",
"manifest_version": 2,
"permissions": [
"storage",
"tabs",
"contextMenus",
"nativeMessaging"
],
"optional_permissions": [
"downloads"
],
"background": {
"persistent": false,
"scripts": [
"config.js",
"common.js"
]
},
"storage": {
"managed_schema": "schema.json"
},
"homepage_url": "https://add0n.com/open-in.html?from=yandex",
"icons": {
"16": "data/icons/16.png",
"32": "data/icons/32.png",
"48": "data/icons/48.png",
"64": "data/icons/64.png",
"128": "data/icons/128.png",
"256": "data/icons/256.png",
"512": "data/icons/512.png"
},
"browser_action": {},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["data/inject.js"],
"run_at": "document_start",
"all_frames": true,
"match_about_blank": true
}],
"options_ui": {
"page": "data/options/index.html",
"chrome_style": true,
"open_in_tab": true
}
}
gitextract_pmrctrx2/
├── README.md
├── brave/
│ ├── config.js
│ └── manifest.json
├── chrome/
│ └── README
├── chromium/
│ └── README
├── common/
│ ├── common.js
│ ├── data/
│ │ ├── inject.js
│ │ └── options/
│ │ ├── index.html
│ │ └── index.js
│ └── schema.json
├── edge/
│ └── README
├── palemoon/
│ ├── config.js
│ └── manifest.json
├── vivaldi/
│ ├── config.js
│ └── manifest.json
├── waterfox/
│ ├── config.js
│ └── manifest.json
└── yandex/
├── config.js
└── manifest.json
SYMBOL INDEX (7 symbols across 2 files)
FILE: common/common.js
function error (line 10) | function error(response) {
function response (line 19) | function response(res, success = () => {}) {
function exec (line 49) | function exec(command, args, callback, properties = {}) {
function find (line 64) | function find(callback) {
function delayOpen (line 126) | function delayOpen(tabs) {
FILE: common/data/options/index.js
function restore (line 10) | function restore() {
function save (line 45) | function save() {
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (33K chars).
[
{
"path": "README.md",
"chars": 489,
"preview": "# open-in\nSend URLs from one browser to another one\n\n## browser-specific projects\n\n* [open-in-chromium](https://github.c"
},
{
"path": "brave/config.js",
"chars": 599,
"preview": "'use strict';\n\nvar app = {\n id: 'com.add0n.node',\n tag: 'brave',\n multiple: true\n};\n\napp.locale = {\n name: 'brave',\n"
},
{
"path": "brave/manifest.json",
"chars": 1133,
"preview": "{\r\n \"name\": \"Open in Brave Browser\",\r\n \"description\": \"Open current page, link, or all tabs in the Brave browser\",\r\n "
},
{
"path": "chrome/README",
"chars": 57,
"preview": "moved to https://github.com/andy-portmen/open-in-chrome/\n"
},
{
"path": "chromium/README",
"chars": 59,
"preview": "moved to https://github.com/andy-portmen/open-in-chromium/\n"
},
{
"path": "common/common.js",
"chars": 5998,
"preview": "/* globals app */\n'use strict';\n\nconst os = {\n mac: navigator.userAgent.indexOf('Mac') !== -1,\n linux: navigator.userA"
},
{
"path": "common/data/inject.js",
"chars": 3893,
"preview": "'use strict';\n\nconst config = {\n button: 0,\n altKey: true,\n ctrlKey: false,\n shiftKey: true,\n metaKey: false,\n ena"
},
{
"path": "common/data/options/index.html",
"chars": 6164,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <title>Open In Options</title>\n <meta charset=\"UTF-8\">\n <style>\n @supports (-moz-ap"
},
{
"path": "common/data/options/index.js",
"chars": 3974,
"preview": "/* globals app */\n'use strict';\n\ndocument.title = 'Open In ' + app.locale.name + ' :: Options';\ndocument.getElementById("
},
{
"path": "common/schema.json",
"chars": 709,
"preview": "{\n \"type\": \"object\",\n \"properties\": {\n \"hosts\": {\n \"title\": \"List of hosts\",\n \"description\": \"List of dom"
},
{
"path": "edge/README",
"chars": 58,
"preview": "moved to https://github.com/Rynu/open-in-edge/tree/master\n"
},
{
"path": "palemoon/config.js",
"chars": 575,
"preview": "'use strict';\n\nvar app = {\n id: 'com.add0n.node',\n tag: 'palemoon',\n multiple: true\n};\n\napp.locale = {\n name: 'Pale "
},
{
"path": "palemoon/manifest.json",
"chars": 1137,
"preview": "{\r\n \"name\": \"Open in Pale Moon\",\r\n \"description\": \"Open current page, link, or all tabs in the Pale Moon browser.\",\r\n "
},
{
"path": "vivaldi/config.js",
"chars": 566,
"preview": "'use strict';\n\nvar app = {\n id: 'com.add0n.node',\n tag: 'vivaldi',\n multiple: true\n};\n\napp.locale = {\n name: 'Vivald"
},
{
"path": "vivaldi/manifest.json",
"chars": 1132,
"preview": "{\r\n \"name\": \"Open in Vivaldi\",\r\n \"description\": \"Open current page, link, or all tabs in the Vivaldi browser.\",\r\n \"ve"
},
{
"path": "waterfox/config.js",
"chars": 569,
"preview": "'use strict';\n\nvar app = {\n id: 'com.add0n.node',\n tag: 'waterfox',\n multiple: true\n};\n\napp.locale = {\n name: 'Water"
},
{
"path": "waterfox/manifest.json",
"chars": 1135,
"preview": "{\r\n \"name\": \"Open in Waterfox\",\r\n \"description\": \"Open current page, link, or all tabs in the Waterfox browser.\",\r\n \""
},
{
"path": "yandex/config.js",
"chars": 571,
"preview": "'use strict';\n\nvar app = {\n id: 'com.add0n.node',\n tag: 'yandex',\n multiple: true\n};\n\napp.locale = {\n name: 'Yandex'"
},
{
"path": "yandex/manifest.json",
"chars": 1137,
"preview": "{\r\n \"name\": \"Open in Yandex browser\",\r\n \"description\": \"Open current page, link, or all tabs in the Yandex browser.\",\r"
}
]
About this extraction
This page contains the full source code of the andy-portmen/open-in GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (29.3 KB), approximately 8.7k tokens, and a symbol index with 7 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.